C++ 코딩 스타일 정리

Fuji ㅣ 2022. 11. 10. 16:58


코드 문서화 ( documentation )

프로그래밍에서 말하는 documentation은 주로 소스 파일에 작성된 주석을 의미한다. 코드를 작성할 당시에 가졌던 생각을 메모해두자.  

코드는 자신이 작성해도 나중에 기본 로직조차 기억이 나지 않을 수 있다. 그러므로 코드를 작성할 때는 이해하기 쉽도록 작성하자. 타인에게 보여질 코드라고 생각하고 작성하자.

다음은 잘 작성된 코드의 대표적인 특징들이다.

 

  • 문서화
  • 분할
  • 명명 규칙
  • 언어 사용
  • 포맷팅

 

 

사용법을 알려주는 주석 

주석을 작성하는 한 가지 이유는 클라이언트에 코드를 사용하는 방법을 알려주기 위해서다. 일반적으로 개발자는 함수의 이름, 리턴값의 타입, 매개변수의 이름 및 타입만 보고도 그 함수의 기능을 쉽게 파악할 수 있어야 한다. 

 

  • 각각의 익셉션에 대응하기 위해 익셉션이 발생한다는 사실을 주석으로 적어주자.
  • int와 같은 리턴 타입이 의미가 불분명할 경우 주석으로 명시한다.

 

하지만 함수 이름만 보아도 알 수 있는 형태거나, 리턴 타입이 type alias에 해당할 경우 굳이 주석을 작성해주지 않아도 된다. 하지만 이러한 형태들이 불분명하다면 주석으로 남겨야한다.

 

  •   사용 예
/*
* 발생 가능한 인셉션:
*   openDatabase()로부터 호출하지 않으면 
*   DatabaseNotOpenedException이 발생한다.
*/
RecordID saveRecord ( Record & record );​

 

 

알고리즘을 설명해주는 주석

만약 보기 힘든 알고리즘 로직이 있다면 코드에서 사용하는 알고리즘을 명시하고 불변 속성에 대한 주석을 추가하면 좋다. 불변 속성 ( invariant ) 이란 루프와 같은 일정한 코드 영역을 실행하는 동안 반드시 만족해야할 조건을 의미한다. 

 

 

메타 정보를 제공하는 주석

메타 정보는 구체적인 동작에 대해서는 표현하지 않고 코드 생성과 관련된 세부사항만 표현한다.  보통 메타 정보는 저자, 작성 일자, 주요 기능등 메타 정보로 표현하는 예를 보여준다.

다만 주석에 너무 신경 쓰다보면 정도를 넘어서기 쉽기 때문에 팀에서 규칙으로 삼기에 가장 적합한 주석의 종류는 반드시 팀원과 상의해서 결정하자.

또한 모든 문장마다 주석을 다는 방식이 바람직하지 않을 때가 많지만, 코드가 굉장히 복잡하고 난해해서 굳이 주석을 다 달아야하는 방식을 적용해야 한다면 코드를 그대로 번역하지 말고 앞에 나온 예제처럼 코드의 작성 의도를 설명한다.

 

 

머리말 주석

소스 파일 최상단에 명시할 내용을 표준 주석으로 정해주면 좋다. 예를 들면 다음과 같다.

 

  • 최종 수정 일자*
  • 최초 작성자*
  • 변경 내역*
  • 파일에서 구현한 기능의 ID
  • 저작권 정보
  • 파일/클래스에 대한 간략한 설명
  • 미완성 기능
  • 발견된 버그

 

여기서 별표를 한 항목은 대부분 소스 코드 관리 시스템에서 자동으로 달아준다. 소스코드 관리 솔루션을 사용하면 여러 유용한 주석들을 달아준다.

Subversion, SVN을 비롯한 몇몇 소스 관리 시스템은 메타데이터를 추가하는 기능을 제공해준다.  C++ 프로그래머는 HTML 기반 문서, 클래스 다이어그램, 유닉스 맨페이지를 비롯한 여러가지 문서를 자동으로 생성해주는 Doxygen 이란 무료 툴을 많이 사용한다. 

 

 

정리

  • 또한 명심해야하는 것은 굳이 주석을 달지 않아도 되는지, 작성한 코드를 수정할 수는 없는지 검토하자.
  • 알고리즘을 작성한다면 로직 설명을 주석으로 남기자
  • API를 사용하는 과정이 명확하지 않다면 사용한 API에 대한 참고 문헌을 남긴다.
  • 코드를 업데이트할 때 주석도 함께 업데이트하자. 주석이 정확하지 않은 코드만큼 이해하기 어려운 것도 없다
  • 대체로 잘 작성된 코드는 주석이 적다. 좋은 코드는 읽기 쉽다. 모든 문장마다 주석을 달아야 한다면 주석에서 표현하는 내용을 가깝게 코드를 수정할 수 없는지 검토하자. 예를들어 함수 이름, 변수, 매개변수, 클래스의 역할이 잘 드러나도록 이름을 고치거나 const도 적절히 활용한다. 

 

 

 

디자인 기준으로 코드 분할하기

리팩토링 ( refactoring ) 이란 코드의 구조를 재조정하는 작업이다. 코드를 리팩토링하는데  사용하는 기법의 예로 다음과 같은 것들이 있다.

 

  • 추상화 수준을 높이는 기법
    - 필드 캡슐화: 필드를 private로 설정하고, get set 메서드로 접근하게 만든다.
    - 타입 일반화: 코드를 좀 더 공유할 수 있도록 좀 더 일반적인 타입을 사용한다.
  • 코드를 좀 더 논리적으로 분할하는 기법
    - 메서드 추출: 거대한 메서드를 좀 더 이해하기 쉽도록 일부를 뽑아내서 새롭게 정의한다.
    - 클래스 추출: 기존 클래스에 있는 코드 중 일부를 새롭게 정의한다.
  • 명칭과 위치를 개선하는 기법
    - 메서드 및 필드 이동: 좀 더 적합한 클래스나 소스 파일로 이동한다.
    - 메서드 및 필드 이름 변경: 목적이 잘 드러나도록 이름을 바꾼다.
    - 올리기 ( pull up ): OOP에서 기본( 베이스, base ) 클래스로 옮기는 기법
    - 내리기 ( push down ): OOP에서 상속 ( 확장, derived ) 클래스로 옮기는 기법

 

프로그램을 구현할 때 모든 기능을 빠짐없이 코드로 작성하기 보다는 코드 분할 기법을 적용해서 나중에 모듈, 함수에서 구현할 부분을 따로 빼놓는 방식으로 작성하면 코드의 밀집도를 낮추고 구조를 좀 더 체계적으로 만들 수 있다.

 

 

 

스타일에 관하여 해결할 문제

스타일에 대한 일관성을 유지하기란 쉽지 않다. 그 이유는 다양하지만 대표적으로 const에 대한 사용을 예로 들 수 있다. const를 제대로 활용하지 못한 라이브러리나 예전 코드를 가져다 사용하게 되면 미숙한 프로그래머는 const를 지워버리는 경우가 생긴다. 결국 const를 전혀 사용하지 않은 프로그램처럼 만들어버린다. 이 부분은 const_cast()로 잠시 const를 사용하지 않는다라고 명시할 수 있지만 경험이 부족한 프로그래머는 떠올리기 쉽지않다.