Files
gh-cubical6-melly/skills/c4model-c4/complexity-metrics.md
2025-11-29 18:17:07 +08:00

365 lines
7.8 KiB
Markdown

# Complexity Metrics Methodology
This guide provides methodology for calculating and documenting code complexity metrics at the C4 Code level.
---
## Metrics Overview
| Metric | Description | Threshold |
|--------|-------------|-----------|
| Lines of Code (LOC) | Actual code lines | Warning: >30, Critical: >50 |
| Cyclomatic Complexity | Decision paths | Warning: >6, Critical: >10 |
| Cognitive Complexity | Mental effort | Warning: >10, Critical: >20 |
| Parameter Count | Function parameters | Warning: >3, Critical: >5 |
| Nesting Depth | Max nesting level | Warning: >3, Critical: >5 |
---
## Lines of Code (LOC)
### Definition
Count of actual code lines excluding:
- Blank lines
- Comments
- Import statements (debatable)
### Calculation
```typescript
// Example function - LOC = 8
function processOrder(order: Order): ProcessedOrder {
const validated = validateOrder(order); // 1
if (!validated) { // 2
throw new Error('Invalid order'); // 3
} // 4
const enriched = enrichOrder(validated); // 5
const processed = applyRules(enriched); // 6
logOrder(processed); // 7
return processed; // 8
}
```
### Thresholds
| Range | Rating | Action |
|-------|--------|--------|
| 1-30 | Good | No action needed |
| 31-50 | Warning | Consider extracting methods |
| >50 | Critical | Must refactor |
---
## Cyclomatic Complexity
### Definition
Number of linearly independent paths through code. Calculated as:
- Start with 1
- Add 1 for each: `if`, `else if`, `case`, `for`, `while`, `do`, `catch`, `&&`, `||`, `?:`
### Calculation Example
```typescript
function processPayment(payment: Payment): Result { // CC = 1 (base)
if (payment.amount <= 0) { // CC = 2
return { error: 'Invalid amount' };
}
if (payment.type === 'credit') { // CC = 3
if (payment.amount > 10000) { // CC = 4
return { error: 'Amount exceeds limit' };
}
return processCreditCard(payment);
} else if (payment.type === 'debit') { // CC = 5
return processDebitCard(payment);
} else if (payment.type === 'crypto') { // CC = 6
return processCrypto(payment);
}
return { error: 'Unknown payment type' };
}
// Total Cyclomatic Complexity = 6
```
### Decision Points
| Construct | Adds |
|-----------|------|
| `if` | +1 |
| `else if` | +1 |
| `case` (switch) | +1 per case |
| `for` | +1 |
| `while` | +1 |
| `do...while` | +1 |
| `catch` | +1 |
| `&&` | +1 |
| `||` | +1 |
| `?:` (ternary) | +1 |
| `?.` (optional chain) | +1 |
| `??` (nullish coalesce) | +1 |
### Thresholds
| Range | Rating | Interpretation |
|-------|--------|----------------|
| 1-6 | Good | Simple, easy to test |
| 7-10 | Warning | Moderate complexity |
| 11-20 | High | Difficult to test |
| >20 | Critical | Untestable, must refactor |
---
## Cognitive Complexity
### Definition
A metric that measures the mental effort required to understand code. Unlike cyclomatic complexity, it:
- Penalizes nesting
- Ignores shorthand structures
- Focuses on readability
### Calculation Rules
1. **Increment for each:**
- `if`, `else if`, `else`
- `switch`
- `for`, `foreach`, `while`, `do`
- `catch`
- `break`/`continue` to label
- Sequences of logical operators
2. **Nesting penalty:**
- Add +1 for each level of nesting when incrementing
### Example
```typescript
function example(arr: number[], target: number): number {
// Base: 0
for (const item of arr) { // +1 (increment)
if (item === target) { // +2 (increment + 1 nesting)
return item;
} else if (item > target) { // +2 (increment + 1 nesting)
if (item % 2 === 0) { // +3 (increment + 2 nesting)
return item * 2;
}
}
}
return -1;
}
// Total Cognitive Complexity = 8
```
### Thresholds
| Range | Rating | Action |
|-------|--------|--------|
| 0-10 | Good | Understandable |
| 11-20 | Warning | Getting complex |
| >20 | Critical | Hard to understand |
---
## Parameter Count
### Definition
Number of parameters a function accepts.
### Guidelines
| Count | Rating | Recommendation |
|-------|--------|----------------|
| 0-3 | Good | Ideal range |
| 4-5 | Warning | Consider parameter object |
| >5 | Critical | Use parameter object |
### Refactoring Example
```typescript
// Before: 6 parameters (Critical)
function createUser(
name: string,
email: string,
age: number,
address: string,
phone: string,
role: string
) { }
// After: 1 parameter object (Good)
interface CreateUserInput {
name: string;
email: string;
age: number;
address: string;
phone: string;
role: string;
}
function createUser(input: CreateUserInput) { }
```
---
## Nesting Depth
### Definition
Maximum depth of nested control structures.
### Calculation
```typescript
function process(data: Data): Result {
if (data.valid) { // Depth 1
for (const item of data.items) { // Depth 2
if (item.active) { // Depth 3
try { // Depth 4
if (item.type === 'A') { // Depth 5 (Critical!)
// ...
}
} catch (e) {
// ...
}
}
}
}
return result;
}
// Maximum Nesting Depth = 5
```
### Thresholds
| Depth | Rating | Action |
|-------|--------|--------|
| 0-3 | Good | Easy to follow |
| 4-5 | Warning | Consider extracting |
| >5 | Critical | Must refactor |
### Refactoring Techniques
1. **Early returns (guard clauses)**
```typescript
// Before
function process(data) {
if (data) {
if (data.valid) {
// actual logic
}
}
}
// After
function process(data) {
if (!data) return;
if (!data.valid) return;
// actual logic
}
```
2. **Extract nested logic**
```typescript
// Before
for (const item of items) {
if (item.active) {
if (item.valid) {
// complex logic
}
}
}
// After
function processItem(item) {
if (!item.active || !item.valid) return;
// complex logic
}
for (const item of items) {
processItem(item);
}
```
---
## Metrics JSON Structure
```json
{
"metrics": {
"lines_of_code": 45,
"cyclomatic_complexity": 8,
"cognitive_complexity": 15,
"parameter_count": 3,
"nesting_depth": 4
}
}
```
---
## Threshold Summary Table
| Metric | Good | Warning | Critical |
|--------|------|---------|----------|
| LOC | 1-30 | 31-50 | >50 |
| Cyclomatic | 1-6 | 7-10 | >10 |
| Cognitive | 0-10 | 11-20 | >20 |
| Parameters | 0-3 | 4-5 | >5 |
| Nesting | 0-3 | 4-5 | >5 |
---
## Observation Examples
### High Complexity Warning
```json
{
"id": "obs-auth-service-complexity-01",
"category": "complexity",
"severity": "warning",
"description": "Cyclomatic complexity of 8 exceeds recommended threshold of 6. Consider extracting authentication steps into separate methods.",
"evidence": [
{
"location": "src/services/auth.ts:45-120",
"type": "metric"
}
],
"tags": ["complexity", "refactoring-candidate"]
}
```
### Critical Nesting
```json
{
"id": "obs-order-processor-nesting-01",
"category": "complexity",
"severity": "critical",
"description": "Maximum nesting depth of 6 makes code difficult to understand. Extract nested logic into helper functions.",
"evidence": [
{
"location": "src/services/order.ts:78-150",
"type": "code",
"snippet": "if (order.valid) { for (...) { if (...) { try { if (...) {"
}
],
"tags": ["nesting", "refactoring-required"]
}
```
---
## Best Practices
### ✅ DO:
- Calculate all five metrics for functions/methods
- Flag any metric exceeding warning threshold
- Provide specific refactoring suggestions
- Include evidence with line numbers
### ❌ DON'T:
- Skip metrics for simple functions
- Ignore nesting depth
- Accept critical thresholds without observation
- Forget to suggest refactoring approaches