At her QCon London keynote, Barbara Liskov pointed out an interesting fact that procedures did not come about due to the need for better structure of computer programs, but due to severe memory limitations of computer systems in '60 and '70. At that time programs were short enough to fit in programmers' heads while memory could barely hold the instructions of the core of the program. It might be this tradition that is influencing all the poorly written procedures that I see quite frequently. In my opinion the main characteristic of a well written procedure is linearity. If a procedure does one thing only, as it should, it should have only one main execution path through it with if statements only handling exceptional cases. A clear signal of poorly written procedure are multi level indents and lots of branching. So whenever I encountered a procedure that looks like this
[sourcecode language="python"] def proc(args): if arg1 is something: do_something(): if arg2 is something, too: do_something_too(): else: do_something_different(): else: do_something_else()
if arg3 is something else: do_something_now() else: do_whatever() [/sourcecode]
I strive hard to reorganize it into something that looks more linear
[sourcecode language="python"] def proc(args): if args are exceptional in any way: return # early
if #exceptional situation: return # exceptional status
do_the_main_thing() return # result [/sourcecode]
Not only is such a procedure much easier to read and comprehend, but it's cyclomatic complexity is much lower thus severely reducing the number of test cases needed to provide full test coverage of the procedure.