프로그램 코딩 시 네이밍 규칙과 들여쓰기

Programming 2011. 1. 21. 10:56 Posted by 알 수 없는 사용자


이 네이밍 규칙은 닷넷 스파이더 팀에서 만든 [C# Coding Standards and Best Programming Practices]를 바탕으로 만들었습니다.
 
1. 네이밍 관례와 표준
   
이 문서 전반에 걸쳐 파스칼 표기법카멜 표기법이 사용된다.  
- 파스칼 표기법 : 모든 단어에서 첫번째 문자가 대문자이며 나머지는 소문자이다(예: BackColor).
- 카멜 표기법 : 최초에 사용된 단어를 제외한 첫번째 문자가 대문자이며 나머지는 소문자이다(예: backColor).

1.1. 클래스 명에는 파스칼 표기법을 사용한다.


public class HelloWorld
{

...

}


1.2. 함수(Method) 명에는 파스칼 표기법을 사용한다.


void SayHello(string name)
{

...

}

  
1.3. 변수와 함수 파라미터에는 카멜 표기법을 사용한다.

int totalCount = 0;
void SayHello(string name)
{

string fullMessage = "Hello " + name;

...

}


1.4. 인터페이스에는 접두사 "I"가 포함된 파스칼 표기법을 따른다.

예 : IEntity

1.5. 변수명에 헝가리안 표기법을 사용하지 않는다.

이전에는 많은 프로그래머들이 변수명에 데이터 타입에 해당하는 접두사를 첨가하였다. 즉, 멤버변수에는 아래와 같이 m_ 을 접두사로 사용하는 것과 같은 헝가리안 표기법을 사용했었다.

string m_sName;
int nAge;


그러나 닷넷 코딩 표준에서 헝가리안 표기법은 추천하지 않는다. 데이터 타입을 사용하는 것과 멤버 변수를 표현하기 위한 m_ 은 사용해서는 안된다. 모든 변수는 카멜 표기법을 사용해야 한다. 몇몇 프로그래머들은 아직 m_ 을 붙이거나 데이터 타입을 표시하는 것을 더 좋아하겠지만, 이제 이것들은 멤버 변수를 확인하기 위한 쉬운 방법이 아니다.
 
1.6. 변수에 모든 의미를 충분히 담아라(약어를 사용하지 말것).

- 좋은 예
  string address
  int salary

- 나쁜 예
  string nam
  string addr
  int sal
 
1.7. "i, n, s,..."같이 한 글자로 된 이름을 사용하지 말것.

i, n, s 보다는 index, temp 와 같은 이름을 사용한다.

한 가지 예외가 있다면 루프에서 반복을 의미하는 변수를 하용하는 경우이다.

for ( int i = 0; i < count; i++ )
{

...

}


만일 변수가 단지 반복을 위한 카운터로만 사용 된다면, 그리고 그것이 루프 안에 있는 다른 어떤 곳에서도 사용되지 않는다면, 많은 사람들은 아직까지 다른 적합한 단어를 만들어서 사용하는 것보다 i 를 사용하는 것을 선호한다.
 
1.8. 지역변수와 멤버변수는 변수명 앞에 밑줄(_)을 사용하여 구별한다. 

지역변수에는 변수명 앞에 밑줄을 사용하지 않는다.
멤버변수에는 m_ 과 같은 헝가리안 표기법을 사용하는 대신 밑줄을 사용하여 지역변수와 구별한다.

1.9. 키워드와 비슷한 이름을 하용하지 말것.

1.10. boolean 이 들어가는 변수, 속성, 함수(method)등은 "is" 또는 유사한 접두사를 사용한다.

예 : private bool _isFinished
 
1.11. 네임스페이스 명은 표준 패턴을 따라야 한다.

<회사명>.<제품명>.<최상위모듈>.<하위모듈>

1.12. UI 구성요소를 위해 적당한 접두사를 사용한다.

UI 구성요소를 적당한 접두사를 사용하여 다른 변수들과 구분할 수 있어야 한다.
여기서 추천하는 서로 다른 두 가지 방식이 있다.
   
1.12.1. 모든 UI 구성요소를 위하여 공통적인 접두사(ui_)를 사용한다.

이것은 모든 UI 구성요소를 묶는데 도움을 줄 것이고, 쉽게 이해하고 접근할 수 있도록 도와 줄 것이다.

1.12.2. 각각의 UI 구성요소마다 접두사를 적용한다.

간단한 목록이 아래에 있다. 닷넷은 다양한 컨트롤들이 제공되므로 더 많은 컨트롤(써드파티 컨트롤을 포함한)에 대한 표준을 정의해야 한다.

      Control       Prefix       Control       Prefix       Control       Prefix
 Label          lbl  ListBox          lst  Image          img
 TextBox          txt  DataList          dtl  Panel          pnl
 DataGrid          dtg  Repeater          rep  PlaceHolder          phd
 Button          btn  CheckBox          chk  Table          tbl
 ImageButton          imb  CheckBoxList          cbl  Validators          val
 Hyperlink          hlk  RadioButton          rdo           -           -
 DropDownList          ddl  RadioButtonList          rbl           -           -

1.13. 파일 명은 클래스 명과 같아야 한다.

예를 들어, 클래스 명이 "HelloWorld" 라면 파일명은 "HelloWorld.cs" 이어야 한다.
 
1.14. 파일 명은 파스칼 표기법을 사용한다.

메서드나 함수 이름은 반드시 동사이면서 소문자로 시작해 대소문자를 섞어 써야 한다.

getName(), computeTotalWidth()


C++ 개발 커뮤니티에서 일반적인 용례이다. 이 형식은 변수 이름과 같지만  C++ 에서 함수는 형식상 변수와 이미 구별된다. 약어와 동의어를 이름으로 사용할 때는 반드시 대문자가 아니어야 한다.

exportHtmlSource();    // 잘못된 경우 : exportHTMLSource();
openDvdPlayer();        // 잘못된 경우 :  openDVDPlayer();


기본 이름에 대해 모두 대문자를 사용하면 위에서 제시한 명명 규칙과 충돌한다. 이런 종류의 변수는 dVD, hTML 등으로 이름 지어야 하나 분명 가독성이 매우 나쁘다. 위의 예에서 보여준 다른 문제는 이런 이름을 다른 것과 붙여 사용할 때 가독성이 심각하게 나빠진다는 점이다. 즉, 약어 다음에 오는 단어가 원하는 만큼 돋보이지 않게 된다.

* 특정한 명명규칙

1.15. get/set은 반드시 속성(attribute)에 직접 접근할 때 사용한다.

C++ 개발 커뮤니티에서 일반적인 용례이며, 자바에서는 거의 표준이 되었다.

employee.getName();
employee.setName(name);

matrix.getElement(2, 4);
matrix.setElement(2, 4, value);

  
1.16. compute는 무언가 계산하는 메서드에서 사용한다.

valueSet->computeAverage();
matrix->computeInverse();


이 것은 시간을 소비할 수 있는 연산이라는 것을 즉시 알아챌 수 있는 단서를 제공해 반복해서 사용한다면 결과를 따로 저장해 두는 것을 고려하도록 할 수 있다. 이처럼 용어를 일관되게 사용하면 가독성을 향상시키게 된다.

1.17. find는 무언가를 찾는 메서드에서 사용한다.

vertex.findNearestVertex();
matrix.findMinElement();


최소한의 계산이 포함된, 간단한 검색 메서드라는 것을 즉시 알아챌 수 있는 단서를 다른 개발자에게 제공한다.
  
1.18. initialize는 객체 또는 개념을 만들 때 사용한다.

printer.initializeFontSet();


영국어 initialise보다 미국어 initialize를 사용해야 하며, 약어 init 는 피하도록 한다.

1.19. GUI 요소(component)를 나타내는 변수는 해당 요소 타입 이름을 접미어로 사용한다.

mainWindow, propertiesDialog, widthScale, loginText, leftScrollbar, mainForm, fileMenu, minLabel, exitButton, yesToggle, 등...


해당 변수 타입을 통해 리소스 객체를 즉시 알아챌 수 있는 단서를 사용자에게 제공하므로 가독성을 향상시킨다.

1.20. 복수형은 객체 모음(collection)을 나타내는 이름에 사용해야 한다.

vector <Point>  point;
int  values[];


변수 타입과 더불어 해당 요소에 수행할 수 있는 연산을 즉시 알아챌 수 있는 단서를 사용자에게 제공하므로 가독성을 향상시킨다.

1.21. 접두어 n 은 객체 수를 나타내는 변수에 사용한다.

nPoints, nLines


객체 수를 나타내는 이 관례적인 표기법은 수학에서 가져왔다.

1.22. 접미어 "No"는 독자적인(Entity) 번호를 나타내는 변수에 사용한다.

tableNo, employeeNo


Entity 번호를 나타내는 이 관례적인 표기법은 수학에서 가져왔다.

세련된 다른 방법은 iTable, iEmployee 처럼 접두어 i 를 붙이는 것이며, 이를 통해 효과적으로 그런 변수를 명명된 반복자로 만들 수 있다.
  
1.23. 반복자 변수는 i, j, k 등으로 호출한다.

for ( int i = 0 ; i < nTables ; i++ )
{

...

}

for ( vector<MyClass>::iterator i = list.begin() ; i != list.end() ; i++ )
{

Element element = *i;

...

}


반복자를 나타내는 이 관례적인 표기법은 수학에서 가져왔다. 변수 이름으로 i 를 제외한 j, k 등은  중첩 루프에서만 사용한다. (옮긴이 주: 이 표기법은 되도록 간단한 루프에서만 사용하고 복잡하거나 긴 루프에서는 의미있는 이름을 사용하는 게 좋다.)

1.24. 접두어 is는 Boolean 변수와 메서드에서 사용한다.

isSet, isVisible, isFinished, isFound, isOpen


C++ 개발 커뮤니티에서 일반적이며, 자바에서는 일부분에서 강제하는 용례이다. 접두어 is를 사용하면 status나 flag처럼 좋지 못한 불린 이름을 선택하는 흔한 문제를 해결할 수 있다. 사실 isStatus나 isFlag는 적절하지 못하므로 더 의미있는 이름을 선택해야 한다.

다음은 상황에 따라 접두어 is 보다 더 나은 방법 몇 가지로 has, can 그리고 should 접두어를 사용한다.

bool hasLicense();
bool canEvaluate();
bool shouldSort();


1.25. 반의어는 반드시 대응하는 연산에 대해 사용해야 한다.

get/set, add/remove,  create/destroy, start/stop, insert/delete, increment/decrement, old/new, begin/end, first/last, up/down, min/max, next/previous, open/close, show/hide, suspend/resume, 등...


대칭 관계를 통해 복잡성을 낮출 수 있다.
  
1.26. 이름에 약어는 피해야 한다.

computeAverage();    // 잘못된 경우 : compAvg();


두 가지 단어 종류를 생각해야 하는데, 첫 번째는 사전에 있는 일반 단어이며 절대 약어로 쓰면 안 된다. 즉, 절대 다음처럼 쓰지 않는다.

command => cmd
copy        => cp
point        => pt
compute  => comp
initialize   => init
등...

그에 반해 약어/두문자어가 더 자연스런 특정 분야의 관용구는 약어 형태를 유지해야 하며, 절대 다음처럼 쓰지 않는다.

html => HypertextMarkupLanguage
cpu  => CentralProcessingUnit
pe   => PriceEarningRatio
등...
  
1.27. 포인터를 이름에 사용하는 것은 특히 피해야 한다.

Line* line;    // 잘못된 경우 : Line* pLine;
                  // 잘못된 경우 : Line* linePtr;


C/C++ 환경에서 많은 변수가 포인터이므로 이와 같은 관례는 따르기가 거의 불가능하다. 또한 C++ 에서 객체는 흔히, 프로그래머가 특정 구현 내용을 무시할 수 있는 간접 타입이다.

포인터를 이름에 사용할 때는 객체의 실제 타입이 특별히 중요할 때에 한해 해당 타입을 강조하기 위해서이다.
  
1.28. 부정적인(negated) Boolean 변수 이름은 반드시 피해야 한다.

bool isError;    // 잘못된 경우 : isNoError
bool isFound;  // 잘못된 경우 : isNotFound


문제는 이런 이름을 논리 부정 연산자와 함께 사용할 때 이중 부정을 통해 결과가 만들어지므로 생긴다.
!isNotFound 의 의미를 즉시 명확하게 알아차릴 수 없다.
  
1.29. 열거 상수는 공통 타입 이름을 접두어로 붙인다.

enum Color {
    COLOR_RED,
    COLOR_GREEN,
    COLOR_BLUE,
};


이러한 것은 해당 선언을 어디에서 찾을 수 있는지, 어느 상수가 함께 속한 것인지, 그리고 그 상수가 어떤 개념을 나타내는지 등 추가 정보를 제공한다. 다른 방법은 Color: : RED, Airline: : AIR_FRANCE 등과 같이 항상 공통 타입을 통해 해당 상수를 참조하는 것이다.

1.30. 예외 클래스는 Exception 접미어를 붙인다.

class AccessException
{
...
}


예외 클래스는 실제 해당 프로그램의 주된 설계 부분이 아니며(옮긴이 주: 프로그램에서 주된 처리 로직이 아니라는 뜻), 이와 같이 이름을 붙이면 다른 클래스와 상대적으로 구별된다.
  
1.31. 함수(무언가를 반환하는 메서드)는 이름 앞에 반환하는 것을, 프로시저(void 메서드)는 이름 앞에 하는 일을 써야 한다.

가독성을 높일 수 있다. 이를 통해 해당 단위에서 해야 하는 것과 특히 하지 않는 모든 것을 명확히 한다. 더불어 해당 코드의 부작용을 더 쉽게 제거할 수 있다.(옮긴이 주: 이 항목은 의미가 명확하지 않음)


2. 들여쓰기

2.1. 들여쓰기에는 TAB 을 사용한다. SPACE를 사용하지 않는다. Tab 사이즈는 4로 정의한다.

2.2. 주석은 코드와 같은 레벨에 있어야 한다(들여쓰기의 레벨을 같이 사용한다.).

좋은 예:
// Format a message and display
string fullMessage = "Hello " + name;
DateTime currentTime = DateTime.Now;
string message = fullMessage + ", the time is : " + currentTime.ToShortTimeString();
MessageBox.Show ( message );
좋지 않은 예:
// Format a message and display
string fullMessage = "Hello " + name;
DateTime currentTime = DateTime.Now;
string message = fullMessage + ", the time is : " + currentTime.ToShortTimeString();
MessageBox.Show ( message );


2.3. 중괄호는 중괄호 밖에 있는 코드와 같은 레벨에 있어야 한다.
             
2.4. 논리적인 코드 그룹은 빈 줄 하나로 구분해야 한다.

좋은 예:
        bool SayHello ( string name )
        {
               string fullMessage = "Hello " + name;
               DateTime currentTime = DateTime.Now;
               string message = fullMessage + ", the time is : " + currentTime.ToShortTimeString();
               MessageBox.Show ( message );
               if ( ... )
               {
                       // Do something
                       // ...
  
                       return false;
               }
  
               return true;
        }
좋지 않은 예:
        bool SayHello (string name)
        {
               string fullMessage = "Hello " + name;
               DateTime currentTime = DateTime.Now;
               string message = fullMessage + ", the time is : " + currentTime.ToShortTimeString();
               MessageBox.Show ( message );
               if ( ... )
               {
                       // Do something
                       // ...
                       return false;
               }
               return true;
        }

 
2.5. There should be one and only one single blank line between each method inside the class.

2.6. 중괄호는 다른 라인과 분리되어 있어야하며 라인을 같이 쓰면 안된다.

좋은 예:
               if ( ... )   
               {
                       // Do something
               }
좋지 않은 예:
               if ( ... )     {
                       // Do something
               }

 
2.7. 지시자(operator)와 괄호 앞뒤로는 한 칸의 공간을 남긴다.

좋은 예:
               if ( showResult == true )
               {
                       for ( int i = 0; i < 10; i++ )
                       {
                              //
                       }
               }
좋지 않은 예:
               if(showResult==true)
               {
                       for(int    i= 0;i<10;i++)
                       {
                              //
                       }
               }

 
2.8. 연관된 코드를 묶을때는 #region을 사용해라.

#region을 사용해서 묶는다면 그 페이지는 훨씬 간략해질 것이다.

 
2.9. private 멤버 변수, 속성, 그리고 메쏘드는 파일의 하단에 그리고 public 멤버들을 파일의 하단에 위치하도록 하라.

switch 문은 다음 형식이어야 한다.

switch (condition) {
    case ABC :
        statements;
        // 지나감

    case DEF :
        statements;
        break;

    case XYZ :
        statements;
        break;

    default :
        statements;
        break;
}

 
각 case 키워드를 전체 switch 문에 대해 들여쓰기한다는 점에 주의한다. 이를 통해 전체 switch 문을 두드러지게 한다. 또한 ":" 문자 앞에 있는 여분의 빈칸에 주의한다. case 문에 break 문이 없으면 항상 명시적으로 '지나감'이라고 주석을 달아야 한다. break 문이 없는 것은 일반적인 오류이므로, 사용하지 않을 때는 의도적이라는 것을 명확히 해야 한다. 

do-while 문은 다음 형식이어야 한다.

do {
    statements;
} while (condition);


이 형식은 위에서 제시한 일반 구역 규칙을 따른다. 
 
while 문은 다음 형식이어야 한다.

while (condition) {
    statements;
}


이 형식은 위에서 제시한 일반 구역 규칙을 따른다. 

부동소수점 상수는 항상 소수점과 함께 써야 한다.

double total = 0.0;          // 아님: double total = 0;
double speed = 3.0e8;    // 아님: double speed = 3e8;

double sum;
    :
sum = (a + b) * 10.0;


이는 정수와 부동소수점 수의 본질적인 차이를 강조한다. 수학적으로 두 모델은 완전히 다르며 호환되지 않는 개념이다. 또한 위의 마지막 예제처럼 코드의 어떤 지점에서 명확하지 않을 수 있는 대입되는 변수(sum)의 타입을 강조한다.

부동소수점 상수는 항상 소수점 앞에 숫자를 써야 한다.

double total = 0.5;    // 아님: double total = .5;


C++ 에서 숫자와 표현식 시스템은 수학에서 빌려왔으므로 가능한 구문에 대한 수학적 관례를 따라야 한다. 또한 .5보다 0.5가 휠씬 읽기 쉬우며 정수 5와 헷갈리지 않는다. 

루프 변수는 해당 루프 바로 앞에서 초기화해야 한다.

isDone = false;        // 아님: bool isDone = false;
while ( !isDone ) {
     ...
}


2.10. do-while 루프는 피한다.

do-while 루프는 해당 루프의 가장 아래에 조건이 있기 때문에 일반적인 while 루프와 for 루프보다 가독성이 떨어진다. 해당 루프의 사용 범위를 이해하려면 반드시 전체 루프를 살펴봐야 한다. 게다가 do-while 루프는 while 루프나 for 루프로 쉽게 바꿔 쓸 수 있으므로 필요하지 않다. 이 구조의 사용을 줄여 가독성을 향상시킨다.

2.11. 루프에서 break와 continue 사용을 피해야 한다.

이 문장은 구조적인 대체 코드보다 가독성을 더 높일 수 있을 때만 사용해야 한다.
  
2.12. 무한 루프는 "while (true)" 형식을 사용한다.

while (true) {
    :
}

for (;;) {       // 아님!
    :
}

while (1) {    // 아님!
    :
}


1에 대해 시험하는 것은 필요하지도 의미적이지도 않다. for (;;) 형식은 가독성이 매우 나쁘며 실제 무한 루프인지 명확하지 않다.
 
2.13. 파일 내용은 반드시 80 열(column) 내로 유지해야 한다.

80 열은 편집기, 터미널 에뮬레이터, 프린터와 디버거의 공통적인 치수이며 여러 사람이 공유하는 파일은 이런 제한을 지켜야 한다. 이를 통해 프로그래머 사이에 파일을 전달할 때 의도하지 않은 줄바꿈을 피할 수 있어 가독성을 향상시킨다.

2.14. 객체 이름이 암시되어 있으면 메서드 이름에서 반복 사용하지 말아야 한다.

line.getLength();     // 잘못된 경우 : line.getLineLength();


클래스 선언에서 두 번째가 자연스러운 것처럼 보이지만 불필요하게 사용한 예이다.


--------------------------------------------------------------------------------------

출처는 아래와 같고, 내용은 저의 블로그 상황에 맞게 약간의 형식만 바꿨을 뿐 수정된 사항은 없습니다.

[출처] 한이, "변수 네이밍 규칙", http://www.hanistory.com/program/69341, Hani's Story

AND