1. 導入:なぜ「認知的複雑度」が重要なのか
開発現場で「このコード、修正するのが怖い」と感じたことはありませんか?その原因の多くは、コードの複雑さにあります。従来の指標である「循環的複雑度」はif文の数を機械的に数えるだけでしたが、これでは「人間が読んで理解する難しさ」を正しく評価できません。そこで登場するのが認知的複雑度(Cognitive Complexity)です。この指標を理解し意識することで、チーム全体のコード品質が向上し、バグの温床を未然に防ぐことができます。
2. 基礎知識:循環的複雑度との違い
循環的複雑度(Cyclomatic Complexity)は、分岐の回数(if, for, whileなど)のみをカウントします。一方、認知的複雑度は「ネストの深さ」や「入れ子の構造」を重視します。例えば、if文の中にさらにif文があるような深いネストは、脳への負荷が非常に高いため、認知的複雑度ではより大きなペナルティが課されます。つまり、機械的な分岐数ではなく、人間がいかに論理の流れを追えるかを評価する指標なのです。
3. 実装/解決策:コードを平坦化する
認知的複雑度を下げるための最も効果的な手段は「早期リターン(Early Return)」です。深いネストを避けるために、条件に合致しない場合は即座に関数を終了させ、メインの処理をインデントの浅い階層に配置します。これにより、コードの視覚的な構造が平坦になり、認知負荷が劇的に軽減されます。
4. サンプルプログラム:リファクタリングの例
以下は、認知的複雑度が高いコードを、早期リターンを用いて改善した比較例です。
[改善前:複雑度が高いコード]
public void processOrder(Order order) {
if (order != null) { // ネストが深くなる入り口
if (order.isValid()) {
if (!order.isProcessed()) {
// 実際のメイン処理
saveToDatabase(order);
}
}
}
}
[改善後:早期リターンによる平坦化]
public void processOrder(Order order) {
// 異常系を先に排除することでネストを深くさせない
if (order == null || !order.isValid() || order.isProcessed()) {
return;
}
// メインの処理を浅い階層に配置
saveToDatabase(order);
}
5. 応用・注意点:現場での活用法
認知的複雑度を下げる際は、以下の点に注意してください。
・関数の分割:一つの関数が長すぎると、どれだけ工夫しても複雑度は下がります。責務を分け、小さな関数を組み合わせて構築しましょう。
・閾値の設定:SonarQubeなどのツールで閾値を設定し、CIパイプラインで自動チェックを行うのが一般的です。ただし、数値を下げること自体が目的にならないよう注意してください。
・やりすぎに注意:早期リターンを多用しすぎて、かえって処理の流れが追いづらくなるケースもあります。「読みやすさ」という本質を忘れず、チームメンバーとペアプログラミングなどで感覚をすり合わせることが最も重要です。

コメント