テキストケース規約:camelCase、snake_case、それぞれの使い分け

7 min2026年6月6日

命名規約がなぜ重要なのか

ソフトウェア開発において、コードを書く時間よりコードを読む時間のほうが圧倒的に長いというのは広く知られた事実です。命名規約(naming convention)は、コードの可読性を飛躍的に向上させる最も基本的な手段です。一貫した命名規約に従うコードベースでは、変数や関数の役割が名前から即座に推測でき、認知負荷が大幅に軽減されます。

命名規約はチーム開発においてとりわけ重要です。10人の開発者がそれぞれ独自のスタイルで命名すれば、コードベースは短期間でカオスになります。getUserName、get_user_name、GetUserName、getusernameが混在する状況では、コードの検索性が損なわれ、タイポによるバグも発見しにくくなります。規約はコミュニケーションコストを削減する共通言語です。

多くのプログラミング言語やフレームワークは公式のスタイルガイドで命名規約を定めています。PythonのPEP 8、JavaのCode Conventions、GoのEffective Go、RustのAPI Guidelinesなど、これらに従うことでエコシステム全体との整合性が保たれます。ライブラリ利用者にとって、予測可能なAPIは使いやすいAPIです。

また、命名規約はコードの構造的な情報を暗黙的に伝達します。PascalCaseならクラスや型、camelCaseならインスタンスや関数、SCREAMING_SNAKE_CASEなら定数、というように、ケーススタイルが識別子の種類を示すメタ情報として機能します。これにより、IDEのシンタックスハイライトがなくても、テキストだけでコードの構造を把握できます。

camelCaseとPascalCase

camelCase(ローワーキャメルケース)は、最初の単語を小文字で始め、後続の単語の先頭を大文字にするスタイルです。getUserName、calculateTotalPrice、isVisibleのように書きます。JavaScript/TypeScript、Java、C#のメソッド名・変数名で最も広く使われており、Web開発者にとって最も馴染み深い形式です。

PascalCase(アッパーキャメルケース)は、すべての単語の先頭を大文字にします。UserProfile、HttpClient、EventEmitterのように書きます。クラス名、インターフェース名、型名に広く使われます。C#ではメソッド名もPascalCaseにする慣習があり、JavaやJavaScriptのメソッド名がcamelCaseであるのと対照的です。

Reactコンポーネント名はPascalCaseが必須です。これはJSXのパーサーが大文字で始まる要素をコンポーネントとして認識し、小文字で始まる要素をHTML要素として扱う仕様上の要請です。<Button />はコンポーネント、<button />はネイティブHTMLです。この区別がPascalCaseを単なる慣習ではなく言語仕様の一部にしています。

TypeScriptのジェネリクスでは慣習的にT、K、Vなどの単一大文字を使いますが、より説明的な名前が必要な場合はTResult、TKeyのようにT接頭辞+PascalCaseを使います。C#のインターフェースにI接頭辞を付ける(IDisposable、IEnumerable)慣習も、PascalCaseの派生形として広く認知されています。

// camelCase:変数、関数、メソッド名に使用
const userName = 'tanaka';
const maxRetryCount = 3;
function calculateShippingCost(weight: number): number { /* ... */ }

// PascalCase:クラス、インターフェース、型、Reactコンポーネントに使用
class UserRepository { /* ... */ }
interface ApiResponse<T> { data: T; status: number; }
type PaymentMethod = 'credit' | 'debit' | 'bank';

// Reactコンポーネント名は必ずPascalCase(JSX仕様上の要件)
function UserProfileCard({ user }: { user: User }) {
  return <div className="profile-card">{user.name}</div>;
}

// C#スタイル:メソッドもPascalCase
// public void SendNotification(string userId) { ... }
// public async Task<User> GetUserByIdAsync(int id) { ... }

snake_caseとSCREAMING_SNAKE_CASE

snake_case(スネークケース)は、すべて小文字で単語をアンダースコア(_)で区切るスタイルです。user_name、calculate_total_price、is_visibleのように書きます。Python、Ruby、Rust、Elixirの変数名・関数名における標準規約です。PEP 8に「関数名と変数名は小文字で、単語をアンダースコアで区切る」と明記されています。

snake_caseの利点は視認性の高さです。アンダースコアがスペースの役割を果たし、長い名前でも単語の境界が一目瞭然です。get_user_profile_by_idはgetUserProfileByIdと比べて、特にフォントサイズが小さい場面や視力が弱い人にとって読みやすいという研究結果があります。一方、タイプ数が増える欠点もあります。

SCREAMING_SNAKE_CASE(全大文字スネークケース)は定数に使われる普遍的な規約です。MAX_RETRY_COUNT、API_BASE_URL、DATABASE_TIMEOUTのように書きます。C、Java、Python、JavaScript、Rustなど、ほぼすべての主要言語で定数にこのスタイルが使われています。「この値は変更してはいけない」という意図を視覚的に伝達します。

データベースのカラム名やテーブル名もsnake_caseが標準です。SQLは大文字小文字を区別しないため、camelCaseではuser_nameとusernameが同一視されてしまいます。snake_caseなら引用符なしで安全に使え、ORMのフィールドマッピング(Pythonのuser_name → DBのuser_name)も直感的になります。PostgreSQLの公式ドキュメントでもsnake_caseが推奨されています。

# Python(PEP 8): 変数・関数は snake_case
def calculate_monthly_payment(principal, annual_rate, years):
    """月々の返済額を計算する"""
    monthly_rate = annual_rate / 12
    num_payments = years * 12
    return principal * monthly_rate / (1 - (1 + monthly_rate) ** -num_payments)

# 定数は SCREAMING_SNAKE_CASE
MAX_LOGIN_ATTEMPTS = 5
DEFAULT_TIMEOUT_SECONDS = 30
API_BASE_URL = "https://api.example.com/v2"

# クラス名は PascalCase(Pythonでも同様)
class UserRepository:
    def __init__(self, db_connection):
        self._db_connection = db_connection  # プライベートは先頭に_

    def find_by_email(self, email_address: str) -> dict | None:
        """メールアドレスでユーザーを検索する"""
        query = "SELECT * FROM users WHERE email = %s"
        return self._db_connection.fetch_one(query, (email_address,))

# Rust: snake_case が言語仕様レベルで強制される
# fn calculate_distance(point_a: &Point, point_b: &Point) -> f64 { ... }
# const MAX_BUFFER_SIZE: usize = 4096;

kebab-caseとその用途

kebab-case(ケバブケース)は、すべて小文字で単語をハイフン(-)で区切るスタイルです。user-profile、api-base-url、my-componentのように書きます。ほとんどのプログラミング言語では識別子にハイフンを使えないため、変数名や関数名には使用できません。しかし、コードの外側では最も広く使われるスタイルの一つです。

URLのパス部分はkebab-caseが事実上の標準です。/user-profile、/blog/my-first-post、/api/v2/order-historyのようにハイフンで単語を区切ります。Googleの公式SEOドキュメントでもURLにはハイフンを推奨しており、アンダースコアよりハイフンのほうがword separatorとして認識されます。これはSEOに直接影響する重要な慣習です。

CSSのプロパティ名とクラス名もkebab-caseです。font-size、background-color、.nav-barのように書きます。BEM(Block-Element-Modifier)記法では.block-name__element-name--modifier-nameとなり、kebab-caseとBEM固有の区切り文字が組み合わされます。CSS Modulesやstyled-componentsでは自動生成されるクラス名にも影響します。

npmパッケージ名、Gitリポジトリ名、Dockerイメージ名もkebab-caseが標準です。react-router-dom、next.js → next(ドットは例外)、my-awesome-libraryのように命名します。ファイルシステムで大文字小文字が区別されない環境(Windows/macOS)でのトラブルを避けるため、すべて小文字+ハイフンにする慣習が定着しています。

各プログラミング言語のデフォルト規約

JavaScript/TypeScriptでは、変数・関数・メソッドにcamelCase、クラス・型・インターフェースにPascalCase、定数にSCREAMING_SNAKE_CASEが標準です。ESLintのnaming-conventionルールでこれを強制できます。ファイル名はkebab-case(user-service.ts)が一般的ですが、コンポーネントファイルはPascalCase(UserProfile.tsx)とするプロジェクトもあります。

PythonはPEP 8が明確に規定しています。変数・関数・メソッドにsnake_case、クラスにPascalCase、定数にSCREAMING_SNAKE_CASE、モジュール名にsnake_case、パッケージ名にlowercase(アンダースコアなし推奨)です。pylintやruffがこれを自動チェックします。特殊メソッドの__init__や__str__はdunder(double underscore)と呼ばれる特殊形式です。

GoはEffective Goに従い、公開(exported)識別子にPascalCase、非公開(unexported)識別子にcamelCaseを使います。snake_caseは使いません。頭字語はすべて大文字(HTTPClient、XMLParser)とするのがGo独自の慣習で、他の言語のHttpClient、XmlParserとは異なります。golintがこれを検出します。

Rustはコンパイラレベルで命名規約を強制します。変数・関数にsnake_case、型・トレイトにPascalCase、定数にSCREAMING_SNAKE_CASEを使わないと警告が出ます。ライフタイムは小文字のアポストロフィ付き('a)、マクロはsnake_case!です。C#はすべてのパブリックメンバーにPascalCase、プライベートフィールドに_camelCase(先頭アンダースコア)が.NETの公式規約です。

// 各言語の命名規約まとめ(TypeScriptで表現)

// JavaScript/TypeScript
const userAge = 25;                          // 変数: camelCase
function getUserById(id: string) {}          // 関数: camelCase
class UserService {}                         // クラス: PascalCase
interface ApiResponse {}                     // インターフェース: PascalCase
const MAX_CONNECTIONS = 100;                 // 定数: SCREAMING_SNAKE_CASE
type RequestMethod = 'GET' | 'POST';         // 型: PascalCase

// Python → snake_case 中心
// user_age = 25
// def get_user_by_id(user_id: str): ...
// class UserService: ...
// MAX_CONNECTIONS = 100

// Go → エクスポートは PascalCase、それ以外は camelCase
// var userAge int = 25           (unexported)
// func GetUserByID(id string)    (exported、IDは全大文字)
// type HTTPClient struct {}      (頭字語は全大文字)

// Rust → snake_case + PascalCase(コンパイラが強制)
// let user_age: u32 = 25;
// fn get_user_by_id(id: &str) -> Option<User> { ... }
// struct UserService { ... }
// const MAX_CONNECTIONS: u32 = 100;

// CSS → kebab-case
// .user-profile { font-size: 14px; background-color: #fff; }

自動変換の落とし穴:略語と特殊なケース

ケース変換ツールを使う際、最も問題になるのが略語(acronym)の扱いです。HTTPResponseをsnake_caseに変換すると、h_t_t_p_responseになるのかhttp_responseになるのか?XMLParserはx_m_l_parserかxml_parserか?この曖昧さはツールによって処理が異なり、プロジェクト内で不整合が生じる原因になります。

各言語コミュニティで略語の扱い方針は異なります。JavaとTypeScriptではHTTP→Http(HttpClient)、URL→Url(UrlParser)のように先頭のみ大文字にするのが主流です。一方、GoではHTTP→HTTP(HTTPClient)、URL→URL(URLParser)のように全大文字を維持します。C#は公式にはPascalCaseルール(HttpClient)ですが、古いAPIにはHTTPWebRequestも残っています。

数字を含む識別子もトリッキーです。base64EncodeはBase64Encode?base_64_encode?ツールによってはbase6_4_encodeのような不自然な分割をすることもあります。iPadやiPhoneのような固有名詞をPascalCaseにするとIPad、IPhoneになり意味が変わります。これらのエッジケースは自動変換後に必ず人間の目で確認する必要があります。

日本語や中国語などのマルチバイト文字を含む識別子の変換も注意が必要です。ユーザー名のような識別子は多くのツールで正しく処理できません。また、既存のコードベースで自動変換を一括適用する場合、文字列リテラル内の名前(JSONのキー名、APIレスポンスのフィールド名など)まで変換してしまい、実行時エラーを引き起こすケースがあります。変換はあくまで識別子に対してのみ適用すべきです。

// 略語の変換例:ツールによって結果が異なる
// 入力: "XMLHttpRequest"

// パターン1(略語を1単語として扱う)
// → camelCase: xmlHttpRequest
// → snake_case: xml_http_request
// → kebab-case: xml-http-request

// パターン2(各文字を分割してしまう)
// → snake_case: x_m_l_http_request ← 望ましくない

// 正しい略語処理の実装例
function smartCamelToSnake(str: string): string {
  return str
    // 略語の境界を検出(HTTPSResponse → HTTPS_Response)
    .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
    // 通常の単語境界(userName → user_Name)
    .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
    // 数字と文字の境界(base64Encode → base64_Encode)
    .replace(/([a-zA-Z])(d)/g, '$1_$2')
    .replace(/(d)([a-zA-Z])/g, '$1_$2')
    .toLowerCase();
}

// テストケース
console.log(smartCamelToSnake('XMLHttpRequest'));  // "xml_http_request"
console.log(smartCamelToSnake('getUserByID'));     // "get_user_by_id"
console.log(smartCamelToSnake('base64Encode'));    // "base64_encode"
console.log(smartCamelToSnake('iOS'));             // "i_os" ← まだ不完全

// ⚠️ JSON キー名の変換は慎重に(APIとの整合性が壊れる)
const apiResponse = { user_name: 'tanaka', created_at: '2024-01-01' };
// フロント用に camelCase に変換するなら、API境界でのみ行う
function toCamelCaseKeys(obj: Record<string, unknown>) {
  return Object.fromEntries(
    Object.entries(obj).map(([key, val]) => [
      key.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),
      val,
    ])
  );
}
// { userName: 'tanaka', createdAt: '2024-01-01' }

チーム規約の策定と運用

チームで命名規約を策定する際、最も重要なのは「完璧な規約」ではなく「一貫性のある規約」です。camelCaseとsnake_caseのどちらが客観的に優れているかという議論に決着はつきません。重要なのは一つを選んで全員がそれに従うことです。議論は30分で終わらせ、リンターで自動化するのが現実的なアプローチです。

ESLint(@typescript-eslint/naming-convention)、pylint、rubocop、rustfmt、golangci-lintなど、主要な言語にはすべて命名規約を自動チェック・自動修正するツールがあります。CI/CDパイプラインに組み込んで「ルール違反があればマージ不可」とすることで、レビューで人間が命名を指摘する手間を完全に排除できます。機械に任せられることは機械に任せましょう。

プロジェクトの成長に伴い、規約に例外が必要になる場面も出てきます。外部APIのレスポンスフィールド名(snake_caseのREST API)をフロントエンド(camelCase)で使う場合、境界層で変換するか、そのまま使うか。ORMのモデルフィールド名はDBに合わせるかアプリケーション層の規約に合わせるか。これらの「境界」について方針を文書化しておくことが、将来の混乱を防ぎます。

コードベースが大きくなった後に規約を変更する場合は、段階的な移行が現実的です。新規コードは新規約、既存コードは触るときに変換、という方針を設け、一括置換のビッグバン移行は避けます。大規模な一括変換はgit blameを壊し、レビュー履歴を追いにくくします。codemods(jscodeshift、rectorなど)を使えば安全にAST単位で変換できますが、それでもPRは適度な粒度に分割しましょう。