mcpField
L
low-complexity

low-complexity

github.com/mryll開発652 回インストール2 週間前に更新
リポジトリ

low-complexity について

関数やメソッドの認知的複雑度と循環的複雑度に目標値を設ける、開発者向けのコーディングスキルです。複雑度の数え方、優先順位付きのリファクタリング手法、分岐やネストを減らす例を示します。

主な機能

  1. 01関数の複雑度目標の設定
  2. 02認知的・循環的複雑度の算出
  3. 03関数抽出とガード節によるリファクタリング
  4. 04ネストと分岐の削減
  5. 05言語慣用表現の活用

活用シーン

  1. 01複雑な関数のレビュー
  2. 02深くネストしたロジックの整理
  3. 03コード変更における複雑度基準の設定

インストール

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

$npx skills add https://github.com/mryll/skills --skill low-complexity

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

同梱ファイルreferences/cognitive-complexity-spec.md

詳細

低複雑度のコード

作成または変更するすべての関数/メソッドは、次の目標を満たす必要があります。

  • 認知的複雑度は 5 以下(SonarSource の指標)。本質的に複雑なロジックでは、10 まで許容されます。15 を超えてはいけません。
  • 循環的複雑度は 5 以下。10 まで許容されます。15 を超えてはいけません。

完全なスコアリングルールについては、cognitive-complexity-spec.mdを参照してください。

認知的複雑度のクイックリファレンス

それぞれ +1: if、三項演算子(? :)、switch(全体)、for、while、do while、catch、else if、else、goto LABEL、break/continue LABEL、再帰サイクル内の各メソッド、同種のブール演算子(&& / ||)の各連続列。

ネストによるペナルティとして +1 を構造上の加算に加算:if、三項演算子、switch、for、while、catch が、別のフロー制御構造の中にネストされている場合。

加算なし: メソッド呼び出し、try、finally、case ラベル、null 合体(?.、??)、早期 return、単純な break/continue、ラムダ(ただしラムダはネストレベルを上げます)。

循環的複雑度のクイックリファレンス

メソッドの開始で +1、次のそれぞれで +1:if、else if、for、while、do while、case、catch、&&、||、三項演算子 ?。これは基本的な定義です。一部の解析ツールでは言語によって異なる場合があります。

必須の削減手法

次の優先順位で適用してください。

  1. メソッド/関数を抽出する — 一貫性のある処理ブロックを、名前付き関数に移します。ネストレベルは 0 にリセットされます。抽出するブロックが一貫した単位を形成する場合は、まずこの方法を選んでください。
  2. 早期 return/ガード節 — 条件を反転させて早期に return し、ネストを 1 レベル減らします。
  3. ネストした条件をフラットなロジックに置き換える — if A { if B { を if A && B { に置き換えます(ネストによるペナルティを削減します)。
  4. if/else の連鎖をポリモーフィズム、ストラテジーパターン、またはルックアップテーブルに置き換える — 分岐を完全に解消します。
  5. ループと条件を宣言的なパイプラインに置き換える — for と if の代わりに、filter/map/reduce、LINQ、またはストリームを使用します。
  6. ブール式を分解する — 複雑な条件を、名前付きのブール変数または述語関数として抽出します。
  7. フラグ変数を早期終了に置き換える — 後続のフロー制御に使われるブールフラグを解消します。
  8. 言語固有のイディオムを使う — null 合体、オプショナルチェーン、パターンマッチング、分割代入を使用します。これらは、同等の if/else の連鎖よりコストが低いことがよくあります(分割代入は加算なし、パターンマッチングは分岐ごとに +1 の if/else と比べ、match 全体で +1)。

適用方法

関数/メソッドを書くときは、次の手順に従ってください。

  1. ロジックを書く
  2. 頭の中で数える:各 if/else if/else/for/while/switch/catch/ternary は +1、構造上の各ネストレベルはさらに +1、ブール演算子の各連続列は +1
  3. スコアが 5 を超える場合は、仕上げる前に上記の手法でリファクタリングする
  4. 大きな関数を 1 つ作るより、小さな関数を複数作る
  5. ネストの深さが 2 を超える場合は、問題の兆候です。すぐに抽出してください

悪い例と良い例

悪い例:ネストした条件分岐(CogC = 9)
def process(user, order):
    if user.is_active:                    # +1
        if order.is_valid:                # +2 (nesting=1)
            if order.total > 100:         # +3 (nesting=2)
                apply_discount(order)
            else:                         # +1
                charge_full(order)
        else:                             # +1
            raise InvalidOrder()
    else:                                 # +1
        raise InactiveUser()              # Total: 1+2+3+1+1+1 = 9
良い例:ガード節と抽出(process CogC=2、charge CogC=2)
def process(user, order):               # CogC = 2
    if not user.is_active:                # +1
        raise InactiveUser()
    if not order.is_valid:                # +1
        raise InvalidOrder()
    charge(order)

def charge(order):                       # CogC = 2
    if order.total > 100:                 # +1
        apply_discount(order)
    else:                                 # +1
        charge_full(order)
悪い例:条件をネストしたループ(CogC = 10)
function findFirst(items, criteria) {
  for (const item of items) {              // +1
    if (item.active) {                     // +2 (nesting=1)
      if (item.type === criteria.type) {   // +3 (nesting=2)
        if (item.score > criteria.min) {   // +4 (nesting=3)
          return item;
        }
      }
    }
  }                                        // Total: 1+2+3+4 = 10
  return null;
}
良い例:フラットな filter と早期 continue(findFirst CogC=5、matches CogC=1)
function findFirst(items, criteria) {      // CogC = 5
  for (const item of items) {              // +1
    if (!item.active) continue;            // +2 (nesting=1)
    if (matches(item, criteria)) return item; // +2 (nesting=1)
  }
  return null;
}

function matches(item, criteria) {         // CogC = 1
  return item.type === criteria.type       // +1 (&& sequence)
    && item.score > criteria.min;
}

コメント