KAHIBARO
Discord Login Register

4.13 Clean Code Principles

Why Clean Code Matters

Clean code is code that is easy to read, easy to understand, and easy to change. You are not only writing for the computer, you are writing for future humans, including your future self.

Imagine opening your own code 6 months later and having no idea what it does. Clean code prevents that.

Goal of clean code:
Write code that is easy to understand and safe to change.

In this chapter you will see simple but powerful habits you can use from your very first programs, no matter which language you use.

We will use Python-style pseudocode for examples, but the ideas apply to any language.

Meaningful Names

Names are the first thing people see in your code. Good names make code almost read like plain English.

Use descriptive variable and function names

Bad:

python
def c(a, b):
    return a * b * 3.14

What is c? What are a and b?

Better:

python
def circle_area(radius):
    return radius * radius * 3.14

Now the name explains what the function does and what the parameter is.

More examples:

Bad nameBetter nameWhy it is better
xuser_ageTells you what the value represents
nmax_retriesShows meaning and intent
pproduct_priceClear business meaning
fread_file_contentVerb + object explains the action
duser_by_idSuggests it is a mapping of id to user

Rule: Prefer clear, longer names over short and confusing names.

If a name saves you one second to type, but costs 10 seconds every time you read it, it is a bad trade.

Use consistent naming style

Within a project, use the same style everywhere.

Common styles:

StyleExampleOften used for
snake_caseuser_profilePython variables, functions
camelCaseuserProfileJavaScript variables, functions
PascalCaseUserProfileClasses, types
SCREAMING_SNAKE_CASEMAX_SIZEConstants

Pick the style that your language community uses and stick to it.

Bad:

python
userName = "Alice"
user_age = 30
UserCountry = "FR"

Better:

python
user_name = "Alice"
user_age = 30
user_country = "FR"

Avoid meaningless prefixes and comments in names

Bad:

python
data1 = "Alice"
data2 = 30
data3 = "FR"

Better:

python
user_name = "Alice"
user_age = 30
user_country = "FR"

Do not encode too much in the name with weird prefixes:

Bad:

python
strUserNm = "Alice"
intUserId = 123

Your type system and IDE can already tell you types.

Make Booleans read like questions

Boolean variables and functions should sound like yes/no questions.

Bad:

python
flag = True
if flag:
    ...

Better:

python
is_active = True
if is_active:
    ...

Bad:

python
def password(user):
    ...

Better:

python
def is_valid_password(user):
    ...

Small, Focused Functions

A function should do one thing, and do it well. If you cannot describe what a function does in a short sentence, it probably does too much.

One responsibility per function

Bad:

python
def process_order(order):
    # 1. validate order
    if not order.items:
        raise ValueError("No items")
    # 2. calculate total
    total = 0
    for item in order.items:
        total += item.price * item.quantity
    # 3. save to database
    db.save(order, total)
    # 4. send email
    send_email(order.user.email, "Order received", "Thanks!")

This function validates, calculates, saves, and sends email. Too many responsibilities.

Better:

python
def validate_order(order):
    if not order.items:
        raise ValueError("No items")
def calculate_order_total(order):
    total = 0
    for item in order.items:
        total += item.price * item.quantity
    return total
def save_order(order, total):
    db.save(order, total)
def notify_order_received(order):
    send_email(order.user.email, "Order received", "Thanks!")
def process_order(order):
    validate_order(order)
    total = calculate_order_total(order)
    save_order(order, total)
    notify_order_received(order)

Now each function has a clear purpose, and process_order reads like a story.

Rule: If you can split a function into smaller functions with clear names, you probably should.

Keep functions short

There is no strict line, but many developers try to keep functions short enough to see fully on one screen, for example 10 to 30 lines.

Compare:

Bad:

python
def handle_user_request(request):
    # 100 lines doing many things
    ...

Better:

python
def handle_user_request(request):
    user = authenticate(request)
    validate_request(request)
    data = parse_data(request)
    result = execute_action(user, data)
    return build_response(result)

Each called function will be shorter and focused.

Avoid too many parameters

If a function has many arguments, it is harder to call correctly and to understand.

Bad:

python
def create_user(name, age, country, email, is_admin, is_active, created_at, updated_at):
    ...

Better, group related data into an object or dictionary:

python
def create_user(user_data):
    ...

Or at least use keyword arguments when calling:

python
create_user(
    name="Alice",
    age=30,
    country="FR",
    email="a@example.com",
    is_admin=False,
    is_active=True,
    created_at=now(),
    updated_at=now(),
)

Comments That Add Value

Comments should explain why something is done, not repeat what is obvious from the code.

Avoid explaining the obvious

Bad:

python
# increase i by 1
i = i + 1

The code already says that.

Better:

python
# move to the next page
current_page = current_page + 1

Now the comment adds context.

Use comments to explain intent, not to fix bad code

Bad:

python
# this function validates user input and saves it to the database and sends an email
def handle_user():
    ...

The real problem is the function does too many things. Fix the code instead:

python
def validate_user_input(...):
    ...
def save_user(...):
    ...
def send_welcome_email(...):
    ...
def handle_user():
    ...

Now you do not need that long comment.

Document reasons, not just behavior

Good uses of comments:

Example:

python
# We use a fixed seed here so that tests are repeatable
random.seed(42)
python
# This query intentionally does not use an index because we need the latest data

Keep comments up to date

Old comments that are no longer true are dangerous.

Bad:

python
# This function returns user age
def get_user_data():
    return {"name": "Alice", "age": 30, "country": "FR"}

If behavior changes and comment is not updated, readers are misled.

Rule: If you change code, update or remove related comments.

Consistent Formatting and Style

Formatting is not about the computer. It is for human eyes. Consistent style makes code easier to scan and read.

Indentation and spacing

Use consistent indentation, usually 2 or 4 spaces. Do not mix tabs and spaces.

Bad:

python
if is_valid:
    print("OK")
      print("Still valid")

Better:

python
if is_valid:
    print("OK")
    print("Still valid")

Use spaces around operators:

Bad:

python
total=price*quantity+tax

Better:

python
total = price * quantity + tax

Break long lines

Very long lines are hard to read and to see in many editors.

Bad:

python
send_email(user.email, "Welcome to our very cool application", "Hello " + user.name + ", thanks for registering. Please click this very long link to verify your account: " + verification_link)

Better:

python
subject = "Welcome to our very cool application"
body = (
    "Hello " + user.name +
    ", thanks for registering. Please click this link to verify your account: " +
    verification_link
)
send_email(user.email, subject, body)

Use blank lines to group logic

Blank lines help structure code visually.

Bad:

python
def process():
    user = get_user()
    if not user:
        return None
    data = load_data()
    result = compute(user, data)
    save_result(result)
    return result

Better:

python
def process():
    user = get_user()
    if not user:
        return None
    data = load_data()
    result = compute(user, data)
    save_result(result)
    return result

Avoiding Repetition (DRY)

DRY stands for "Don't Repeat Yourself". Repeated code is harder to maintain, because you must change it in many places.

Extract repeated code into functions

Bad:

python
def send_welcome_email(user):
    body = "Hello " + user.name + ", welcome!"
    send_email(user.email, "Welcome", body)
def send_password_reset_email(user, token):
    body = "Hello " + user.name + ", reset your password: " + token
    send_email(user.email, "Reset password", body)

Both build email bodies in similar ways.

Better:

python
def build_greeting(user):
    return "Hello " + user.name + ", "
def send_welcome_email(user):
    body = build_greeting(user) + "welcome!"
    send_email(user.email, "Welcome", body)
def send_password_reset_email(user, token):
    body = build_greeting(user) + "reset your password: " + token
    send_email(user.email, "Reset password", body)

Now if you want to change the greeting, you change one place.

Avoid copy-paste logic

Suppose you validate email in two places:

Bad:

python
def register_user(email):
    if "@" not in email or "." not in email:
        raise ValueError("Invalid email")
    ...
def update_email(user, new_email):
    if "@" not in new_email or "." not in new_email:
        raise ValueError("Invalid email")
    ...

Better:

python
def validate_email(email):
    if "@" not in email or "." not in email:
        raise ValueError("Invalid email")
def register_user(email):
    validate_email(email)
    ...
