camelCase vs kebab-case, 왜 언어마다 다른 표기법을 쓰나
같은 프로젝트 안에서도 JavaScript 변수는 myVariable인데 CSS 클래스는 my-class로 쓰고, URL은 my-page-slug로 씁니다. 이 불일치가 단순한 스타일 취향처럼 보이지만, 실제로는 각 언어의 문법 제약이라는 명확한 기술적 이유에서 비롯됩니다. 이 가이드는 왜 프로그래밍 언어는 camelCase를 강제하다시피 하고, CSS·URL은 kebab-case를 자유롭게 쓰는지를 문법 수준에서 설명합니다.
1. 하이픈은 왜 변수명에 못 들어가나: 뺄셈 연산자 충돌
JavaScript, Java, C, Python 같은 프로그래밍 언어의 문법에서 하이픈(-)은 이미 뺄셈 연산자로 예약되어 있습니다. 만약 my-variable이라는 이름을 변수명으로 쓸 수 있다면, 파서는 이것이 하나의 식별자인지 아니면 "my라는 변수에서 variable이라는 변수를 뺀다"는 뺄셈 표현식인지 구분할 수 없습니다. 실제로 브라우저 콘솔에서 let my-variable = 5;를 실행하면 문법 오류(SyntaxError)가 발생합니다. 언어 설계자 입장에서는 이 모호성을 원천 차단해야 했고, 그 결과 대부분의 C 계열·스크립트 언어가 식별자에서 하이픈 사용을 아예 금지했습니다.
2. 대안이 camelCase가 된 이유: 언더스코어와의 경쟁
하이픈을 못 쓰니 여러 단어를 하나의 식별자로 합칠 방법이 필요했고, 후보는 크게 두 가지였습니다. 단어 사이에 언더스코어(_)를 넣는 snake_case와, 단어 경계를 대문자로 표시하는 camelCase입니다. 둘 다 문법적으로는 문제가 없어 실제로 언어별·커뮤니티별로 다른 선택을 했습니다. C 표준 라이브러리와 Python은 snake_case 전통을 이어받았고, Java는 언어 설계 초기부터 camelCase를 공식 명명 규칙으로 채택했으며 이후 JavaScript가 Java의 명명 관례를 그대로 물려받았습니다. 즉 camelCase 자체가 문법적으로 강제된 유일한 선택지는 아니지만, 하이픈이 막혀 있다는 제약만큼은 두 표기법 모두에 공통으로 적용됩니다.
| 표기법 | 하이픈 사용 | 프로그래밍 언어 식별자로 사용 가능? |
|---|---|---|
| camelCase (myVariable) | 없음 | 가능 |
| snake_case (my_variable) | 없음 | 가능 |
| kebab-case (my-variable) | 있음 | 불가능 (뺄셈 연산자와 충돌) |
3. CSS·URL은 왜 kebab-case가 자유로운가
CSS 클래스명, HTML 속성명, URL 슬러그는 애초에 프로그래밍 언어의 "식별자"가 아니라 단순한 문자열입니다. CSS 파서는 .my-class를 뺄셈 표현식으로 해석할 이유가 없습니다 — CSS 문법 자체에 산술 연산이 없기 때문입니다. URL 경로도 마찬가지로 브라우저나 서버가 특정 문자를 연산자로 해석하지 않는 순수한 경로 문자열이라, 하이픈을 넣는 데 아무 문법적 제약이 없습니다. 오히려 kebab-case는 몇 가지 실용적 이점까지 있습니다. 소문자와 하이픈만 사용하면 대소문자를 구분하지 않는 파일시스템(Windows 등)이나 일부 URL 처리 환경에서 myPage와 mypage가 같은 것으로 취급되는 혼동을 원천적으로 피할 수 있고, 검색엔진도 하이픈을 단어 구분자로 인식해 URL 슬러그의 가독성과 SEO에 유리합니다. URL 슬러그 생성기나 슬러그 검사기로 URL을 만들 때 자동으로 kebab-case가 기본값인 것도 이런 이유입니다.
4. 실무 관례 매트릭스: 어디서 어떤 케이스를 쓰나
snake_case — Python 변수·함수명(PEP8), SQL/DB 컬럼명
kebab-case — CSS 클래스명, URL 슬러그, HTML 속성 (하이픈이 문법적으로 자유로운 영역)
PascalCase — JS/TS·C# 클래스명, React/Vue 컴포넌트명
UPPER_SNAKE_CASE — 환경변수(.env), 상수 선언
흥미로운 점은 같은 JavaScript 생태계 안에서도 문맥에 따라 케이스가 갈린다는 것입니다. 변수·함수는 문법 제약 때문에 camelCase를 쓰지만, 같은 JS 파일 안에서 CSS-in-JS로 클래스명을 다룰 때는 'my-class'처럼 문자열 안에 kebab-case를 그대로 넣습니다. 문법적 제약은 "식별자로 쓰이는가, 문자열로 쓰이는가"에 따라 갈리는 것이지 언어 자체의 취향이 아닙니다.
5. 변환할 때 흔히 놓치는 지점: 약어와 숫자
텍스트 케이스 감지기로 실제 코드베이스의 식별자를 케이스별로 변환해보면 대부분 문제없이 동작하지만, 약어 뒤에 숫자나 다른 대문자가 붙는 패턴(예: HTML5Parser, userID2Name)은 감지 규칙이 단어 경계를 명확히 잡지 못해 "알 수 없음"으로 표시될 수 있습니다. 이는 이 도구만의 한계가 아니라, 케이스 변환 자체가 "소문자에서 대문자로 바뀌는 지점"을 단어 경계로 삼는 규칙 기반 방식이기 때문에 연속된 대문자(약어)가 낀 경우 범용적으로 발생하는 모호성입니다. 약어가 포함된 식별자를 변환할 때는 결과를 항상 눈으로 한 번 더 확인하는 습관이 필요합니다.
자주 묻는 질문
Q. 왜 JavaScript 변수명에는 하이픈을 쓸 수 없나요?
하이픈이 이미 뺄셈 연산자로 예약되어 있어서입니다. my-variable을 식별자로 허용하면 파서가 이를 뺄셈 표현식과 구분할 수 없기 때문에 문법 오류로 처리됩니다.
Q. CSS 클래스명은 왜 하이픈을 자유롭게 쓸 수 있나요?
CSS 문법에는 애초에 산술 연산자가 없고 클래스명이 프로그래밍 언어의 식별자가 아니라 단순 문자열로 처리되기 때문에, 하이픈을 연산자로 오인할 여지가 없습니다.
Q. snake_case도 하이픈 문제를 피할 수 있는데 왜 JS는 camelCase를 쓰나요?
둘 다 문법적으로는 가능하지만, Java의 명명 관례를 JavaScript가 그대로 물려받으면서 camelCase가 커뮤니티 표준으로 굳어졌습니다. 문법이 강제하는 것은 "하이픈 금지"까지이고, camelCase냐 snake_case냐는 언어·커뮤니티의 관례 선택입니다.
Q. 텍스트 케이스 감지기가 모든 문자열의 케이스를 정확히 판별하나요?
camelCase·PascalCase·snake_case·kebab-case 등 표준 패턴은 정확히 판별합니다. 다만 약어 뒤에 숫자나 대문자가 곧바로 붙는 패턴(HTML5Parser 등)은 단어 경계 판별 규칙의 한계로 "알 수 없음"으로 나올 수 있어 결과를 확인하는 것이 좋습니다.