Function Length: Why 5 Lines is Better Than 50
Learn: Function Length: Why 5 Lines is Better Than 50
Welcome to TopperBlog! 👋
I'm a tech content creator passionate about helping developers level up their careers and master cutting-edge technologies.
🎯 What I Write About:
• AI/ML Engineering & LLMs
• Web3 & Blockchain Development
• System Design & Architecture
• Interview Preparation (FAANG)
• Freelancing & Remote Work
• Modern Tech Stacks (Next.js, React, Rust, TypeScript)
• Performance Optimization & Best Practices
💼 Mission: Sharing practical, actionable insights that accelerate your tech career and maximize your earning potential.
📚 15+ In-Depth Guides covering everything from earning $10k/month as a freelancer to cracking FAANG interviews.
🌐 Let's connect and grow together in this amazing tech journey!
#TechBlogger #SoftwareEngineering #CareerGrowth #WebDevelopment #AIEngineering
Function Length: Why 5 Lines is Better Than 50 (And Why Your Future Self Will Thank You)
Look, I'm going to level with you. We've all been there. You open a file, scroll down to find that one function you need to modify, and suddenly you're in line 847 of a single method that's longer than a CVS receipt. Your eyes glaze over. You question your career choices. You wonder if it's too late to become a woodworker.
I once inherited a function called processUserData() that was 312 lines long. Three. Hundred. Twelve. Lines. It validated inputs, called APIs, transformed data, sent emails, logged events, updated caches, and—I kid you not—played a success sound. It did everything except make me coffee, though honestly, I needed one after reading it.
That function was a crime scene, and the Single Responsibility Principle was the victim.
The Problem: When Functions Become Novellas
Here's the thing about long functions: they're like that friend who tells a story but keeps adding "Oh, and another thing!" until you've forgotten why you're even listening.
Long functions are cognitive overload in code form. When you're reading a 50-line function, you're juggling:
- What does this function actually do?
- Which variables matter right now?
- What's the state at line 37 versus line 12?
- Where does this loop end again?
- Why is there a random database call in the middle of validation logic?
- Is this comment from 2019 still relevant?
- Who hurt the person who wrote this?
The average human can hold about 7 (±2) items in working memory at once. A 50-line function with multiple responsibilities, nested conditionals, and side effects? That's like trying to juggle chainsaws while reciting Shakespeare. Backwards. In Klingon.
Why This Actually Matters (Beyond Your Sanity)
"But it works!" you say. Sure. So does duct tape on a leaking pipe. Temporarily.
The Real Costs:
1. Debugging becomes archaeological excavation When something breaks in a 50-line function, you can't just look at it and know where the problem is. You have to trace through the entire narrative, understanding every plot twist. That bug fix that should take 5 minutes? Now it's 2 hours.
2. Testing becomes a nightmare
How do you unit test a function that does seven different things? You end up with test cases like testProcessUserDataWhenUserIsValidAndEmailServiceIsUpAndCacheIsEmptyAndItsTuesday(). Nobody wants to write that. Nobody wants to maintain that.
3. Reusability goes out the window
You need to send an email in another part of your codebase? Too bad—that logic is buried in line 187 of processUserData(), tangled up with validation and database calls. Time to copy-paste and create your second crime scene.
4. Code reviews become hostage situations "Hey, can you review my PR?" Opens file Sees 300-line function Closes laptop Moves to another country
Enter: The Single Responsibility Principle
The Single Responsibility Principle (SRP) is deceptively simple: A function should do one thing, and do it well.
Not one category of things. Not one area of things. One. Thing.
Think of it like a restaurant kitchen. You don't have one chef who takes orders, cooks every dish, washes dishes, manages inventory, and handles the books. You have a line cook, a dishwasher, a sous chef, a manager. Each person has one job. When something goes wrong, you know exactly who to talk to.
Your functions should work the same way.
The Solution: Breaking It Down
Let's look at a real example. Here's the kind of monstrosity I see way too often:
// ❌ The "Does Everything" Function
async function handleUserRegistration(userData) {
// Validate email format
if (!userData.email || !userData.email.includes('@')) {
throw new Error('Invalid email');
}
// Check password strength
if (!userData.password || userData.password.length < 8) {
throw new Error('Password too weak');
}
if (!/[A-Z]/.test(userData.password)) {
throw new Error('Password needs uppercase');
}
if (!/[0-9]/.test(userData.password)) {
throw new Error('Password needs number');
}
// Check if user exists
const existingUser = await db.query(
'SELECT * FROM users WHERE email = ?',
[userData.email]
);
if (existingUser.length > 0) {
throw new Error('User already exists');
}
// Hash password
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(userData.password, salt);
// Create user
const userId = await db.insert('users', {
email: userData.email,
password: hashedPassword,
created_at: new Date()
});
// Send welcome email
await emailService.send({
to: userData.email,
subject: 'Welcome!',
template: 'welcome',
data: { name: userData.name }
});
// Log event
await analytics.track('user_registered', {
userId: userId,
timestamp: Date.now()
});
// Update cache
await cache.invalidate('user_count');
return { userId, email: userData.email };
}
This function is 50+ lines and does at least 7 different things. It's a Swiss Army knife when you need a scalpel.
Now, let's apply the Single Responsibility Principle:
// ✅ Each Function Has ONE Job
function validateEmail(email) {
if (!email || !email.includes('@')) {
throw new Error('Invalid email');
}
}
function validatePasswordStrength(password) {
if (!password || password.length < 8) {
throw new Error('Password too weak');
}
if (!/[A-Z]/.test(password)) {
throw new Error('Password needs uppercase');
}
if (!/[0-9]/.test(password)) {
throw new Error('Password needs number');
}
}
async function checkUserExists(email) {
const users = await db.query(
'SELECT * FROM users WHERE email = ?',
[email]
);
return users.length > 0;
}
async function hashPassword(password) {
const salt = await bcrypt.genSalt(10);
return bcrypt.hash(password, salt);
}
async function createUser(email, hashedPassword) {
return db.insert('users', {
email,
password: hashedPassword,
created_at: new Date()
});
}
async function sendWelcomeEmail(email, name) {
return emailService.send({
to: email,
subject: 'Welcome!',
template: 'welcome',
data: { name }
});
}
async function trackRegistration(userId) {
return analytics.track('user_registered', {
userId,
timestamp: Date.now()
});
}
// The orchestrator - reads like a recipe
async function handleUserRegistration(userData) {
validateEmail(userData.email);
validatePasswordStrength(userData.password);
if (await checkUserExists(userData.email)) {
throw new Error('User already exists');
}
const hashedPassword = await hashPassword(userData.password);
const userId = await createUser(userData.email, hashedPassword);
await sendWelcomeEmail(userData.email, userData.name);
await trackRegistration(userId);
return { userId, email: userData.email };
}
Look at that orchestrator function. It's 13 lines, and you can understand exactly what happens during user registration just by reading the function names. It reads like a checklist:
- Validate email ✓
- Validate password ✓
- Check if user exists ✓
- Hash password ✓
- Create user ✓
- Send welcome email ✓
- Track registration ✓
Each helper function is 3-7 lines. Each does ONE thing. Each has a clear, obvious name.
"But Now I Have So Many Functions!"
Yes. Yes, you do. And that's good.
This is the part where developers push back. "Now I have to jump around to different functions!" "It's more code!" "It's over-engineered!"
Let me address these:
"I have to jump around!" Modern IDEs let you jump to function definitions with a single keystroke. And honestly? Would you rather jump to a 5-line function with a clear name, or scroll through 50 lines trying to find the relevant section?
"It's more code!" More lines ≠ more complexity. The refactored version is actually less complex because each piece is simpler. Complexity isn't about line count—it's about cognitive load.
"It's over-engineered!" Over-engineering is building a spaceship when you need a bicycle. This is just... engineering. It's building things that are maintainable, testable, and understandable.
The Real Wisdom: Think in Layers
Here's what I've learned after years of writing and maintaining code: good code is like a good book with clear chapters.
Your main function is the table of contents. It tells you what happens, in order, at a high level. Each helper function is a chapter that handles one specific thing. If you need details, you dive into that chapter. If you just need the overview, you read the table of contents.
This is called levels of abstraction, and it's your secret weapon.
// High-level abstraction - the "what"
async function processOrder(order) {
validateOrder(order);
const payment = await processPayment(order);
await updateInventory(order);
await sendConfirmation(order, payment);
return payment;
}
// Each function handles one level of detail
// If you need to know HOW we validate, you look at validateOrder()
// If you need to know HOW we process payment, you look at processPayment()
// But you don't need to know ALL the details to understand the flow
When to Break the Rule (Yes, There Are Exceptions)
Look, I'm not a zealot. Sometimes a function needs to be longer than 5 lines. Here's when:
1. It's genuinely doing one thing that requires setup A function that initializes a complex data structure might be 15-20 lines, but if it's all related to that one initialization task, that's fine.
2. Breaking it up would make it less clear
If you'd have to create a function called helperForLinesTwentyToTwentyFive(), you've gone too far. Function names should describe what they do, not where they are.
3. The function is a pure algorithm Some algorithms are just inherently longer. A sorting algorithm, a complex calculation—these might be 30+ lines but still do "one thing."
The key question: Can someone understand what this function does without reading every line?
If the answer is no, it's probably too long.
The Actionable Takeaway: The 5-Minute Refactor
You don't have to refactor your entire codebase today. Start small:
This week, pick ONE long function and try this:
- Read it and list what it does (not how, just what)
- If your list has more than one item, you've got multiple responsibilities
- Extract each responsibility into its own function
- Name each function clearly - if you can't name it clearly, you haven't identified the responsibility correctly
- Make your original function the orchestrator that calls these new functions
Do this once a week. In a month, you'll have refactored four functions. In a year, 52. Your codebase will be dramatically better, and you'll have built the habit of writing shorter functions from the start.
The Bottom Line
Short functions aren't about being pedantic or following rules for rules' sake. They're about respecting future you (and your teammates).
When you write a 5-line function instead of a 50-line function, you're saying:
- "I care about the person who has to debug this at 2 AM"
- "I want this code to be testable"
- "I believe this logic might be useful elsewhere"
- "I respect my team's time and sanity"
Your 50-line function might work today. But six months from now, when you need to add a feature, fix a bug, or figure out why users in Australia are seeing weird behavior, you'll wish you'd broken it up.
Be kind to future you. Write short functions. Follow the Single Responsibility Principle.
Your future self—and your team—will thank you.
Now if you'll excuse me, I have a 200-line function to refactor. Wish me luck. 🫡
TL;DR: Long functions are hard to read, test, debug, and reuse. Break them into small functions that each do ONE thing. Your main function becomes a readable orchestrator. Yes, you'll have more functions. No, that's not a bad thing. Start small: refactor one long function this week.