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

한빛출판네트워크

IT/모바일

프로그래밍 스타일(6)

한빛미디어

|

2005-10-14

|

by HANBIT

14,191

저자: 한동훈

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

2.7 명명 규칙

명명규칙에는 많은 것들이 있다. 지역 변수, 모듈 변수, 전역 변수와 같이 변수의 범위를 지정하는 헝가리안 표기법도 있고, 파스칼식의 변수 명명법도 있고, 낙타혹 표기법도 있고, _을 이용한 표기법, Perl의 세계에서만 쓰이는 표기법등 그 표기법도 셀 수 없이 많다. 어떤 표기법이 가장 좋다는 생각은 옮지않다. 어떤 프로그래머들은 헝가리안 표기법이야말로 써서는 안되는 그야말로 쓰레기 표기법이라고 혹평하고 있으며, 다른 프로그래들, 그들 대부분은 윈도우 프로그래머인,은 헝가리안 표기법이야말로 단순하면서 사용하기 쉬운 표기법이라고 한다.

그만큼 명명규칙에는 많은 논쟁이 있다. 필자는 어떤 것이 옳다고 얘기할 수 없다. 다만, 자신의 마음에 들면 쓰고, 마음에 들지 않으면 쓰지 마라. 그리고 이 부분은 자신의 프로그래밍 경험이 쌓여감에 따라서 다시 한 번 펼쳐보고 다시 한 번 생각해보는 것으로 자신의 방법을 세워나가길 바란다. (이점에 있어서는 필자도 마찬가지다.)


2.7.1 변수의 범위를 정하는 표기법을 사용하라

대부분의 언어에서 헝가리안 표기법을 사용하는 것은 바람직하다. 전역변수를 뜻하는 g, 멤버 변수, 즉 클래스 전체에서 쓰이는 변수를 뜻하는 m과 이러한 접두어가 붙지 않는 지역변수와 같이 변수의 범위에 따라 나누는 것도 적절하다.

헝가리안 표기법이 싫다면, 변수명 전체를 대문자로 쓰거나 변수의 첫번째 글자만을 대문자로 쓰는 것과 같은 표기법으로 전역 변수라는 것을 나타낼 수 있다. 코드로 표현하면 다음과 같을 것이다.

PAY_METHOD
Pay_Method
PAYMETHOD
PayMethod

이러한 변수 표기법을 써도 좋다. 전역 변수를 PayMethod와 같이 첫글자를 대문자로 쓰기로 했다면 지역 변수들은 payMethod와 같이 첫글자를 무조건 소문자로 시작하는 것도 좋은 방법이다.

헝가리안 표기법은 변수의 범위외에 변수의 타입을 접두어로 표기한다. 문자열에 대해서는 str을 쓰거나 객체에 대해서는 obj, long 타입에 대해서는 lng 등을 사용하고, 컨트롤에 대해서는 cmd, lst등의 여러가지 접두어를 사용한다.

헝가리안 표기법을 따르기로 했다면 이러한 표기를 따르도록 하고, 만약 다른 접두어를 사용하려 한다면 팀원간에 협의하에 다른 접두어를 사용하도록 한다.

예를 들어서 필자는 예전에는 레코드셋 객체에 대해서 objRsEmployee와 같이 사용했지만, 현재는 rsEmployee와 같은 접두어를 사용한다. rs와 같은 접두어를 사용한다면 이러한 표기법에 대해서 팀원간에 의견을 나누고 문서로 만들어서 팀원 모두가 공유하여야한다.

헝가리안 표기법을 따르는 것과 따르지 않는 것은 여러분의 자유다. 그러나 어떤 프로젝트에서 사용할 표기법을 만들고, 팀원간에 그 표기법을 공유해야한다. 또한, 프로젝트 진행중에 그 표기법에서 문제점이 나타나더라도 표기법을 변경해서는 안된다. 이미 진행된 프로젝트는 정한 표기법에 따라서 진행하고, 나타난 문제점은 프로젝트가 끝난 다음에 분석하여 다음 프로젝트를 위해서 보다 다듬어진 표기법을 만들도록 한다.

