설계 | 팀 코드 컨벤션

있어서 유용했던 컨벤션

팀 코드 컨벤션을 협의해야 합니다. 읽고, 관리하기 쉬운 코드를 작성하기 위한 일종의 코딩 스타일 규약으로, 팀이 어떤 스타일로 코딩을 할 것인가를 사전에 약속하는 것입니다. 저희가 사전에 협의한, 그리고 따로 협의하지는 않았지만 암묵적으로 지켰던 코드 컨벤션들은 다음과 같습니다.

헤더 파일에서 private 접근자를 public 접근자보다 위에 놓는 점을 제외하면 대부분 c++의 코드 컨벤션 규칙들을 그대로 사용했습니다.

들여쓰기

  • 띄어쓰기가 아니라 tab으로 한다.

변수명

  • 클래스의 멤버 변수 앞에 m_을 붙이며 소문자와 '_'을 사용해 스네이크 표기로 명명한다.

.함수

  • 함수는 소문자로 시작하며 '_'대신 대문자를 중간에 사용하여 카멜 표기로 명명한다.

  • getter, setter 함수는 예외적으로 스네이크 표기로 명명하며 멤버변수와 이름을 일치시킨다. get_m_variable, set_m_variable과 같이 사용한다.

  • constructor, setter의 인자명은 멤버변수명에서 m_ 접두사만 제거하고 그대로 사용한다.

캐노니컬

  • 모든 클래스는 캐노니컬 폼을 준수한다.

괄호

const std::string& Server::get_m_server_name() const { return (this->m_server_name); }
  • 한 줄로 쓸 수 있는 코드(주로 getter)는 한 줄에 쓴다.

	char *
	strdup(const char *s)
	{
  • 리턴 자료형 타입은 함수 이름과 분리한다.

  • 포인터 아스테리스크(*)는 리턴 자료형 뒤에 붙인다.

  • 여는 괄호는 독립적인 줄에 위치시킨다.

헤더파일 내 나열 순서

  • enum, static 변수, 멤버 변수, private 멤버 메소드, 캐노니컬 폼, getter, setter, public 멤버 메소드, 중첩 예외 클래스 순서로 작성한다.

  • 성격이 같은 변수/메소드들은 붙여서 기술하고, 성격이 다르다면 한 줄 개행하고 가급적 주석으로 표시한다.

소스파일 내 나열 순서

/* ************************************************************************** */
/* ------------------------------ CONSTRUCTOR ------------------------------- */
/* ************************************************************************** */
  • 헤더파일과 같은 순서대로 작성한다.

  • 성격이 다른 메소드들은 위와 같이 주석으로 영역을 명확하게 구분한다.

namespace {
	int	setEnv(char **env, int idx, std::string key, std::string val) {...}
	char **dupBaseEnvWithExtraSpace(Config *config, const Request& request) {...}
	std::string getCGIEnvValue(const Request& request, std::string token, Server *server = NULL, Config config = Config()) {...}
}

char**
Server::createCGIEnv(const Request& request)
{
	char **env = dupBaseEnvWithExtraSpace(m_config, request);
	int idx = ft::lenDoubleStr(m_config->get_m_base_env());
	setEnv(env, idx++, "AUTH_TYPE", "");
	setEnv(env, idx++, "CONTENT_LENGTH", getCGIEnvValue(request, "CONTENT_LENGTH"));
	...
}
  • 헤더파일 내 명시된 멤버 메소드를 구현하기 위해 필요한 유틸 함수의 경우 프로젝트 전체에 쓰일만한 범용성이 있다면 libft에, 해당 소스 파일에서 여러 번 쓰일 가능성이 있다면 소스 파일 상단 util 섹션에 구현한다. 오직 하나의 멤버 메소드만을 위한 유틸 함수들은 위의 예제처럼 해당 메소드의 바로 위에 noname namespace를 만들어서 묶는다.

없어서 아쉬웠던 컨벤션들

반면, 미리 사전에 협의하지 못해서 아쉬웠던 컨벤션들은 주로 캐너니컬 폼에 관한 것으로 다음과 같습니다.

  • 생성자 호출시 Member initializer를 통한 초기값 할당과 생성자 코드를 통한 초기값 할당을 어떤 기준으로 나눌 것인가?

  • string, int, pointer 등 변수 자료형에 따른 디폴트 값 할당을 구체적으로 어디까지 어떻게 할 것인가?

  • 할당자(operator=) 사용시 getter를 사용할 것인가?

  • 모든 not public 멤버 변수에 대해 getter와 setter를 만들 것인가?

  • 소멸자 안의 코드를 어떻게 선언할 것인가?

Last updated