mcpField
C
clean-code

clean-code

github.com/wondelai開発2.5k6.7k 回インストール7 週間前に更新
リポジトリ

clean-code について

clean-code は、読みやすさと保守性を重視してコードを作成、レビュー、リファクタリングするための開発スキルです。命名、関数、エラー処理、テスト、コードの問題点を扱い、改善箇所を特定する評価方法も備えています。

主な機能

  1. 01意図が伝わる命名原則
  2. 02責務を絞った関数設計
  3. 03コメントと書式の指針
  4. 04エラー処理の実践
  5. 05ユニットテストの原則
  6. 06コードの問題点の診断

活用シーン

  1. 01プルリクエストの可読性レビュー
  2. 02読みにくい関数のリファクタリング
  3. 03テストとエラー経路の品質評価

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/wondelai/skills --skill clean-code

インストール後、Claude Code で/clean-codeを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
code-smells.md
comments-formatting.md
error-handling.md
functions-and-methods.md
naming-conventions.md
testing-principles.md

詳細

クリーンコードフレームワーク

意図が伝わり、予期せぬ動作を最小限に抑え、変更を受け入れやすいコードを書くための規律あるアプローチです。新しいコードの作成、プルリクエストのレビュー、レガシーシステムのリファクタリング、コード品質に関する助言の際に、これらの原則を適用してください。

基本原則

コードは書くよりもはるかに頻繁に読まれます。読み手を優先しましょう。 読む回数と書く回数の比率は10対1を大きく上回るため、名前の選択、関数の境界、書式の決定はすべて、明瞭さを高めるか、コストを増やすかのどちらかです。クリーンコードは、よく書かれた文章のように読めます。名前から意図が伝わり、関数は一歩ずつ物語を語り、ボーイスカウトルールが適用されます。つまり、見つけたときよりもコードをきれいにしておきましょう。

評価

目標:10/10。 以下の原則に照らして、あらゆるコードを0〜10で評価してください。現在のスコアと、10/10に到達するために必要な具体的な改善点を報告してください。

  • 9-10: 名前から意図が伝わり、関数は小さく焦点が絞られ、エラー処理に一貫性があり、テストは明快で網羅的です
  • 7-8: おおむねクリーンですが、名前に若干の曖昧さがあるか、長い関数がいくつかあります。テストでエッジケースが不足している場合もあります
  • 5-6: 良いパターンと、不明瞭な名前、重複したロジック、一貫性のないエラー処理が混在しています
  • 3-4: 複数の役割を持つ長い関数、誤解を招く名前、不十分または欠落したテストがあります
  • 1-2: ほとんど解読できません。マジックナンバー、不可解な略語、構造の欠如、テストの欠如があります

クリーンコードフレームワーク

コードの意図を明確に伝え、変更に適応できるようにするための6つの規律です。

1. 意味のある名前

基本概念: 名前は意図を明らかにし、誤解を招かず、コードを文章のように読めるものにする必要があります。名前の説明にコメントが必要なら、その名前は適切ではありません。

効果がある理由: 名前は最も広く使われるドキュメントです。適切な名前を選べば実装を読む必要がなくなりますが、不適切な名前では、すべての読み手が意図を逆算しなければなりません。

主なポイント:

  • 名前は、それが存在する理由、何をするか、どのように使われるかに答える必要があります
  • エンコーディング、接頭辞、型情報は使いません(ハンガリアン記法は使いません)。1文字の名前を使うのは、スコープが非常に小さいループカウンターに限ります
  • クラス名には名詞を、メソッド名には動詞を使います
  • 1つの概念には1つの単語を使います。fetch、retrieve、getを混在させないでください
  • スコープが広いほど、より長く説明的な名前が必要です
  • 自由に名前を変更してください。IDEを使えば簡単です

コードへの適用例:

コンテキストパターン例
変数意図が伝わる名前dではなくelapsedTimeInDays
ブール値述語形式isActive、hasPermission、canEdit
関数動詞+名詞calc()ではなくcalculateMonthlyRevenue()
クラス責務を表す名詞InvoiceManagerではなくInvoiceGenerator

