C++/Google C++ Style Guide

Comments

ukjin 2025. 6. 22. 22:16
반응형

Comments는 code의 가독성을 유지하기 위해 매우 중요하다. 다음 rule은 무엇을 comment 해야만 하는지 그리고 어디에 comment 해야만 하는지를 설명한다. 하지만 기억하자: comment는 매우 중요하지만, best code는 self-documenting이다. type과 variable의 합리적인 이름은 comments를 통해 설명해야만 하는 모호한 이름을 사용하는 것보다 훨씬 더 낫다.

comments를 작성할 때, audience를 위해 작성한다: 코드를 이해하기를 필요로하는 다음 contributor - 다음은 당신이 될 수도 있다.

Comment Style

일관성이 있다면 // 또는 /* */ syntax를 사용한다.

각각 syntex는 사용 가능하지만, // 가 더 일반적이다. 어디에 사용되는 style이 무엇인지 그리고 comment하는 법에 따라 일관성을 유지한다.

File Comments

license bolier plate와 함께 각 file를 시작한다.

만약 source file (.h file 같은)이 다수의 user-facing abstractions (common functions, related classes, etc)를 선언한다면, abstractions의 collection을 설명하는 comment를 포함한다. 무엇이 여기에 맞지 않는지를 미래 authors가 알 수 있도록 충분한 설명을 포함한다. 하지만, 개별 abstractions에 관한 자세한 문서는 이러한 abstraction에 속하지 file level에는 속하지 않는다.

예를 들어, 만약 frobber.h의 file comment를 작성한다면, frobber.cc 또는 frobber_test.cc 에는 file comment를 포함할 필요는 없다. 반면, 연관된 header file이 없는 registered_objects.cc에서 class의 collection을 작성한다면, registered_objects.cc에 file comment를 포함해야만 한다.

Legal Notice and Author Line

모든 file은 license boilerplate를 포함해야만 한다. project에 사용되는 license를 위한 적절한 boilerplate는 선택한다 (예를 들어, Apache 2.0, BSD, LGPL, GPL).

만약 author line에서 file를 크게 변경한다면, author line 삭제를 고려한다. 새로운 files은 주로 copyright notice 또는 author line을 포함하지 않는다.

Struct and Class Comments

모든 non-obvious class 또는 struct declaration은 무엇을 위해 그리고 어떻게 사용되는지 설명하기 위한 comment를 포함해야만 한다.

// Iterates Over the contents of a GargantuanTable.
// Example:
//    std::unique_ptr<GargantualTableIterator> iter = table->NewIterator();
//    for (iter->Seek("foo"); !iter->done(); iter->Next()) {
//        process(iter->key(), iter->value();
//    }
class GargantuanTableIterator {
    ...
};

Class Comments

class comment는 class를 어떻게 그리고 언제 사용해야하는지 알려주는 충분한 정보 뿐 아니라 class를 정확하게 사용하기 위해 필요한 추가 고려사항을 reader에게 제공해야만 한다. class가 동기화 가정이 있다면 문서화한다. 만약 여러 thread에서 접근될 수 있는 class의 instance라면, multithread 사용과 관련된 rule과 불변성을 문서화하는데 추가적인 주의가 필요하다.

class comment는 주로 class의 단순하고 집중적인 사용을 문서화하는 작은 예제 코드 조각을 위한 좋은 장소이다.

충분히 분리된 경우(e.g., .h and .cc files), class의 사용을 설명하는 comments는 interface definition과 함께 해야한다; class operation과 implementation에 관한 comments는 class의 method의 implementation과 함께해야만 한다.

Function Comments

comments 선언은 function의 사용을 설명한다(명백하지 않을 경우); function definition에서 comment는 동작을 설명한다.

Function Declarations

거의 모든 function declaration은 앞에 function이 무엇을 하는지 그리고 어떻게 사용하지를 설명하는 comments를 가져야만 한다. 이러한 comments는 function이 매우 단순하거나 명백할 경우 생략할 수도 있다(e.g., class의 명백한 속성에 관한 단순한 접근)

cc 파일에 선언된 private methods와 functions라도 면제되지 않는다. function comments는 "This function"이 암묵적인 주어로 작성되어야만 하며 동사 구(verb phrase)로 시작해야만 한다; 예를 들어, "Open the file"보다 Opens the file". 일반적으로, 이러한 comments는 function이 task를 어떻게 수행하는지는 설명하지 않는다. 대신 function definition에 comment를 남겨야만 한다.

