DEV Community

Kanani Nirav
Kanani Nirav

Posted on • Updated on

The Five Lines of Code Principle: Why Less is More in Programming

In this article, we’ll Learn a simple principle that can help you refactor your code more effectively “The Five Lines of Code Principle”. This principle states that any method should be no longer than five lines of code. If a method is longer than five lines, it should be broken down into smaller methods that each perform a single responsibility.

Five Lines of Code

In the world of software development, efficiency is key. Whether you’re building an application, a website, or any other piece of software, the goal is always to make it run as smoothly and quickly as possible. One of the most important principles to follow when it comes to writing efficient code is the Five Lines of Code Principle.

What is the Five Lines of Code Principle?

The Five Lines of Code principle is a programming best practice that emphasizes the importance of keeping functions short and simple. The idea is that a function should be no longer than five lines of code, and ideally even shorter.

This principle is based on the observation that shorter functions are easier to understand, debug, and modify than longer functions. By breaking down a complex task into a series of shorter functions, programmers can create more modular and maintainable code.

Why Five Lines of Code?, Key Benefits of the Five Lines of Code Principle

You might be wondering why five lines of code is a good limit for a method. Why not four, six, or ten? The answer is that five lines of code are not a magic number, but rather a guideline that encourages good coding practices and habits. Here are some of the benefits of following this rule:

  1. It makes your code more readable: A short method is easier to understand than a long one, as it has less complexity and noise. It also adheres to the principle of least surprise, which means that it behaves as its name implies and nothing else. A short method also fits better on a screen or a page, which reduces scrolling and eye strain.

  2. It makes your code more testable: A short method is easier to test than a long one, as it has fewer inputs and outputs, fewer branches and paths, and fewer dependencies and side effects. It also follows the single responsibility principle, which means that it does one thing and one thing well. A short method also makes your tests more focused and isolated, which improves their quality and reliability.

  3. It makes your code more maintainable: A short method is easier to modify than a long one, as it has less coupling and cohesion, less duplication and repetition, and less fragility and rigidity. It also follows the open/closed principle, which means that it is open for extension but closed for modification. A short method also makes your changes more localized and traceable, which reduces the risk of errors and conflicts.

  4. It makes your code more extensible: A short method is easier to reuse than a long one, as it has more abstraction and encapsulation, more polymorphism and inheritance, and more composition and delegation. It also follows the interface segregation principle, which means that it provides only what its clients need and nothing more. A short method also makes your code more modular and decoupled, which increases its flexibility and adaptability.

How to write Five Lines of Code?

The following are some tips to help you write Five Lines of Code:

  • Know your language: Familiarize yourself with the programming language you’re using, its syntax, built-in functions, and libraries. This knowledge can help you leverage the language’s capabilities and write efficient code.

  • Think outside the box: To write a program in 5LOC, you need to think creatively and explore different approaches to a problem. The less conventional solution may lead to an optimal code.

  • Use built-in functions and libraries: Make use of built-in functions, libraries, and frameworks that can help you reduce code complexity and simplify the program’s logic.

  • Keep it simple: Avoid complex logic, nested loops, or too many conditional statements. Instead, try to break down the problem into smaller, more manageable parts that can be solved with simple code.

  • Optimize for readability: Although the goal is to write a program in five lines of code, readability should not be sacrificed. Use descriptive variable names and comments to help others understand the code’s purpose and functionality.

Let’s Understand the “Five Lines of Code Principle” with Ruby example

calculate_total is a function that calculates the total price of a shopping cart in an online store.

Step 1: Identify a function that is longer than five lines.

def calculate_total(cart)
  total = 0
  cart.each do |item|
    price = item[:price]
    price *= (1 - item[:discount]) if item[:discount]
    price *= (1 + item[:tax]) if item[:tax]
    total += price
  end
  total
end
Enter fullscreen mode Exit fullscreen mode

This function is 10 lines long, which is more than five. So we need to refactor it using the Rule of Five.

Step 2: Find a meaningful chunk of code inside that function that can be extracted into a separate function.

A logical chunk of code that we can extract into a separate function is the one that computes the price of each item, considering the discount and the tax. Since we do this calculation for every item in the cart, it makes sense to wrap it in a function. We can name this function calculate_item_price.

Step 3: Give a new function a descriptive name that explains what it does.

