複雑さの評価と認知負荷の測定基準
ソフトウェアの複雑さは保守性の静かな敵です。 AIが生成したコード 長い関数、深い入れ子、および結合により、必要以上に複雑になる傾向があります。 コンポーネント間の過剰な接続。この複雑さを測定し制御することは、維持するために不可欠です 長期的に見て健全なコードベース。
この記事では、高度な複雑さのメトリクスについて説明します。 認知負荷 alle ハルステッドメトリクス、あげてください アーキテクチャフィットネス機能 AI によって生成されたコードを評価し、複雑さを軽減するための実用的なツールを紹介します。
何を学ぶか
- 認知的複雑さと、それが AI コードにとって循環的複雑さよりも関連性がある理由
- ハルステッドの指標: ボリューム、難易度、計算量
- AI のアーキテクチャ上の影響を評価するためのアーキテクチャ フィットネス関数
- 複雑なコード生成における AI 特有の傾向
- 複雑さのメトリクスに基づいたリファクタリング戦略
- AI コードの複雑さのしきい値としきい値を設定する方法
認知の複雑さ: 理解の難しさの測定
La 認知の複雑さ コードを理解するのがどれだけ難しいかを測定します 人間です。実行パスをカウントする循環的複雑さとは異なり、 認知的複雑さは、コードのロジックに従うために必要な精神的努力を評価します。 特に、深いネストと線形フローの中断にペナルティが発生します。
AI によって生成されたコードの場合、認知の複雑さは特に関連性のある指標です AI が生成するコードは、論理的には正しいように見えても、不必要に複雑になることがよくあるためです。 専門の開発者が作成しないレベルのネストを使用して、読み取りと保守を行うことができます。
# Calcolo della cognitive complexity
class CognitiveComplexityCalculator:
"""Calcola la complessità cognitiva secondo il modello SonarSource"""
def __init__(self):
self.complexity = 0
self.nesting_level = 0
def calculate(self, ast_node):
"""Calcola la complessità cognitiva di una funzione"""
self.complexity = 0
self.nesting_level = 0
self._visit(ast_node)
return self.complexity
def _visit(self, node):
"""Visita ricorsiva dell'AST con calcolo incrementale"""
import ast
# Incrementi strutturali (B1): +1 per break nel flusso lineare
if isinstance(node, (ast.If, ast.For, ast.While)):
self.complexity += 1 # incremento base
self.complexity += self.nesting_level # incremento nesting
self.nesting_level += 1
for child in ast.iter_child_nodes(node):
self._visit(child)
self.nesting_level -= 1
return
# Incrementi per operatori logici composti
if isinstance(node, ast.BoolOp):
# Sequenze di and/or contano +1 per switch di operatore
self.complexity += 1
# Incrementi per break nel flusso: else, elif, except
if isinstance(node, ast.ExceptHandler):
self.complexity += 1
self.complexity += self.nesting_level
# Ricorsione e goto (in linguaggi che li supportano): +1
# Lambda annidate: +1 + nesting
if isinstance(node, ast.Lambda):
self.complexity += 1 + self.nesting_level
for child in ast.iter_child_nodes(node):
self._visit(child)
# Esempio di codice AI con alta cognitive complexity
# vs versione refactored
# ALTO: Cognitive Complexity = 21
def process_order_ai(order):
if order: # +1
if order.status == "pending": # +2 (nesting=1)
for item in order.items: # +3 (nesting=2)
if item.quantity > 0: # +4 (nesting=3)
if item.in_stock: # +5 (nesting=4)
try: #
charge(item) #
except PaymentError: # +6 (nesting=4)
if item.retry_count < 3: # +7 (nesting=5)
retry(item)
else:
cancel(item)
return None
# BASSO: Cognitive Complexity = 7
def process_order_refactored(order):
if not order or order.status != "pending": # +1
return None
for item in order.items: # +1
process_single_item(item) # funzione estratta
def process_single_item(item):
if item.quantity <= 0 or not item.in_stock: # +1 (+1 operatore)
return
try_charge_item(item) # funzione estratta
def try_charge_item(item):
try:
charge(item)
except PaymentError: # +1
if item.retry_count < 3: # +2 (nesting=1)
retry(item)
else: # +1
cancel(item)
Halstead の指標: ボリューム、難易度、労力
Le ハルステッドメトリクス1977 年にモーリス ハルステッドによって開発され、提供します。 オペレーター数に基づくソフトウェアの複雑さの定量的尺度 ソースコード内のオペランド。 AI によって生成されたコードの場合、これらのメトリクスは次のことを明らかにします。 興味深いパターン: AI は多数の一意の演算子を含むコードを生成する傾向があります ただし、オペランドの種類は限られています。
import math
class HalsteadMetrics:
"""Calcola le metriche di Halstead per il codice sorgente"""
def __init__(self, operators, operands):
# n1 = numero di operatori distinti
# n2 = numero di operandi distinti
# N1 = numero totale di operatori
# N2 = numero totale di operandi
self.n1 = len(set(operators))
self.n2 = len(set(operands))
self.N1 = len(operators)
self.N2 = len(operands)
def vocabulary(self):
"""n = n1 + n2: vocabolario del programma"""
return self.n1 + self.n2
def length(self):
"""N = N1 + N2: lunghezza del programma"""
return self.N1 + self.N2
def volume(self):
"""V = N * log2(n): volume del programma"""
n = self.vocabulary()
N = self.length()
return N * math.log2(n) if n > 0 else 0
def difficulty(self):
"""D = (n1/2) * (N2/n2): difficolta del programma"""
if self.n2 == 0:
return 0
return (self.n1 / 2) * (self.N2 / self.n2)
def effort(self):
"""E = D * V: effort di implementazione"""
return self.difficulty() * self.volume()
def time_to_program(self):
"""T = E / 18: tempo stimato in secondi (Stroud number)"""
return self.effort() / 18
def bugs_estimate(self):
"""B = V / 3000: stima dei bug (metrica empirica)"""
return self.volume() / 3000
def summary(self):
"""Riepilogo completo delle metriche"""
return {
"vocabulary": self.vocabulary(),
"length": self.length(),
"volume": round(self.volume(), 2),
"difficulty": round(self.difficulty(), 2),
"effort": round(self.effort(), 2),
"time_seconds": round(self.time_to_program(), 2),
"estimated_bugs": round(self.bugs_estimate(), 3)
}
Halstead メトリクス: AI コードのしきい値
| メトリック | 良い | 許容できる | 評論家 |
|---|---|---|---|
| ボリューム(V) | <100 | 100-1000 | >1000 |
| 難易度(D) | <10 | 10-30 | >30 |
| 努力(E) | <1000 | 1000-10000 | >10000 |
| 推定バグ数(B) | <0.1 | 0.1~0.5 | >0.5 |
アーキテクチャ フィットネス機能
Le アーキテクチャフィットネス機能 コードがどの程度優れているかを評価する指標です チームによって定義されたアーキテクチャ上の制約が尊重されます。 AI によって生成されたコードの場合、これらは AI はプロジェクトのアーキテクチャを認識していないため、この機能は重要です。 循環依存関係や過剰な結合などの構造違反を導入する またはアーキテクチャレイヤーの違反。
# Architecture Fitness Functions per codice AI
class ArchitectureFitness:
"""Valuta l'aderenza architetturale del codice AI"""
def __init__(self, project_structure, architecture_rules):
self.structure = project_structure
self.rules = architecture_rules
def evaluate_all(self):
"""Esegue tutte le fitness functions"""
return {
"coupling": self._check_coupling(),
"cohesion": self._check_cohesion(),
"layer_violations": self._check_layer_violations(),
"circular_dependencies": self._check_circular_deps(),
"component_size": self._check_component_size(),
"overall_fitness": self._calculate_overall_score()
}
def _check_coupling(self):
"""Misura l'accoppiamento tra moduli"""
# Afferent coupling (Ca): chi dipende da me
# Efferent coupling (Ce): da chi dipendo
# Instability = Ce / (Ca + Ce)
results = []
for module in self.structure.modules:
ca = len(module.dependents)
ce = len(module.dependencies)
instability = ce / (ca + ce) if (ca + ce) > 0 else 0
results.append({
"module": module.name,
"afferent": ca,
"efferent": ce,
"instability": round(instability, 2),
"status": "OK" if instability < 0.7 else "WARNING"
})
return results
def _check_layer_violations(self):
"""Verifica che i layer architetturali siano rispettati"""
# Es: presentation non deve importare da data layer
violations = []
for rule in self.rules.get("layer_rules", []):
source = rule["from_layer"]
forbidden = rule["cannot_import"]
imports = self.structure.get_imports(source)
for imp in imports:
if any(f in imp for f in forbidden):
violations.append({
"from": source,
"imports": imp,
"forbidden_layer": forbidden,
"severity": "HIGH"
})
return violations
複雑なコード生成における AI のトレンド
数千の AI 出力を分析すると、不必要な複雑さの繰り返しパターンが明らかになります。 これらの傾向を理解することは、チームが最も適切なコントロールを構成し、 ガイドは、より単純なコードを取得するようにプロンプトを表示します。
- オーバーエンジニアリング: AI は、単純なソリューションで十分なパターン (工場、戦略、観察者) を追加します
- 深い入れ子: AI は、1 ~ 2 で十分な 4 ~ 5 のネスト レベルを頻繁に生成します。
- 神の機能: 実行する処理が多すぎて、数百行もある長すぎる関数
- 時期尚早な抽象化: 拡張性を必要としないコード用のインターフェイスと抽象クラス
- コピー&ペーストの進化:AIは一般化するのではなく、わずかに複製および変更します
AI コードの推奨される複雑さのしきい値
- 機能別の認知の複雑さ: 最大 15 (人間のコードの場合は 25)
- 最大ネスト深さ: 3 レベル (人間のコードの場合は 4 レベル)
- 機能別の行: 最大 40 (人間のコードの場合は 60)
- 関数ごとのパラメータ: 最大 4 (人間のコードの場合は 5)
- モジュールごとの依存関係: 最大 8 つの外部インポート (人間のコードの場合は 10)
- ハルステッドの難易度: 最大 25 (コード信号が密すぎる)
メトリクス主導のリファクタリング戦略
複雑さのメトリクスは、コードをブロックするためだけでなく、コードをブロックするためのガイドとしても使用されます。 リファクタリング。それぞれの高い指標は、特定の単純化戦略を示しています。 体系的に応用できます。
メトリックマップのリファクタリング
| 問題が検出されました | メトリック | リファクタリング戦略 |
|---|---|---|
| 深い入れ子 | 認知の複雑性が高い | 早期復帰、ガード条項、抽出方法 |
| 関数が長すぎます | ハルステッドの大音量 | 抽出メソッド、単一責任 |
| パラメータが多すぎます | ハルステッドの難易度が高い | パラメータオブジェクト、ビルダーパターン |
| 過度の依存関係 | 高い遠心性カップリング | 依存関係の注入、インターフェイスの分離 |
| クラスが大きすぎます | LOC + 不安定性 | クラスを抽出し、責任ごとに分解する |
時間の経過に伴う複雑性の監視
コードベースの複雑さは、個別に監視するのではなく、時間の経過に伴う傾向として監視する必要があります。 時間厳守の測定。健全なコードベースでは、複雑さが安定または軽減されます。あ 特に AI コーディング ツールの導入に関連して、複雑さが絶え間なく増加しています。 即時の対応が必要なアラーム信号。
結論
複雑さはソフトウェアの品質にとって最も厄介な敵であり、AI によって生成されたコードです それを増幅させる傾向があります。認知の複雑さ、ハルステッドのメトリクス、フィットネス アーキテクチャ 関数は、この複雑さを測定、監視、制御するためのツールを提供します 体系的に。
次の記事では、 生産性指標:測り方 AI が開発速度に与える影響、生産性のパラドックスはデリケートなものです AI 支援開発のコンテキストにおけるスピードと品質のバランス。
シンプルさは最高の洗練です。 AI が生成したコードについては、 シンプルさにはメトリクスが必要であり、規律には継続的なリファクタリングが必要です。