2.7.1.1 헝가리안 표기법의 쇠퇴

앞에서도 말했지만 기존의 코드에 자신의 코드를 추가해야하는 경우에는 자신의 스타일 보다는 기존 코드와의 조화가 중요하기 때문에 기존 코드의 스타일을 따라야한다고 했다. 때문에 MFC는 헝가리안 표기법을 사용하고 있고, Win32 API로 헝가리안 표기법을 따르기 때문에 대부분의 MFC 프로그래머는 헝가리안 표기법을 따르고 있다.

그러나 Java/C#을 비롯한 언어들은 타입에 있어 엄격한 언어이며, 개발툴에서는 이런 특성을 쉽게 이용할 수 있기 때문에 헝가리안 표기법을 사용하지 않아도 쉽게 변수의 타입을 알 수 있기 때문에 헝가리안 표기법을 사용하지 않는다. 또한, C# 클래스 라이브러리 개발자를 위한 가이드라인 문서를 보아도 헝가리안 표기법을 사용하지 않고 파스칼 명명법을 사용하라고 되어 있다.

C 언어에서도 typedef를 이용해서 특정 유형의 자료 구조에 대한 연산은 모두 typedef로 선언된 타입을 이용한다. 때문에, 헝가리안 표기법은 윈도우 프로그래밍인 경우에만 널리 쓰이고 있다.

2.7.2 변수의 이름은 최대한 알기 쉽게 해라

어떤 변수 이름이 알기 쉬운 것인가? 라는 것에도 의견이 다르다.
종업원 수에 대해서 변수명을 지어보라고 하면 사람들마다 다른 변수명을 내놓을 것이다.

iEmployee, employee, NumEmployee, NumberEmployee, NumberOfEmployee, EmployeeNumber, EmployeeNo와 같이 다양하게 될 것이다.

숫자라는 것을 뜻하는데 num, no, number, numberof가 쓰일 수도 있고, 여기에 헝가리안 표기법과 같은 접두어가 더해지면 문제는 더욱 더 다양해진다.

대부분의 경우에 num, no와 같은 축약형은 사람들마다 선호하는 축약형이 다르기 때문에 문제를 복잡하게 만들기 때문에 적절하지 않다. NumberOf와 같은 것들도 임의적인 것들이기에 적합한 것은 아니다. 대부분의 경우에 NumberEmployee나 EmployeeNumber와 같은 것들을 쓰는 것이 적당하다. 리눅스 커널을 작성한 라이너스(Linus Torvalds)는 숫자에 대해서 전역상수는 NR_로, 변수는 nr_로 시작하는 명명법을 사용하고 있다. 이 명명규칙은 리눅스 커널 전반에 걸쳐 일관되게 사용되고 있다.

축약형을 사용하기로 했다면 항상 축약형만을 사용해야 한다. 이에 대해서는 2.7.2.1을 살펴본다.

2.7.2.1 축약형에 대한 규칙

읽기 쉬운 변수명도 중요하지만 굉장히 긴 함수명을 입력하는 것도 괴로운 일일 것이다.
.NET Framework를 보면 다음과 같은 함수가 있다.

txtResult.Text = FormsAuthentication.
      HashPasswordForStoringInConfigFile(
                  txtValueToHash.Text, "sha1");

필자가 아는 범위에서는 닷넷에서 가장 긴 함수 이름중에 하나에 속할 것이다. HashPasswordForStoringInConfigFile() 이라는 함수는 굉장히 길다.

