7.8 KiB
7.8 KiB
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
// 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
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 |
| ` | |
?: (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
-
Increment for each:
if,else if,elseswitchfor,foreach,while,docatchbreak/continueto label- Sequences of logical operators
-
Nesting penalty:
- Add +1 for each level of nesting when incrementing
Example
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
// 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
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
- Early returns (guard clauses)
// Before
function process(data) {
if (data) {
if (data.valid) {
// actual logic
}
}
}
// After
function process(data) {
if (!data) return;
if (!data.valid) return;
// actual logic
}
- Extract nested logic
// 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
{
"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
{
"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
{
"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