최근 수정 시각 : 2025-01-31 14:47:00

코딩 스타일


1. 개요2. 중요성3. 들여쓰기
3.1. 탭3.2. 스페이스
4. 괄호의 위치
4.1. 주요 유형4.2. K&R과 BSD 비교 예제
5. 변수/함수 명칭의 작성 스타일
5.1. 카멜 표기법(Camel Case)5.2. 파스칼 표기법(Pascal Case)5.3. 스네이크 표기법(Snake Case)
5.3.1. Screaming Snake Case
5.4. 케밥 표기법(Kebab Case)5.5. 헝가리안 표기법(Hungarian Notation)
6. 자동화7. 기타

1. 개요

Code Conventions

소스 코드의 가독성을 올리고 혼동을 피하기 위해 작성 시 지키도록 강제되는 불문율적 또는 성문율적 편집 규약.

영어로는 코드 컨벤션이라 하며 현업에서는 영어 쪽으로 더 많이 지칭한다.

2. 중요성

대부분의 범용 프로그래밍 언어는 자유도가 매우 높기에 특정한 동작을 수행하는 여러 방법이 동시에 존재할 수 있다. 이런 탓에 개별 언어에 익숙해진 프로그래머들은 실제 언어와 유사하게 대개 자신만의 말투나 특정 습관을 가지게 되곤 하는데, 문제는 이러한 습관이 사람별로 다르기 때문에 협업에서 문제가 발생한다.

컴퓨터 입장에선 똑같은 결과를 내기만 하면 상관이 없지만, 정작 이러한 코드를 읽고 작성하는 것은 인간이기에 타인이 작성한 코드를 읽을 때 오해가 생기거나, 타인의 코드를 이해하는 데에 지나치게 많은 시간을 할애하게 된다. 심지어는 본인이 작성한 코드조차 현재와 스타일이 달라 유지보수에 어려움을 겪게 되기도 한다. 또한 나쁜 코딩 스타일에 익숙해질 경우 능률이 저하되거나 공동작업에서 혼란을 더욱 가중시킬 수도 있다. 특히, 코딩 스타일이 카멜레온마냥 수시로 변하는 것은 가장 안 좋은 습관 중 하나다. 결국 이러한 혼란과 시간 낭비를 줄이고 유지보수를 용이하게 하기 위해 어느 정도 통일된 규칙이 필요해지게 된다.

협업에서 발생할 수 있는 이런 위험을 사전에 줄이고자, 대다수의 IT 기업 및 이러한 기업에서 진행하는 거대한 프로젝트에는 지켜야 할 코딩 스타일을 미리 정의해 놓거나 때론 이를 강제하는 린터를 도입해둔 경우가 많다. 비단 기업뿐만 아니라 오픈 소스 프로젝트에서도 이러한 강제적 규약을 쉽게 볼 수 있다.

3. 들여쓰기

파일:FB_IMG_1686560399406.jpg
코딩 스타일로 본 조선붕당의 이해

들여쓰기를 으로 하느냐 스페이스로 하느냐는 텔레타이프 터미널이 도입된 이래 개발자들의 유서 깊은(?) 논쟁거리 중 하나이다. 특히 텍스트 에디터가 점점 똑똑해지고 코드 포맷터와 같은 기술이 발전함에도 불구하고 발전된 기능이 서로의 단점을 상쇄하며(...) 현재는 둘 중 무엇을 써도 표시 길이 설정 가능 여부만 제외하면 아주 큰 차이는 나지 않게 되었다.#

2013년 GitHub에 올라온 코드를 분석한 결과 2:1의 비율로 탭보다는 스페이스를 선호하는 모습을 보이고 있다.#

한편 탭과 스페이스의 들여쓰기법을 같은 소스 코드에 여기저기 썼다가는 코드에 혼돈의 카오스가 펼쳐지고, 팀 프로젝트일 경우 팀원들로부터 욕이란 욕은 다 먹게 될 가능성이 높으므로 절대로 그러지 말자. 물론 어지간한 IDE에서는 코드 포맷팅을 지원하므로 한 번 돌려주면 깔끔해진다. 사실 탭과 공백만으로 코딩을 하는 제정신 아닌 언어가 있기는 하다

