12 Steps to Better Code – Revised, now 7

May 11, 2009

Note: This is a work in process, but I wanted to get it out “as is” to see what others think.

Unit testing is now such a paramount part of producing quality software that its absence from the list alone necessitates a revision of Joel’s 12 Steps to Better Code. There are other enhancements to include based on what we have learned in the almost 9 years since their original publication. Also, 7 Steps sounds sexier.

So here’s my revised list. Use these steps to evaluate a software organization the same quick-and-dirty way Joel describes in his original article.Remember, there is no silver bullet.

  1. Do you have (something at least resembling) a spec that solves a real user/business problem?
  2. Do your developers have frequent code design sessions and mutual code reviews?
  3. Do you use unit and regression tests that are very easy to write and execute?
  4. Do you have automated continuous builds that include running all unit and integration tests?
  5. Do programmers have quiet working conditions and regular, 40-hour-week work schedules?
  6. Do you have testers with input in the development life cycle and the requirements?
  7. Do you have an integrated system for bug tracking, development tasks, source control browsing/statistics and a wiki?

Compared to the original list, I enhanced and combined some of the original items, added a few and re-ordered the whole list. I also dropped a lot (see below). In addition to applying my own experience as a software development team member, I integrated a few ideas repeated in other comments on the original list. I purposefully avoided buzz words such as agile or pair programming, because they are mostly polarizing and would distract from the real goal of this (and the original) test: evaluate the quality of your software development process and have a simple guideline for improving it.

Before I go into detail about the items on the list, I want to comment on what I dropped:

Original 1. Do you use source control? From a perspective of necessity to the software development process, using source control, even if you are the only one on the project, is equivalent to providing electricity to your computer. I am not going to put the latter on the list, either.

Original 2. Can you make a build in one step? I removed this for two reasons: First, it is inherent in the new step 4. Second, tools for doing very sophisticated things with builds are readily availably nowadays (Ant, NAnt, SCons, Cruise Control …).

Original 5. Do you fix bugs before writing new code? This did not really get dropped, but it may be hard to recognize as inherent to step 3 of the new list. More details on this below.

Original 6. Do you have an up-to-date schedule? This is not always applicable based on context and it’s also a very controversial item with no simple solution. Most software teams have experienced that meeting a schedule is a rare event, even if you keep moving the delivery date. Some teams try to solve the problem with frequent, small release cycles; other teams try to find different solutions. In essence, how this problem gets solved has often more to do with actual business requirements than with the quality of your software development process. Adhering to the 7 steps in the new list while at the same time meeting business requirements will essentially force this problem into a particular, workable solution. Also, since step 4 is essentially assuring that there is (almost) always releasable software, it may provide management with an opportunity to make more flexible release decisions.

Original 9. Do you use the best tools money can buy? Depending on your context, the best tools are actually free nowadays. You should still have the best tools, but what they are is so specific to a particular team’s requirements that it is quite difficult to evaluate a team based on the ones used.

Original 11. Do new candidates write code during their interview? As much as I would like that to happen, team environments differ so significantly that this just is not a reliable indicator for a functioning software development process. What about open source projects that don’t hire people? There are many ways to evaluate a new team member and integrate him/her in the existing team process that are better than the traditional interview. One is to have a conditional agreement and get the new guy/gal to write code.

Original 12. Do you do hallway usability testing? What if there is no hallway? Teams differ too widely in their structure to make this an indicator for a good process. The requirement that the end-result of a functioning process must be usable is embedded in the new steps. But usable does not always mean usable by an end-user. A software component, for example, must be easily usable by other software developers; “hallway” testing in the way Joel described it is not going to help there. Steps 2 and 7 on the new list may.

The new 7 Steps to Better Code

1. Do you have (something at least resembling) a spec that solves a real user/business problem?

This is the most important step, period. If you find a team that writes software without this, run. Not having to solve a real, existing, validated user or business problem will guarantee that requirements change in such extreme ways that they cannot be reasonably accommodated or even anticipated with any of the other 6 steps. Schedules will never be met (because early releases will demonstrate incorrect or insufficient requirements) and everyone will be frustrated from very early on. It’s a vicious cycle. It’s like taking a road trip without an idea where you are going, just because it sounds like fun. But everyone in the car will be screaming and cussing.