이런 극단적인 경우는 아니더라도 Password에 대해서는 Pwd로 사용한다던가, Document에 대해서는 Doc, Employee에 대해서는 Emp와 같은 축약형을 사용할 수 있을 것이다. 축약형이 필요한 경우에는 팀내 협의를 거쳐서 그에 대한 공통된 지침을 만들어서 사용해야 한다. 축약형을 사용하기로 결정했다면 Pwd만 쓰여야지 Password가 쓰여서는 안된다.

2.7.3 성격에 따라 명명하라

성격에 따른 명명법은 변수보다는 주로 클래스 파일이나 모듈 파일의 명명에 많이 사용하게 되지만, 변수 또한 다르지 않다.

다음과 같은 두 가지 코드에 대해서 한 번 생각해 보자.

ProvinceCodeAdd
UserJobCodeAdd
UserResidenceCodeAdd
UserAdd

AddProvinceCode
AddUserJobCode
AddUserResidenceCode
AddUser

첫번째와 두번째는 모두 다르다. 첫번째는 어떤 대상이 중심이 되는 명명법이고, 두번째는 어떤 행위가 중심이 되는 명명법이다. 필자는 첫번째와 같은 명명법은 주로 변수명에 사용한다. 물론, 변수명이니 뒤에 붙은 Add는 뺀다. 이러한 명명법을 사용하는 경우는 UserName, UserAge, UserPhoneNumber와 같이 어떤 대상을 위주로 명명하는 경우다. 객체에서 클래스를 명명하는 경우에는 User.Name, User.Age, User.PhoneNumber와 같이 명명하게 되고, 이러한 속성들의 값은 UserName, UserAge, UserPhoneNumber등에 저장하는 습관을 같고 있다.

두번째와 같이 주로 어떤 행위에 대해서 명명하는 경우에는 대부분 모듈이나 함수명이 된다. 어떤 행위에 해당하는 동사를 앞으로 두는 것으로 코드를 찾는 것이 쉬워지고, 코드를 유추하는 것도 쉽다. PrintPage, PrintScreen과 같이 Print + "Print할 디바이스 명"의 형식으로 사용한다.

2.7.4 클래스의 표기법을 통일하라

조금 이상하게 들릴지 모르지만, 프로젝트가 보다 큰 프로젝트라면 하나의 팀에서 모든 작업이 이루어지지 않고, 팀별간에 작업이 나누어지게 된다. 객체지향 언어를 사용하기로 결정했다면, 클래스의 속성, 메소드의 표기법에 대해서 일관성을 갖도록 한다.

여기에는 약간의 문제점이 있다. 팀전체가 다른 팀의 소스까지 모두 볼 수 있도록 전체에서 일관된 코딩 스타일을 사용할 것인가, 아니면 팀내에서는 개개인 각자의 코딩 스타일을 그대로 사용하지만 클래스에서 노출되는 메소드 명명법에 대해서 일관된 스타일을 사용할 것인가라는 것이다.

많은 사람들은 객체 지향 프로그래밍이고, 클래스의 내부에 대해서 신경쓰지 않아도 되고, 각자의 코딩 스타일을 지켜(?)나갈 수 있으므로 두번째를 좋아할지도 모른다. 물론, 두번째를 써도 된다. 그러나 개인적으로는 팀간에 소스 코드를 공유하고, 수정하는 일이 없더라도 소스 코드에 대해서도 일관된 스타일을 사용하는 것이 좋다.

필자는 전체가 일관된 스타일을 쓰는 곳에서 일을 할 때, 그 스타일을 익히는 것은 다소 짜증나고 귀찮았지만, 익숙해지고 몇 개의 프로젝트를 끝낸 다음에, 다른 팀의 완전히 다른 소스를 넘겨받아서 프로젝트를 진행하게 되었을 때도 편하게 코드를 읽을 수 있었고, 코드에서 사용된 흐름도, 코드 체계, 코드 설명에 대한 문서들을 찾는 방법을 알고 있었고, 코드에서 이 부분은 어떤 것을 처리하는 부분인지 쉽게 알 수 있었다.