3.1.

탭 문자는 스페이스에 비해 접근성이 높고 개별 사용자의 자유를 보장한다.# 사용자가 탭 문자의 표시 길이를 원하는 대로 설정할 수 있기 때문에 똑같은 코드베이스를 열더라도 2칸 들여쓰기를 원하는 사람은 2칸을, 4칸 들여쓰기를 원하는 사람은 4칸 들여쓰기된 코드를 볼 수 있다.# 만약 스페이스를 사용한다면 코드 포맷터를 통해 일괄적인 변환을 하더라도 커밋 직전에 이를 되돌려야 한다. 탭과 길이 설정을 사용하면 코드를 전혀 수정하지 않고도 모든 사용자가 원하는 수준의 들여쓰기 표시가 가능하므로, 사실상 스페이스 진영에서 벌어지는 2칸 4칸 논란을 종결시킬 수 있다.#

실제로 시각장애인들이 코드를 읽기에도 탭 사용이 더 접근성이 높다.#

실제 문자가 하나라는 것은 생각보다 장점이 많다. 탭은 의미적(semantic)으로 들여쓰기만을 의미하므로 일반 공백과 구분되며, 따라서 두 개 이상의 연속된 공백은 바로 포맷 오류임을 알 수 있다. 또한 들여쓰기에서 커서를 이동시킬 때도 화살표 키/백스페이스 키 한 번이면 되니 편집이 훨씬 쉬워진다. 들여쓰기를 지울 때마다 매번 네 번씩 백스페이스를 누를 필요가 없다는 것.[1]

탭 사용을 주장하는 측의 또다른 주장은 들여쓰기에서 탭 사용이 저장공간을 아낄 수 있다(space-efficient)는 것이다. 다만 이는 현대에 들어서는 크게 중요한 내용은 아닌데, 프로젝트의 파일이 총 200개 정도 되고, 각 파일이 400줄 내외에 평균 2-depth의 들여쓰기를 한다면 4칸 스페이스 들여쓰기를 전부 탭으로 치환했을 때 줄어드는 용량이 500 킬로바이트도 안 된다.

3.2. 스페이스

스페이스를 사용했을 때의 장점은 지금 자신이 보고 있는 코드가 다른 사람의 에디터에서도, 어디에서든 항상 똑같이 보임을 보장해준다는 것이다.# 결국 논리적인 길이는 같다지만, 똑똑하지 않은 컴파일러가 내뱉는 에러 코드의 줄, 열 번호 등이 자신이 보고 있는 것과 다르다면 어떨까?[2]

현재 발달한 대부분의 에디터에서는 소프트탭(softtab)을 지원하므로 키보드에서 물리적인 탭 키를 눌러도 실제로는 정해진 만큼의 공백이 자동으로 삽입된다.# 이는 다시 말해 들여쓰기 문자로 스페이스를 선택해도 매번 두번 또는 네번씩 스페이스 연타를 할 필요가 없다는 것으로, 스페이스 들여쓰기 사용을 더 쉽게 만들어준다.

탭 문단에서 말한 시맨틱(semantic)과는 별개로, 코드에서 스페이스와 탭 두 종류의 화이트스페이스를 둘다 사용하는 것은 혼동을 일으킬 수 있다. 특히 탭은 에디터에 따라 태뷸레이션 정렬이 된 채 렌더되므로#, <공백>, <탭><탭>이 똑같은 길이로 보일 수 있다.# 특히 Python처럼 들여쓰기에 스페이스가 섞여있으면 오류를 뿜는 언어를 사용할 때는 이러한 상황을 최대한 피해야 한다.

대신 요즘에는 들여쓰기를 두 번 하냐 네 번 하냐로 갈린다. HTML이나 YAML 등은 코드 라인이 길어지는 경향이 있어 두 번 들여쓰기를 선호하는 경우가 많다.

4. 괄호의 위치

