Skip to main content

Section 12.6 Function Length

Subsection 12.6.1 Challenges with Long Functions

Function length is the squishiest of the three principles we have listed. There is no hard and fast rule about how long a function should be. However, longer functions are generally harder to understand and maintain. Anytime a function starts approaching 15+ lines of code, it is worth thinking about whether it can be simplified or broken down into smaller functions.
Sometimes, a long function is a sign of some other problem, like violating the single responsibility principle. But length itself increases the cognitive load on the programmer reading the code.
There is a famous finding in cognitive psychology that places the human working memory at about 7Β±2 items. A person can remember about 5 to 9 pieces of information in their head at once. To remember more than that requires committing some of the information to long-term memory or β€œchunking” items.
A common example - if you are trying to remember a phone number, you normally don’t think of it as a series of 10 items like: 5 0 3 5 5 5 3 2 5 1. Instead, you mentally group the numbers into chunks: 503, 555, and 3251. Thinking of 503 as a group instead of three digits reduces the number of things you are trying to remember at once. (And if you are used to the 503 area code, you already will have a long-term mental chunk for it.)
When a programmer is reading through a function, the 7Β±2 mental limit applies to the things they are trying to keep track of. Rather than try to remember each symbol and word, good programmers mentally β€œchunk” code that they are reading to stretch what they can keep track of. Instead of thinking of cin >> variable1 as three separate pieces of information (cin, >> and variable1), they might think of the whole chunk as β€œget input into variable1”. They will even chunk multiple lines into a single mental group: β€œoh, those 5 lines just calculate the triangleArea” and then stop paying attention to the details inside that β€œchunk”.

Note 12.6.1.

Programmers often use blank lines to break parts of a function into distinct blocks. This helps the reader spot the logic that the writer used while β€œchunking” the code.
Listing 12.6.1.
// (chunk 1)
cin >> variable1;
cin >> variable2;
cin >> variable3;

// (chunk 2)
variable4 = variable1 + variable2;
variable5 = variable2 * variable3;
variable6 = variable4 + variable5;

// (chunk 3)
cout << "The result is: " << endl;
cout << variable6 << endl;
These tricks are how we use our memory capacity of 7ish items to read and understand code that is much longer than 7 lines. But if a function is too long, or the logic is too complex to easily chunk, it will become harder to understand the code. We will have to reread the logic multiple times before being able to grasp how all the parts fit together.
Longer functions are also more difficult to test and debug. If a test reveals that a 100 line function has a bug, there are 100 possible lines of code where the bug could be. If a 15 line function has a bug, there is simply less code to wade through. (It is also likely that the shorter function is less complex, making each line that much easier to understand!)

Warning 12.6.2.

The number of lines of code in a function is only a rough measure of its complexity. Fitting more logic into fewer lines does not necessarily make the function simpler or easier to understand.
It is often easier to read 15 lines of simple, straightforward code than 5 lines of code that is using complex syntax and fancy tricks to pack the same work into fewer characters. Each line in the simple code can be quickly read and then mentally chunked. The short complex code likely requires the reader to slow down and carefully parse each line, making it harder to grasp the overall logic.

Subsection 12.6.2 Dealing with Function Length

If a function starts feeling long, we should stop and decide: Is it trying to do too much? Are there subtasks it can be broken into?
Look for groups of lines in the function that work together to produce a single value or perform a single task. Consider breaking each of those groups into their own functions.
For example, maybe inside a 20 line function you do 5 lines of calculations to get triangleArea. All the code after those 5 lines only depends on final value for triangleArea and not any of the work done to calculate it. Those 5 lines would be a good candidate to β€œchunk” into a separate function getTriangleArea would make the code clearer and easier to read. The main function would then just call getTriangleArea and use the result.
There are algorithms that involve a significant number of steps which are all tightly interrelated. In those cases you may not be able to cleanly break out parts of the logic. But in many cases, there will be opportunities to simplify and clarify the code by breaking it into smaller pieces.

Subsection 12.6.3 Too Short Functions

Can functions be too short? Not really. There is a slight amount of processing overhead involved in calling a function. In theory it is faster to just do int area = length * width; than to call a function that does the same work:
// Too short??? Probably not!
int  calculateRectangleArea(int length, int width) {
    return length * width;
}
However, compilers do all kinds of optimizations that can eliminate that overhead. Any modern compiler will likely generate the same machine code for int area = calculateRectangleArea(length, width); as it would for the code int area = length * width;. So in practice, there is likely no performance difference, and the benefits of using functions (like improved readability and maintainability) far outweigh the costs. The reader who sees calculateRectangleArea will immediately understand what it does, without having to mentally parse the implementation details (β€œhrmmm, length * width, oh that is just calculating the area”). And if we ever need to fix a bug with our calculation, we can do so in one place without having to find and change every instance of length * width in our code.
You have attempted of activities on this page.