In an earlier post, I tried to spell out the signs that i look for, that tell me the code base is bad. However the relative importance of each of those items are not spelt out. Obviously, failing to catch errors is a more serious flaw than, say, a badly formatted code base or one junk variable name. So let me try and categorize the relative importance of those flaws into broad categories
- Level 5 – Program does work as intended (Bad-ness rating 10 out of 10)
- Level 4 – Does not catch any errors and breaks very often. This obviously is a broken program or a Proof-of-concept. (Bad-ness rating 9 out of 10)
- Program crashes / shutdowns
- Memory leaks
- Level 3 – Does not guard against “can happen” errors (Bad-ness Rating = 8 out of 10. Will surely break soon)
- Return values ignored – especially bad if done so for user functions (vs system apis)
- Uncaught or worse swallowed exceptions (unless intentionally so)
- System apis and resources not used like they are intended to
- Unvalidated inputs
- Unvalidated user inputs
- Unvalidated pointers
- Unvalidated String lengths
- Too many compiler warningsHeres a sample of code at this level
- Level 2 – Tough to maintain (Bad-ness Rating = 6 out of 10. Will break during next few maintenance cycles as it is hard to see how the code flows and what are the likely errors to catch and safe-guard against)
- Level 1 – Tough to understand (Bad-ness Rating = 5 out of 10). No immediate breaks but will cause code to go to the previous level in a few release cycles)
- One category of BAD-ness leads to another – This cannot be proved, but has to be observed to be understood. One has to be part of quite a few no of projects and failed modules to know what transpires and how this comes about.
- Sweet spot of bad code is at Level 2, where the code handles the errors that it has been tested against but is tough to maintain and definitely going down hill without some major code rework. However most code bases i must say, stay in this level for some time, creating patches on top of patches to keep the code base running, until say a few years down the lane, the effort is no more worth it and the product is end- of-life-d. The architecture of the code base defines, how extensible it can be, even in the face of vast swathes being buggy and hard to maintain.In due time of-course, in big companies, a brand new version is created to accommodate the feature requests if the product manages to go into the market. This happens typically because the older version is not maintained well enough to be extensible to accommodate the new requests. The time-lines are typically strict again and the new code base manages to reach the same level as the older version but is yet again difficult to extend and maintain.
- Regular maintenance is necessary to maintain even the same Bad-ness levels – A code base can just as easily slip from level 1 to 2 (very easy) as it can go from level 2 to level 3. In short, there is no safe period and regular maintenance / refactor work is always required to keep the code base hale and hearty.
- Incentive to move from level 2 of bad-ness to level 1 is typically missing – Since a code base at level 2 and the one at level 1 are both outwardly similar, there is very less incentive to move to this more healthier level in almost all organizations.From a management point of view too, a dirty but working code base is more important than a beautiful but late code base.My solution ? add small maintenance and refactoring patches before every release cycle, so that beauty cost is amortized into the releases fairly without major business impact. However if possible i would say it is better to create code as best as it can be done the first time over. Re-works are almost always error prone and tough to orchestrate, especially if your code base is at level 2 to start with.
- Big programs will exist at many bad-ness levels at once – Big projects have multiple modules and multiple teams that work on it. Depending on the sheer luck of how the teams are assigned and who gets to work on what and the culture that prevail within each of these teams, the quality levels can vary from one module to another. The weighted average of the quality levels across the different modules (weighted based on functionality importance as rated by customers) would then determine the quality of the big ones. The size of the project typically ensures that “code smells” do not get noticed too much, much like a slum that grows on one side of the city, until it is too late or the issues that arise are too many.
Creating quality code is hard. One has to understand the fundamentals behind the notion of quality, as a function of the code base, rather than a fashionable management by-word, if any drives for quality can succeed in software projects.