4.1. 주요 유형

괄호의 위치에 따른 코딩 스타일에는 대표적으로 K&R[유래], BSD(Allman)[4], GNU 3개가 있다.

각 코딩 스타일은 서로 장단점이 있으며, 당연한 이야기지만 자기가 익숙한 스타일이 다른 코딩 스타일보다 더 좋아 보인다. 다수의 프로그래머가 모였을 때 혼란의 원인이 되기도 한다. 코딩 스타일은 부먹찍먹 논쟁과 흡사하다. 서로간의 취향 차이일뿐 완벽한 코딩 스타일이란 존재하지 않으므로 자신이 사용하는 코딩 스타일이 다른 스타일보다 우월하다고 주장하는 우를 범하지 말도록 하자.

대부분의 언어는 대표 코딩 컨벤션을 가지고 있다. 일반적으로 그 언어의 표준을 따르게 되며, 프로젝트별로 코딩 스타일이 정해져 있는 경우도 있다. 따라서 개인 프로젝트가 아닌 이상, 자기가 좋아한다고 해서 마음대로 코딩 스타일을 변경하기는 힘들다.
K&R
if (...) {
    처리1();
    처리2();
}
여는 블록을 if와 같은 행에 배치한다. 코드 줄 수를 절약하여 한눈에 많은 코드를 볼 수 있고 수평으로 많은 코드를 작성할 수 있다. 흔히 C 계열 창시자들이 사용하던 스타일이다.
Java 계열 Eclipse / 구글 C++[5], JavaScript[6] 등의 기본 포맷팅이다.
블록 내에 문장이 하나만 있을 경우에는 중괄호를 쓰지 않는 것이 특징이며, 문장이 하나인 경우에도 중괄호를 써주는 것은 One True Brace(1TBS or OTBS)라고 한다.
BSD
if (...)
{
    처리1();
    처리2();
}
GNU의 블럭의 소속을 분명히 한다는 장점과 K&R의 수평으로 많은 코드를 작성할 수 있다는 장점을 가져와 결합한 스타일이다. 줄 수는 GNU 스타일만큼 늘어나지만 수평으로는 K&R만큼 빽빽하게 쓸 수 있다.
Visual Studio에서의 기본 포맷팅이다.
GNU
if (...)
    {
        처리1();
        처리2();
    }
블록을 if문 아래에 작성한다. 블록이 if에 속한 블럭임을 분명히 표시하여 구조가 잘 보인다. 허나 들여쓰기를 많이 해서 처리하기에 수평으로 많은 코드를 작성할 수 없다.
물론, 일반적인 들여쓰기를 공백 4자로 두고, 괄호의 들여쓰기는 2자로 두는 등의 방법도 존재한다.

위 설명에서는 조건문과 반복문, 함수 등의 차이는 대충 뭉뚱그렸는데, 실제로는 조건문과 반복문, 함수 등에서 들여쓰기의 차이를 두는 경우도 있다.

K&R과 Allman을 합친 Horstmann 스타일이 따로 존재한다.

#!syntax cpp
int main()
{   while (x == y)
    {   something();
        somethingelse();

        if (some_error)
        {   /* the curly braces around this code block could be omitted */
            do_correct();
        }
        else
            continue_as_usual();
    }

    finalthing();
}


그 외 다양한 스타일은 위키 문서를 참조하자.

4.2. K&R과 BSD 비교 예제

같은 코드를 K&R과 BSD로 작성하고 비교해 보자.
K&R
#!syntax cpp
if (a == 1) {
    for (i = 0;i < 1000;i++) {
        if (b == 10) {
            처리1();
            처리2();
        } else if (c == 10) {
            처리3();
            처리4();
        }
    }
}
BSD
#!syntax cpp
if (a == 1)
{
    for (i = 0;i < 1000;i++)
    {
        if (b == 10)
        {
            처리1();
            처리2();
        }
        else if (c == 10)
        {
            처리3();
            처리4();
        }
    }
}

