The number of lines of code can give a hint to complexity, for example, an app with one line of code is simpler than an app with ten thousand lines of code. Even though this seems like an open and shut case there are some caveats to it. Measuring complexity using an application’s lines of code on its own doesn’t tell much because sometimes more lines decrease complexity. For example, an application may have more lines than necessary due to the overhead of adding extra classes and methods/functions to make your application align more with SOLID principles and to improve its readability.

Lines of code complexity example

The below line is complex and can be made simpler by expanding it into more lines, demonstrating that line count is not a direct indicator of complexity:

var qualifiedProfiles = profiles.Where(profile => profile.Nodes.Any(n => n.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) && ((profile.Specs ?? new List< Spec>() { new Spec() { Core = 1 } }).Where(s => s.Core == 1 && s.Mem > 8).ToList().Count() > 12)).ToList();

The above line of code would be easier to read, understand and debug if broken down into multiple lines:

List< Profile> qualifiedProfiles = new List< Profile>();

foreach(var profile in profiles)
{
    var specs = profile.Specs ?? new List()
            {
                new Spec()
                {
                    Core = 1
                }
            };

    var qualifiedSpecs = specs.Where(s => s.Core == 1 && s.Mem > 8).ToList();

    if(qualifiedSpecs.Count() > 12)
    {
        if(profile.Nodes.Any(n => n.Name.Equals(name, StringComparison.OrdinalIgnoreCase)))
        {
            qualifiedProfiles.Add(profile);
        }
    }
}

Of course this code could be borken down further by removing all linq but I think that is an ok use of linq, ie having one operation per line, and no nested operations.

The impact of style on Lines of Code

To use lines of code to measure complexity you have to compare apples to apples, ie if all code was written in the same style and followed the same practices then you could say app A is more complex than app B. When apps are written very differently a single line of code may create more complexity than ten lines of another app. Therefore in order to use line count as a measure of complexity, it has to be taken into account that it is a relative measure, and not an absolute measure. Since the style of the code affects the complexity of each line, there is no hard absolute rule saying "after 1000 lines it becomes complex". For example: declarative programming vs Imperative Programming, which will show a clear style difference that can affect the lines of code. Or even a simple style difference of same line brackets vs next line brackets:


public void MyMethod()
{
    // This method produces an extra line due to the braket
    // If you have 1000 methods in your application, you have 1000 extra lines
    // but that does not make this style worse
}

public void MySameMethod() {
    // Do Something
}

Instead of looking at the lines of code for the entire system, look at the lines of code for each service/module/class/method. If you follow a modular design with SOLID principles, you may have more lines of code overall but each section will be kept small and simple. Therefore look at your methods and keep them simple, look at your classes and keep them simple, look at your project and keep it simple.

The size of your classes/methods needs to be balanced. Both too large and too small can cause issues:

Excessively large classes/methods

Have you ever opened a project and found a few classes but they each have methods which are over a 1000 lines long? Scrolling through a class of over 10000 lines becomes difficult to understand, read, and maintain. Single Responsibility Principle was born to combat this problem.

Excessively small classes/methods

Often developers understand Single Responsibility Principle to mean, a class should only do one thing. Have you ever opened a project and its broken up into 100+ modules, each containing 100s of classes each with one tiny method? Now you have landed up with extreme complexity. While it is easy to understand an individual method, it becomes extremly difficult to understand how it all fits together. In my opnion this is more complex than a single large method. To prevent this it is important to remember to high cohesion with the Single Responsibility Principle.

To better understand this balance see my post on Single Responsibility Principle and modular design.

Check out these links for more info:

My design and architecture repo