Perl 스타일 가이드

Perl 스타일 가이드 (perlstyle)

코드를 어떻게 보기 좋게 적을지는 프로그래머마다 저마다 취향이 있겠죠. 그래도 프로그램을 읽고·이해하고·유지보수하기 쉽게 만들어 주는 몇 가지 일반 원칙은 있어요. 이 문서는 펄의 창시자 래리 월(Larry Wall)이 제안한 스타일 선호를 중심으로, 실제로 써먹을 만한 코딩 관례를 정리한 가이드예요.

출처: perldoc - perlstyle

가장 중요한 것: strict와 warnings

무엇보다 중요한 건 모든 코드에서 strictwarnings를 쓰거나, 아니면 그렇게 하지 않는 이유를 아는 거예요. 특정 코드 구간에서만 끄고 싶다면 no warningsno strict로 명시적으로 끄면 되고, 이는 끄고 싶은 특정 warnings/strict 기능으로 범위를 좁힐 수 있어요. -w 플래그와 $^W 변수는 이 용도로 쓰면 안 돼요. 코어나 CPAN의 모듈처럼 여러분이 작성하지 않았지만 사용하는 코드에까지 영향을 줄 수 있거든요.

간결하게 이걸 정리하는 방법은 use VERSION 문법으로 5.36 이상 버전을 요청하는 거예요. 그러면 strictwarnings pragma(그리고 몇 가지 유용한 named feature들)가 한 번에 켜져요.

use v5.36;

레이아웃에 대한 래리의 취향

코드 배치의 미학에 대해 래리가 강하게 신경 쓰는 것은 딱 하나예요. 여러 줄 BLOCK의 닫는 중괄호가 그 구문을 시작한 키워드와 세로로 맞춰야 한다는 점이에요. 그 외에는 강하지 않은 선호들이 있는데, 대략 이렇습니다:

  • 들여쓰기는 4칸.
  • 가능하면 여는 중괄호를 키워드와 같은 줄에, 아니면 맞춘다.
  • 여러 줄 BLOCK의 여는 중괄호 앞에 공백을 둔다.
  • 한 줄짜리 BLOCK은 중괄호 포함 한 줄에 둘 수 있다.
  • 세미콜론 앞에는 공백을 두지 않는다.
  • "짧은" 한 줄 BLOCK에서는 세미콜론을 생략해도 된다.
  • 대부분의 연산자 주위에 공백을 둔다.
  • "복잡한" 첨자(대괄호 안) 주위에 공백을 둔다.
  • 서로 다른 일을 하는 덩어리 사이에는 빈 줄을 둔다.
  • else를 중괄호와 같은 줄에 붙이지 않는다(uncuddled elses).
  • 함수 이름과 여는 괄호 사이에 공백을 두지 않는다.
  • 각 쉼표 뒤에 공백을 둔다.
  • 긴 줄은 연산자 뒤에서 끊는다(and, or는 제외).
  • 현재 줄의 마지막 괄호 뒤에 공백을 둔다.
  • 대응하는 항목을 세로로 정렬한다.
  • 명확성이 해치지 않는 한 불필요한 구두점은 생략한다.

래리는 이 각각에 이유가 있긴 하지만, 모든 사람의 머리가 자기처럼 돌아간다고 주장하진 않아요.

좀 더 실질적인 스타일 문제

  • 할 수 있다고 해서 그렇게 해야 하는 건 아니에요. Perl은 무엇을 하든 여러 방법을 주도록 설계돼서, 그중 가장 읽기 쉬운 걸 고르는 걸 고려해 보세요. 예를 들어:
open(my $fh, '<', $foo) || die "Can't open $foo: $!";

이게

die "Can't open $foo: $!" unless open(my $fh, '<', $foo);

보다 나아요. 두 번째 방식은 문장의 핵심을 수식어(modifier) 속에 숨겨버리거든요. 반면에

print "Starting analysis\n" if $verbose;

$verbose && print "Starting analysis\n";

보다 나아요. 핵심은 사용자가 -v를 입력했는지가 아니니까요.

  • 마찬가지로, 연산자가 기본 인자를 가정하게 해준다고 해서 그 기본값을 꼭 써야 하는 건 아니에요. 기본값은 원샷 프로그램을 쓰는 게으른 시스템 프로그래머를 위해 있는 거예요. 프로그램을 읽기 좋게 만들고 싶다면 인자를 명시하는 걸 고려하세요.

  • 같은 맥락에서, 많은 곳에서 괄호를 생략할 수 있다고 해서 생략해야 하는 건 아니에요:

return print reverse sort num values %array;
return print(reverse(sort num (values(%array))));

의심스러우면 괄호를 써요. 최소한 다음에 오는 불쌍한 사람이 vi에서 % 키를 두드리며 헤매는 일은 막을 수 있어요.

  • 의심이 없더라도, 나중에 코드를 유지보수할 사람(그리고 아마 괄호를 엉뚱한 곳에 넣을 사람)의 정신 건강을 생각해 보세요.

  • 루프 중간에서 빠져나올 수 있게 last 연산자를 제공하는데, 루프의 위나 아래에서 빠져나오려고 억지 부리지 마세요. 조금 밖으로 내려(아웃덴트) 더 잘 보이게 하면 되죠:

LINE:
for (;;) {
    statements;
  last LINE if $foo;
    next LINE if /^#/;
    statements;
}
  • 루프 레이블 쓰기를 두려워하지 마세요. 레이블은 가독성을 높이고 다중 레벨 루프 탈출을 가능하게 해주는 것이니까요. (앞의 예 참고)

  • void 컨텍스트에서 grep()(또는 map())이나 백틱을 쓰지 마세요. 즉, 반환값을 그냥 버릴 때 말이에요. 그 함수들은 반환값이 있으니 그것을 활용하세요. 아니면 foreach() 루프나 system() 함수를 쓰고요.

  • 이식성을 위해, 모든 머신에서 구현돼 있지 않을 수 있는 기능을 쓸 때는 그 구문을 eval로 테스트해서 실패하는지 봐요. 어떤 기능이 특정 버전/패치레벨에서 구현됐는지 안다면 $](English$PERL_VERSION)를 검사해서 거기 있는지 확인할 수 있어요. Config 모듈로도 Perl이 설치될 때 Configure 프로그램이 결정한 값을 조회할 수 있어요.

  • 기억하기 쉬운(니모닉) 식별자를 고르세요. 니모닉이 뭘 뜻하는지 기억 못 한다면 문제가 있는 거예요.

  • $gotit 같은 짧은 식별자는 괜찮지만, 긴 식별자는 단어 사이를 밑줄로 구분하세요. $VarNamesLikeThis보다 $var_names_like_this가 일반적으로 읽기 쉬워요. 특히 영어가 모국어가 아닌 사람에게요. VAR_NAMES_LIKE_THIS와도 일관되게 맞는 단순한 규칙이기도 해요.

    패키지 이름은 때때로 이 규칙의 예외예요. Perl은 비공식적으로 integerstrict 같은 "pragma" 모듈에 소문자 모듈 이름을 예약해요. 그 외 모듈은 대문자로 시작하고 대소문자를 섞어 쓰되, 아마 밑줄은 없는 게 좋아요. 원시 파일 시스템이 모듈 이름을 몇 바이트 안에 들어가는 파일로 표현해야 하는 한계 때문이에요.

  • 변수의 범위나 성격을 나타내는 데 대소문자를 쓰는 게 도움이 될 수 있어요. 예를 들어:

$ALL_CAPS_HERE   constants only (beware clashes with perl vars!)
$Some_Caps_Here  package-wide global/static
$no_caps_here    function scope my() or local() variables

함수·메서드 이름은 전부 소문자가 가장 잘 맞는 것 같아요. 예: $obj->as_string(). 밑줄로 시작하면 그 변수·함수를 정의한 패키지 밖에서 쓰면 안 된다는 뜻으로 표시할 수 있어요.

  • 정말 지저분한 정규식이 있다면 /x/xx 수정자를 쓰고 공백을 넣어서 라인 노이즈처럼 보이지 않게 해요. 정규식에 슬래시나 백슬래시가 있다면 구분자로 슬래시를 쓰지 마세요.

  • and·or 연산자를 써서 리스트 연산자에 괄호를 너무 많이 치지 않게 하고, &&·|| 같은 구두점 연산자의 사용을 줄여요. 서브루틴을 함수나 리스트 연산자처럼 호출해서 과도한 앰퍼샌드(&)와 괄호를 피하세요.

  • 반복되는 print() 대신 here document를 써요.

  • 대응하는 항목을 세로로 정렬하세요, 특히 한 줄에 들어가기 너무 길 때요:

$IDX = $ST_MTIME;
$IDX = $ST_ATIME 	   if $opt_u;
$IDX = $ST_CTIME 	   if $opt_c;
$IDX = $ST_SIZE 	   if $opt_s;

mkdir $tmpdir, 0700	or die "can't mkdir $tmpdir: $!";
chdir($tmpdir)      or die "can't chdir $tmpdir: $!";
mkdir 'tmp',   0777	or die "can't mkdir $tmpdir/tmp: $!";
  • 시스템 호출의 반환 코드를 항상 확인하세요. 좋은 에러 메시지는 STDERR로 나가고, 어떤 프로그램이 문제를 일으켰는지, 실패한 시스템 호출과 인자가 무엇이었는지, 그리고 (매우 중요!) 무엇이 잘못됐는지 표준 시스템 에러 메시지를 담아야 해요. 간단하지만 충분한 예:
opendir(my $dh, $dir)	 or die "can't opendir $dir: $!";
  • 문자 치환(transliteration)을 정렬할 수 있으면 정렬해요:
tr [abc]
   [xyz];
  • 재사용성을 생각하세요. 비슷한 일을 또 하고 싶을 수도 있는데 원샷 코드에 머리를 쓸 이유가 있나요? 코드를 일반화해 보세요. 모듈이나 객체 클래스를 만들어 보세요. use strictuse warnings가 켜진 상태에서 깔끔하게 돌아가게 만들어 보세요. 코드를 공개해 보세요. 세계관을 바꿔 보세요. 생각해 보세요... 아, 됐네요.

  • 코드를 문서화하고 Pod 형식을 일관되게 쓰세요. 흔히 기대되는 관례는:

    • C<> — 함수·변수·모듈 이름(그리고 파일핸들이나 특정 값처럼 코드의 일부로 볼 수 있는 것은 대체로 전부)에 씀. 함수 이름은 뒤에 괄호를 붙인 function()이 더 읽기 좋다고 여겨짐.
    • B<>cat이나 grep 같은 명령 이름에 씀.
    • F<> 또는 C<> — 파일 이름에 씀. F<>가 파일 이름을 위한 유일한 Pod 코드여야 하지만, 대부분의 Pod 포매터가 이를 이탤릭으로 렌더링해서 슬래시·백슬래시가 있는 Unix/Windows 경로는 덜 읽기 쉬울 수 있어요. 그럴 땐 C<>가 낫죠.
  • 일관되게 하세요.

  • 좋게 대하세요.

더 알아보기 (Learn more)

  • perldoc perlstyle(원문) — 래리 월의 모든 스타일 선호
  • perlpod — Pod 문서 형식
  • perlsyn — Perl 문법