def calculate_item_price(item)
  price = item[:price]
  price *= (1 - item[:discount]) if item[:discount]
  price *= (1 + item[:tax]) if item[:tax]
  price
end
Enter fullscreen mode Exit fullscreen mode

Step 4: Replace the original chunk of code with the new function.

def calculate_total(cart)
  total = 0
  cart.each do |item|
    price = calculate_item_price(item)
    total += price
  end
  total
end
Enter fullscreen mode Exit fullscreen mode

We can make it even shorter by using a built-in method of arrays called, reduce which applies a block to each element of an array and accumulates the result.

Step 5: Repeat steps 2–4 until the original function is five lines or less.

def calculate_total(cart)
  cart.reduce(0) do |total, item|
    total + calculate_item_price(item)
  end
end
Enter fullscreen mode Exit fullscreen mode

We have successfully refactored it using the Rule of Five. We can also make it more concise by using a one-line block for calculate_item_price.

def calculate_item_price(item)
  item[:price] * (1 - (item[:discount] || 0)) * (1 + (item[:tax] || 0))
end

def calculate_total(cart)
  cart.reduce(0) { |total, item| total + calculate_item_price(item) }
end
Enter fullscreen mode Exit fullscreen mode

Now both functions are one line long, which is very simple and clear. We have completed the example.

Conclusion

Overall, applying the Five Lines of Code Principle is a best practice that can help programmers to create more maintainable, reusable, and efficient code. By breaking down complex tasks into smaller, more manageable functions, programmers can improve code readability, testability, and collaboration, while also identifying and optimizing performance bottlenecks. To implement this principle in your own code, focus on one task per function, use descriptive function names, keep functions short and simple, avoid nested functions, and prioritize readability over brevity. By following these tips, you can create more effective and efficient code that is easier to maintain and understand over time.

By following the steps outlined in this article, you can refactor your code more effectively and keep your codebase healthy.

Reference:

If You are using Medium Please support and follow me for interesting articles. Medium Profile

If this guide has been helpful to you and your team please share it with others!

Top comments (29)

Collapse
 
bcouetil profile image
Benoit COUETIL 💫

I'm sorry but the original function is fairly easy to understand, and 10 lines is still small.

Your end result is less understandable IMHO, more cognitive load. Maybe because I'm not proficient in this language.

In the end, a developer spend 90% of his time reading code. That is all that should matter : readability for maintainability.

Collapse
 
syedashrafulla profile image
Syed Ashrafulla

+1 that the original code is easier to read. I think this is a classic article of advice that has no fundamental justification. Five could be three or ten and the rule still doesn't make sense; I think the actual issue is the metric.

An alternative would be time for another person to understand the function. If another person can write the pseudocode for an existing function within X minutes of reading, it's a good function. Extra points for not having many comments (b/c comments don't run, code runs, so self-documenting code is more trustworthy than commented code).

Collapse
 
bcouetil profile image
Benoit COUETIL 💫

We mainly agree, but I have to disagree on the "no-comment" dogma. The code, as perfect as it can be, gives the "how". Sometimes, and quite often, I have to give the "why" in comments, for my readers and my future self.

Thread Thread
 
syedashrafulla profile image
Syed Ashrafulla

Agreed, I prefer an economy of comments rather than no comments.

Thread Thread
 
mochadwi profile image
Mochamad Iqbal Dwi Cahyo

Agreed for the why part, it's help for our future-self as human tends to forgot what we've done in the past (that is not my code 🤣)

Thread Thread
 
jfftck profile image
jfftck

I am in the comments at the dependency boundaries, where you are using code from a library and you need to document why your adapter code is needed. I would also like to point out that logging to telemetry instead of comments can add more details on the why of that section of code while ensuring that you would need to update the telemetry values when you alter the code. Most of the time when I see comments, they are reiterating what the code already tells me in the first place and add no value.

The tools out there already generate documentation based off of the function/method and the only other helpful comments would be examples of using the function/method, that is the best use case for adding them.

I agree that comments muddy the waters with unnecessary details that can be made irrelevant, if the team is focused on pushing features, and it turns into additional tech debt. But this statement depends greatly on the team's process and if it is part of their procedure to ensure comments are always relevant, I have no objections to using them.

Collapse
 
ant_f_dev profile image
Anthony Fung

I agree that shorter functions are easier to read, but I'd be careful about this one.

