Counting Steps, Not Seconds
Why we measure algorithms in steps instead of seconds, and how to count the work a loop really does.
Your function works beautifully in testing. Ten contacts, instant. You ship it. Three months later the app has a million users and that same function locks the server for minutes at a time.
Nothing broke. The code just met a bigger input.
A stopwatch can't warn you about this. Seconds depend on the machine, the Python version, what else is running — and your test data is always tiny. So computer scientists measure something sturdier: how the number of steps grows as the input grows.
We call the input size n — the number of items your code has to handle. 10 contacts: n = 10. A million: n = 1,000,000. The question that predicts everything: when n doubles, what happens to the work?
Let's count steps in a function you could have written in your first Python week:
def find_max(numbers):
biggest = numbers[0]
for num in numbers:
if num > biggest:
biggest = num
return biggestThe loop body runs once per item. For a list of 10 numbers, ~10 comparisons. For a million, a million comparisons. The work grows in step with n — double the list, double the work. We say the work grows linearly.
Counting like this feels almost too simple, but it's the exact skill: find the loop, ask how many times it runs, done. It only gets interesting when loops start hiding inside other loops…
How many steps does this count?
items = [8, 3, 9, 5]
steps = 0
for item in items:
steps = steps + 1
print(steps)- A4
- B3
- C5
- D0
Now the plot twist: at a wedding, the host greets every guest at the door — 50 guests, 50 greetings. Linear. But then every guest clinks glasses with every other guest: 50 × 49 ≈ 2,500 clinks. Double the guests and greetings double… but clinks quadruple.
In code, the "everyone with everyone" shape is a nested loop — a loop inside a loop:
for a in guests: # runs n times
for b in guests: # runs n times PER a
clink(a, b) # runs n × n times totalOne more rule, and it's a relief: constants don't change the story. A loop that does 2 quick actions per item does 2n steps — but 2n and n grow the same way (double the input, double the work). When n is a million, the difference between n and 2n is noise; the difference between n and n² is a server on fire. We keep the growth shape, drop the constant.
A search loop scans a list from front to back. The list grows from 1,000 items to 2,000. In the worst case, the work roughly…
- ADoubles
- BQuadruples
- CStays the same
- DGrows by one step
Nested loops now. What does this print?
items = [1, 2, 3]
steps = 0
for a in items:
for b in items:
steps = steps + 1
print(steps)- A9
- B3
- C6
- D27
- We measure algorithms by counting steps as a function of n (the input size), never with a stopwatch — seconds vary, growth doesn't.
- The key question: when n doubles, what happens to the work?
- One loop over n items → n steps (linear): double the input, double the work.
- A nested loop → n × n steps: double the input, quadruple the work — the wedding-clink explosion.
- Constants don't matter: 2n grows like n. We care about the shape of growth, not the exact count.
Next lesson: the industry's shorthand for these growth shapes — Big-O notation, the vocabulary every interview is conducted in.