Saturday, February 26, 2005

Code Quality and the "Total Software Product Quality Triangle"

Today I came across "The Code Quality Myth" by Frank Sommers. Several quotes in the article really hit home. I could have written some of this essay. For instance, "I have almost never met a developer working on real-life, production software in a business environment who was completely satisfied with the code he was working on."

The code I am "proudest" of is typically short, "one-offs". This is typically stand-alone software or routines that serves one tiny purpose and is not tightly integrated into a larger product. Usually this software is not written under deadline, and is almost always a version 1.0 or a complete rewrite with few aspects of backwards compatibility. I am usually very proud of software when I have time to "do it right," and the quality is generally the best possible that I can produce.

Frank pretty much echoes my above sentiment with "I almost discern an inverse relationship between how satisfactory a piece of code is to the developers working on that code, and the amount of money that code makes for those developers' employers." Commenter Robert to that essay asked for metrics on that statement - I think he misses the salient points I am about to cover here.

Frank later talks about how the source code is not what we ship, and that only the binary matters - since this is typically all that the customer sees. This is where our opinions start diverging, and Frank misses one point that is staring him in the face: Why is this the case?

After 1.0 is released, or when that pristine little one-off class is integrated into a larger program, things start to go sour. Now we have to start working on new stuff and maintain backwards compatibility with the old stuff. It may be quite clear that the current API or XML Schema is not perfect for the new feature. Rather than refactoring or rewriting, we (as developers under a deadline) merely attempt to shoehorn the new feature into the old codebase. This is not perfect, pretty, or something to be proud of - but we think that we will be able to "do it right" for the next iteration, whose time ultimately rarely ever comes.

Besides the "shoehorning" there are other issues. Perhaps you want to move from the Old Hungarian into the New Hungarian. Perhaps there is a new "coding style" that you are supposed to use from now on. Different programmers working on the same class introduces some additional considerations. Maybe all of your string manipulation functions from today forward are to use the new "strsafe.h" functions. Whatever the reason, this results in fragmentation of your codebase. Some of it is the "new" way, some of it is the "old" way, and you get that massive maintenance programmer headache when attempting to context switch between two or more different coding philosophies in the same routine! Are you proud of this mess - heck no! Is this improving overall code quality and maintainability? Likely not!

The last thing that spices the code up a bit are platform differences and/or new technologies. Maybe you are porting a single class at a time to UNICODE and have ugly #ifdef's all over the place. Perhaps you want to take advantage of http.sys in XPSP2 and Server 2003 while still working under OS's that don't support it. Plus, that hack-around for people with IE4 installed is still lurking in the bowels of the core program. While this may assist in code "robustness" it certainly does not contribute to overall quality or maintainability.

In short, ALL source code gets uglier with time. For many reasons it has to. A solid developer knows that he or she can do much better in a rewrite with hindsight as our guide. An experienced (pre-agile) developer will architect classes with some degree of foresight (and bloat) to help mitigate this. The experienced agile developer (working with an organization that uses the agile philosophy) will write the bare minimum such that the affected classes need to be refactored for any major change to mitigate hacking around.

Planning for dealing with these future changes is what can help lessen the ugliness of the underlying code. In my opinion, the agile refactoring philosophy is one of them. Too many development organizations fear refactoring as "introducing risk" from 1.0 to 1.0.1 instead of fearing future effects of hack-arounds. This fear is unfounded (since it is easily mitigated with automated unit testing), and the tradeoff in having quality code vs. unmaintainable goo to propagate forward into the next major version is a no-brainer. Consider that the 1.0.1 fixes will be integrated back into the mainline. Is the fix you are making the correct one for the future? Does the fixed code look the same as it would have been written in 1.0 had it worked?

This is where Frank and I start converging again. "...total product quality, as Edwards Deming noted, is not the result of merely improving the quality of a single activity, but is rather the outcome of a set of processes focusing on the quality of the total output... Developer testing, agile development methods, quality assurance, continuous integration - these are all processes that facilitate a high quality of total output." We begin to diverge from there almost immediately.

To use an analogy that Steve McConnell did not, overall software quality is similar to the "Fire Triangle." To have fire, there needs to be Oxygen, Heat, and Fuel. Note that you can have all three without actually having fire - as fire is the result of the chemical exothermic reaction that occurs when all three of the other elements are present under the right conditions. Once fire occurs, take any one of these elements away, and there is no more fire.

In software development, I propose the "Total Software Product Quality" triangle. The three components are "Solid Code", "Complete Unit Testing," and "Continuous Integration Testing." In the presence of a "solid management process" that combines the three elements under the right conditions, we can have "Total Software Product Quality." Take any one of these elements away, and there is no more total quality - only fires that will need to be put out later at a tremendous cost.

1 comment:

ttChipster said...

Steve,

Nice post; I haven't followed all the links yet, but working on it. I've already passed it on to several people who need to help us move in this direction. Thanks.