SpecThis logo

Branch Count

Measuring decision points and code paths in your functions

What is Branch Count?

Branch count measures the number of decision points in your code. Each decision point creates a branch where the code execution can go in different directions. This metric is closely related to cyclomatic complexity, which is a widely-used measure of code complexity.

Higher branch counts mean more possible execution paths through your code, which makes it harder to test thoroughly, increases the likelihood of bugs, and makes the code more difficult to understand.

How It's Calculated

Calculation Method

The branch count increments by 1 for each of the following control flow constructs:

  • if statement
  • else if clause
  • for loop
  • while loop
  • do-while loop
  • case in a switch statement
  • catch block
  • Ternary operators (? :)
  • Logical operators (&&, ||)

A function with no branches (just sequential statements) has a branch count of 0.

Code Examples

Example 1: Branch Count = 0

A simple function with only sequential statements has no branches.

function calculateArea(width, height) {
  const area = width * height;
  console.log("Area calculated");
  return area;
}

// Branch Count: 0
// No decision points, just sequential execution

Example 2: Branch Count = 2

An if-else statement creates 2 branches.

function checkAge(age) {
  if (age >= 18) {           // Branch 1: if
    return "Adult";
  } else {                    // Branch 2: else (implicit)
    return "Minor";
  }
}

// Branch Count: 2
// Two possible paths through the function

Example 3: Branch Count = 4

Multiple if-else if conditions increase the branch count.

function getGrade(score) {
  if (score >= 90) {         // Branch 1
    return "A";
  } else if (score >= 80) {  // Branch 2
    return "B";
  } else if (score >= 70) {  // Branch 3
    return "C";
  } else {                   // Branch 4 (implicit)
    return "F";
  }
}

// Branch Count: 4
// Four different execution paths

Example 4: Logical Operators Count as Branches

Logical AND (&&) and OR (||) operators create additional branches.

function canVote(age, citizen) {
  if (age >= 18 && citizen) {   // Branch 1: if
                                 // Branch 2: && (short-circuit)
    return true;
  }
  return false;
}

// Branch Count: 2
// 1 for 'if', 1 for '&&'

function isValidEmail(email) {
  if (!email || !email.includes("@")) {  // Branch 1: if
                                         // Branch 2: || (short-circuit)
    return false;
  }
  return true;
}

// Branch Count: 2

Example 5: Switch Statements

Each case in a switch statement counts as a branch.

function getDayType(day) {
  switch (day) {
    case "Monday":      // Branch 1
    case "Tuesday":     // Branch 2
    case "Wednesday":   // Branch 3
    case "Thursday":    // Branch 4
    case "Friday":      // Branch 5
      return "Weekday";
    case "Saturday":    // Branch 6
    case "Sunday":      // Branch 7
      return "Weekend";
    default:            // Branch 8
      return "Invalid";
  }
}

// Branch Count: 8
// Each case clause is a decision point

Example 6: High Branch Count = 12 (Problematic)

Complex business logic can quickly accumulate many branches.

function calculateShipping(order) {
  let cost = 0;

  if (order.country === "USA") {           // Branch 1
    if (order.state === "AK" || order.state === "HI") {  // Branch 2, 3
      cost = 25;
    } else if (order.total > 100) {        // Branch 4
      cost = 0;  // Free shipping
    } else {
      cost = 10;
    }
  } else if (order.country === "Canada") { // Branch 5
    if (order.total > 150) {               // Branch 6
      cost = 15;
    } else {
      cost = 25;
    }
  } else {
    cost = 50;
  }

  if (order.isPriority && cost > 0) {      // Branch 7, 8
    cost *= 2;
  }

  if (order.hasInsurance) {                // Branch 9
    cost += 5;
  }

  if (order.isGift) {                      // Branch 10
    cost += 3;
  }

  return cost;
}

// Branch Count: 12
// Too many paths - hard to test and maintain!

Example 7: Refactored (Branch Count Reduced)

Breaking into smaller functions reduces branch count per function.

// Main function: Branch Count = 3
function calculateShipping(order) {
  let cost = getBaseCost(order);

  if (order.isPriority && cost > 0) {  // Branch 1, 2
    cost *= 2;
  }

  cost += getAddOns(order);

  return cost;
}

// Helper function: Branch Count = 5
function getBaseCost(order) {
  if (order.country === "USA") {                        // Branch 1
    return getUSAShipping(order);
  } else if (order.country === "Canada") {              // Branch 2
    return order.total > 150 ? 15 : 25;                 // Branch 3
  }
  return 50;
}

// Helper function: Branch Count = 3
function getUSAShipping(order) {
  const isRemote = order.state === "AK" || order.state === "HI";  // Branch 1, 2

  if (isRemote) {                                       // Branch 3
    return 25;
  }

  return order.total > 100 ? 0 : 10;
}

// Helper function: Branch Count = 2
function getAddOns(order) {
  let addOn = 0;

  if (order.hasInsurance) {  // Branch 1
    addOn += 5;
  }

  if (order.isGift) {        // Branch 2
    addOn += 3;
  }

  return addOn;
}

// Maximum Branch Count per function: 5
// Much easier to test and understand!

Testing Implications

Test Cases Needed

To achieve 100% branch coverage, you need to test every possible path. The number of test cases grows exponentially with branch count:

Branch CountMinimum Test Cases
22-4 tests
56-32 tests
1011-1,024 tests
2021-1,048,576 tests

Recommended Thresholds

Sensitivity LevelMax BranchesUse Case
High≤ 5Critical paths, security code
Medium≤ 15Most business logic
Low≤ 25Legacy systems being improved

Refactoring Strategies

1. Extract Functions

Break complex conditionals into separate, well-named functions. Each function should have a single, clear purpose.

2. Use Lookup Tables or Maps

Replace long if-else or switch statements with data structures.

// Before: 7 branches
function getDiscount(customerType) {
  if (customerType === "gold") return 0.20;
  else if (customerType === "silver") return 0.15;
  else if (customerType === "bronze") return 0.10;
  // ... more cases
}

// After: 0 branches
const DISCOUNTS = {
  gold: 0.20,
  silver: 0.15,
  bronze: 0.10,
  // ... more mappings
};

function getDiscount(customerType) {
  return DISCOUNTS[customerType] || 0;
}

3. Use Strategy Pattern

For complex conditional logic, use object-oriented design patterns to encapsulate different behaviors.

4. Simplify Boolean Logic

Reduce nested conditions by combining or inverting logic.

// Before: 3 branches
if (user.isActive) {
  if (user.hasPermission) {
    if (user.emailVerified) {
      grantAccess();
    }
  }
}

// After: 1 branch
if (user.isActive && user.hasPermission && user.emailVerified) {
  grantAccess();
}

Related Metrics

  • Nesting Depth: High branch count often correlates with deep nesting
  • Cyclomatic Complexity: Directly derived from branch count (complexity = branches + 1)
  • Test Coverage: More branches require more test cases