I am repeating this in different words because it’s so important: Make sure that what your team is building is needed. It could be written on a napkin, but it’s has been validated to be a real need. Otherwise, don’t bother.

2. Do your developers have frequent code design sessions and mutual code reviews?

This step migrated from the bottom of my first draft to almost the top because besides having something real to build, I have come to experience this step as absolutely fundamental to building quality software. Frequent design and code reviews may be new to some and not be going far enough for others. A third group of people might experience some serious discomfort on reading this, because it affects the developer’s ego. Even if you are a team of one, have someone else look over your ideas of how you want to build software. Doing so causes several things to happen:

  1. You will seriously think through the problem first before writing any code, because you will have to talk to someone else about why you think your approach is correct.
  2. While working on 1., you will uncover any deficiencies in the requirements given to you, before you wasted time writing code solving the wrong problem; even before you wasted another programmers time reviewing your design.
  3. Both code design sessions and code reviews will dramatically enhance code quality. I consider myself a decent software engineer, but none of the stuff I come up with on my own is half as good as what I produce if I cooperate with another developer on it, even if the other developer is less skilled.
  4. Less skilled developers will quickly improve their coding and design skills as a result of the frequent interaction with more advanced programmers.

I have experience with pair programming and love doing it. But, in today’s typical software business environments, it simply is not reasonable to expect two people to sit next to each other 6 to 8 hours a day while only one of them is writing code. An average of one hour per developer per day doing code design sessions and mutual code reviews with feedback will go almost as far as pair programming in code quality improvements and team education/IP transfer, with much lower personnel costs.

3. Do you use unit and regression tests that are very easy to write and execute?

Even though I frequently interact with developers who see unit testing as an afterthought, my own experience with Test-driven Development has proven to me that this is by far the best way I, as an individual, can produce quality software. In order for the individual programmer to even be able to use TDD, the software process/environment must make it extremely easy to write and execute tests. This has further-reaching implications than most realize:

First, the tools for unit testing must be available, and if they are not, they need to be devised first. This is true whether you are writing a web application, a scientific application, an embedded or mobile application or a device driver. Your ability to take the smallest unit of code and test it independently of the rest of the system will enable you to produce very high quality code.

Second, as a corollary, this approach forces you to design your software system so that you even can isolate every small unit of functionality. That is very important for future code quality: On the one hand it makes the components of your system as independent as possible, allowing you to easily replace each of them with new implementations down the road to accommodate new requirements. On the other hand, it enables you to enhance code coverage as well as write robust regression tests down the road, which is important, because it is unlikely that you are starting out with 100% statement or branch coverage.

Third, in combination with the “pass” requirement described in step 4, this step means that every new bug gets a regression test that must pass before new software can be written.

Forth, the entire system needs to be flexible and should be able to be “brought up” automatically into which-ever state is needed. See the next step for more about that:

4. Do you have automated continuous builds that include running all unit and integration tests?

Build in this context means something that automatically composes your system in its entirety and executes a vigorous functional validation test suite against it. It doesn’t just mean compile, which is not applicable in many contexts anyway. There are some contexts in which even the automated acceptance tests have part of the system stubbed out, for example when writing embedded software. But if you can feasibly devise a system that is equivalent to the final deployment, even if it takes extra work, then you should make the effort. For example, if there is any way that you can get your embedded code to automatically deploy to that FPGA chip you are trying to program, you should attempt to make it happen and write a test suite against the actual chip. If you are writing legacy FORTRAN code, find a way to emulate your entire system and run the tests against that.

+ whatever Joel had to say on the one-step build.

There is no excuse for not doing continuous testing.

The principle behind this step is that new code must never break the build; and if it is broken, it’s the first thing that gets addressed before anything else. As a consequence, bugs are always fixed first, because a new regression test for an existing bug would break the build until the bug is fixed.

The immediate business benefit is two-fold: On one hand, this approach provides a level of business process stability and security, because business owners can asses the state of the product simply by analyzing the result of the latest continuous build (which they should be able to do easily). On the other hand, it provides scheduling flexibility, because business owners can make release decisions for any of the passed builds.

