本記事について
当サイトを閲覧いただきありがとうございます。 本記事はシリーズ『生成AI時代のアーキテクチャ超入門』の「アプリケーションアーキテクチャ」カテゴリ第3弾として、命名とコード規約について解説する記事です。
コードを書く時間より「読む時間」のほうが圧倒的に長い。読みやすさはチーム生産性そのものです。本記事では命名の基本原則・ケースの使い分け・Linter/Formatter・ディレクトリ構成・PRレビュー・CODEOWNERS・Gitコミット規約まで、「議論を自動化で終わらせる」規約運用の全体像を示します。
このカテゴリの他の記事
「名前」で9割決まる
命名やスタイルの一貫性は地味で、派手な成果にはなりません。ですが長期で見れば最もROI(Return On Investment、投資対効果)が高い投資の一つで、規約がないチームでは、レビューのたびに「変数名」「インデント」「括弧の位置」といった本質的でない議論が繰り返されます。こうした消耗を機械的に潰してしまえば、人間の頭は設計の議論に向けられます。
過去に、毎回のPRで「変数名はcamelCaseかsnake_caseか」の議論が湧き、1PRにつき30分以上のコメントラリーをしている現場を見たことがあります。チームにPrettierを導入した翌週には、その手の議論は消えた、という話もよく聞きます。規約はそれだけで生産性の底上げになります。
優秀な設計でも、命名と一貫性が崩れていれば読めません。「人間向けの設計」を忘れないことが大事です。
命名の基本原則
良い命名には共通する原則があります。Robert C. Martin『Clean Code』で整理されたもので、「意図が明確・嘘をつかない・発音できる・検索できる」の4点を押さえるだけで、可読性は一気に変わります。
flowchart TB
NAME([命名のチェック])
INTENT[意図を表す<br/>d → daysUntilExpiration]
NOLIE[嘘をつかない<br/>List<T>の中身がSet<T>はNG]
NOAMBI[誤解を避ける<br/>process()は曖昧]
SAY[発音できる<br/>genymdhms → generationTimestamp]
SEARCH[検索できる<br/>1文字変数は局所のみ]
GOOD([可読性UP<br/>コメントほぼ不要])
NAME --> INTENT --> GOOD
NAME --> NOLIE --> GOOD
NAME --> NOAMBI --> GOOD
NAME --> SAY --> GOOD
NAME --> SEARCH --> GOOD
classDef root fill:#fef3c7,stroke:#d97706;
classDef rule fill:#dbeafe,stroke:#2563eb;
classDef goal fill:#dcfce7,stroke:#16a34a;
class NAME root;
class INTENT,NOLIE,NOAMBI,SAY,SEARCH rule;
class GOOD goal;
| 原則 | 内容 |
|---|---|
| 意図を表す | d ではなく daysUntilExpiration |
| 嘘をつかない | List<T> という名前で実態が Set<T> ではダメ |
| 誤解を避ける | process() のような曖昧な名前は避ける |
| 発音可能 | genymdhms より generationTimestamp |
| 検索可能 | 1文字変数はループ変数程度に限定 |
命名はコードに書かれた最大のドキュメントです。命名が良ければコメントはほぼ不要になります。
命名規則(ケースの使い分け)
変数・関数・クラス・ファイル名をどのケースで書くかは、言語ごとに事実上の標準が決まっています。JavaScriptで変数を user_name と書いたり、Pythonのクラスを user_profile と書いたりすると、文法上は動いても読み手に違和感と認知負荷を与えます。言語の慣習はコミュニティ合意の蓄積であり、これを尊重することが読みやすさに直結します。
ケースの統一が効くのは、一貫性があると「これは何か」を形から瞬時に判断できるようになるからです。PascalCase なら型、camelCase なら変数や関数、SCREAMING_SNAKE_CASE なら定数、と一目で判別できるため、読む速度そのものが上がります。
| ケース | 用途例 |
|---|---|
| camelCase | JS/TS/Java/Kotlin の変数・関数 |
| PascalCase | クラス・型 |
| snake_case | Python / Ruby / DB列名 |
| kebab-case | ファイル名・URL |
| SCREAMING_SNAKE_CASE | 定数 |
言語の慣例に合わせます。同一言語内での混在は絶対に避けるのが鉄則です。
対象別の命名パターン
変数・関数・クラスなど、対象ごとに鉄板の命名パターンがあります。これに従うだけで、読む人が「これは何か」を瞬時に判断できるようになります。
| 対象 | パターン | 例 |
|---|---|---|
| 関数 | 動詞 + 目的語 | createUser, validateEmail |
| boolean | is / has / can プレフィックス | isActive, hasPermission |
| クラス | 名詞 | OrderService, UserRepository |
| インターフェース | 名詞 | UserRepository or IUserRepository(好み) |
| イベント | 過去形 | UserRegistered, OrderPlaced |
| 定数 | 全大文字・意図を表す | MAX_RETRY_COUNT |
イベントは過去形が鉄則です。Register ではなく UserRegistered と書くと「起きたこと」が明確になります。
避けたい命名
以下のような命名はコードベース全体の品質を下げるため、レビューで必ず指摘するべきです。
❌ data, info, util ← 何も伝えていない
❌ temp, tmp ← そのまま永続化される罠
❌ mgr, mng, svc ← 過剰な略語
❌ foo, bar ← テストコード以外で使わない
❌ getUserList vs getUsers ← 同義語の混在
❌ newUser, oldUser ← 時間が経つと意味不明に
略語を使う場合は、プロジェクト固有の略語辞書(user = u は禁止、identifier = id はOK、など)を作ってチームで統一します。チームで禁止リストを共有しておくと、レビューでの指摘が楽になります。
「User / Member / Account / Customer 問題」(業界事例)
ある大手ECの案件で、同じ顧客情報を扱う機能なのに User / Member / Account / Customer の4つが混在していた、という話が語り草になっています。検索系APIも findUser / getMember / searchAccount の3系統が「同じテーブルを叩いていた」そうで、新しくジョインしたエンジニアは毎回「今回の要件はどれを直せば正解なのか」を先輩に聞いて回る必要があったとのことです。
3年目くらいの中堅が「User と Customer はどう違うんですか」と質問して、誰も明確に答えられず、その場で仕様書と業務用語集の齟齬が明らかになった、というやつもよく聞きます。原因はシンプルで、初期のDDDで言うところのUbiquitous Language(ユビキタス言語、チーム全員が同じ意味で使う共通語彙)が定義されていなかっただけ。各機能チームが別々にコードを書き、それぞれがドメイン用語をぶつけ合うように命名した結果、後から入った人間ほど「辞書を脳内で作る時間」が増えていきます。
規約とは結局、「この辞書を先に作って共有しておく仕事」に他なりません。同じ概念には一つの名前。用語辞書はコードを書き始める前に作ります。
Linter と Formatter
Linter は品質問題を検出するツール、Formatter は見た目を自動で整えるツールです。これらを使えば、「タブかスペースか」「セミコロンをつけるか」といった本質的でない議論を強制終了させられます。
| 言語 | Linter | Formatter |
|---|---|---|
| JS / TS | ESLint / Biome | Prettier / Biome |
| Python | Ruff / Pylint | Black / Ruff |
| Go | golangci-lint | gofmt |
| Rust | Clippy | rustfmt |
| Java | Checkstyle / SpotBugs | google-java-format |
高速・統合型の Biome / Ruff が本命です。CIで強制して議論を終わらせます。
Formatterの哲学
Prettier や gofmt のような現代のフォーマッタは、設定可能項目を「意図的に少なく」する哲学で設計されています。「好みで選べる項目が多いと、それが新たな議論の種になる」という経験則で、議論する余地そのものを潰しにいく設計です。
❌ タブ派 vs スペース派で毎回揉める
✅ Prettier / gofmt で決定、議論終了
チーム内で「このフォーマッタに従う」と決めた瞬間、スタイル議論はほぼ発生しなくなります。議論のコストをゼロにすることが目的で、見た目の好みは二の次です。
ツールの決定は「誰も100%満足しないが、全員が許容できる」レベルで十分です。
ディレクトリ構成
ディレクトリ構成は大きくレイヤー型と機能型(Feature型)に分かれます。規模とチームの働き方で適切な方が変わります。
[Layer型] [Feature型]
src/ src/
├─ controllers/ ├─ users/
├─ services/ │ ├─ controller.ts
├─ repositories/ │ ├─ service.ts
├─ models/ │ └─ repository.ts
└─ orders/
├─ ...
- 小規模・初心者が多い → Layer型(層の役割が明確)
- 中〜大規模・多チーム並列開発 → Feature型(機能ごとにコードがまとまり並列開発しやすい)
Feature型は「モジュラーモノリスやマイクロサービス化の前段階」として機能します。
コメントの原則
コメントは「WHY」(なぜ)を書くもので、「WHAT」(何を)を書くものではありません。名前で伝わることをコメントに書くのは、コードと矛盾した時に混乱の種になるだけです。
| 書くべき | 書かない |
|---|---|
| WHY(理由・背景) | WHAT(コード読めば分かる) |
| 非自明な制約・回避策 | 名前で伝わる内容 |
| 外部仕様への依存 | 作業履歴・担当者名 |
| TODO(期限付き) | 古いコード(Gitに任せる) |
❌ // iを1加算する
✅ // 配列末尾にセンチネルを置くので+1する(旧APIの制約)
コメントは腐ります。更新されずに残ったコメントは嘘になります。「最良のコメントは書かなくて済む命名」です。
PRレビューの原則
PR(プルリクエスト)レビューは品質を守る場であり、チームの学びの場でもあります。「レビュー文化がチームの技術力を決める」と言っていいほど効きます。
- 責める場ではなく、学ぶ場として運営する
- コードに対してコメントする(人を批判しない)
- 小さなPRが速いレビューを生む(〜400行が目安)
- 即応(24時間以内)で滞留を防ぐ
- Nit(些細)/ Suggestion / Blocker を明示する
「Must / Should / Nit」のラベルをコメントに付けると、レビュワーの意図が明確に伝わります。
CODEOWNERSによるガードレール
決済・インフラ・セキュリティなどの重要ファイルは、必ず担当チームのレビューを経てマージする必要があります。GitHub の CODEOWNERS を使うと、特定ファイルの変更時に自動で担当者にレビュー依頼が飛びます。
# .github/CODEOWNERS
/src/payment/ @payment-team
/infra/ @sre-team
/.github/ @admin-team
/src/auth/ @security-team
機密部分や高難度コードを、知らない人が勝手にマージできない状態を作れます。マージ保護ルールと組み合わせれば、重要箇所のレビューが確実に走ります。
大規模プロジェクトではCODEOWNERSなしは事故の温床です。早期に設定するべきです。
Gitコミットメッセージ規約
チーム開発ではコミットメッセージの形式を統一することで、履歴の検索性やチェンジログの自動生成が容易になります。Conventional Commits が事実上の標準です。
feat: ユーザー検索APIを追加
fix: ログイン時のセッション固定脆弱性を修正
docs: READMEに環境変数の説明を追加
refactor: UserService を分割(責務過多のため)
chore: 依存ライブラリを更新
プレフィックス(feat / fix / docs / refactor / chore / test / perf 等)を付けることで、「何のコミットか一目で分かる」ようになります。Conventional Commits を採用すると、semantic-release で自動バージョニングができます。2018年にAngularチームが公開した規約が、2026年時点の事実上の標準です。
コード規約運用の段階別ロードマップ
規約は「READMEに書けば守られる」はほぼ幻想。CIで機械的に強制する段階を踏むのが定石です。
| フェーズ | 導入ツール | チェックタイミング | 目標時間 |
|---|---|---|---|
| ① pre-commit | Biome / Ruff / gofmt(Formatter) | コミット時(ローカル) | 5秒以内 |
| ② pre-push | ESLint / Clippy(Lint)+ 型チェック | push直前 | 30秒以内 |
| ③ PR | 全Lint + テスト + カバレッジ | GitHub push時 | 10分以内 |
| ④ CODEOWNERS | 重要ファイル変更時に担当チームレビュー強制 | PR作成時 | 自動 |
| ⑤ リリース前 | SemanticRelease(Conventional Commits)で自動バージョニング | merge時 | 自動 |
Prettier・gofmt・Biome のような「意図的に設定を絞ったツール」が好まれるのは、「タブかスペースか」の議論を発生させない設計思想のため。Ruff は Python 界隈で ruff format + ruff check が Black + Flake8 + isort を置き換える勢いで急速に普及しています。
規約はCIで機械的に強制します。口頭・README・「気をつけます」は効きません。
命名・コード規約の鬼門・禁じ手
命名とスタイルで事故る典型を整理します。どれもチーム全体の生産性を削る地雷です。
| 禁じ手 | なぜダメか |
|---|---|
| 同じ概念を複数の名前で扱う(User / Member / Account / Customer) | 新人が毎回「どれを直せば正解か」と聞き回る事態に |
data / info / util / temp / mgr などの曖昧語 | 意図ゼロ。temp が本番で永続化される事故の定番 |
| チーム内で異なるLinter設定を使う | PR差分がフォーマット差で埋もれ、本質的変更が見えなくなる |
| Linter警告を後でまとめて直す | 警告が100個を超えた時点で誰も見なくなる。ゼロ維持が現実解 |
略語を個人判断で決める(usr / custmr) | プロジェクト固有辞書なしの略語は読めなくなる |
| コミットメッセージを自由形式で書く | 履歴検索・チェンジログ生成・semantic-release が全て効かない |
| CODEOWNERSなしで決済・認証・インフラのコードをマージ | 知らない人が機密コードを勝手に変更できる状態。事故の温床 |
| 4層以上の深いディレクトリ階層 | importパスが長くなり、IDEの補完精度も落ちる |
| コメントにWHAT(何を)を書く | コードと矛盾した時に嘘になる。書くべきはWHY(なぜ) |
| PRの粒度が1000行超 | レビューが形骸化。400行以下が目安、理想は100行 |
規約は議論するものではなく、ツールに任せるものです。Prettier vs タブ派の議論は技術的に終わっています。
AI時代の視点
AI駆動開発(バイブコーディング)が前提になると、命名とコード規約は「AIを縛る仕様書」として機能します。AIは制約がないと自由すぎる命名で無秩序なコードを生成しますが、Linter・Formatter・型を設定しておけば、AIがそれに従うコードだけを通せます。
| AI時代に有利 | AI時代に不利 |
|---|---|
| ESLint・Ruff等をCIで強制 | READMEに書いてあるだけの規約 |
| Biome / Ruff等の統合ツール | 分散した設定ファイル |
| Conventional Commits等の機械可読規約 | 自由形式のコミットメッセージ |
| CODEOWNERSで重要部分を保護 | 誰でもマージできる状態 |
AIに生成させたコードは即座にLinter/Formatterを通して、ルール違反があれば自動修正する運用が鉄板です。コミットメッセージもAIがConventional Commits形式で生成できるため、規約ベースのワークフロー全体がAIと相性よく回ります。「規約=AIへの指示書」として設計するほど、AIは驚くほど正確なコードを書くようになります。
よくある勘違い
- 「規約は書いてあれば守られる」 → READMEに書いただけでは絶対に守られません。CIで強制して初めて規約です
- 「Linter警告は後でまとめて直す」 → 警告が増えるほど誰も見なくなります。ゼロを維持するのが現実解
- 「命名は些細な問題」 → 命名のブレは時間とともに指数関数的にチームの生産性を削ります。初日に決めるべきこと
- 「Prettierの設定で揉める」 → フォーマッタの設定議論は目的が逆。議論しないために導入しているツール
決めるべきこと — あなたのプロジェクトでの答えは?
以下の項目について、あなたのプロジェクトの答えを1〜2文で言語化してみてください。曖昧なまま着手すると、必ず後から「なぜそう決めたんだっけ」が問われます。
- 命名規則(ケース・プレフィックス・禁止用語)
- Linter / Formatterの選定と設定
- ディレクトリ構成(Layer型 / Feature型)
- コメント方針
- PRサイズの目安・レビューSLA
- CODEOWNERSの運用
- Gitコミットメッセージ規約(Conventional Commits等)
最終的な判断の仕方
命名とコード規約の核心は「議論を自動化で終わらせること」です。命名やスタイルは一つひとつが小さい判断ですが、チーム全員が毎日触れるため、累計の議論コストは設計議論を圧迫するほど大きくなります。
優れた解決策は「どちらが正しいか」を議論することではなく、Linter・Formatterで機械的に決めてしまい、人間の頭を本質的な設計議論に解放することです。Prettier・gofmt・Biome・Ruff のように設定項目を絞ったツールが好まれる理由もここにあります。全員が100%満足する必要はなく、全員が許容できて議論が起きなければそれで十分です。
決定的な軸は「規約を機械可読にできているか」です。READMEに書かれた規約は守られません。守らせる唯一の方法は、LinterとFormatterとCIで強制することで、これは人間のためだけでなくAIへの制約としても決定的に効きます。
AIは制約がないと自由すぎる命名・無秩序なコードを生成しますが、規約が機械可読であれば、AI生成コードを自動で検査・修正できます。Conventional Commits・CODEOWNERS・型・Lintルール。これらはAIへの指示書として機能し、コード規約が整っているプロジェクトほどAI生成の精度が上がります。「人間のためのドキュメント」ではなく「機械が検証できる規約」を優先するのが鉄則です。
選定の優先順位をまとめると次の通りです。
- 命名は意図を表現する(名前 > コメント > ドキュメント)
- Linter / FormatterをCIで強制(議論より自動化)
- 規約を機械可読にする(CODEOWNERS / Conventional Commits)
- PRは小さく・レビューは速く(400行以内・24時間SLA)
まとめ
本記事は命名とコード規約について、命名原則・Linter/Formatter・PRレビュー・CODEOWNERS・Conventional Commitsまで含めて解説しました。如何だったでしょうか。
議論を自動化で終わらせ、規約を機械可読にする。これがAI時代も含めた2026年のコード規約運用の現実解です。
次回はアプリケーションアーキテクチャカテゴリの最終記事、エラーハンドリング(Result型・Circuit Breaker・冪等性)について解説します。
シリーズ目次に戻る → 『生成AI時代のアーキテクチャ超入門』の歩き方
それでは次の記事も閲覧いただけると幸いです。
📚 シリーズ:生成AI時代のアーキテクチャ超入門(28/89)