Code is read far more often than it's written. You โ or a teammate โ will come back in 6 months and need to understand it. Clean code means writing for humans, not just computers.
Two programs can do the exact same thing, but one is a joy to read and the other is a headache. Let's learn the difference.
๐ท๏ธ Rule 1: Good names
Names should tell you what something is or does. Avoid x, data2, and tmp.
# ๐ต Mystery code
d = 86400
t = s / d
# ๐ Clear code
SECONDS_PER_DAY = 86400
days = total_seconds / SECONDS_PER_DAY
๐ก Naming guide
Variables & functions: snake_case
Constants: UPPER_CASE
Functions are verbs (calculate_total), variables are nouns (total_price).
๐ง Rule 2: Small functions that do one thing
A function should do one job. If you need "and" to describe it, split it up.
If you copy-paste code, turn it into a function instead. One place to fix bugs, one place to improve.
# Instead of repeating the greeting three times...
def greet(name):
return "Hello, " + name + "!"
print(greet("Mia"))
print(greet("Leo"))
๐ฌ Rule 4: Comments explain WHY, not WHAT
A comment like # add 1 to x is useless โ the code already says that. Good comments explain why something is done, or warn about a tricky case.
# Good: explains the reasoning
# Tax is applied only after the discount, per store policy
final = (price - discount) * 1.08
โ What you learned
Write code for humans to read.
Use descriptive names; functions are verbs, variables are nouns.
Keep functions small โ one job each.
DRY: don't repeat yourself.
Comments explain why, not what.
๐ฎ Time to Practice!
Refactor messy code into clean code. ๐งผ
๐ท๏ธ
Task 1: Rename for Clarity
Easy
This works but is unreadable. Rewrite it with clear names so it computes hours from minutes. 150 minutes โ 2.5 hours.
๐ซ
Task 2: Apply DRY
Medium
Write one greet(name) function and call it for Mia, Leo, and Zoe instead of repeating the print statement. Expected three greeting lines.
def greet(name):
return "Hello, " + name + "!"
for person in ["Mia", "Leo", "Zoe"]:
print(greet(person))
๐ง
Task 3: One Function, One Job
Medium
Split the work into two clear functions: area(w, h) and perimeter(w, h). For a 5ร4 rectangle: area 20, perimeter 18.
def area(w, h):
return w * h
def perimeter(w, h):
return 2 * (w + h)
print(area(5, 4))
print(perimeter(5, 4))
๐๏ธ Extra Practice โ Engineering Reps
Clean code is a habit, not a talent. Each drill below hands you messy code โ your job is to make it obvious at a glance. The output must stay exactly the same!
๐ข
Task 4: Kill the Magic Numbers
Easy
This line is a mystery: print(2 * 3.14159 * 5). Rewrite it with named constants PI and radius, plus a circumference variable, so a stranger understands it instantly. Print the value.
31.4159
PI = 3.14159
radius = 5
circumference = 2 * PI * radius
print(circumference)
๐ก๏ธ
Task 5: Guard Clauses Beat Deep Nesting
Medium
Deeply nested ifs are hard to read. Write can_vote(person) that returns early with a clear message: no name โ "No name given", under 18 โ "Too young", not registered โ "Not registered", otherwise "May vote". Test it with a valid voter and an under-18.
May vote
Too young
def can_vote(person):
if not person.get("name"):
return "No name given"
if person["age"] < 18:
return "Too young"
if not person.get("registered"):
return "Not registered"
return "May vote"
print(can_vote({"name": "Ana", "age": 20, "registered": True}))
print(can_vote({"name": "Ben", "age": 12, "registered": True}))
๐ท๏ธ
Task 6: Name Booleans Like Questions
Easy
Bad: flag = True. Good: is_logged_in = True, has_premium = False, can_download = is_logged_in and has_premium. Write those three lines and print can_download. Notice how the last line reads like English.
One function is doing three jobs: cleaning a name, scoring it, and printing a report. Split it into clean(name), score(name) (length ร 10) and report(name) that uses the other two. Call report(" aLiCe ") to print Alice scores 50.
Three lines repeat the same 20% discount: 10 * 0.8, 25 * 0.8, 40 * 0.8. Replace them with a DISCOUNT constant and an apply_discount(price) function, then print the three results with 2 decimals. Changing the sale later should mean changing one line.
8.00
20.00
32.00
DISCOUNT = 0.8
def apply_discount(price):
return price * DISCOUNT
for price in [10, 25, 40]:
print(f"{apply_discount(price):.2f}")
๐งฝ
Task 9: Boss Level: The Big Clean-Up
Boss
Here is truly awful code: def f(l):\n t=0\n for i in l:\n if i>0: t=t+i\n return t/len(l). Rewrite it properly: a descriptive name, a docstring, clear variable names, and a guard for an empty list (return 0). Print the result for [4, -2, 10] and for [].
4.666666666666667
0
def average_of_positive_values(numbers):
"""Return the average of the positive numbers, or 0 for an empty list."""
if not numbers:
return 0
total = 0
for number in numbers:
if number > 0:
total += number
return total / len(numbers)
print(average_of_positive_values([4, -2, 10]))
print(average_of_positive_values([]))