How to Split Large Functions and Work With Short Functions


When it comes to coding, it is important to keep your functions short and sweet.

This will make your code more readable and easier to debug. However, there are times when you will need to split up a large function into smaller ones.

The article aims to answer some common questions about working with methods/functions: should you split large functions/methods even if small functions will be called only one? Is it wrong to have one-line functions/methods that are called only once? And when and how to remove a short function?

Should I have many smaller functions/methods or one big function/method?

There are 4 reasons why you should have smaller functions over big functions or methods:

  1. Big functions often violate the Single Responsibility Principle.
  2. Small functions are easy to read and extend.
  3. Big functions are hard to debug and test.
  4. Short functions help with code reuse.

Let’s discuss every reason in detail.

1. Big functions often violate the Single Responsibility Principle

A big method usually has a complicated code that often violates the Single Responsibility Principle (SRP).

The SRP is a software design principle in object-oriented programming introduced by Robert C. Martin in his book ‘Clean Code’ which states that “every class or module should have one responsibility and one reason to change.” In other words, a class should focus on one single purpose. It should not contain methods that perform too many different tasks.

The same rule applies to functions.

Robert C. Martin states:

Functions should do one thing. They should do it well. They should do it only.”

Functions that have multiple responsibilities can change because of multiple reasons. There is a risk of introducing bugs in the program every time you change such big functions. A sign of clean code is having short functions that perform exactly a single specific task. When functions perform a single task, it is easier to test and change it in the future, making your code much cleaner.

2. Small functions make it easier to read and extend its functionality

Robert C. Martin also states:

“The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that.”

If a function has many lines of code, like 200 to 300, it is challenging to read and extend the code if you want to expand the functionality without breaking it. The more lines of code added to the functions, the more complex it becomes, taking a long time to read and understand its functionality.

On the other hand, it is easier to read, understand, and explain several different short methods than fewer big methods. Therefore, a good rule of thumb is to write functions that are no more than 30 lines of code long and have a clear purpose.

3. Big functions make it harder to test and debug

Large functions often contain several different execution paths or more decision structures, increasing cyclomatic complexity. As stated in the article about nested loops, cyclomatic complexity is a factor that determines the hardness of understanding and testing a piece of code. Therefore, writing unit tests for such big functions covering all the possible execution paths is harder.

unit testing

But you can easily write unit tests for several short methods covering all the possibilities one big function would contain. Also, debugging long functions is not easier than shorter ones. Suppose there is a bug in the production code that needs an immediate fix. In that case, no one wants to spend much time understanding the code rather than introducing a fix to resolve it as quickly as possible.

4. Short functions help reuse the code

Having shorter methods that perform a specific task enables reusing them throughout the program. In contrast, when a function performs multiple tasks, not every other class requires all of them. Hence it takes work to reuse larger methods. It also means you are likely to repeat the codes in other classes.

But is it a good practice to split long functions/methods into smaller ones that will be called only once?

thinking

You can refactor long functions by splitting them into short methods, even if they are called only once. For example, suppose you have a method that takes a URL and response as input parameters and saves the response with one of the URLs’ variable parameters into a table.

private static void ProcessResponse(string reqUrl, string response)
{

    //https://learning.stg.com/module/moduleid
    string[] str = reqUrl.Split('/');
    int length = str.Length;
    string moduleid = str[length - 1];

    if (!string.IsNullOrEmpty(moduleId))
    {
        //logic to save the response with the module id in the database
    }
}

You can further shorten the method ProcessResponse by separating URL parsing and saving values into two methods. But the method that does the URL parsing will be called only once inside the method.

private static void ProcessResponse(string reqUrl, string response)
{
    //https://learning.stg.com/module/moduleid
    string moduleId = ExtractModuleId(reqUrl);

    if (!string.IsNullOrEmpty(moduleId))
    {
        //logic to save the response with the module id in the database
    }
}

private static string ExtractModuleId(string reqUrl)
{
    //https://learning.stg.com/module/moduleid
    string[] str = reqUrl.Split('/');
    int length = str.Length;
        
    return str[length - 1];
}

But is it good practice? Again, yes, it is a good practice, and here is why. The first reason to say it is ok is that it significantly improves the readability of the code.

In the above example, even though the method indicates it processes the response, it first processes the request URL and proceeds with its true purpose. Even though the ExtractModuleId is called only once, it is now much clearer to the reader what exactly the function does.

When introducing such methods that call only once, it is equally important to use appropriate access identifiers. For example, if you declare such methods public, the readers may also confuse that they are being used elsewhere in the application.

Thus, to avoid confusion, declare the methods that are called only once as private. Even better, declare them as private static if possible. It will be easier for you to refactor and move them into another class in the future if you need to do that.