名前の変更やレビューの際は、references/naming-conventions.mdを参照してください。言語ごとの慣習、発音・検索しやすい名前の一覧、変更前後の例が掲載されています。

2. 関数

基本概念: 関数は小さく、1つのことを適切に実行するものにします。理想的には4~6行、引数は0~2個、抽象化のレベルは1つです。

効果がある理由: 小さく単一目的の関数は、名前を付けやすく、理解、テスト、再利用も簡単です。長い関数はバグを隠し、テストを難しくし、責任が増えていきます。

重要なポイント:

  • ステップダウンルール:コードは上から下へ読み進められ、各関数が次の抽象化レベルの関数を呼び出します
  • 引数の数:0個が最適、1個は問題なく、2個も許容範囲です。3個以上は正当な理由が必要です
  • フラグ引数は問題の兆候です。関数が2つの処理をしているため、分割します
  • コマンド・クエリ分離:状態を変更するか値を返すかのどちらかにし、両方は行いません
  • 抽出できるものはすべて抽出します。名前を付けた関数として切り出せるなら、そうします
  • 隠れた副作用をなくします。関数名で処理の全容が伝わるようにします

コードへの適用例:

コンテキストパターン例
長い関数名前を付けた手順に分割するvalidateInput(); transformData(); saveRecord();
フラグ引数2つの関数に分割するrender(isPrint) ではなく renderForPrint() / renderForScreen()
エラーケース冒頭にガード節を置くエラー時は早期リターンし、正常系の処理を1つにまとめる
多数の引数パラメーターオブジェクトを導入するreport(start, end, format, locale) ではなく new DateRange(start, end)
副作用効果を明示するセッションを開始する checkPassword() は名前を変更するか、処理を分離する

長い関数を分割する際は、references/functions-and-methods.mdを参照してください。引数の数に関するルール、コマンド・クエリ分離、ステップダウンの具体例を確認できます。

3. コメントとフォーマット

基本概念: コメントは、コードで自分の意図を表現できていないことの表れです。コメントが必要な場合は、何をするかではなく、なぜそうするかを説明します。フォーマットによって、コードをざっと読みやすくする視覚的な構造を作ります。

効果がある理由: コードは変わってもコメントは変わらないことが多く、コメントは劣化します。その結果、ドキュメントがないよりも悪い状態になります。整ったフォーマットにより、開発者は新聞を読むように、まず見出しを確認し、必要に応じて詳細を読めます。

重要なポイント:

  • 最良のコメントは、適切な名前を付けて切り出した関数です
  • 許容されるコメント:ライセンスヘッダー、TODO、公開APIのドキュメント、真に「なぜ」を説明するもの
  • コメントアウトしたコードや作業記録のコメントは削除します。バージョン管理が記録しています
  • 概念の間には縦方向の余白を設け、概念の中は密度を高めます。変数は使う場所の近くで宣言します
  • 新聞の比喩:ファイルの先頭に高水準の関数を置き、その下に詳細を記述します

コメントを残す価値があるか判断する際は、references/comments-formatting.mdを参照してください。良いコメントと悪いコメントの一覧、および縦方向のフォーマットに関するルールを確認できます。

4. エラー処理

基本概念: エラー処理はビジネスロジックとは別の関心事です。戻り値コードではなく例外を使い、すべての例外にコンテキストを含め、null を返したり渡したりしないでください。

効果がある理由: 戻り値コードを使うと、正常系にチェック処理が増えますが、例外を使えば両者を明確に分離できます。null を返すと、すべての呼び出し元で null チェックが必要になり、チェック漏れがあると発生箇所から離れた場所でクラッシュします。

