How Long Should a Function Be? (And Why It’s the Wrong Question to Ask)
Function length is the wrong focus. What matters is how clearly your code communicates intent.
Most hard-to-understand code is not wrong. It is just structured in a way that hides its intent.
In many cases, the problem is not complexity itself, but where that complexity lives. We tend to express domain concepts through control flow—if statements, switch blocks, nested conditionals—rather than through explicit structure. That makes the code harder to read, harder to change, and harder for AI to work with.
Design Right-Sized Functions
Many a code reviewer has battled over function length. The argument usually alternates between two polar opposites: should we prefer many small methods, or is it better to keep related code in one large chunk?
Ultimately, that question misses the point. It is the wrong question to ask. Rather, we should focus on right-sizing our functions.
Fundamentally, the cost of working with code is dominated by how long it takes to answer questions like:
What does this code do?
What will break if I change it?
Where should I make the change?
Large functions increase that cost because they force us — and our agents — to scan, interpret, and simulate more logic before we can act. Right-sized functions reduce that burden. Not by being small, but by being understandable.
Introduce Functions Your Brain Loves
Human working memory is limited. We do not read code token by token—we read by chunking.
A good function acts as a cognitive unit. It lets us replace a block of logic with a single idea.
Compare:
if (user.isVip() && order.amount() < 20000 && !order.hasDispute()) {
// ...
}with:
if (isEligibleForFastTrackRefund(user, order)) {
// ...
}It’s a simple example, yet the second version compresses detail into meaning. It allows the reader to move forward without simulating every condition.
That matters even more in an AI-driven workflow. As humans, we are no longer just authors of code. We are:
orchestrators and technical leaders, guiding agents toward the right implementation,
and reviewers, validating and correcting what those agents produce.
Both roles depend on quickly understanding intent. Functions that align with how we think make that possible.
Introduce Functions Your AI Agent Loves
The same properties that help humans understand code also benefit AI systems—but for different reasons.
AI models do not “understand” code the way humans do. They infer meaning from patterns in tokens and depend heavily on what is explicitly expressed in the code.
Research shows that naming plays a critical role. When meaningful identifiers are replaced with arbitrary names, model performance drops significantly. Current models rely heavily on literal features—names, structure, and local context—rather than inferred semantics.
That has practical implications:
A well-named function communicates intent directly.
A poorly named function forces the model to reconstruct meaning.
Larger, unstructured methods increase the amount of code the model must process before making a safe change.
In other words, good function design reduces both cognitive load and token load.
How long should a function be? Findings from research
So, all this talk about right-sized functions. Couldn’t we just come up with a number? Sure. What about 24? That number comes from a 2022 study which examined the evolution of ∼785K Java methods.
24 lines is lower than all corporate coding standards I’ve ever seen. Those tend to settle for variations of the idea that the whole function should fit on screen or, old school, a page of paper. (See the coding rules from NASA’s Jet Propulsion Lab for a good example).
But even a number backed by data is misleading. Code doesn’t magically become unreadable once you add line 25. Size alone is a poor predictor of complexity.
Empirical research consistently shows that maintainability and understandability cannot be reliably inferred from method length. Such models are not very accurate. Instead, factors like naming, cohesion, nesting depth, and domain complexity are all more important.
With coding agents now working directly on our code, hard limits become even less useful. Agents benefit from explicit structure and clear intent, not from arbitrary line counts.
🎗️ There is no fixed number of lines that makes a function “good”.
A long function is not a problem by itself. A function that mixes multiple concerns, hides intent, or resists naming is.
So the goal of refactoring is not shorter functions per se. It is better structure.
When we extract well-named functions with clear purpose, we introduce meaningful chunks into the design. Those chunks make it easier to reason about the system and often reveal better abstractions.
Refactoring is not about slicing code into smaller pieces. It is about discovering the right boundaries.
Making it worse: split at random
Discovering the right boundaries is not as simple as just extracting pieces of code into functions.
Consider this:
// ⚠️ WARNING: do *not* try this at home
void processOrder(Order order) {
impl1(order);
impl2(order);
}
void impl1(Order order) {
// first half of logic
}
void impl2(Order order) {
// second half of logic
}This satisfies a line-count rule. It also keeps your company-mandated linting tool happy. What it doesn’t do is improve understanding.
Splitting functions based on arbitrary thresholds makes the design worse. Code that belongs together should stay together. Split by concept, never by lines.
Beyond Method Extraction: define concepts
Now, there’s one more thing to consider. Making a method shorter is not necessarily about splitting it into smaller ones. (In fact, I suspect that this misconception is a common reason for the keyboard wars around function length).
Consider:
String allowedHumidityBand = request.allowedHumidityBand();
String[] humidityParts = allowedHumidityBand.split(”-”);
int minHumidity = Integer.parseInt(humidityParts[0]);
int maxHumidity = Integer.parseInt(humidityParts[1]);In the preceding code, there seems to be a domain concept involving humidity limits. But that concept is scattered across Strings and ints. The reader has to infer that all of these values are really one thing: a humidity band.
A simple improvement is to define that concept directly:
HumidityBand humidityLimit = parseHumidityBand(request.allowedHumidityBand());That is a small change, but it matters. Yes, we went from four lines of code to one, but length is secondary. The important part is that the code now aligns with the problem domain. The parsing details are encapsulated, so they no longer distract from the overall purpose of the method. You, and your agent, can now talk about a HumidityBand instead of passing around parsing artifacts and loose integers. That makes the intent clear.
From Hidden Logic to Explicit Structure
Functions are the first unit of structure in a codebase. They define how logic is grouped, how intent is communicated, and how change is localized. If the function boundaries are wrong, everything built on top of them becomes harder to understand and harder to evolve.
That is why function design matters so much. It is where structure begins.
It’s also where this series continues. In the next posts, we’ll take on specific patterns that turn tangled control flow into explicit structure:
conditionals → named rules
branching → tables
logic blobs → composable pipelines
If you enjoy taking messy code apart and rethinking its design, you’ll like what’s coming next. (And yes, we’ll break a few “best practices” along the way).
My next post is one of the most common problems: selection logic hidden inside conditionals. Subscribe if you want those patterns as they’re published, and see you soon!

