How to Write Clean Code
Clean code isn’t about being fancy. It’s about writing code that makes sense at 2 a.m., six months later, when you’re tired and slightly annoyed. If future-you can read it without swearing, you did it right.
Below are practical principles, rewritten with Python examples and less fluff.
Use Clear, Consistent Naming
Names are not vibes. They are contracts.
- Variables should describe what they hold, not how they’re used.
- Functions should say exactly what they do. If it sounds vague, it probably is.
# Bad
x = 7
def process(data):
return data * x
# Good
TAX_RATE = 0.07
def calculate_tax(amount):
return amount * TAX_RATE
If you need a comment to explain a name, the name is wrong.
Choosing good names feels slow. Debugging bad ones is slower.
Keep Functions Small and Single‑Purpose
One function. One job. No side quests.
# Bad
def create_user_and_send_email(data):
user = save_user_to_db(data)
send_welcome_email(user.email)
log_action("user_created")
# Good
def create_user(data):
return save_user_to_db(data)
def send_welcome(user):
send_welcome_email(user.email)
If you can’t describe what a function does in one sentence without using “and”, split it.
Comments: Explain Why, Not What
Python is readable. Don’t insult it with obvious comments.
# Bad
# increment i by 1
i += 1
# Good
# retry once to handle flaky network issues
retry_count += 1
Comments should capture intent, trade‑offs, or context — things the code itself can’t say.
Refactor Aggressively (But Intentionally)
Refactoring isn’t cleanup. It’s part of writing.
- Kill duplicate logic
- Flatten complex conditionals
- Rename things that aged badly
# Bad
if user.is_admin == True:
has_access = True
else:
has_access = False
# Good
has_access = user.is_admin
If something feels clunky, it probably is.
Consistent Formatting Is Non‑Negotiable
Arguing about style is a waste of life. Let tools decide.
- Use
blackfor formatting - Use
rufforflake8for linting - Enforce it in CI
Consistency > personal preference. Always.
Avoid Deep Nesting
Nested code is cognitive debt.
# Bad
if user:
if user.is_active:
if user.has_permission("edit"):
edit_resource()
# Good
if not user or not user.is_active:
return
if user.has_permission("edit"):
edit_resource()
Early returns are your friend. Use them.
Handle Errors Like You Expect Them
Errors are not edge cases. They are the case.
# Bad
def read_file(path):
return open(path).read()
# Good
def read_file(path):
try:
with open(path) as file:
return file.read()
except FileNotFoundError:
return None
Fail loudly when needed. Fail gracefully when possible.
Stay DRY (But Don’t Be Weird About It)
Don’t copy‑paste logic. Abstract it — carefully.
# Bad
def get_admin_users(users):
return [u for u in users if u.role == "admin"]
def get_editor_users(users):
return [u for u in users if u.role == "editor"]
# Good
def filter_users_by_role(users, role):
return [u for u in users if u.role == role]
Abstraction should reduce clarity only if it reduces repetition more.
Readability Beats Cleverness. Every Time.
If your code looks smart but reads like a puzzle, you lost.
# Bad
result = [x for x in data if not x % 2]
# Good
def get_even_numbers(numbers):
return [n for n in numbers if n % 2 == 0]
Computers don’t care. Humans do.
Clean Code Is a Habit, Not a Talent
Nobody writes clean code by accident. You write it, then you rewrite it.
- Re‑read your code
- Delete more than you add
- Optimize for the next reader
Clean code is empathy, applied to software.