예를 들면, 이런거다. 1000번대 이름을 갖는 코드들은 현금 계정을 처리하는 코드들이고, 2000번대 이름을 갖는 코드들은 물자 계정을 처리하는 코드들이라는 것이며, S로 끝나는 코드들은 어떤 데이터들의 요약을 행하는 코드들이라는 것과 같은 것이다. 물론, 코드안에 사용된 변수들도 이러한 통일된 규칙을 갖고 있었기 때문에 전혀 다른 업무를 처리하는 프로그램이지만 무리없이 코드를 분석하고 일을 진행할 수 있었다.

2.8 if의 스타일

if, select와 같은 분기문을 사용할 때는 항상 중첩된 분기문을 쓰지 않도록 해야한다. 분기문 내의 코드가 길어지면 길어질수록 코드 중간에 나오는 else와 같은 문장이 어떤 if에 속한 것인지 이해하기가 어렵게 된다.

If 조건문
   아주 긴 코드
   ...
   ...
   ...

else
   코드
end if

이와 같은 구조를 갖는 코드가 있다면 else 부분에 있는 조건문을 if에 있는 조건문과 바꾸는 것이 좋다.

If 조건문
   코드
else
   아주 긴 코드
   ...
   ...
   ...
end if

이와 같이 하는 것이 더 코드를 이해하기 쉽도록 해준다. 또한 if 문과 else 문에는 반드시 어떠한 조건이 일어나는 경우에 분기가 일어나는지 주석을 달아야한다. 종종, 바쁘다는 이유만으로 If나 else에 주석을 생략하거나 간략하게 달아놓은 경우 한참 시간이 흘러서 다시 보게되면 무엇을 판단하는 것인지 이해하기 어려운 경우가 많다. 그래서 어떤 경우에 분기가 일어나는지 이해하는 데 주석을 다는 것보다 더 많은 시간이 걸린다. 대개의 경우에 충분한 주석을 다는 것으로 디버깅시에 여러분의 노력은 충분한 보상을 받을 것이다.

if에 주석을 다는 경우에는 개인적으로 다음과 같은 주석 스타일은 바람직하지 않다.

If 조건문 // 이것은 주석입니다.

대개의 경우에 이것은 간단한 주석인지 모르나, 조건문이 길어지는 경우에 80 컬럼을 넘어가게된다. 모든 프로그래머가 여러분과 같이 80 컬럼이상을 표시하는 디스플레이와 에디터에서 작업하는 것은 아니다. 또한, 필자처럼 1280*1024나 1600*1200과 같은 높은 해상도에서 작업하는 것은 아닐것이다. 여러분의 코드를 보게될 다른 사람을 배려하도록 한다. 개인적으로 만든것이라 하더라도, 누군가는 언젠가 여러분의 코드를 보게 된다.

분기문에는 다음과 같은 주석을 쓰는 것이 좋다.

// trax가 술에 취한 경우에 실행되는 부분입니다.
If 조건문

개인적으로 코드의 주석을 소설처럼 읽듯이 코드를 읽는 경우가 아니라, 코드에 쓰인 조건문이 너무 많아서 코드 전체가 분기문으로 뒤덮인 경우에는 코드에 보다 집중하기 위해 다음과 같은 주석 스타일을 쓰기도 한다.

If 조건문
// trax가 술에 취한 경우에 실행되는 부분입니다.

두 가지의 차이는 첫번째는 주석을 보고 코드를 이해하기 좋다는 것이고, 두번째는 코드에 대해서 이미 잘 알고 있고, 주석보다는 코드의 로직을 판단하는데 더 용이하다는 것이다. 시선이 가장 먼저 가는 것에 따른 차이다. 그러나 대개의 경우에는 첫번째와 같은 주석을 쓰는 것이 좋다.

2.9 함수의 길이

