Clean Code Principles: 7 Rules That Turn You from Amateur to Pro
Writing code that works is the first step. Writing code that others can read, maintain, and extend is what separates professionals from hobbyists.
There is a moment in every developer journey where the code works but nobody including yourself can understand it two weeks later. That is the moment where clean code stops being a nice-to-have and becomes a necessity.
Clean code is not about aesthetics. It is about communication. Code is read far more often than it is written, and the primary audience is not the computer. It is the human who has to change it next.
Rule 1: Name things as if a stranger will read them
Variable names like `x`, `temp`, and `data` tell the reader nothing. Compare for yourself:
python
# Bad
x = get_d()
t = x * 0.19
r = x + t
# Good
net_amount = calculate_item_value()
vat = net_amount * 0.19
gross_amount = net_amount + vat
The cost of a long name is a few keystrokes. The cost of a cryptic name is minutes of confusion multiplied by every person who reads it.
Rule 2: Keep functions small and focused
A function should do one thing and do it well. If you need the word *and* to describe what it does, it does too much:
python
# Bad – does two things
def process_order(order):
# Validation
if not order.get("product"):
raise ValueError("Product missing")
if order["quantity"] < 1:
raise ValueError("Invalid quantity")
# Saving
db.execute("INSERT INTO orders ...")
send_email(order["customer"])
# Good – separated concerns
def validate_order(order):
if not order.get("product"):
raise ValueError("Product missing")
if order["quantity"] < 1:
raise ValueError("Invalid quantity")
def save_order(order):
db.execute("INSERT INTO orders ...")
send_email(order["customer"])
Rule 3: Avoid deep nesting
Use early returns to eliminate nesting:
python
# Bad – deeply nested
def user_access(user, resource):
if user:
if user.is_active:
if user.has_permission(resource):
return resource.data
else:
raise PermissionError()
else:
raise ValueError("User inactive")
else:
raise ValueError("No user")
# Good – flat with early returns
def user_access(user, resource):
if not user:
raise ValueError("No user")
if not user.is_active:
raise ValueError("User inactive")
if not user.has_permission(resource):
raise PermissionError()
return resource.data
Rule 4: DRY, but do not over-abstract
If you find yourself copying the same five lines three times, extract a function. But if two pieces of code look similar today but serve different purposes, forcing them into a shared abstraction will cause pain later when they need to diverge.
Rule 5: Handle errors explicitly
Swallowing exceptions with an empty `catch` block is one of the fastest ways to create impossible-to-diagnose bugs:
python
# Bad – error swallowed
try:
result = api_call()
except Exception:
pass # What happened? Nobody knows.
# Good – explicit handling
try:
result = api_call()
except ConnectionError:
logger.warning("API unreachable, using cache")
result = load_from_cache()
except ValueError as e:
logger.error(f"Invalid API response: {e}")
raise
Rule 6: Code explains itself, comments explain the why
python
# Bad – obvious
counter += 1 # Increment counter
# Good – explains a non-obvious business rule
# Orders under 10 EUR get bundled because
# shipping costs would exceed the item value
if order.value < 10:
mark_for_bundling(order)
Rule 7: Refactor continuously, not in big rewrites
Clean code is not achieved in a heroic session. It emerges from small improvements. Every time you touch a file, leave it slightly better. Rename a confusing variable. Extract a helper. Remove dead code.