def update_email(user, new_email):
    validate_email(new_email)
    ...

Simplicity Over Cleverness

Simple code is usually better than "smart" code that is hard to understand.

Prefer clear loops over complex one-liners

Many languages let you write very short but dense statements. Use them carefully.

Compare:

python
# Complex one-liner
result = [x * 2 for x in numbers if x % 2 == 0]

This is fine if you know the syntax, but for a beginner it might be confusing.

You can write:

python
result = []
for number in numbers:
    if number % 2 == 0:
        result.append(number * 2)

Both are correct. Use the simpler form if your team is new, or if the logic is more complex.

Avoid unnecessary clever tricks

Bad:

python
# Using a hacky trick to convert boolean to int
value = True + True + False  # 2

Better:

python
value = int(True) + int(True) + int(False)

Or simply count with clear logic.

Do not prematurely optimize

Do not try to make code "extremely fast" before you know where the real performance problem is.

Bad:

python
# Very complex code to avoid a tiny extra loop

Better:

Rule: Make it work, then make it clear, then, if needed, make it fast.

Defensive Programming and Error Handling Style

Clean code is also about how you handle incorrect data and unexpected situations.

(You will see full error handling techniques in a dedicated chapter, here we focus on style.)

Fail fast and clearly

When inputs are invalid, handle it early.

Bad:

python
def divide(a, b):
    return a / b  # May crash later if b is 0

Better:

python
def divide(a, b):
    if b == 0:
        raise ValueError("b must not be zero")
    return a / b

Now the error is clear and close to the cause.

Avoid deeply nested code

Deep nesting makes code hard to read.

Bad:

python
def process(user):
    if user is not None:
        if user.is_active:
            if has_permission(user):
                do_something()

Better, use early returns:

python
def process(user):
    if user is None:
        return
    if not user.is_active:
        return
    if not has_permission(user):
        return
    do_something()

Writing Simple Tests Early

Testing has its own chapter, but as a clean code habit you should think about tests as you write code.

Functions that are easy to test are usually clean

Pure functions, that take inputs and return outputs without hidden effects, are easier to test and easier to reason about.

Example of a pure function:

python
def calculate_total(price, quantity, tax_rate):
    return price * quantity * (1 + tax_rate)

This is easy to test:

python
assert calculate_total(10, 2, 0.1) == 22

If a function reads global variables, writes files, prints to console, and returns a value, it becomes much harder to test and understand.

So by designing functions that are easy to test, you also improve cleanliness.

Clean Code in Small Programs vs Large Systems

As a beginner you might wonder if clean code is only for large applications. It is not.

Small scripts

Even a 20-line script benefits from:

Example:

Bad:

python
import sys
f = open(sys.argv[1])
c = f.read().split("\n")
for l in c:
    if l != "":
        print(l)

Better:

python
import sys
def read_lines(file_path):
    with open(file_path) as f:
        return f.read().splitlines()
def print_non_empty_lines(lines):
    for line in lines:
        if line:
            print(line)
def main():
    file_path = sys.argv[1]
    lines = read_lines(file_path)
    print_non_empty_lines(lines)
if __name__ == "__main__":
    main()

Even though it is longer, it is much clearer.

Large backend applications

When your project grows, these small habits become essential:

Clean code scales better.

Practicing Clean Code

Clean code is not something you learn once. It is a habit you build.

Simple practice ideas

A small refactoring exercise

Start with this messy code:

python
def handle(u, a):
    if a > 18:
        print("ok")
        print("welcome " + u)
    else:
        print("no")

Try to turn it into cleaner code:

Possible version:

python
ADULT_AGE = 18
def is_adult(age):
    return age >= ADULT_AGE
def greet_user(name):
    print("welcome " + name)
def handle_user(name, age):
    if not is_adult(age):
        print("Access denied")
        return
    print("Access granted")
    greet_user(name)

Now the code explains itself.

Summary

Key ideas from this chapter:

Clean code principle: Code is read far more often than it is written.
Always optimize for the reader.

These habits will make all later backend topics, such as web frameworks, databases, and APIs, easier to understand and safer to implement.

Views: 7

Comments

Please login to add a comment.

Don't have an account? Register now!