컴퓨터 세계에서 가장 길이길이 남겨진 이야기중에 하나는 아주 크고, 어려운 문제가 있다면 그것을 잘게 쪼개고, 하나씩 해결해 나가다보면 전체를 해결할 수 있다는 것이다. 영어로 쓰면 Divide and Conquer! 라던가?

보통 클래스 전체를 작성하는 경우가 아니라 특정 함수만을 작성하거나 함수를 수정하는 경우에 새로운 주석을 작성한다. 함수의 기능에 대한 주석을 작성할 때, 한 두줄 이내로 함수의 기능이 무엇인지 설명하지 못한다면 함수에 지나치게 많은 기능이 있는 것이다. 이러한 경우에는 좋지못한 함수를 작성한 것이다. 함수는 작고 간결해야한다. 모든 기능을 갖고 있는 만능 함수는 복잡하고 이해하기 어렵기 때문에 버그를 갖기 쉬우며, 유지보수하기 어렵다. 따라서, 함수의 기능을 한 두줄 이내로 설명하기 어렵다면, 설계자에게 설계가 잘못된 것인지 문의해서 확인할 필요가 있고, 설계를 수정해야한다.

대부분의 모듈들이 1,000 - 2,000 라인 정도의 길이를 갖고 있었는데, 그중에 한가지 모듈만이 가장 많은 처리를 하고 있었고, 18,000 라인 정도의 길이로, 다른 코드들에 비해서 10배 이상이나 긴 코드를 갖고 있었다. 결국, 다른 모듈들에 발생한 버그들은 쉽게 처리할 수 있었지만, 모든 기능을 갖고 있는 18,000 라인을 갖고 있는 모듈에서 버그가 발생하면 몇시간이 아니라 며칠에 걸쳐서 디버깅을 해야했던 경험이 있다.

단 몇 줄의 코드를 작성하더라도 여러분이 생각지 못한 버그는 반드시 있다. 그렇다면 여러분은 단 몇시간동안 디버깅하겠는가, 머리를 싸매며 며칠동안 디버깅하겠는가?(야근 필수다~ ^^;)

2.10 들여쓰기 형식

들여쓰기에 대해서는 많은 사람들이 다르게 생각할 것이다. 아마, 아주 구시대 프로그래머들에게는 들여쓰기는 탭의 기본 간격인 8칸일 것이고, COBOL 프로그래머들은 7번째 칸부터 시작하면 주석, 8번째 칸부터 시작하면 데이터 타입 선언과 같은 규칙을 따라야할 것이다.

결국 들여쓰기는 언어에 따라서, 여러분의 취향에 따라서 선택사항이다. 8칸 들여쓰기를 고수하는 사람도 있고, 4칸 들여쓰기, 2칸 들여쓰기를 좋아하는 사람도 있다. 필자는 대부분의 언어에서 2칸 들여쓰기를 좋아한다. 그러나 어떤 사람은 3칸 들여쓰기를 좋아하기도 한다. 어떤 들여쓰기를 하건간에 해당 프로젝트에서는 정해진 들여쓰기 간격을 지켜야한다.

탭 간격을 조정하거나 여백 문자로 바꿀 수 있는 적절한 에디터를 사용하도록 한다. 그렇게 하지 않으면 이러한 탭 여백을 변경할 수 없는 에디터에서는 코드의 들여쓰기가 엉망이 된 채 표시되고, 아무리 간단한 코드라도 이해할 수 없게 된다.

연구 결과에 의하면 3칸 들여쓰기를 사용할 때 코드를 가장 읽기 쉽다고 한다. VI에서는 ~/.vimrc로 설정을 제어할 수 있다. 다음은 VI에서 자주 사용되는 설정들이다.

set tabstop=2
set shiftwidth=2
set expandtab
set backspace=indent,eol,start
set softtabstop=2
set cindent
set autoindent
set smartindent
set incsearch
syntax on
set background=dark
set joinspaces
set smarttab
set showmatch " (), {}, []괄호 매치를 보여준다
TAG :
댓글 입력
자료실