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!
Top comments (29)
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.
+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).
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.
Agreed, I prefer an economy of comments rather than no comments.
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 🤣)
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.
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:
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.
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.
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.
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
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.
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
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!
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! 👍
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.
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.