function declaration에서 comment에 남길 것들:

  • inputs과 outputs이 무엇인지. 만약 function argument names이 `backtick`으로 제공된다면, code-indexing tools는 문서를 더 좋게 보여줄 수도 있다.
  • class member function의 경우: object는 method 호출 지속 시간을 초과해 reference 또는 pointer arguments를 기억하는지 아닌지. 이것은 constructors에서 pointer/reference arguments는 동일하다.
  • 각 pointer argument에 관해, null을 허용하는지 그리고 그렇다면 무슨일이 일어나는지.
  • 각 output or input/output argument에 관해, argument가 특정 state에 있을 경우 무슨 일이 일어나는지. (E.g., state가 추가되거나 덮어쓰이는지?).
  • function의 사용 법에 따라 성능 영향이 있는 경우

예시:

// Returns an iterator for this table. positioned at the first entry
// lexically greater than or equal to `start_word`. if there is no 
// such entry, returns a null pointer. The client must not use the
// iterator after the underlying GargantuanTable has been destroyed.
//
// This method is equivalent to:
//     std::unique_ptr<Iterator> iter = table->NewIterator();
//     iter->Seek(start_word);
//     return iter;
std::unique_ptr<Iterator> GetIterator(absl::string_vie start_word) const;

하지만, 불필요하게 장황하거나 완전히 명백한 말을 언급하지는 말자.

function override을 문서화 할 때, override 된 function의 comment를 반복하는 것보다 override 자체에 집중한다. 많은 경우 override는 추가적은 문서를 필요로하진 않기에 cooment도 불필요하다.

constructor와 destructor를 comment 할 때, code를 읽는 살마이 constructor와 destructor가 무엇을 위한 것인지 알도록 하며 comments가 단순히 "destorys this object"이면 유용하지 않다. Constructor가 인자와 함께 무엇을 하는지를 문서화하고 destructor가 무엇을 정리하는지 문서화한다. 사소하다면 comment는 skip한다. 일반적으로 destructors는 header comment를 가지지 않는다.

Fucntion Definitions

만약 function이 어떻게 작업을 수행하는지 모호하다면, function definition은 설명하는 comment를 가져야만 한다. 예를 들어, definition comment에서 사용한 coding tricks를 설명할 수 있고, 경험했던 overview를 제공하거나 실행가능한 대안을 사용하는 것 보다 해당 방식으로 function을 구현하는 것을 왜 선택했는지를 설명할 수 있다. 예를 들어, function의 first half를 위해 lock을 왜 획득해야만 하지만 second half에는 불필요한지를 언급할 수 있다.

.h 파일 또는 어디에든 function declaration에 제공된 comments를 반복해서는 안된다. function이 무엇을 하는지는 간략하게 요약 가능하지만 어떻게 수행하는지에 좀더 집중하자.

Variable Comments

일반적으로 variable의 실제 이름은 variable이 무엇을 위해 사용되는지에 관한 직관을 충분히 줄만큼 설명적이어야만 한다. 특정 경우에서 더 많은 comments가 필요하다.

Class Data Members

각 class data member의 목적 (또한 instance varaible 또는 member variable를 호출하는)은 명확해야만 한다. 만약 type과 name으로 표현되는 어떤 불변 조건(특수한 값, member 간 관계, 수명 필요성)이 명확하지 않다면, comment되어야만 한다. 하지만, type과 name이 충분하다면(int num_events_;), comment는 불필요하다.

특히, nullptr 또는 -1 같이  sentinel values가 명백하지 않을 때 의미와 존재를 설명하는 comment를 추가한다.

 

private:
    // Used to bounds-check table accesses. -1 means
    // that we don't yet know how many entires the table has.
    int num_total_entires_;

Global Varialbes

모든 global variables는 무엇인지, 무엇을 위해 사용되는지 (불명확하다면) 왜 global로 될 필요가 있는지 설명하는 comment를 가져야만 한다. 예를 들어:

// The total number of test cases that we run through in this regression test.
const int kNumTestCases = 6;

 

Implementation Comments

구현에서 까다롭거나 불명확하거나 흥미롭거나 코드의 중요한 부분은 comment를 가져야만 한다.

Explanatory Comments

까다롭거나 복잡한 code blocks는 앞에 comments를 가져야만 한다.

 

Function Argument Comments

