A question that constantly comes up from people that care about writing good code, is: what’s the right size for a method or function, or a class, or a package or any other chunk of code? At some point any piece of code can be too big to understand properly – but how big is too big?
It starts at the method or function level.
In Code Complete, Steve McConnell says that the theoretical best maximum limit for a method or function is the number of lines that can fit on one screen (i.e., that a developer can see at one time). He then goes on to reference studies from the 1980s and 1990s which found that the sweet spot for functions is somewhere between 65 lines and 200 lines: routines this size are cheaper to develop and have fewer errors per line of code. However, at some point beyond 200 lines you cross into a danger zone where code quality and understandability will fall apart: code that can’t be tested and can’t be changed safely. Eventually you end up with what Michael Feathers calls “runaway methods”: routines that are several hundreds or thousands of lines long and that are constantly being changed and that continuously get bigger and scarier.
Patrick Duboy looks deeper into this analysis on method length, and points to a more modern study from 2002 that shows that code with shorter routines has fewer defects overall, which matches with most people’s intuition and experience.
Smaller must be better
Bob Martin takes the idea that “if small is good, then smaller must be better” to an extreme in Clean Code:
The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that. Functions should not be 100 lines long. Functions should hardly ever be 20 lines long.Martin admits that “This is not an assertion that I can justify. I can’t produce any references to research that shows that very small functions are better.” So like many other rules or best practices in the software development community, this is a qualitative judgement made by someone based on their personal experience writing code – more of an aesthetic argument – or even an ethical one – than an empirical one. Style over substance.
The same “small is better” guidance applies to classes, packages and subsystems – all of the building blocks of a system. In Code Complete, a study from 1996 found that classes with more routines had more defects. Like functions, according to Clean Code, classes should also be “smaller than small”. Some people recommend that 200 lines is a good limit for a class – not a method, or as few as 50-60 lines (in Ben Nadel’s Object Calisthenics exercise)and that a class should consist of “less than 10” or “not more than 20” methods. The famous C3 project – where Extreme Programming was born – had 12 methods per class on average. And there should be no more than 10 classes per package.
PMD, a static analysis tool that helps to highlight problems in code structure and style, defines some default values for code size limits: 100 lines per method, 1000 lines per class, and 10 methods in a class. Checkstyle, a similar tool, suggests different limits: 50 lines in a method, 1500 lines in a class.
Rule of 30
Looking for guidelines like this led me to the “Rule of 30” in Refactoring in Large Software Projects by Martin Lippert and Stephen Roock:
If an element consists of more than 30 subelements, it is highly probable that there is a serious problem:What does this look like? Take a biggish system of 1 million NCLOC. This should break down into:a) Methods should not have more than an average of 30 code lines (not counting line spaces and comments).
b) A class should contain an average of less than 30 methods, resulting in up to 900 lines of code.
c) A package shouldn’t contain more than 30 classes, thus comprising up to 27,000 code lines.
d) Subsystems with more than 30 packages should be avoided. Such a subsystem would count up to 900 classes with up to 810,000 lines of code.
e) A system with 30 subsystems would thus possess 27,000 classes and 24.3 million code lines.
- 30,000+ methods
- 1,000+ classes
- 30+ packages
- Hopefully more than 1 subsystem
Are these rules useful? How should you use them?
Using code size as the basis for rules like this is simple: easy to see and understand. Too simple, many people would argue: a better indicator of when code is too big is cyclomatic complexity or some other measure of code quality. But some recent studies show that code size actually is a strong predictor of complexity and quality – that
“complexity metrics are highly correlated with lines of code, and therefore the more complex metrics provide no further information that could not be measured simplify with lines of code”.In "Beyond Lines of Code: Do we Need more Complexity Metrics" in Making Software, the authors go so far as to say that lines of code should be considered always as the "first and only metric" for defect prediction, development and maintenance models.
Recognizing that simple sizing rules are arbitrary, should you use them, and if so how?
I like the idea of rough and easy-to-understand rules of thumb that you can keep in the back of your mind when writing code or looking at code and deciding whether it should be refactored. The real value of a guideline like the Rule of 30 is when you're reviewing code and identifying risks and costs.
But enforcing these rules in a heavy handed way on every piece of code as it is being written is foolish. You don’t want to stop when you’re about to write the 31st line in a method – it would slow down work to a crawl. And forcing everyone to break code up to fit arbitrary size limits will make the code worse, not better – the structure will be dominated by short-term decisions.
As Jeff Langer points out in his chapter discussing Ken Beck’s four rules of Simple Design in Clean Code:
“Our goal is to keep our overall system small while we are also keeping our functions and classes small. Remember however that this rule is the lowest priority of the four rules of Simple Design. So, although it’s important to keep class and function count low, it’s more important to have tests, eliminate duplication, and express yourself.”Sometimes it will take more than 30 lines (or 20 or 5 or whatever the cut-off is) to get a coherent piece of work done. It’s more important to be careful in coming up with the right abstractions and algorithms and to write clean clear code – if a cut-off guideline on size helps to do that, use it. If it doesn't, then don’t bother.
9 comments:
As always nice post, very succinct, thanks Jim =)
I'm with Robert Martin's smaller is better. One thing he discusses is mixed levels of abstraction - following this I rarely have methods longer that ten lines.
While it may smell like you're desperate to do functional, you end up building internal DSLs and discover a surprising amount of reuse at this low level.
Keep it small and let your compiler do the inlining (or VM JIT-ing, etc).
On a similar vein, a recent Micheal Feathers post discusses Behavioural Economics wrt Code; adding new methods vs adding code to existing methods and the same for classes (addition or extension).
Large methods/classes will only get larger, unless somebody takes the conscious decision to refactor.
@earcam, Good point - large classes and methods tend to get larger, so you are putting yourself at more risk of having the code get out of control. If you start off small, it would be difficult to get into this kind of trouble.
If you follow the paradigm "code is comment" Smaller methods with names that describe the intent of the method will make the experience of the person who come to visit your code richer.. and eventually u will end up with a lot of reusable methods as well as easily unit testable.. Through smaller methods some fixed contracts will emerge which never will have to be changed when the code evolves as long as the requirement doesn't drastically change.. just my 2 cents..
How about a rule:
A method must be understandable to a developer reviewing it within 30 seconds.
It should take less than 30 seconds for a developer to understand what a method is doing, even if the methods it calls are not understood.
@Rob greene,
Brilliant. I like your suggested new rule of 30 seconds :-)
I am looking at a javascript file(one among many in the project) developed by someone else. This file has 10K plus lines and 823 methods. The next one I am working on has 12K plus lines and 471 methods. And there is a related java file that has 2 core methods that each run to 300 plus lines - this java file runs to 6K plus lines. There is no time to refactor. I need to just make changes to existing code for the feature I am developing. What can I do?
I call it the 10/100 rule.
Methods shouldn't be more than 10 lines of code.
Classes shouldn't more than 100 lines of code.
It isn't just based on "opinion" it is based on the result of a decade of practice. It is also based on the fact that common engineering design patterns automatically appear and are automatically used appropriately when following this rule.
Feel free to read more about it here:
http://www.rhyous.com/2014/02/10/the-10100-rule-following-this-one-development-rule-will-improve-your-code/
What approach i should follow to refactor my class if it already have 40,000 lines of code and i need to add more
@AndD: you could try just about anything to break that class out. Whatever you do will help make the problem simpler. Start doing it now.
Post a Comment