Converting RGB to HSL isn't an overly complex algorithm, but it takes more than five lines. (search for the function rgbToHsl in the linked code). I'm not sure if the five line principle would make it easier to more difficult to read.

I feel that this might be true for an implementation of something more complex too, e.g. the SIFT algorithm.

When implementing a complex algorithm, the nature of the algorithm means that there will be a lot going on. To condense everything to five line methods would mean either:

  • Code that could be expressed as multiple atomic lines are condensed into 'magic' one-liners, making it more difficult to either read or debug.
  • There are going to be a lot of functions. This potentially leads to 'function hell' and difficulty understanding a deep callstack.
Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

I also agree that splitting into too many small functions makes code harder to read. Instead of reading through the code's actions in sequential order, you end up having to jump up and down through your code to see what's going on.

While functions should generally remain short, targeting a specific line-count seems overly simplistic and I wouldn't recommend it as more than a rule of thumb for new developers. And even then, 5 seems excessively short.

Collapse
 
ant_f_dev profile image
Anthony Fung

Completely agree that having to jump up and down is distracting. I personally target the height of the screen as an approximate maximum length. Even then there are some complex functions that overflow. But if breaking them up makes them even more complex, I leave them as is.

Collapse
 
lexlohr profile image
Alex Lohr

Not the number of lines is important, but how well the code conveys your understanding of the problem it solves to the reader.

If an operation takes six separate steps, reducing it to five lines or splitting it into two operations for no other reason than that you want to avoid having more than 5 lines is not going to improve the quality of your code.

Collapse
 
kanani_nirav profile image
Kanani Nirav • Edited

Thank you all for commenting.

I highly recommend you all to please watch Five Lines of Code • Christian Clausen • GOTO 2022 — YouTube reference video and Expert Talk: Five Lines of Code • Christian Clausen & Julian Wood • GOTO 2022.

I agree sometimes it is difficult to write code within 5 lines but the five lines of code principle is not a strict rule you can adjust accordingly.

If you want to see a real-life example please visit Rails GitHub Repository. The average all-method length is between 5~10 lines.

This article example is simple but there is a lot more you can do using this principle. That's why I recommend you all to please watch the GOTO Conference Video, Christian Clausen explains it very well.

Collapse
 
blindfish3 profile image
Ben Calder

I started watching the video; but then had to fast forward through a lot of it: I just couldn't bear to watch it 🤢

He's basically taken a sensible principle: "keep functions short" and turned it into a dogmatic rule with a completely arbitrary limitation. He gives absolutely no compelling reason for why a 5 lines maximum is best and then demonstrates what felt like a really convoluted process for refactoring that was simply too painful to watch.

As the comments on the video - as well as the responses here - make clear; the "Five Lines of Code Principle" is not something any sensible developer should adopt. Just "keep functions short" + DRY

Collapse
 
wizdomtek profile image
Christopher Glikpo ⭐

It's not always possible to accomplish a task in just five lines of code, and there are certainly cases where longer code is necessary. However, by striving to keep code as simple and concise as possible, developers can improve the quality and maintainability of their code.Thanks for sharing

Collapse
 
prescottbreeden profile image
prescottbreeden

I have seen this mentality try to scale to over 10million loc and the end result is a code-base that is fragmented beyond comprehension with rampant duplication. Less we forget Goodhart's law: the moment a measure becomes a target it ceases to be a good measure.

Collapse
 
brense profile image
Rense Bakker

I agree it's good to stick with small concise functions and maybe 5 lines is the magic number, but I don't think it should be a goal on itself. It's important to know why you want functions to stay small and you did a good job of explaining that in the article! 👍

Collapse
 
thomashighbaugh profile image
Thomas Leon Highbaugh

I love the principle behind the article, as most code can and should be refactored to simplify the logic. We just can't forget the rationale behind the principle before applying it, which in the example or any blind application of such a principle may actually further complicate and hinder our code just as much as bloated and overly complex methods.

The rationale behind this principle is that it should increase the readability of the code. It's intended application is more like a heuristic than a logical fallacy, which for those that don't know formal logic this means that it is used more tentatively and not robotically because sometimes it is wrong. You could also think of it as a horizon one moves towards on a sphere, where you can never reach the horizon per se but after pursuing it for some period can look back and see the progress you have made anyway (much like most ethical codes that accept human imperfection).

