# 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