主なポイント:

  • 先に try-catch を書きます。これによってトランザクションの境界が定まります
  • 非検査例外を優先します。検査例外はオープン/クローズドの原則に反します
  • 例外クラスは障害の種類ではなく、呼び出し元のニーズに基づいて定義します
  • null を返さないでください(空のコレクション、Optional、または例外を使います)。null を渡すことも避けてください
  • 特殊ケース/Null Object パターン:null の代わりに、デフォルトの振る舞いを持つオブジェクトを返します

コードへの適用例:

コンテキストパターン例
null の返却空のコレクションまたは Optionalreturn null ではなく return Collections.emptyList()
エラーコード例外に置き換えるthrow new InsufficientFundsException(balance, amount)
サードパーティ APIアダプターでラップするPortfolioService がベンダー API をラップし、その例外を変換します
特殊ケースNull Object パターンnull チェックの代わりに、デフォルトの振る舞いを持つ GuestUser を使います
エラーのコンテキスト操作と状態を含める"Failed to save invoice #1234 for customer 'Acme'"

例外や null の方針を設計する際は、references/error-handling.md を参照してください。特殊ケースパターンとサードパーティ API のラップ例を紹介しています。

5. ユニットテスト

基本概念: テストは第一級のコードとして扱い、本番コードと同じ規律でクリーンに保ちます。汚れたテストはテストがないよりも悪く、変更のたびに足かせとなります。

効果がある理由: クリーンなテストは実行可能なドキュメントであり、リファクタリングのセーフティネットにもなります。一方、汚れたテストは理解しにくいテストコードを読み解く作業を、あらゆる変更に伴わせます。

主なポイント:

  • TDD の三つの法則:最初に失敗するテストを書くこと、失敗させるのに必要な最小限のテストだけを書くこと、合格させるのに必要な最小限のコードだけを書くこと
  • テストごとに一つの概念を扱います。論理的なアサーションを一つにし、必ずしも assert を一つにする必要はありません
  • F.I.R.S.T.:高速(Fast)、独立(Independent)、再現可能(Repeatable)、自己検証可能(Self-validating)、適時(Timely)
  • ドメイン固有のテスト言語を構築します。DSL のように読めるヘルパーを使います
  • テストコードも本番コードと同じように積極的にリファクタリングします

コードへの適用例:

コンテキストパターン例
テスト構造準備・実行・検証(Arrange-Act-Assert)セットアップ、実行、検証を明確に分けます
テストの命名シナリオ+期待される動作test1 ではなく shouldRejectExpiredToken
共通セットアップビルダー/ファクトリーのヘルパーaUser().withRole(ADMIN).build()
不安定なテスト外部依存を取り除く時刻、ネットワーク、ファイルシステムをモックします

テストの作成や整理の際は、references/testing-principles.md を参照してください。TDD の法則、F.I.R.S.T. の詳しい説明、クリーンなテストのパターンを紹介しています。

6. コードの不吉な臭いとヒューリスティック

基本概念: 不吉な臭いは、より深刻な設計上の問題を示す表面的な兆候です。素早く見分け、曖昧な「クリーンアップ」ではなく、的を絞ったリファクタリングを適用できるようにしましょう。

効果がある理由: 不吉な臭いは、詳細な分析をしなくても起こりうる問題を示すヒューリスティックです。コードレビューの直感を、具体的で繰り返し実行できる手法に変えてくれます。

主なポイント:

  • 関数に関する不吉な臭い:引数が多すぎる、出力引数、フラグ引数、使われていない関数
  • 一般的な不吉な臭い:重複、抽象化のレベルが不適切、機能の横恋慕、マジックナンバー
  • テストに関する不吉な臭い:カバレッジ不足、スキップされたテスト、境界条件や失敗経路の未テスト
  • 小さくテスト済みの手順でリファクタリングしましょう。リファクタリングと機能追加を同時に行ってはいけません
  • ボーイスカウト・ルール:コードを見つけたときよりもきれいな状態にしておきましょう

コードでの適用例:

コンテキストパターン例
重複共通ロジックを抽出する共通の検証 → validateEmail() ヘルパー
機能の横恋慕メソッドをデータのクラスに移動するcalculator.total(order) ではなく order.calculateTotal()
デッドコード削除する未使用の関数や到達不能な分岐を削除する
マジックナンバー名前付き定数そのままの 5 ではなく MAX_LOGIN_ATTEMPTS = 5
ショットガン手術関連する変更をまとめる散在するロジックを単一のモジュールにまとめる

不吉な臭いの名前がすぐに思い浮かばない場合は、references/code-smells.md を参照してください。カテゴリ別の完全な一覧と、それぞれに対応する的を絞ったリファクタリングが記載されています。

よくある間違い

間違いうまくいかない理由修正方法
名前を省略する書く時間は数秒節約できても、読む時間が何時間も増えます説明的な完全な名前を使いましょう。IDE の自動補完を活用できます
「賢い」ワンライナー書くのは印象的でも、デバッグが不可能になります読みやすい名前付きの手順に展開しましょう
リファクタリングの代わりにコメントを書くコメントは劣化します。真実を示すのはコードです適切な名前を付けた関数を抽出しましょう
汎用的な例外をキャッチする想定されるエラーとともにバグも握りつぶします特定の例外をキャッチし、それ以外は伝播させましょう
エラー経路のテストがない正常系は動いても、エッジケースでクラッシュしますすべての分岐、境界、失敗モードをテストしましょう
時期尚早な最適化わずかな性能向上のために意図が見えにくくなりますまずコードをクリーンにし、測定したボトルネックを最適化しましょう
ゴッドクラス1 つの 2000 行のクラスがすべてを担いますSRP を適用し、責務ごとに分割しましょう
テストなしのリファクタリングリグレッションに対する安全網がありませんまず特性化テストを書きましょう
規約に一貫性がないファイルごとに別のコードベースのように感じられますスタイルに合意し、リンターとフォーマッターで徹底しましょう
どこでも null を返すnull チェックがウイルスのように広がりますOptional、空のコレクション、または Null Object を使いましょう

クイック診断

質問いいえの場合対応
関数の本体を読まずに、それぞれの関数を理解できますか?名前から意図がわかりません処理内容を表す名前に変更しましょう
すべての関数が 20 行未満ですか?関数が多くの処理を担っていますサブ処理を名前付きヘルパーに抽出しましょう
コメントアウトされたコードブロックはありませんか?デッドコードが混乱を招いています削除しましょう。バージョン管理に履歴があります
エラー処理はビジネスロジックと分離されていますか?try-catch がメインの流れを煩雑にしていますハンドラーを抽出し、戻り値コードより例外を使いましょう
すべてのクラスに単一の責務がありますか?クラスに無関係な役割が蓄積しています目的を絞った、適切な名前のクラスに分割しましょう
すべてのパブリックメソッドにテストがありますか?変更に対する安全網がありませんこれ以上変更する前にテストを追加しましょう
テスト名は動作を説明していますか?失敗の解釈が難しくなりますshouldDoXWhenY に名前を変更しましょう
重複は 3 箇所未満ですか?コピー&ペーストによってバグが広がっています共通ロジックを抽出しましょう(§6)
マジックナンバーは名前付き定数になっていますか?生の値に意図が隠れています定数に名前を付けましょう(§6)
すべてのテストが 10 秒未満で実行されますか?テストが遅く、実行されなくなります外部依存をモックし、統合テストを分割しましょう

参考資料

ソフトウェア職人技に関する Robert C. Martin の記念碑的なガイドに基づいています。

著者について

**Robert C. Martin(「アンクル・ボブ」)**は、1970 年からプログラミングに携わり、アジャイルマニフェストを共同執筆し、Uncle Bob Consulting と Clean Coders を設立しました。彼の著書である Clean Code、The Clean Coder、Clean Architecture、Clean Agile は、ひと世代の開発者のコード品質に対する考え方を形作りました。また、彼の基本的な主張は、速く進む唯一の方法は、正しく進めることだというものです。

コメント