Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Clean Code Principles  ›  Lesson

Minimize Cyclomatic Complexity

Minimize cyclomatic complexity 15 minCyclomatic complexity counts the independent paths through a function, and guard clauses, lookup tables and the right built-in constructs keep that count low.

Minimize Cyclomatic Complexity

Shelfwise's shipping function has grown one if at a time. Now nobody is sure which combination of country, weight and total leads to which price, and the tests cover only half of the cases. There is a number that measures this problem, and a set of habits that shrink it.

The rule

Every branch is another path to test; flatten and name them.

Cyclomatic complexity counts the independent paths through a function. The quick way to work it out: decision points + 1. Decision points are if, elif, for, while, except and case, and many tools also count each and and or. An else adds no decision; it is the other side of the if.

def shipping_cost(order):
    if order.country == "IN":
        if order.total >= 500:
            return 0
        else:
            return 40
    else:
        if order.express:
            return 900
        else:
            return 600

Three ifs, so complexity is 3 + 1 = 4. That means four paths, and at least four tests to exercise them all.

Three habits bring the number down:

  • Guard clauses. Handle the special case first and return early, so the main path is not nested.
  • Lookup tables. A dictionary replaces a long if/elif chain that maps one value to another.
  • The right construct. Built-ins such as any(), all(), sum() and max() say what you mean and hide the loop.
RATES = {"IN": 40, "US": 600, "UK": 550}

def shipping_cost(order):
    if order.total >= FREE_SHIPPING_THRESHOLD:
        return 0
    return RATES.get(order.country, DEFAULT_RATE)

This version has one decision, and a new country is a new row of data rather than a new branch. (Notice it also changed the rules: free shipping now applies in every country, and the express price is gone. Flattening is a good moment to check which of the old branches were really intended, and to keep the ones that were.)

The shortcut

Scan for decision keywords, count them, add one. If the number passes about 10, the function is asking to be split or flattened.

Counting a stock checkStep 1 of 4
  1. List the decisions

    for line in cart: is one. if line.qty > line.book.stock: is two.

The trap is thinking a short function is automatically simple. Five ifs squeezed into eight lines still means six paths.

Drills

Answer fast — trust the rule.

quick drill

A function has one for loop containing one if. What is its cyclomatic complexity?

quick drill

What does a guard clause do?

quick drill

A 12-branch if/elif chain maps a country code to a tax rate. What is the best replacement?

quick drill

Which is the clearest way to ask "is every line in the cart paid for?"

Remember

  • Complexity is decision points + 1; each path is another case to test.
  • Flatten with guard clauses, lookup tables and built-ins like any() and all().
  • Trap: short does not mean simple; count the branches, not the lines.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainFlatten the shipping rules

A Shelfwise function picks a shipping rate with five nested if/elif/else branches keyed on the destination country, plus one check that orders of 500 or more ship free. Explain how you would reduce its cyclomatic complexity and why that makes it easier to test.