As I mentioned a couple of posts ago, I was recently out in Oslo teaching a course on Lean software development. One of the points I make is: Quality is free (or at least cheaper) provided you invest in improving quality.
This section of the course included an exercise were I ask the participants to think of things they could do to improve code quality. On this occasion the exercise went particularly well and resulted in the list in the picture below:
Lets run through these one by one – not necessarily in the order on the sheet:
Test Driven Development: if there is one practice above all others which contributes to better code quality and fewer bugs it is TDD. On the plus side it can be used on any type of project, Agile, Waterfall or other. Its roots go back a long way but it was a forgotten practice until XP resurrected it. When run as part of a continuous integration cycle with frequent automated builds and tests the practice is Unit Testing on steroids.
However it doesn’t just happen by mandating it so. Most developers don’t know how to do it, they need training and help (coaching) to do it. Even then it is going to be a learning experience, don’t expect it to become prevalent overnight.
(And before you say “But we have a legacy system with 1 million lines of code so it won’t work for us” please read my implications of the power law.)
Acceptance Test Driven Development (ATDD) is the next level up from unit test based TDD. Here those making the requests for development not only specify their acceptance criteria but do so before any development happens, and do so in a way that they can be automatically executed. In many cases professional Testers need to work with the “Customers” to create such tests.
Continuos Integration (CI): This is a valuable practices on its own – making sure code builds and new code doesn’t break anything that already exists. When coupled with TDD and ATDD to created automated, repeatable, test suites, it is an order of magnitude more valuable.
Pair Programming: The controversy over pair programming seems to have died down, but then so too have examples of people actually doing it. A shame really. It is instant code review, it is two-heads better than one (think of commercial pilots or surgical teams). It also allows developers to focus intensely on the work in hand – few distractions from telephone calls, e-mails, SMS, and all the other rubbish that distracts us so easily.
Code review: The next best thing to pair programming. If people won’t pair then at least code review. Put in place a light weight process which happens as soon after the code is written as possible. The big formal process so many of us learnt about in school aren’t practical – only NASA can really afford them anyway. Instead use a lightweight process, you will get 80% of the benefit for 20% of the cost.
Static analysis tools: in the past static analysis tools have gotten a bad name for themselves. The current generation are a lot better and while they are not a true substitute for a code review (because in a code review both reviewer and reviewee learn) they are very cheap to use. Sure you might have to buy a license but once you’ve done that and set them up in the build system they run every time code is checked in and can highlight potential issues very quickly.
Coding standards: Traditionally I’m not a fan of coding standards. In my experience too many teams waste to much time debating and arguing over coding standards and when they are put in place they can be used as a tool for some developers to bully others. However, if you can overcome those problems then they have a valuable contribution to make.
Start by having a group discussion – face-to-face, not over e-mail or on a mailing list – about what could be in a coding standard. Find the areas of agreement and have three or four categories: a very few items as “mandatory”, more items as “recommended” and more as “candidates.” This third group are possible candidates for inclusion in recommended or mandatory but need some consideration. The fourth group for things you agree not to standardise on.
Then review these guidelines every three or four months. Promote some from candidate to recommended, and from recommended to mandatory, and if some aren’t working then remove them or demote them. (This recommendation is broadly in line with Les Hatton’s suggestions in Safer C.)
Then, don’t use coding standards as part of your review. Developers should follow them out of honour. But just in case you miss one, automate them. Set your static analysis tools up to run your coding standards against code which is checked in. Remove the human from the loop and remove the bullying.
Automate: In case it hasn’t sunk in yet, most of the suggestions so far can be automated, and should be automated. Not automating them means they take time to do and are therefore expensive in the long run. Automation might cost in the short run but it makes things cheaper overall.
Refactoring (& refactoring tools): The whole point of refactoring is to improve the code quality and, more importantly, the overall design. If it isn’t then something is wrong. You can, and people do, refactor without automated unit tests but this is equivalent to a high-wire act without a safety net. With the safety net in place refactoring should be a frequent activity and one which doesn’t take up lots of time.
As an old C++ hand I’m always impressed by the refactoring tools available to Java and C# developers. These should lead to more frequent, quicker and safer refactorings.
Hopefully it is immediately obvious how the above can lead to better code. Some of the other items on the list aren’t so obvious but I think they are worth including.
Show and Tell (early): maybe not immediately obvious why this one should lead to better code but it will. By regularly showing potential customers of the software what they are getting developers need to keep their code near to release state. This forces more, smaller, steps in development.
The second reason why this helps is that feedback comes more regularly. This provides positive guidance on what is going right and will point out when things are going in the wrong direction.
Finally, if developers are scared to show their work in progress to users and customers then its time to run up the red flags and look for trouble.
User Tests extends this reasoning. User tests provide another line of testing which helps detect problems early.
Similarly, working on smaller pieces/projects provides for more small steps. Before each step there is an opportunity for re-adjustment and course correction both at the work planning level and at the code level.
Finally, Team cohesion is important because without it the team are running in different directions and doing different things with the code. Part of team cohesion must be a shared view on the development objectives, the design ideas in the code and what makes for good code.
This isn’t an exhaustive list, just the ones my students in Oslo came up with; if you have any more suggestions please add a comment, thanks.