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.
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:
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.
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.
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.
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
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
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
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
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
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:
Five Lines of Codes • Christian Clausen • GOTO 2022 — YouTube
If you want to learn more about the Five Lines Of Code Principle and how to apply it in practice, I found the book Five Lines of Code: How and when to refactor by Christian Clausen. It is a great book that teaches you how to refactor your code in a clear, practical, and fun way.
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!
Latest comments (29)
If you ever feel like moving multiple lines of code to a single line would improve readability, you're either doing it wrong or you're just a really bad developer
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!
"Every function should be as simple as it can be, but not simpler!"
... is the golden rule of all ages.
5LOC violates the last part (sometimes), so it's not a good principle.
IMHO in 5LOC the following code is more readable:
def calculate_total(cart)
total = 0
cart.each do |item|
total += calculate_item_price(item)
end
total
end
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.
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):
.reduce
.calculate_item_price
That's already many context switching in single function imo
5 lines is too short, even for ruby. SRP will lead you to smaller line counts in general, but setting any hard number of lines is missing the point.
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.
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.
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.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