Are having short functions that are called only once a sign of a code smell? No. Not at all.

A code smell is an issue that indicates there is a deeper problem in the code, and you can spot them easily. Some examples of a code smell are a duplicated code, a long method, or a long class. Short methods help to eliminate all that problematic code. Therefore, they are not considered a code smell.

What about one-line functions that are called only once?

When refactoring bigger functions into multiple functions, you may have to write one-line functions that are called only once. Is it a good practice as well? It really depends on what that function does. For example, refer to the following code.

public static void PrintMessage(string message)
{
    Console.WriteLine(message);
}

The method only prints an input message and is used only in the declared class itself. Therefore, you don’t necessarily need a separate function to declare one line of code if it is concise and does not need to be reused in other codes.

But suppose you have a code line that contains difficult-to-read and complex expressions that ultimately require to span multiple code lines. For example, look at the following code.

public static bool CanUserUpdateCourse(UserData user)
{
    return (user.isNotStudent() && user.active()) ||
            (user.hasPermissionToViewTheCourse() && user.UpdateTries > 100);
}

The above code includes a complex boolean expression that needs to evaluate to get the intended outcome. In such cases, defining them in a separate method improves the code readability, helps to understand the complex expression better, and may allow reusing the code line in other classes and methods.

However, if you are sure you do not need these other parts of the code, then it is ok to include this complex expression in the existing method using a local boolean variable.

When should you extract functionality in a separate function/method?

Here are some questions to help you identify whether you need to extract some of the existing code into a new function/method.

Are you copying and pasting functions in other classes?

Have you ever reused 95% of the methods’ code by making small changes and including it in another program? Then you most likely have copied and pasted the original method to a separate class and made the required changes to fit it into the new class or module.

That is when you should extract the functionality into a separate function rather than duplicate the code in another place. Then you can call the same method in every place it needs to use. If the method functionalities need to differ in every class, use parameters to handle that variation.

Does your code have functions with more than 30 code lines?

Also, let’s say you see a method containing more than 200 lines of code and can only see part of the method body at a time. In that case, it indicates that it needs refactoring by extracting its functionalities into separate methods.

In his book Code Complete, Steve McConnell states that, in theory, the number of lines of code that fit on a screen is the maximum code limit a function should contain. His reference studies have found that if a function contains code lines between 65 and 200, it is the most desired state or ‘sweet spot,’ and the function will be less error-prone.

Is it very hard to determine the exact number of lines after which you should make the method smaller. But as a general rule, if your method has more than 30 lines of code, you need to examine it. A very long method reduces the code readability, maintainability, and extensibility.

Also, if you constantly need to change that method, you may end up with pretty big code that is difficult to maintain. Therefore, when you see such long methods, it is time for you to extract them into separate methods.

It is easy to extract common functionalities into separate methods.

Most modern IDEs provide this refactoring technique as in-built functions. For example, Visual Studio provides a built-in tool, Extract method refactoring, using which you can automatically extract the long code into separate functions.

If you need to extract the method manually and know exactly what steps you need to follow, you can refer to the Extract Method article.

When and how to eliminate the short function?

Sometimes, it is good to eliminate short functions into many short functions that delegate responsibilities throughout the method body at different times. However, even though having short functions is a good practice, using them unnecessarily makes it harder to read the code and may confuse the reader.

You can eliminate short functions with the Inline Method refactoring technique. Take a look at the following code example.

public static int ExemptStudent()
{
    return HasStudentExceededAttempts() ? 0 : 1;
}

public static bool HasStudentExceededAttempts()
{
    return numberOfAttempts > 10;
}

The method ExemptStudent body needs to evaluate if the number of attempts is greater or less than a specific value to return the correct value. The method HasStudentExceededAttempts is unnecessary here.

When refactoring this behavior, you must ensure the method you are going to remove is not used in other sub-classes. If not, you can replace all the method calls with the method content and delete the method. The following code shows what it looks like after performing inline method refactoring.

public static int ExemptStudent()
{
    return numberOfAttempts > 10 ? 1 : 0;
}

Conclusion

Keeping functions simple and letting them perform only a specific task is a good programming practice you should follow. The larger method violates the Single Responsibility Principle making it harder to change the code, read and understand its functionality, and expand. Also, smaller functions promote code re-usability and reduce cyclomatic complexity.

You can refactor larger methods by splitting them into several methods that do unique work. There is no issue even if the method calls only once in the code.

Sometimes, you might have encountered short one-line methods. The requirement to have such methods depends on their re-usability and readability. If your method contains more than 30 lines of code and you often have to reuse about 95% of the function code by copying and pasting, those signs indicate you need to extract their functionalities into separate methods.

Finally, you can use the Inline Method refactoring to eliminate short functions and avoid over-using them unnecessarily.

Recent Posts