BSD 쪽이 좀 더 아래로 길어지는 것을 볼 수 있다. 코드를 종이에 뽑을 일이 있으면 이 문제는 좀 더 중요해진다. 그리고 자기가 소스 코드 몇 줄을 작성하였는지 뽐 낼 때는 BSD를 써서 조금 늘려 자랑한다 그래서 출판물에서는 종이 비용을 아끼기 위해 K&R을 선호하는 경향이 있다. 그리하여 대부분의 프로그래밍 언어 교재가 K&R 스타일로 작성되기 때문에 코딩을 갓 접한 학생들이 K&R 스타일에 자연스럽게 익숙해져 있기도 하다. 물론 개인 취향에 따라 나중에 BSD 스타일을 접하고선 갈아타버리기도 한다.

한편, 무슨 일이 생겨서 저 반복문을 반복문이 아니게 해야 한다고 하자. BSD는 for문이 있는 줄만 통째로 지워도 된다. for문에 붙어 있던 중괄호는 단순 블록이 되어 코드에 영향을 미치지 않는다. 물론 변수 i가 for문의 조건식 안에서 선언되었다면 컴파일 에러가 발생하므로 주의.
BSD
#!syntax cpp
if (a == 1)
{
    //for (i = 0;i < 1000;i++)
    {
        if (b == 10)
        {
            처리1();
            처리2();
        }
        else if (c == 10)
        {
            처리3();
            처리4();
        }
    }
}

그런데 K&R 스타일에서는 그렇게 하면 여는 괄호만 지워지고 닫는 괄호는 안 지워진다. 그래서 리팩토링이 좀 귀찮아진다.
K&R
#!syntax cpp
if (a == 1) {
    //for (i = 0;i < 1000;i++) {
        if (b == 10) {
            처리1();
            처리2();
        } else if (c == 10) {
            처리3();
            처리4();
        }
    }
}

사실 이 논란은 C/C++ 쪽에서 주로 일어나는 편이고, Java나 JavaScript, C# 등의 다른 프로그래밍 언어에서는 대부분 한 쪽으로 통일된 추세이다.

5. 변수/함수 명칭의 작성 스타일

식별자 명칭을 작성할 때 이름을 정의하는 것도 코딩 스타일 중 일부이다. 이 식별자에는 변수함수명, 타입명, 이름공간(네임스페이스) 이름을 모두 포함한다. 심지어 대형 프레임워크나 프로젝트에는 파일명에도 스타일을 적용하는 경우도 있다. 대표적으로 파일명으로 동적 라우팅을 하는 Next.js, Astro나 2차 확장자(*.service.ts, *.dto.ts 등)로 코드의 종류를 결정하는 Angular, nestjs등이 존재한다.

대표적인 표기법은 다음 6가지가 있으며, 헝가리안 표기법을 제외하고는 언어에 따라 적절히 혼합된다. 예를 들어 Java의 경우 변수, 메서드 등에는 카멜 표기법, 클래스 등의 타입에는 파스칼 표기법, 상수에는 대문자 스네이크 표기법이 권장되고 있다. C#은 Java와 비슷하지만 메서드에도 파스칼 표기법으로 쓴다는 점이 다르다. 파일명의 경우는 보통은 스네이크 표기법이 권장되고 있으나, Java, C# 등 일부 언어에서는 (대표) 타입명과 동일한 파일 이름을 권장하기도 한다.

5.1. 카멜 표기법(Camel Case)

camelCase

여러 단어를 연달아 사용할 때 각 단어의 첫 글자를 대문자로 적되, 맨 앞에 오는 글자는 소문자로 표기하는 것이다.

낙타의 등에 있는 혹과 같다고 하여 카멜(Camel) 표기법이라고 부른다. 표기에서도 볼 수 있듯 봉이 하나이기 때문에 단봉낙타 표기법이라고도 하며, 파스칼 표기법과 비교하여 lowerCamelCase라고도 한다. 중간에 XML, JSON 같이 식별자 이름에 약자가 포함되는 경우는 해당 약자를 모두 대문자로 쓸 수도 있다.
예: parsedXMLElement

