블럭/레벨간의 확인가능하고 일정하게 지켜진다면, 들여쓰기에 대한 제약은 전혀 두지 않기로 한다.
단, 볼랜드 방식인 레벨마다 2칸의 탭간격을 추천한다.
특히 조건문이나 출력문의 내용이 길어져서 옆줄로 길어진 경우, 다음줄로 내려쓰고 들여쓰기하여 구분할 수 있도록 한다.
1.2 주석
기본적인 주석은 중괄호 { } 로 한다.
부수적으로 (* *) 방식은 개발중에 임시로 사용되는 주석 용도로만 사용한다.
// 방식 주석은 한 줄만 주석처리 할 때 사용하도록 한다.
유닛 파일 가장 위에는 다음과 같은 파일 헤더를 붙인다.
{***************************************************************}
{ }
{ This line describes the purpose of the unit }
{ }
{ Copyright (c) 2001 godrm@netsgo.com }
{ }
{ All rights reserved. }
{ }
{***************************************************************}
1.3 컨디션 설정
오브젝트 파스칼 컴파일러 지시자에 사용되는 것과 마찬가지로 { } 로 컨티션 설정을 한다.
for I := 0 to 10 do begin// Incorrect, begin on same line as forfor I := 0 to 10 do// Correct, begin appears on a separate linebegin
블럭문내의 마지막 명령줄의 생력가능한 세미콜론도 찍어주는 것을 원칙으로 한다.
begin
MyStatement;
MyNextStatement;
MyLastStatement; // semicolon optional
end;
2. 파일이름
파일이름에는 InfixCaps 혹은 Camel Caps 방식인 단어 첫 알파벳만 대문자를 쓰는 방식으로 한다.
단, 확장자는 소문자로 한다.
2.1 프로젝트 파일
프로젝트명은 될 수 있으면 프로젝트의 내용을 설명하도록 만들며,
정해진 프로젝트 코드명이 있을 경우에는 코드명을 사용한다.
2.2 폼 파일
폼 파일명은 기능별 혹은 구성별로 붙일 수 있는 기능성이름과 Form이라는 postfix를 사용한다.
( 실제로 폼의 .dfm 파일은 유닛 파일명을 저장할 때, 같은 이름으로 그대로 저장된다. )
유의사항: 폼 파일명은 디자인한 폼 클래스의 인스턴스명이 아니다.
폼의 인스턴스는 TForm 클래스명인 Form이라는 prefix를 붙인다. (3.8 인스턴스명 참조)
폼 설명
폼 파일명
About Form
AboutForm.dfm
Main Form
MainForm.dfm
2.3 유닛 파일
델파이 폼의 유닛 이름은 자동적으로 폼 파일과 같은 이름을 사용한다. (2.2 폼 파일이름 참조),
반면에 일반 유닛일 경우에는 Unit이라는 postfix를 사용한다.
단, C/C++의 헤더파일을 변환하는 경우에는 확장자를 제외한 파일명을 그대로 사용한다.
유닛 설명
유닛 파일명
About Form Unit
AboutForm.pas
Service Unit
ServiceUnit.pas
Windows.c
Windows.pas
2.4 데이터모듈 파일
데이터 모듈의 파일명에는 DM이라는 postfix를 사용한다.
DM 설명
DM 파일명
Client Data Module
ClientDM.dfm
Customer Data Module
CustomerDM.dfm
2.5 패키지 파일
패키지 파일명에는 구분할 수 있는 prefix에
디자인타임패키기와 런타임패키지를 구분할 수 있는 infix와
지원하는 델파이버전을 나타내기 위한 D4, D5, D6와 같은 postfix로 구성한다.
"iiilibvv.pkg" - design package
"iiistdvv.pkg" - runtime package
3. 오브젝트파스칼
3.1 예약어
모든 오브젝트파스칼 예약어는 소문자로 쓰도록 한다.
3.2 함수명
함수명은 동사(+목적어) 형태로 사용하며, 값을 가져오는 경우 Get, 값을 설정하는 경우 Set을 쓴다.
InfixCaps 방식을 사용한다.
procedure ThisIsMuchMoreReadableRoutineName;
procedure FormatHardDrive;
procedure SetUserName;
function GetUserName: string;
3.3 변수명
변수명은 명사 형태로 사용하며, InfixCaps 방식을 사용한다.
변수선언을 할 때는 같은 형끼리는 복수선언하며, 다른 형끼리는 단수선언만 한다.
델파이에서는 WIN32 형식인 헝가리언 표기법을 권장하지 않는다.
하지만, WIN32 API를 사용할 경우나, VisualStudio와 같은 다른 툴과의 연동을 위해서는 사용해도 무방하다.
var
nLoop, MyNumber: Integer; // Correct
lpstrMyString: String; // Incorrect
클래스의 멤버 변수일 경우, F(Field) prefix를 주로 사용한다.
필요에 따라서 P(Pointer-포인터형변수), G(Global-전역변수), L(Local-지역변수), X(temp-임시변수), A(argument-함수파라미터)등의 prefix를 붙일 수 있다.
3.4 데이터타입
내부 테이터형은 소문자로 표기하며, WIN32 API 데이터형은 대문자로 표기한다.
var
MyString: string; // reserved word
WindowHandle: HWND; // Win32 API type
I: Integer; // type identifier introduced in System unit
열거형은 선언할 때는 T(Type) prefix를 붙이며, 열거형 내부 목록에는 열거형에 대한 구분자(혹은 약자)를 2-3글자 prefix로 붙인다.
TSongType = (stRock, stClassical, stCountry);
배열형의 경우에는 T prefix, Array postfix를 붙이며,
또한 데이터의 포인터형은 P(Pointer) prefix를 덧붙인다.
type
PCycleArray = ^TCycleArray;
TCycleArray = array[1..100] of Integer;
레코드의 경우에도 T prefix를 사용하며, 레코드 내부 변수에는 붙이지 않는다.
type
PEmployee = ^TEmployee;
TEmployee = record
Name: string;
Rate: Double;
end;
3.5 구문
(1) if문
if문은 적어도 두 줄로 내려쓴다.
다만 수행문이 짧으면 한 줄로 써도 무방하다.
// CORRECT
if A < B then DoSomething;
// CORRECT
if A < B then
DoSomething;
if-else문의 경우 소스의 논리 구조를 표현하는 수단이다.
각 논리 블록간의 관계가 명확하게 구분된다면, 자유로운 레벨간의 들여쓰기와 begin-end 표시가 허용된다.
그리고 특히 if문이 반복되서 길 게 사용될 경우 begin-end를 표시하여 범위를 명확하게 한다.
가능하면 if-else를 반복해서 사용하지 않도록 하며, 될 수 있으면 case문으로 구성한다.
// INCORRECT
if A < B then
if C < B then
DoSomething
else if D < B then
DoSomething;
// CORRECT
if A < B then
begin
if C < B then
DoSomething;
end
else if D < B then
DoSomething;
if문안에 if문의 구조가 5단계이상 들어가지 않도록 코드를 간결화한다.
여러 조건들은 나열할 때는 왼쪽부터 빈도가 높고, 가능성이 높은 것을 선택한다.
if Condition1 and Condition2 and Condition3 then
(2) case문
case문은 순서가 있는 데이터형에만 사용할 수 있다.
case-else문도 if-else와 같이 논리 블록간이 명확하게 구분되는 범위에서 들여쓰기가 허용된다.
if문과 마찬가지로 중요도와 빈도가 높은 것이 윗쪽에 있도록 한다.
각 case마다 4-5줄을 넘어가지 않도록 하며, 길어질 경우 따로 함수를 작성하도록 한다.
// CORRECT
case Control.Align of
alLeft, alNone: NewRange := Max(NewRange, Position);
alRight: Inc(AlignMargin, Control.Width);
end;
// CORRECT
case x of
csStart:
begin
j := UpdateValue;
end;
csBegin: x := j;
csTimeOut:
begin
j := x;
x := UpdateValue;
end;
end;
// CORRECT
case ScrollCode of
SB_LINEUP, SB_LINEDOWN:
begin
Incr := FIncrement div FLineDiv;
FinalIncr := FIncrement mod FLineDiv;
Count := FLineDiv;
end;
SB_PAGEUP, SB_PAGEDOWN:
begin
Incr := FPageIncrement;
FinalIncr := Incr mod FPageDiv;
Incr := Incr div FPageDiv;
Count := FPageDiv;
end;
else
Count := 0;
Incr := 0;
FinalIncr := 0;
end;
// CORRECT (볼랜드 스타일)
case ScrollCode of
SB_LINEUP, SB_LINEDOWN:
begin
Incr := FIncrement div FLineDiv;
FinalIncr := FIncrement mod FLineDiv;
Count := FLineDiv;
end;
SB_PAGEUP, SB_PAGEDOWN:
begin
Incr := FPageIncrement;
FinalIncr := Incr mod FPageDiv;
Incr := Incr div FPageDiv;
Count := FPageDiv;
end;
else
Count := 0;
Incr := 0;
FinalIncr := 0;
end;
(3) while문 (repeat문)
while문에서는 가능하면 루프중에 빠지지않고, loop조건으로만 종료되도록 구성한다.
// INCORRECT
while x < j do begin
DoSomething;
DoSomethingElse;
end;
// CORRECT
while x < j do
begin
DoSomething;
DoSomethingElse;
end;
// CORRECT
repeat
x := j;
j := UpdateValue;
until j > 25;
(4) for문
만약 1씩 증가가 아닌 경우라면, while문을 이용해서 마지막값부터 거꾸로 루프를 돌도록 한다.
// INCORRECT
for i := 0 to 10 do begin
DoSomething;
DoSomethingElse;
end;
// CORRECT
for i := 0 to 10 do
begin
DoSomething;
DoSomethingElse;
end;
// CORRECT
i := AList.Count-1;
while i => 0 do
i := i - 2;
(5) with문
with문을 사용할 경우에는 복수객체나 구조체를 참조하지 않도록 주의하며,
같은 이름의 다른 객체의 프로퍼티나 메소드를 참조하지 않는지 확인해야 한다.
with Record1, Record2 do
3.6 에러처리구문
에러처리 (Exception Handling)는 에러 복구와 리소스 보호의 역할을 한다.
(1) try..finally
되도록 각 동적할당마다 try..finally 구문을 사용하여 예외사항에 대비한다.
다음의 예제는 동적할당된 클래스를 참조할 때, 예외가 발생할 수 있는 숨겨진 버그가 있다.
SomeClass1 := TSomeClass.Create
SomeClass2 := TSomeClass.Create;
try
{ do some code }
finally
SomeClass1.Free;
SomeClass2.Free;
end;
다음의 예제는 숨겨진 버그를 없애는 올바른 방법이다.
SomeClass1 := TSomeClass.Create
try
SomeClass2 := TSomeClass.Create;
try
{ do some code }
finally
SomeClass2.Free;
end;
finally
SomeClass1.Free;
end;