언어는 약속이다.
코딩 또한 약속된 문법은 같지만 수많은 사람들이 본인만의 스타일로 코딩을 한다.
정답은 없지만 구글처럼 체계가 잘 잡힌 회사라면 코딩 규약도 깔끔하게 잘 잡혀있지 않을까?
모두가 100% 공감할 수는 없겠지만 그래도 구글이니 한번 알아보자.
구분선 아래는 개인적인 의견이 아닌 구글 공식 가이드의 번역임
일반적인 이름 규칙
다른 팀에서도 알아볼 수 있을 정도로 가독성이 좋으며 분명한 이름이어야 한다.
목적과 의도에 맞는 이름으로 지을 것.
이름이 길어지는 것은 신경쓰지 않는다. 그것보다 훨씬 중요한 것은 그 코드를 처음보는 사람을 즉시 이해 가능하게 하는 것이다.
단어 사이의 글자를 지워 약어로 만드는 것은 좋지않다. 단, 위키피디아에 실려 누구나 알 수 있을 정도의 약어라면 사용 가능. iteration variable 인 i 와 template의 T처럼 범용적으로 사용되는 약어라면 바람직하다.
파일 이름
파일 이름은 모두 소문자여야 하고 특수문자 중 언더스코어 ( _ ) 와 대쉬 ( - ) 만을 포함한다.
<예시>
- my_useful_class.cc
- my-useful-class.cc
- myusefulclass.cc
- myusefulclass_test.cc
C++ 파일은 .cc 로 끝나야하며 헤더파일은 .h 로 끝나야한다.
/usr/include 에 이미 포함되어 있는 이름을 파일 이름으로서 사용하지 않는다. (e.g. db.h)
일반적으로 파일이름은 매우 구체적이어야 한다.
예를 들어서 logs.h 보다는 http_server_logs.h 가 더 바람직함.
관련 파일들은 쌍으로 짝지어 이름 짓는 것이 좋다. (e.g. foo_bar.h , foo_bar.cc)
타입 이름
타입이름은 언더스코어 ( _ ) 를 포함하지 않으며 대문자로 시작하고 각 단어의 시작도 대문자로 한다.
<예시>
- class UrlTableTester { ...
- typedef hash_map<UrlTableProperties *, std::string> PropertiesMap;
- using PropertiesMap = hash_map<UrlTableProperties *, std::string>;
- enum UrlTableErrors { ...
변수 이름
- 일반적인 변수 이름
모두 소문자로 이루어지며 각 단어사이는 언더스코어 ( _ ) 가 온다.
클래스의 멤버 변수의 이름은 언더스코어 ( _ ) 로 끝낸다. (구조체 제외)
<예시>
- std::string table_name;
- std::string a_struct_data_member;
- std::string a_class_data_member_;
- 상수 이름
const 로 선언되는 상수는 "k" 를 붙혀 구분짓고 각 단어는 대문자로 시작한다.
언더스코어 ( _ ) 는 대문자로 구분할 수 없는 경우만 구분자로서 사용한다.
<예시>
- const int kDaysInAWeek = 7;
- const int Android8_0_0 = 24; // Android 8.0.0
- 함수 이름
보통의 함수는 대문자로 시작하며 각 단어도 대문자로 시작한다.
<예시>
- AddTableEntry()
- DeleteUrl()
- OpenFileOrDie()
- 네임스페이스 이름
네임스페이스의 이름은 모두 소문자로 구성하며 최상위 네임스페이스 이름은 프로젝트 이름을 기반으로 한다.
잘 알려진 최상위 네임스페이스 이름과의 충돌을 피해서 짓는다. 보통의 경우 팀이나 구성원의 프로젝트에 관한 이름이 포함되어진다.
- 메크로 이름
솔직히 우리는 메크로를 많이 안쓰지 않는가.
그렇지만 정말 꼭 써야겠다면 모두 대문자로 쓰고 언더스코어 ( _ ) 로 연결한다.
<예시>
- #define ROUND(x) ...
- #define PI_ROUNDED 3.0
주석
주석은 코드의 가독성을 위해 필수적이다.
그렇지만 정말 좋은 코드는 주석없이도 스스로 읽히는 코드이다.
후에 누구든 주석을 읽을 수 있으니 일반적으로 작성되어야 한다.
- 일반적인 주석 스타일
// 와 /* */ 는 모두 바람직하되 일관성 있게 사용한다.
// 을 사용하는 것이 일반적이다.
- 클래스에 관한 주석
클래스가 어디에서 어떻게 사용되는지를 서술한다.
<예시>
// Iterates over the contents of a GargantuanTable.
// Example:
// GargantuanTableIterator* iter = table->NewIterator();
// for (iter->Seek("foo"); !iter->done(); iter->Next()) {
// process(iter->key(), iter->value());
// }
// delete iter;
class GargantuanTableIterator {
...
};
- 함수에 관한 주석
모든 함수는 선언되는 곳 앞에 어떻게 쓰이는지에 대한 주석이 있어야한다.
함수에 관한 주석은 동사로 시작하며 명령보다는 서술적으로 쓴다. (e.g. Opens the file)
// Returns an iterator for this table. It is the client's
// responsibility to delete the iterator when it is done with it,
// and it must not use the iterator once the GargantuanTable object
// on which the iterator was created has been deleted.
//
// The iterator is initially positioned at the beginning of the table.
//
// This method is equivalent to:
// Iterator* iter = table->NewIterator();
// iter->Seek("");
// return iter;
// If you are going to immediately seek to another place in the
// returned iterator, it will be faster to use NewIterator()
// and avoid the extra seek.
Iterator* GetIterator() const;
단, 불필요하게 너무 많이 쓰지 않고 애매한 것들만 명백하게 언급한다.
- TODO 주석
TODO 주석은 단기적이며 일시적으로만 사용한다.
TODO 와 같이 모두 대문자인 형식을 지켜서 쓰며 이는 후에 검색되어지기 위함이다.
TODO 는 작성자의 이름, 이메일, 버그 ID 등과 함께 사용하여 문제해결에 대한 참조를 해놓는다.
<예시>
// TODO(jwk70915@gmail.com): Use a "*" here for concatenation operator.
// TODO(Jinuk) change this to use relations.
// TODO(bug 12345): remove the "Last visitors" feature
함수를 대문자로 시작하는 등 누군가에겐 낯선 규칙일 수 있지만
협업하는 모든 인원이 문서의 내용을 잘 지키기만 한다면 정말 좋은 규칙이 될 것 같다.