5.2. 파스칼 표기법(Pascal Case)

PascalCase

이 역시 연달아 오는 단어의 모든 앞글자를 대문자로 표기하는 것은 카멜 표기법과 같지만, 맨 앞에 오는 문자까지도 대문자로 표기한다.

카멜 표기법과 비교하여 UpperCamelCase라고도 하며, 봉이 둘이기 때문에 쌍봉낙타 표기법이라고도 한다. 전술했듯 식별자의 특성에 따라 카멜 표기법과 파스칼 표기법을 적절하게 혼합하여 쓰는 작성 스타일이 대세로, 변수 정의에는 카멜 표기가, 타입 정의에는 파스칼 표기가 대세이다. 언어에 따라 전부 카멜, 전부 파스칼로 표기할 것을 권장하기도 한다.

5.3. 스네이크 표기법(Snake Case)

snake_case

단어 사이에 언더바_를 넣어서 표기하는 것이다.

허나 한 단어에 언더바를 붙인 _apple 등의 명칭은 C++의 장래 예약어 확장을 위해 지양되고 있다. 자세하게는, 언더바를 사용한 후 바로 대문자로 시작하는(e.g. _Apple, _Banana, _Cucumber) 식별자나 인접한 언더바(_a_apple, _b_Banana), 또는 두 개의 언더바(\Apple, \banana)는 모든 스코프에서 지양된다. 언더바로 시작하는 모든 식별자는 전역 스코프에서만 지양된다. 언더바 바로 뒤의 문자를 대문자로 하면 Train_Case, 소문자로 하면 spiral_case로 불린다.

언어 내의 식별자뿐만 아니라, 언어가 적힌 파일명을 작성하는 데에도 주로 사용된다. 파일명에 공백이 들어가면 터미널에서의 작업이 힘들기 때문.

5.3.1. Screaming Snake Case

SCREAMING_SNAKE_CASE

snake case와 비슷하게 단어 구분자로 _를 사용하지만, 나머지 문자를 전부 대문자로 적는 표기법. MACRO_CASE라고도 부른다.

주로 상수 정의, 환경 변수 정의 등에 사용된다. 한글 등에는 없는 특징이지만 영어에서 문장을 전부 대문자로 적을 경우 굉장히 강조되어, 마치 화자가 소리치는 것 같은 느낌을 준다. 따라서 주로 경고의 의미가 있거나, 사용 시 주의해야 하는 경우 이렇게 표기하기도 한다.

상수 개념이 없는 파이썬 같은 언어에서 상수를 선언할 때에 권장되는 방법이기도 하다. const나 final 등으로 알아서 값 변경을 차단해주는 타 언어와 달리 파이썬 같은 경우는 실수로 값을 변경하지 않도록 그냥 개발자가 조심해야 하기 때문에, 일반 용도의 변수가 아님을 대문자로 적어 강조하는 것이다.

5.4. 케밥 표기법(Kebab Case)

kebab-case

snake case와 거의 비슷하지만 구분자로 -를 사용한다. 단어들이 마치 케밥 꼬치에 꽂힌 것처럼 보인다고 해서 붙은 이름이다.

현업에서 사용되는 언어들 중 케밥케이스를 공식 컨벤션으로 강제하는 언어는 사실상 없다. 오히려 불가능한 경우가 많은데, 컴파일러가 변수명의 '-'를 '빼기'로 인식하는 경우가 많기 때문. 주로 파일명 등을 공백 없이 작성할 때나 CSS 클래스명 등의 특수한 경우에 사용된다.

5.5. 헝가리안 표기법(Hungarian Notation)

접두어에 자료형을 붙인다. Windows API가 이 표기법을 사용한다.

예시로 strName, bBusy, szName 등이 있다. 장점은 변수명만 봐도 자료형을 유추할 수 있어 가독성과 편의성이 향상된다는 것이다. 때문에 자료형 지원이 다양하지 않았던 시기에는 자주 사용되었다. 단점은 접두어만큼 변수명이 길어지기 때문에 사람에 따라서는 오히려 역으로 가독성이 깎일 수 있다는 것과, 개발 도중에 자료형이 바뀐다면 모든 변수명을 수정해주어야 하는 난감한 상황이 연출된다는 것이다.[7]

