コーディングルール
コードを扱う全作業に適用する行動指針。コードの実装・修正・リファクタリング・レビューでは、以下のルールと対象リポジトリ固有の指示に従う。
トレードオフ:これらのガイドラインは、スピードよりも慎重さを重視しています。些細な作業については、ご自身の判断で対応してください。
1. コーディングの前に考える
推測しない。分からないことを隠さない。トレードオフを表に出す。
実装の前に:
- 前提としていることを明示的に述べる。不確かな場合は質問する。
- 複数の解釈が存在する場合は提示する。黙って一つを選ばない。
- よりシンプルなアプローチがあるならそう言う。必要であれば反論する。
- 何かが不明確なら手を止める。何が分からないのかを明確にし、質問する。
2. シンプルさを最優先に
問題を解決する最小限のコード。憶測に基づくものは書かない。
- 求められたこと以上の機能は作らない。
- 一度しか使わないコードに抽象化を持ち込まない。
- 求められていない「柔軟性」や「設定可能性」は作らない。
- 起こり得ないシナリオのためのエラーハンドリングは書かない。
- 不要な複雑さは削るが、行数を減らすために処理・宣言・分岐を詰め込まない。短さより、人間が後で読んで理解できることを優先する。
自問すること: 「シニアエンジニアが見たら『これは複雑にしすぎ』と言うだろうか?」 答えが Yes ならシンプルにする。
3. 外科手術のような変更
必要な箇所だけに触れる。片付けるのは自分が散らかしたものだけ。
既存コードを編集するとき:
- 周辺のコード・コメント・フォーマットを勝手に「改善」しない。
- 壊れていないものをリファクタリングしない。
- 自分ならそう書かないとしても、既存のスタイルに合わせる。
- 無関係なデッドコードに気づいたら報告する。勝手に削除しない。
自分の変更によって不要になったもの(オーファン)について:
- 自分の変更によって未使用になった import・変数・関数は削除する。
- 依頼されていない限り、以前から存在するデッドコードは削除しない。
判定基準: 変更したすべての行が、ユーザーの依頼内容に直接ひも付いていること。
4. ゴール駆動の実行
成功基準を定義する。検証できるまでループする。
タスクを検証可能なゴールに変換する:
- 「バリデーションを追加して」→「不正な入力に対するテストを書き、それを通す」
- 「バグを直して」→「バグを再現するテストを書き、それを通す」
- 「X をリファクタリングして」→「リファクタリング前後でテストが通ることを確認する」
複数ステップのタスクでは、簡潔な計画を示す:
1. [ステップ] → 検証: [チェック内容]
2. [ステップ] → 検証: [チェック内容]
3. [ステップ] → 検証: [チェック内容]
強い成功基準があれば自律的にループできる。弱い基準(「動くようにして」)では絶えず確認が必要になる。
これらのガイドラインが機能していると言えるのは、差分における不必要な変更が少なく、複雑化による書き直しが少なく、間違いの後ではなく実装前に明確化のための質問が行われる場合です。
5. 意味のまとまりごとに空行で区切る
可読性は必須の完了条件。フォーマッターが通るだけでは満たしたことにならない。
実装が複数行にわたって続く場合は、処理を意味のあるまとまりとして捉え、まとまりの間に空行を1行入れる。
- 関数・メソッド・コンストラクター・独立したイベントハンドラー・テストケースの間には必ず空行を1行入れる。説明コメントは対象の宣言に付け、空行はコメントの前に置く。
- 入力の準備、検証、計算・変換、状態更新・保存、結果の返却など、処理の目的が切り替わる箇所で区切る。
- 関数の最上位だけでなく、分岐・ループ・try/catch・コールバックの内部でも同じ基準を適用する。ガード節の後に実処理や返却が続く場合は区切る。
- 同じ目的のために密接に関連する行はまとめ、行数だけを基準に機械的に区切ったり、すべての行の間に空行を入れたりしない。
- ここでいうまとまりは読みやすさのための論理的な区切りを指す。区切るためだけにブロックや関数を追加しない。
- TypeScript / JavaScriptでは、分岐・ループの本体が1行でも波括弧を省略しない。複数の変数をカンマで連結せず、宣言を分ける。
- 非同期処理や変換を入れ子にして処理順序が読みにくくなる場合は、意味のある名前の中間変数で段階を表す。
- 新規・変更箇所に適用し、無関係な既存コードの空行まで変更しない。
例:入力の準備、検証、更新、返却を空行で区切る。
const name = input.name.trim();
const email = input.email.trim();
validateName(name);
validateEmail(email);
const user = await updateUser({ name, email });
return toUserResponse(user);
6. コメントで処理の目的と理由を残す
初めて読む人が、会話履歴や実装者の記憶なしに意図を理解できるようにする。
- 関数・メソッドには役割の概要を添える。必要に応じて入力の前提、戻り値、外部への書き込みも説明する。自明なアクセサーや単純な式のコールバックに機械的な説明は足さない。
- 関数コメントの冒頭は「鑑定レコードを取得する。」「処理結果をメールで通知する。」のように、その関数が何をするかを短い一文で言い切る。理由、制約、実装手段から書き始めず、最初の一文だけで役割が分かるようにする。
- 目的、判断理由、制約は概要の次の行以降に記載する。「一言でいうと」「〜という関数」といった前置きは付けない。本体、テスト補助関数、名前付きアロー関数にも同じ基準を適用する。
- 認証・認可、状態遷移、保存順序、排他制御、再送、タイムアウト、例外処理、後始末などは、その命令を「何のために」「なぜその位置や順序で」実行するのかを該当箇所に書く。
- コードを日本語に置き換えただけのコメントではなく、守る条件や避けたい問題を説明する。コードで保証していないことをコメントで保証しない。
- テストにも検証する状況と理由を残し、準備・実行・期待値の確認を空行で分ける。複数の状況を順に確認する場合は、それぞれの目的を示す。
- テスト用の埋め込みスクリプトやフィクスチャも読みやすく整形し、長い1行へ圧縮しない。
- コードを修正したらコメントとの整合性も確認し、古い説明を残さない。
/**
* 本人の鑑定レコードを取得する。
* 所有者が一致しない場合は、他人の鑑定の存在を知らせないため404として扱う。
*/
async function getJob(uid: string, id: string) {
// 実装
}
7. 名前だけで何をするか分かるようにする
関数名は「何を」「どうする」まで言い切る。呼び出し側を読んだだけで処理内容が分かることを完了条件にする。
- 関数・メソッドは動詞+目的語で命名する。
call・invoke・handle・run・get・put・send・api・result のように動作か対象のどちらかが欠けた名前は使わない。callPersistence・uploadJobFile・sendResultNotification のように、対象を補って何をするかが読める名前にする。
- 同じ動詞でも対象が違えば名前を分ける。
download を「MCP経由でジョブのファイルを取る」と「Storageから直接オブジェクトを取る」の両方に使わず、downloadJobFile と downloadObject のように区別する。
- 検証して例外を投げる関数は
validateOwnership・assertActive のように、失敗時に止まることが分かる名前にする。判定結果を返すだけなら isInsideDirectory のように真偽を返す形にする。
- Promise を返す変数や待機用の関数は
cancellationWatch・waitForExit・waitUntil のように、何を待っているかを名前に含める。
- テスト補助も同じ基準で命名する。
seed・until・id のような短い名前は、seedQueuedReading・waitUntil・readingIdFor のように用途を含める。
- 標準的な慣習で意味が固定されている名前は例外とする。エントリポイントの
main、Route Handler の GET・POST、フレームワークが要求するメソッド名はそのまま使う。
- 名前を変えたら、呼び出し元、テスト、ドキュメントに残る旧名もすべて追従させる。関数コメントに旧名の説明を残さない。
// 悪い例:何を呼ぶのか、何を返すのかが名前から分からない
const record = await call(uid, 'get', id);
await put(ctx, 'conversation.jsonl', data);
// 良い例:MCPの永続化操作を呼ぶこと、ジョブのファイルを上げることが読める
const record = await callPersistence(uid, 'get', id);
await uploadJobFile(ctx, 'conversation.jsonl', data);
8. 完了前に人間の視点で読み直す
- フォーマット後、変更した関数とテストの全体を実際に読み直す。差分の追加行だけで判断しない。
- 関数の境界、ネスト内の処理の区切り、目的と理由のコメント、名前だけで処理内容が分かるかを確認する。初見の人が処理順序や副作用を追えない箇所は、完了報告前に修正する。
- フォーマッターは字下げや表記を整える道具であり、論理的な区切りやコメントの十分さを判定する代わりにはしない。
- 可読性だけの修正では処理順序・例外・非同期処理の寿命を維持し、型検査と変更に応じたテストで確認する。可読性の違反が残ったまま、検査の成功だけを根拠に完了としない。