변수 이름 하나 지으려다 userId, user_id, UserID, user-id 사이에서 고민한 적 있으시죠. 저도 프로젝트를 옮길 때마다 헷갈려서 한 번 정리해 두기로 했어요. 결론부터 말하면 camelCase는 JavaScript·Java 계열의 변수와 함수, snake_case는 파이썬·러스트 함수와 DB 테이블·컬럼, kebab-case는 URL·CSS 클래스·파일명, PascalCase는 거의 모든 언어의 클래스와 타입, CONSTANT_CASE는 상수와 환경변수에 씁니다. 그리고 한 프로젝트 안에서 "계층마다 다른 표기"를 쓰는 건 정상이고, 중요한 건 경계에서 한 번만 변환하는 거예요.
이 글은 표기법별 규칙, 언어별 공식 스타일 가이드의 관례, 약어 처리 같은 애매한 경우, DB에서 화면까지 이름이 어떻게 바뀌는지를 순서대로 정리했어요. 예시 변환은 대소문자 변환기의 단어 분리 규칙과 같습니다.
핵심 요약
표기법은 단어를 어떻게 붙이느냐의 차이예요. 대문자로 붙이면 camel·Pascal, 밑줄이면 snake, 하이픈이면 kebab입니다.
언어마다 공식 관례가 정해져 있으니, 새로 정하기보다 그 언어의 스타일 가이드를 따르는 게 가장 좋아요.
URL과 CSS는 소문자 kebab-case, DB는 소문자 snake_case가 사실상 표준이에요.
DB의 user_id와 API·JS의 userId처럼 계층마다 표기가 달라지는 건 자연스럽고, 변환은 한 곳에서만 하세요.
네이밍 컨벤션 5가지, 한 표로 비교
먼저 같은 세 단어 "user profile image"를 각 표기법으로 써 보면 차이가 바로 보여요.
| 표기법 | 예시 | 규칙 | 주로 쓰는 곳 |
|---|---|---|---|
| camelCase | userProfileImage | 첫 단어 소문자, 이후 단어 첫 글자 대문자 | JS·Java 변수·함수, JSON 키 |
| PascalCase | UserProfileImage | 모든 단어 첫 글자 대문자 | 클래스, 타입, React 컴포넌트, C# 메서드 |
| snake_case | user_profile_image | 전부 소문자, 밑줄로 연결 | 파이썬·러스트 함수·변수, DB 테이블·컬럼 |
| kebab-case | user-profile-image | 전부 소문자, 하이픈으로 연결 | URL 경로, CSS 클래스, 파일명, npm 패키지 |
| CONSTANT_CASE | USER_PROFILE_IMAGE | 전부 대문자, 밑줄로 연결 | 상수, 환경변수(.env) |
이름의 유래도 재미있어요. camelCase는 중간의 대문자가 낙타 혹 같아서, kebab-case는 하이픈이 꼬치에 꿴 모양 같아서 붙은 이름이에요. PascalCase는 파스칼 언어에서 이 표기를 즐겨 쓴 데서 왔고, CONSTANT_CASE는 SCREAMING_SNAKE_CASE라고도 부릅니다.
kebab-case가 코드 변수에 거의 안 쓰이는 이유는 단순해요. 대부분의 언어에서 하이픈은 빼기 연산자라, user-id라고 쓰면 user 빼기 id로 해석되거든요. 그래서 kebab-case는 코드 바깥, 즉 URL·CSS·파일 이름처럼 문자열로 다뤄지는 곳에서만 씁니다.
언어별 네이밍 관례 (공식 스타일 가이드 기준)
새 프로젝트에서 표기법을 직접 정할 필요는 거의 없어요. 언어마다 공식 또는 사실상 표준인 스타일 가이드가 있고, 린터도 그 규칙을 기본값으로 검사하니까요.
| 언어 | 변수·함수 | 클래스·타입 | 상수 | 근거 |
|---|---|---|---|---|
| JavaScript / TypeScript | camelCase | PascalCase | UPPER_SNAKE (관례) | 생태계 관례, 주요 스타일 가이드 |
| Java / Kotlin | camelCase | PascalCase | UPPER_SNAKE | 언어 공식 코딩 컨벤션 |
| Python | snake_case | PascalCase (CapWords) | UPPER_SNAKE | PEP 8 |
| Rust | snake_case | PascalCase (UpperCamelCase) | UPPER_SNAKE | Rust API Guidelines, 컴파일러 경고 |
| Ruby | snake_case | PascalCase | UPPER_SNAKE | 커뮤니티 스타일 가이드 |
| C# | 메서드 PascalCase, 지역변수 camelCase | PascalCase | PascalCase | .NET 명명 지침 |
| Go | 비공개 camelCase, 공개 PascalCase | 동일 | 동일 | Effective Go (첫 글자 대소문자가 공개 여부) |
| Swift | camelCase | PascalCase | camelCase | Swift API Design Guidelines |
| PHP | 메서드 camelCase | PascalCase | UPPER_SNAKE | PSR-1 |
Go는 첫 글자로 공개 여부가 갈려 camel·Pascal을 함께 써서 제외했어요
표로 보기
| 구분 | 언어 수 |
|---|---|
| camelCase | 6 |
| snake_case | 3 |
| PascalCase | 1 |
눈여겨볼 차이가 두 가지 있어요. 첫째, Go는 표기법이 문법이에요. 함수 이름이 대문자로 시작하면 패키지 밖에서 쓸 수 있고, 소문자면 패키지 안에서만 보여요. 둘째, C#은 메서드도 PascalCase라 Java에서 넘어오면 처음에 어색합니다. getUser()가 아니라 GetUser()예요.
파이썬에서 클래스는 PascalCase지만 모듈(파일) 이름은 짧은 소문자를 권장하고 밑줄도 허용해요. 그래서 user_service.py 안에 class UserService가 있는 모양이 자연스럽습니다.
DB 컬럼명은 왜 snake_case일까
데이터베이스는 거의 모든 팀이 소문자 snake_case를 씁니다. 취향 문제가 아니라 실제 이유가 있어요.
- 대소문자 처리가 DB마다 다르다: PostgreSQL은 따옴표 없는 식별자를 소문자로 바꿔 저장해요.
CREATE TABLE Users (userId int)라고 만들면 실제 이름은 users, userid가 되고, 대문자를 살리려면 매번"userId"처럼 큰따옴표를 붙여야 해요. MySQL은 운영체제와 설정에 따라 테이블 이름의 대소문자 구분이 달라집니다. - SQL 키워드와 구분: 관례적으로 SQL 키워드를 대문자(SELECT, FROM)로 쓰기 때문에, 식별자를 소문자 snake_case로 쓰면 쿼리에서 눈에 잘 띄어요.
- 도구 호환성: BI 도구, 엑셀 내보내기, 데이터 분석 라이브러리 대부분이 소문자 밑줄 이름을 무난하게 다룹니다.
테이블 이름을 단수(user)로 할지 복수(users)로 할지는 팀마다 갈리는데, 한 DB 안에서 섞지만 않으면 어느 쪽이든 괜찮아요. 다만 user, order, group 같은 단어는 SQL 예약어와 겹쳐서 복수형이 덜 번거롭습니다.
URL은 kebab-case, 밑줄보다 하이픈인 이유
URL 경로는 소문자 kebab-case가 표준처럼 쓰여요. 이 사이트 주소도 /text/case-converter/처럼 되어 있죠. 이유는 세 가지예요.
- 검색엔진이 하이픈을 단어 구분자로 인식합니다. 구글 검색 센터의 URL 구조 가이드도 단어 구분에 밑줄 대신 하이픈을 쓰라고 권장해요.
- 밑줄은 링크 밑줄에 가려져요. 문서나 메일에서 링크에 밑줄이 그어지면
user_profile의 밑줄이 안 보여서 공백으로 착각하기 쉬워요. - 대소문자 혼동 방지: URL 경로는 서버에 따라 대소문자를 구분해서,
/About과/about이 다른 페이지가 될 수 있어요. 전부 소문자로 통일하면 이 문제가 없습니다.
한글 URL은 인코딩되면서 길어지는 문제가 있는데, 이건 URL 인코딩과 한글 URL 글에 따로 정리했어요.
CSS 클래스와 HTML 속성의 표기
CSS는 속성 이름부터 background-color, font-size처럼 kebab-case라 클래스 이름도 kebab-case를 쓰는 게 자연스러워요. BEM 방식에서는 card__title--active처럼 블록·요소·수정자를 밑줄 두 개와 하이픈 두 개로 구분합니다.
재미있는 건 HTML과 JS가 만나는 지점이에요. HTML의 data-user-id 속성은 JS에서 element.dataset.userId로 읽혀요. 브라우저가 kebab-case를 camelCase로 자동 변환해 주는 거죠. CSS 속성도 마찬가지로 JS에서는 style.backgroundColor로 씁니다. 같은 대상이 언어 경계를 넘을 때 표기가 바뀌는 게 웹의 기본 설계라는 걸 보여 주는 예예요.
약어(ID·URL·HTTP)는 어떻게 쓰나
표기법에서 가장 의견이 갈리는 부분이 약어예요. userID인가 userId인가, XMLHttpRequest인가 XmlHttpRequest인가.
- Java·JS·C# 쪽 주류: 약어도 일반 단어처럼 첫 글자만 대문자(
userId,HtmlParser). 마이크로소프트 .NET 지침은 두 글자 약어만 전부 대문자(IOStream)로 두고, 세 글자 이상은 첫 글자만 대문자(HtmlButton)로 쓰라고 해요. - Go: 약어는 대소문자를 통일(
userID,ServeHTTP,urlParser).Url처럼 섞어 쓰지 않는 게 관례예요. - 표준 API의 예외: 브라우저의
XMLHttpRequest는 앞 약어는 전부 대문자, 뒤 약어는 첫 글자만 대문자라는 일관성 없는 이름으로 유명합니다. 오래된 API라 그대로 남아 있어요.
변환 도구 입장에서는 userId가 다루기 쉬워요. 대소문자 변환기는 연속된 대문자를 약어로 보고 XMLHttpRequest를 xml, http, request 세 단어로 나눠 xml_http_request로 바꿉니다. userID도 user, ID로 나눠 user_id가 돼요. 반면 userIDList처럼 약어 뒤에 단어가 바로 붙으면 사람도 기계도 헷갈리니, 새로 짓는 이름이라면 userIdList를 추천해요.
변환 규칙과 흔한 실수
여러 표기를 오가다 보면 생기는 실수가 꽤 정해져 있어요.
- 숫자 위치:
version2Update는 version2, update로 나뉘어version2_update가 돼요.version_2_update를 기대했다면 원래 이름부터version2를 한 단어로 볼지 정해야 합니다. - 아포스트로피: "don't stop"을 camelCase로 바꾸면
dontStop이 돼요. 작은따옴표는 지워집니다. - 한글 이름: 한글은 대소문자가 없어서 camelCase·PascalCase 구분이 의미가 없어요. "회원 목록"은 snake_case로
회원_목록이 됩니다. 코드 식별자로 한글을 쓸 수 있는 언어도 있지만, 협업과 도구 호환성 때문에 영어 이름을 권합니다. - Title Case와 혼동: "The Lord of the Rings"처럼 관사·전치사를 소문자로 두는 Title Case는 제목용이지 식별자용이 아니에요. 엑셀 PROPER 함수는 모든 단어 첫 글자를 대문자로 바꿔 관사 예외가 없습니다.
- 한 파일 안에서 섞기:
getUser,get_order,FetchItem이 한 모듈에 섞여 있으면 검색도 리뷰도 어려워져요. 린터(ESLint, Pylint, clippy)의 이름 규칙을 켜 두면 자동으로 잡힙니다.
DB·API·프런트 사이 변환은 어디서 할까
실무에서 가장 현실적인 고민은 "DB는 user_id인데 JS는 userId를 쓰고 싶다"예요. 선택지는 대략 세 가지예요.
| 방식 | 장점 | 단점 |
|---|---|---|
| ORM·매퍼에서 변환 | 각 계층이 자기 관례를 지킴 | 설정 한 번 필요 |
| API 직렬화 단계에서 변환 | 프런트는 camelCase만 봄 | 서버 코드에 두 표기가 공존 |
| 전 계층 snake_case 통일 | 변환 없음, 단순 | JS 린터 경고, 관례와 어긋남 |
공개 API는 회사마다 달라요. GitHub REST API나 Stripe API는 JSON 키에 snake_case를 쓰고, 구글 JSON 스타일 가이드는 camelCase를 권장합니다. 어느 쪽이든 API 문서에 한 가지로 고정하는 게 핵심이에요. 응답 일부는 created_at, 일부는 updatedAt이면 클라이언트 개발자가 매번 확인해야 하거든요.
변환 위치는 한 곳으로 정하세요. 저는 ORM이나 직렬화 라이브러리의 이름 변환 옵션을 쓰고, 컬럼 목록을 손으로 옮겨야 할 때만 대소문자 변환기에 한 줄에 하나씩 붙여서 camelCase 칸을 통째로 복사해요.
자주 묻는 질문
camelCase와 PascalCase 차이는 뭔가요?
둘 다 단어를 붙이고 각 단어 첫 글자를 대문자로 쓰지만, camelCase는 첫 단어를 소문자로(userName), PascalCase는 첫 단어도 대문자로(UserName) 시작해요. 보통 변수·함수는 camelCase, 클래스·타입은 PascalCase를 씁니다.
파이썬은 왜 snake_case를 쓰나요?
파이썬 공식 스타일 가이드 PEP 8이 함수와 변수 이름에 소문자와 밑줄을 쓰도록 정했기 때문이에요. 클래스는 CapWords(PascalCase), 상수는 대문자와 밑줄을 씁니다. 대부분의 파이썬 린터가 이 규칙을 기본으로 검사해요.
URL에는 밑줄과 하이픈 중 뭘 써야 하나요?
하이픈을 쓰세요. 검색엔진이 하이픈을 단어 구분자로 인식하고, 링크 밑줄에 밑줄 문자가 가려지는 문제도 없어요. 경로는 전부 소문자로 통일하는 게 좋습니다.
DB 컬럼은 snake_case인데 JSON은 camelCase로 해도 되나요?
네, 흔한 구성이에요. ORM이나 직렬화 단계에서 한 번만 변환하도록 정해 두면 각 계층이 자기 관례를 지킬 수 있어요. 중요한 건 API 응답 안에서 두 표기를 섞지 않는 거예요.
userID와 userId 중 뭐가 맞나요?
언어 관례에 따라요. Java·JS·C#은 보통 userId처럼 약어도 첫 글자만 대문자로 쓰고, Go는 userID처럼 약어의 대소문자를 통일해요. 팀 규칙이 없다면 변환 도구와 잘 맞는 userId를 추천합니다.
정리
네이밍 컨벤션은 정답을 고르는 문제가 아니라 그 언어와 계층의 관례를 따르는 문제예요. JS·Java는 camelCase, 파이썬·러스트·DB는 snake_case, URL·CSS는 kebab-case, 클래스는 PascalCase, 상수와 환경변수는 CONSTANT_CASE. 이 다섯 줄만 기억해도 대부분의 고민이 끝나고, 계층 사이 변환은 한 곳에서만 하면 됩니다.
변수명 목록을 한꺼번에 바꿔야 할 때는 대소문자 변환기에 한 줄에 하나씩 넣어 보세요. 9가지 표기가 동시에 나옵니다. 이름 목록에 중복이 섞였다면 목록 중복 제거와 정렬도 참고하세요.