Thursday, January 23, 2014

The Method To My Madness

Just about everyone has a preferred coding style. It generally manifests in formatting choices. For example, although the Java standard for braces is to have open braces at the end of a line, I refused to follow that standard. My reason is because I actually learned C and C++ before Java came on the scene, and I learned to format my C and C++ code with braces on their own lines and indented in pairs. As a result, I learned to pair braces according to their matched indentation, and that familiarity is why I continue to do so. Sure, I sometimes get remarks from other Java programmers at times, and I have occasionally clashed with official company styles. To them I say: let me do what I know; I am good at it! To be fair, of course, I never demand a particular style from anyone else either -- though reviewing the code of someone that is inconsistent in their own style will get complaints from me. Be consistent!

There is another aspect to my coding style which gets a lot more questions, and that is because it is more than just simple formatting: I write my code specifically to avoid break statements, continue statements, and nested returns. As an example, a double nested loop in my code will resemble:

boolean closed = false;

for (int i=0; !closed && i < fooList.size(); ++i)
{
    List<Bar> barList = foolist.get(i).getBarList();
    for (int j=0; !closed && j < barList.size(); ++j)
    {
        closed = barList.get(j).isClosed();
    }
}

return closed;

Colleagues reviewing my code often ask why I don't just use the nested return such as:

for (Foo foo : fooList)
{
    for (Bar bar : foo.getBarList())
    {
        if (bar.isClosed())
        {
            return true;
        }
    }
}

return false;

This is my answer:

The looping style I use is related to what I learned in one of my graduate-level courses in Computer Engineering when we studied formal proofs of computer programs. I happen to be very mathematically minded and even got a minor in Mathematics as an undergrad, so this particular subject appealed to me. I was also curious how IBM had done some significant development with software validation via formal proofs and no testing and found the results to be at least as high in quality (fewer bugs) as software developed with testing.

Formally proving the correctness of a loop requires stating the invariant of that loop and the condition of the loop. The way I write the condition in the for loop, the invariant and condition can be easily determined by examination. In this case the outer loop invariant is i <= fooList.size() and the condition is as written: !closed && i < fooList.size(). The inner loop is similar.

Since the nested return is logically equivalent, the invariants and conditions are the same, but determining them from examination is extremely difficult. I do not expect anyone to formally prove my loop, but if desired it could be. For myself, I find it easier to validate my style when reviewing code since I tend to think more mathematically.

That is how I got to writing my loops this way. After I had been doing this a short while, I discovered a particular advantage that is even more appealing to me: the single exit point. By having a single exit point, I have a single clear location where I can set a breakpoint or insert a log statement when debugging. I also have an obvious variable to watch (closed in this case). I also have a clear delineation for the beginning and ending of a try block in the event that an exception needs to be caught. This has led me to write my if statements without nested returns as well. All in all, it feels more disciplined to me.

Since this style has paid such dividends to me over the years, I continue to use it. That’s why you don’t find nested return, break, or continue statements in my code. I don’t usually mind if others use them — unless I see a continue statement with a label then I do complain rather loudly.

No comments:

Post a Comment