Search this blog

04 September, 2009

Code quality

Sooner or later, in every company there will be a discussion about code quality, how to monitor it, and how to make engineers care more, design and produce better code. How to massage and hone the existing one into more improving its quality...

Well it's everything very useful but sometimes we go to much into the details and lose focus on the only thing that really matters. What we always have to remember is that code rots, and it's inevitable.

It's up to your company to come up with a balance between how much effort you have to spend on design and maintenance, you can make quick and dirty hacks that will rot fast, or well designed software that rots slower but won't hit the target (because it moved somewhere else while you were designing for it)...

Or you can be smart and do iterative development with many short cycles and a lot of refactoring. In the end, the only thing you really want to avoid is to stick with only one pair of shoes for the rest of your life.

Make your code perishable, plan for its death, do not rely on its existence. Modules, interfaces, dependency control, that's your only goal when you're thinking about long-term. You have to be able to throw away everything.

The added bonuses of designing code this way are everywhere. You can throw less experienced programmers to a feature just because you know that it won't affect anything else than itself, and it can be replaced later on. Good code won't be built on top of bad code, bad code does not spread. You can create DLLs and achieve faster iteration. Your compile/link times will be faster and you can create testbeds with only the features a given area needs. You can do automatic/unit tests more easily. You can multithread more easily, and so on.


Daniel said...

Awesome post. I would be interested in hearing more concrete ways to write self contained, throw away-able code, perhaps via an example. It's easy to write self contained code at the small scale with typical OO approaches, but it gets really difficult at larger scales with components with complex interactions.

DEADC0DE said...

Writing modular code is not hard at any scale, per se. But at larger scales is easier to have dependencies creep in, so enforcing modularity is what you want to do.

A good start is to separate public headers from package-private ones, and have class-private declarations directly in the cpp files. Then you can enforce, possibly via a tool, a few rules on the public headers, for example that they may contain only interface classes or plain structures... Doxygen can do the trick.

That done, one of the most reasonable things is to have a programmer responsible mainly of the project structure, and lock the project makefiles from edits by anyone else.

Communication between modules can happen in different ways, I would suggest not to even assume that any module you're depending on really exist. Just import its interface and query for it, like you would do with a COM service. This way, unit testing will be easier too. Moving modules to separate DLLs will be easier too, and it's really important to kill link times and allow hot-reloading of code.

If you're starting from scratch, this is easy. But if you have a project where this is not the case... well there things become a little more complicated :D