Tuesday, August 30, 2011

write small functions

In my teams there is always a rule, that maximum function size is 25 lines. Every time when a new team member joined the group, he/she expressed that it is not possible to follow this rule every time and they will have to write longer functions. So I always told them, Ok, but then they have to convince me that there is no way to break this long function in smaller logical chunks. In my 15 years of experience, no one succeeded. I could always show them a way of logically breaking the function in smaller function.

Many team members asked why 25 lines limit and what is the benefit ???. While I explained the reasons verbally to my team members I thought, this time I will document 'why' on the blog.
  1. Entire function has to be visible in one page.
    We write code once and edit it few times, but we read it many more times. Hence the code has to be optimized for easy reading, understanding. If I have to scroll or do page up/page down to read a function it breaks the flow. If entire function is visible on one page, then it is easy to ready, understand and hence debug. It is also easy to spot potential problem when whole function is visible.Since typically editor one page is about 25 to 30 lines, hence maximum function size is about 25 lines.
  2. Reduce the code complexity
    Code with high complexity is difficult to understand and modify.Generally it is recommended to limit the cyclomatic complexity to 15.Once you have a limit on function size, it automatically limits the complexity to manageable proportions. After all, how complex the code can get in 25 lines ??.
  3. Reduce multiple returns
    Multiple returns from a function (especially more than 2-3 returns) make the code difficult to understand. I have seen functions which are 500-1000 lines and with 25-30 return statements. Usually these functions end up having many bugs.
    Also in C++, you have to manually add any cleanup (e.g. free the memory or close files etc). before every return statements. (Of course you can use techniques like RAII to simplify the clean up).
    Still with small function size, automatically limits number of 'return' from a function
  4. Easy to spot errors (especially clean up errors)
    Many times in functions you allocate memory, open files, database connections etc. and you have to cleanup/release these resources. If you have large function, it is difficult spot where all memory is allocated, files opened etc and what point it needs to be freed, files closed. With smaller functions is easier to spot these kinds of errors.
  5. For new code stick to this rule
    For new code stick to this rule. If you are maintaining/enhancing existing code, it is very tempting to jump into large scale refactoring of existing code in one-go. Don't make that mistake.
    If there is a large function but there are no bugs reported or traced to that function, don't refactor it to smaller functions. Leave it as it is.
    However, if you are fixing a bug in a large function refactor the portion where you did the bug fix into a smaller function. Don't try to break 500 line function into 20 functions in one-go. So if you have a 500 line function, after refactoring it may become two functions of 480 lines and 20 lines. If one more bug is reported in the same function do one more small refactoring. Very soon number of large functions will reduce and code will be cleaner and simpler. Check the Refactoring website and follow the guidelines from Martin Fowler's Refactoring Book.
This one thumb rule has worked well for me in practice. What is your experience on writing smaller functions ? Do you have any such rule which worked for you ?