Now the example you provided was 10 lines of code, double the number the rule calls out. However, if we first ask ourselves would comprehensibility and readability actually be improved to split that apart and thus remember one function of 5 lines while parsing another, I don't think most people would. I get the example was overly simplistic to demonstrate the rule, it just may be wise to note that and to mention the rule's motivating factor (modular, readable code) is something to keep in mind when writing and refactoring code as a sort of internal test to use prior to further breaking code down.

Another interesting exception to the concept is illuminated by the notion of turning every single line of code into a method and why that is not done. The reason we don't have each line wrapped in a method structure is because at that point the method structure code and the call to the method become unnecessary fluff that adds lines of code without being meaningful to us as humans reading it and often to the interpreter or compiler that already tosses out much that humans add to understand code (comments anyone?). Thus it is clear the purpose of creating methods bundling functionality is to wrap a related set of lines, functionality or object traits into a single structure we can call later without rewriting all of those lines over and over again. While a good rule of thumb to try to keep your methods below 5 or even 10 (15 if it pleases you, this number is somewhat arbitrary in importance ultimately) there are times this won't be possible and that's worth remembering before refactoring your codebase by this or another rule mechanically without attempting to parse the meaning of the rule.

Which I don't mean to be a criticism of the article really, just something to keep in mind. I loved the article and find your writing on the topic unusually pleasant to read as compared to most other articles I see on platforms intended for developers lately. Good work and keep it up!

Collapse
 
jogra27 profile image
jogra27

I generally agree with what you have said but sometimes too many functions provide additional security risks and poorer performance. There is always a balance between purpose and style.

Collapse
 
lionelrowe profile image
lionel-rowe

There's a tradeoff between conciseness and indirection. All else being equal, conciseness is good, and indirection is bad. But by increasing the conciseness of the function, you also increase the indirection: now the reader of your code needs to look in one more place outside the parent function to understand it. It's not too much of an issue in your toy example, but it would be much more of a problem if the original function had been, say, 25 lines — according to your metric, you'd need a minimum of 5 functions (probably 6 or more) to capture that functionality, which would most likely just be a mess of bad abstractions.

Indirection can be a worthwhile tradeoff if the abstractions are good, especially if the logic of the child functions is reused in many places. But indirection in order to meet an arbitrary metric will only make your code worse.

Collapse
 
mochadwi profile image
Mochamad Iqbal Dwi Cahyo

Imho, we can just focus on what part of our function that needs to be testable, in this article the calculate_item_price is what matter, the calculate_total (could be considered private function), and might unnecessary to test, and we can just skip this, the first part using for each are already enough, it's in between jump into many separate function and still concise.

caveats the one line (increase cognitive loads as mentioned in the other comments):

  1. We need to check for .reduce
  2. We need to check .calculate_item_price

That's already many context switching in single function imo

Collapse
 
treezones profile image
TreeZone

This is excessive. Imo the defaults built into SonarCloud's cognitive complexity methodology are about right and stop you from creating an unreadable mess most of the time. Compressing everything into 5 lines of code means you will likely spend more time refactoring than you should with net zero or negative readability benefits.

Collapse
 
rcoops profile image
rcoops

You had me until the final step squashing into 1 line. Less lines is most certainly not the same as more readable!
This last part surprised me as you (@kanani_nirav) yourself explicitly point out "Optimize for readability".
If one of the arguments is that more lines is harder to understand, surely it can be inferred that 'more going on in a single line' can be too.

Collapse
 
jfftck profile image
jfftck

I would agree with the author that the original function is doing more than one task and should be converted into two, but step 3 was all the reduction necessary to fix the issue.

I would only take the calculate_total function and make it take another argument for a get_price function, that way, if there are different calculations per country, you can pass in the specific calculate_item_price function that you need and not have that code turn into a large mess.

Also, this makes for better unit tests, calculating total has a dependency on calculating item price and that shouldn't be a hard dependency. This is the whole point of test driven development, you find the boundaries of each unit because the tests are simple. The function given at the beginning could be simple enough that it wouldn't make a large difference, but there are many other examples where it would.

So, this article is giving the same advice as TDD, where you reduce the concerns of your functions by finding the smaller units, but it left the hard dependency to calculating total and that part is more important than getting the lines of code down to a specific number.

Collapse
 
wufenstein profile image
wf

This may be the worst programming advice I've ever read.

Collapse
 
treezones profile image
TreeZone

I wonder how long it'll be before Chat GPT starts applying it 🤔