Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Defensive Programming

โญ beginnerโณ 10 min read๐Ÿ“ Lesson 29 of 169

Validate at the boundary, raise on broken invariants, and turn silent bugs into loud ones.

raise throws an exception deliberately โ€” when the data is wrong, fail loudly:

def set_price(price):
    if price < 0:
        raise ValueError(f"price cannot be negative, got {price}")
    return price

A function that fails fast with a clear message is kinder than one that returns nonsense and lets the bug surface three layers away. Raising early converts a silent logic error into a loud, debuggable runtime error.

Defensive checks in practice

def average(values):
    if not values:                 # None, [], empty โ€” all falsy
        raise ValueError("average of empty data is undefined")
    return sum(values) / len(values)

The check is one line; the debugging time it saves is hours. As a rule: validate at the boundary (where data enters your program), raise inside (when your own invariants break).