Skip to main content

Sign in to CleanKata

Track your progress, earn XP, and unlock every lesson.

By signing in you agree to our Terms of Use and Privacy Policy.

Clean Code50 XP6 min

Small Functions

Functions should do one thing, do it well, and do it only.

Do One Thing

Functions that do one thing are easy to name, easy to test, and impossible to misuse. "One thing" means one level of abstraction — not one line of code. If you can extract a piece into a well-named function without it feeling contrived, your original function was doing two things.

Does many things

function processUserRegistration(data):
    // validate
    if not data.email or "@" not in data.email:
        return { error: "invalid email" }
    if not data.password or length(data.password) < 8:
        return { error: "password too short" }
    // hash password
    hashed = hash(data.password)
    // save to db
    user = { email: data.email, password: hashed }
    db.insert("users", user)
    // send email
    sendEmail(data.email, "Welcome!", "Thanks for joining.")
    return { ok: true }

One thing each

function registerUser(data):
    validateRegistration(data)
    user = createUser(data.email, data.password)
    db.save(user)
    sendWelcomeEmail(user)

function validateRegistration(data):
    requireValidEmail(data.email)
    requireStrongPassword(data.password)

function createUser(email, password):
    return { email: email, password: hash(password) }

One Level of Abstraction

Mixing high-level logic (sendEmail()) with low-level detail (hashlib) in the same function is disorienting. Readers can't tell what's important and what's implementation noise. The Step-Down Rule: every function should read like a paragraph — each line calls functions one level below it.

// ✗ Mixed levels — high-level intent buried in low-level noise
function checkout(cart, user):
    total = sum of (item.price * item.qty) for each item in cart.items
    tax = total * 0.08
    final = total + tax
    conn = db.getConnection()        // ← suddenly low-level
    cursor = conn.cursor()
    cursor.execute("INSERT INTO orders ...", user.id, final)
    conn.commit()
    http.post("https://mail.svc/send", { ... })  // ← even lower
// ✓ One level — each line is at the same altitude
function checkout(cart, user):
    total = calculateTotal(cart)
    order = saveOrder(user, total)
    notifyUser(user, order)

Arguments and Side Effects

The ideal number of function arguments is zero. One is fine. Two is acceptable. Three or more — consider a parameter object. Flag arguments (is_admin=True) are a code smell: they announce the function does two things. Side effects are lies — a function named check_password that also logs the user in breaks the single-responsibility contract and surprises every caller.

Flag arg + side effect

function getUser(userId, includeDeleted):
    // does TWO things depending on flag
    if includeDeleted:
        return db.queryAll(userId)
    return db.queryActive(userId)

function checkPassword(user, password):
    if user.password == hash(password):
        session.login(user)   // ← surprise side effect!
        return true
    return false

No flags, no surprises

function getActiveUser(userId):
    return db.queryActive(userId)

function getUserIncludingDeleted(userId):
    return db.queryAll(userId)

function isCorrectPassword(user, password):
    return user.password == hash(password)

function login(user):          // side effect is explicit
    session.start(user)

Code Challenge

This function does at least 4 things. Can you name each responsibility and extract it into its own function?

💡Key takeaway

A function should do one thing, at one level of abstraction, with a name that makes a comment unnecessary.

🔧 Some exercises may still have errors. If something seems wrong, use the Feedback button (bottom-right of the page) to report it — it helps us fix it fast.

Hint: Start by listing everything the function does on paper. Then look for the natural 'seams' — where one concern ends and another begins. Each seam is a function boundary.

✗ Your version

Small Functions — CleanKata — CleanKata