과거에는 거의 표준 수준의 코딩 스타일인 시절도 있었지만 2020년대에는 예전에 비해서는 잘 사용되지 않는 스타일이 되었는데, 현대에는 자료형도 문서 데이터도 더 다양해졌고, IDE(통합 개발 환경)의 발전으로 변수 위에 마우스만 가져다 대도 타입을 곧바로 확인할 수 있게 되었기에 굳이 변수명까지 이중으로 표기해야 할 필요성이 줄어든 것이 크다. 자료형이 명백하게 제한되는 경우라 해도 보통은 다른 표기법으로 대체되는 경향이 크다.
파일:상세 내용 아이콘.svg   자세한 내용은 헝가리안 표기법 문서
번 문단을
부분을
참고하십시오.

6. 자동화

어떤 특정 코딩 스타일로 합의를 했더라도 이를 매번 코드 리뷰 단계에서 수동으로 강제하기는 힘들다. 이를 해결하기 위해 CI 또는 커밋 단계에서 자동으로 특정 규칙을 강제하는 도구들을 도입하게 된다. 주로 자동으로 포맷을 정렬해 주는 도구를 코드 포매터, 정해진 규칙을 기반으로 나쁜 습관들을 막아 주는 도구를 린터라고 한다.

6.1. 코드 포매터

파일:상세 내용 아이콘.svg   자세한 내용은 코드 포매터 문서
번 문단을
부분을
참고하십시오.

7. 기타

디자인 패턴과 코딩 스타일/코드 컨벤션을 헷갈려하는 주니어들이 많은데, 두 개념은 본질적으로 다른 것이다. 디자인 패턴은 프로그래머들이 자주 마주하는 문제들을 해결할 때 더 보편적이고, 쉽게 확장 가능한 방법으로 설계함으로써 코드의 기술적 부채를 줄이는 공학적(engineering) 기법들의 총칭이라면, 코드 컨벤션은 단순히 사람이 보기 좋으려고 문장 부호, 이름 등을 특정한 형식으로 쓰기를 강제하는 잡다한 규칙들의 집합이다.

물론 코드 컨벤션도 지키지 않으면 코드가 매우 엉망이고 지저분하게 보이겠지만, 디자인 패턴을 지키지 않으면 제품의 유지보수 비용이 급격하게 하락하고 곧장 스파게티 코드가 되어 버려, 훨씬 중요한 개념이다. 실제로 코드 컨벤션은 회사나 프로젝트마다 미세하게 다른 경우가 많지만, 디자인 패턴과 클린 아키텍처 원칙은 개개인의 입맛에 따라 달라지는 것이 결코 아니다.

[1] 소프트탭을 정말 잘 지원하는 에디터의 경우, 삽입뿐만 아니라 들여쓰기의 삭제까지고 정밀하게 한 칸으로 처리해주기 때문에 이는 항상 맞는 말은 아니다.[2] 대부분의 경우 최신 컴파일러들은 이런 문제를 전부 고려하고 설계되고, diagnose로 에디터 내에서 직접 표시를 해주기 때문에 큰 문제는 없다.[유래] Kernighan&Ritchie의 <The C Programming Language>에서 쓰였기 때문.[4] C언어에서 주로 Allman 이라 부른다. 한때 메일 서버계의 IE로 불리던 sendmail의 저자이며, 게이 프로그래머로 유명한 Eric Allman의 이름에서 따옴.[5] https://google-styleguide.googlecode.com/svn/trunk/cppguide.html[6] https://google.github.io/styleguide/javascriptguide.xml[7] 특히 컨테이너 계열에서 자주 일어난다. ArrayList 계열 컨테이너를 LinkedList나 다른 Set, Map, Hash 등의 컨테이너로 바꿀 때. 물론 리펙토링 기능이 있다면 그걸 쓰면 편하지만 그마저도 귀찮다.