function argument의 의미가 불명확할 경우, 다음 해결책 중 하나를 고려하자:

  • 만약 literal constant라면, 같은 constant가 동일하다고 암묵적으로 가정하는 방식으로 여러 함수에서 호출된다면, 명시적인 제약조건으로 만들고 그것을 유지하도록 보장된 명명된 constant를 사용해야만 한다.
  • bool argument를 enum argument으로 function signature 변경을 고려하자. 이것은 self-describing argument value로 만들 것이다.
  • 몇몇 configuration option을 가지는 function의 경우, single class 또는 struct를 정의해 모든 option을 고려하고 instance로 전달하자. 이러한 접근은 몇몇 이점이 있다. call site에서 name이 option을 참조하며 이러한 의미를 명확하게 한다. 또한 function argument 개수를 줄이며 function call이 읽고 쓰기 쉽게 하도록 한다. 추가된 이점으로 인해, 다른 option을 추가할 때 call site를 변경하지 않아도 된다.
  • named variable과 함께 크거나 복잡한 nested expression을 대체한다.
  • 최후의 수단으로 call site에서 argument의 의미를 명확하게 하는 comment를 사용한다.

다음 예제를 고려한다:

// What are these arguemnts?
const DecimalNumber product = CalculateProduct(values, 7, false, nullptr);

versus:

ProductOptions Options:
options.set_precision_decimals(7);
options.set_use_cahce(ProductOptions::kDontUseCache);
const DecimalNumber product = 
    CalculateProduct(values, options, /* completion_callback=*/ nullptr);

Don'ts

명백한 것은 언급하지 않는다. 특히, C++를 잘 이해하는 reader에게 행동이 명백하다면, 코드가 무엇을 하는지 설명하지 않는다. 대신 왜 code가 무엇을 하는지를 설명하는 더 높은 수준의 comment를 제공하거나 self describing하도록 한다.

Compare this:

// Find the element in the vector.     <-- Bad: Obvious!
if (std::find(v.begin(), v.end(), element) != v.end()) {
    Process(element);
}

To this:

// Process "element" unless it was already processed.
if (std::find(v.begin(), v.end(), element) != v.end()) {
    Process(element);
}

Self-describing code 는 comment를 필요로 하지 않는다. 위 예제에서 comment는 명백하다.

if (!IsAlreadyProcessed(element)) {
    Process(element);
}

Punctuation, Spelling, and Grammer

punctuation, spelling, grammer에 주의를 기울인다; 잘못 작성된 comment보다 잘 작성된 comment가 더 읽기 쉽다.

Comments는 narrative text(이야기 텍스트)만큼 읽기 쉬워야만 하며 적절한 대문자와 punctuation과 함께 사용되어야 한다. 많은 경우, 완전한 문장은 문장 조각보다 더 읽기 쉽다. 더 짧은 comments, code의 line 끝의 comments 같은,은 가끔 formal하지 않지만 스타일의 일관성은 유지되어야만 한다.

semicolon을 사용해야만 할 때 reviewer가 comma를 사용한다고 지적하는 것은 답답할 수도 있지만, 코드의 높은 수준의 명확성과 가독성을 유지하기 위한 중요한 점이다. 적절한 punctuation, spelling, grammar는 이러한 목적을 가능하게 한다.

 

 

TODO Comments

code가 임시적이거나 short-term solution, 충분하지만 완벽하진 않을 경우, TODO comment를 사용한다.

TODOs는 모두 대분자로 TODO string을 포함해야만 하며 bug ID, name, e-mail 또는 person의 identifier 주소가 따라오거나 TODO로 참조된 problem에 관한 최고의 context로 처리되어야만 한다.

// TODO: bug 1234567 - Remove this after the 2047q4 cmopatibility window expires.
// TODO: example.com/my-design-doc - Manually fix up this code the next time it's touched.
// TODO(bug 1234567): Update this list after the Foo service is turned down.
// TODO(John): Use a "\*" here for concatenation operator.

만약 TODO가 "At a future data do something" 형식이라면 매우 구체적인 일자("Fix by November 2005") 또는 매우 구체적인 event ("Remove this code when all clients can handle XML reponses")를 포함하도록 보장한다.

반응형

'C++ > Google C++ Style Guide' 카테고리의 다른 글

Exceptions to the Rules  (0) 2025.06.25
Naming  (1) 2025.06.19
Other C++ Features  (0) 2025.05.26
Google-Specific Magic  (0) 2025.05.26
Functions  (1) 2025.05.25