Because many software projects have multiple concurrent release cycles in various release states and therefore keep multiple branches of code around, this step forces every single component of the system to be designed with the utmost flexibility. An often overlooked component are database systems, which, as a consequence of steps 3 and 4, need to be automated in their creation and management. The initial effort to getting this done right will result in significant savings down the road.

5. Do programmers have quiet working conditions and regular, 40-hour-week work schedules?

The same arguments that Joel had 9 years ago all still apply and it’s sad to see that we haven’t made much progress … despite there being so much evidence out there collected by others that support this point so sufficiently that the best I can do is repeat it:

  1. Don’t kill the zone, because it is expensive to get back into it.
  2. Remember the law of diminishing returns. More work does not necessarily mean more (or better) output. It usually means the opposite.

6. Do you have testers with input in the development life cycle and the requirements?

What good is testing if it is not used to find problems? What if the problem is not a bug in the software, but something else, for example, in the process or with the requirement? What if a usability tester can spot a usability bug in the requirements before any code is ever written? Human testing must be used to uncover all the problems that cannot be found with automated tests. Depending on a team’s composition, testers may not even write any automated tests, but simply observe or review them for correctness.

The biggest issue is if there is no independent quality control, someone to keep requirement writers and software developers on their toes to build quality software; the kind of quality control that rejects code changes if there is not sufficient unit test coverage, the kind that protects developers against silly requirements, the kind that in very few teams actually exists.

In small teams, anyone may be a tester and it may be beneficial to the quality of the final product to give everyone the ability to veto requirements, design, code or even test results.

7. Do you have an integrated system for bug tracking, development tasks, source control browsing/statistics and a wiki?

One would think this should be treated like source control, and hopefully in 9 years from now we can do that. But the current state of affairs in many teams is what I call the “SharePoint” problem: multiple bug tracking systems, word documents, spreadsheets, tables, wiki entries, lists, text notes, print-outs, JPEGs, Photoshop and Illustrator files and who knows what are littered over many servers and drives, with many duplicates and no way of finding anything. Some people try to solve this problem by installing a full text search system against the entire mess only to find out that for any reasonable search they find hundreds of unorganized documents or nothing. Or there is no reasonable search term to define.

All communication, requirements, comps, tasks, bugs, and documentation need to be in a single place. E-mail should never contain specifications. At best, it must only contain a link to a wiki page that has the specifications on it so it can be discussed there. If the source code is the specification, create a new tracking item for the discussion pointing to the code and e-mail the link to the tracking item. That requires whatever system you are using to support the easy creation of links to pretty much any item in it. At best, don’t use e-mail for this stuff at all, but have a good notification system.

For every modification to be done to the system, there ought to be a tracking item that allows visibility into the change for all stake holders: the business owner, the developer and the tester. This is true for any software project.

Without such a system, it’s hard to do any of the other 6 reasonably efficiently.


One Response to “12 Steps to Better Code – Revised, now 7”

  1. Michael Cowan Says:

    You have some good points and while I don’t have the time to reply to all of them I will single out a few.

    #1) I agree with the SourceControl statement (and the quip about electricity made me laugh)

    #2) I disagree that you satisfy the intent behind Joel’s Original Step 5 – Fixing bugs before writing new code. I believe the intent was to fix not just the bugs that appear in continuous integration cycles, but to address all bugs found on existing features before adding a new feature.

    I do not believe every bug can be automated and added into the build, there will still be a significant number of bugs reported by customers/qa that you have to decided to immediately address or postpone.

    #3) I am not sure that your New Step #1 about a spec is clear enough. I do not think there are more than a handful of teams out there just writing software with no plan whatsoever (today I will change all the buttons on my form to be radio buttons in group boxes, because that would be cool!)

    All teams have some idea what they want to do, the real problem is how to get everyone on the same page so that when something is built it is the right thing and everyone is satisfied.

    My last company had a lot of written specs and still missed dates (for many reasons), while my current company has produced complex and interconnected products for years without any written specifications.

    The key is communication, the method of communication is not really important. I think you are on the right track with the on a napkin, or a document statement, but it would be better (imo) if you expanded on your ideas more and gave some examples of the right things that you could do.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: