One of the most important factors that contributes to a software project’s success is how maintainable the software is. Maintainability in turn, is often driven by soft factors – factors that often can't be quantified or easily measured. This is one reason why so many projects churn out software of poor quality and consistently miss deadlines. Managers often have checklists covering tools, technologies and processes but miss the bigger picture. Instead of utilizing strict rules and checklists, one must work on developing a culture of simplicity that directly leads to the creation of quality, maintainable software. A company can have great engineers but if the culture isn't right, you'll still end up with a poor product. Hopefully this article will shed some light on how one goes about developing that culture.
The Twin Plagues of Under-Engineering and Over-Engineering
Before I get into what to do right, I want to touch on a couple problems that commonly derail a project. Too often software design and development end up falling prey to one of two extremes: over-engineering or under-engineering/hacking.
Under-engineering is easily explainable and we've seen it all before. Individuals who do not coordinate with each other or simply just learned bad habits often don't put into practice a good design strategy. Eventually the code starts to resemble a giant ball of twine and bug fixes that should take hours end up taking days or even weeks.
Just as common, but perhaps less recognized is the over-engineering phenomenon. Often this is the result of individuals who have learned various design patterns and believe that they should be (over)used at every turn. Also known as being ‘pattern-happy’, this tendency can actually be as dangerous to the success of a project as under-architecting a system. Over-engineering behavior is problematic because it causes finite amounts of overhead code to be included for every bit of functionality implemented. Over time, these bits of overhead really start adding up and negatively contribute to the maintenance cost of the product.
The end result of over- and under-engineered systems is the same - maintenance effort of the software becomes onerous for even the simplest of functional additions. This maintenance overhead results in regularly missed schedules and frustrated developers.
The Four Pillars
Remembering what I call the four pillars of maintainable software will help ensure that your product doesn't become an unmanageable beast.
Note that these may seem somewhat obvious at first glance, but they're easy to ignore or brush off. You'd be surprised at the number of individuals who claim that their development techniques adhere to these principles but whose work shows a complete disregard for them. You'll notice that I don't cover some concrete recommendations we've all heard before such as commenting code. At this point, the vast majority of developers know that they should be commenting code, however many overlook more nebulous aspects of successful software development that, in my view, are even more important.
PILLAR 1: KISS – KEEP IT SIMPLE STUPID
You many have heard of the KISS rule – Keep It Simple Stupid. As it implies, this indicates that you should always maintain simplicity in every aspect of your product – from the design, to implementation, even the software process. The inherent complexities present in large projects make development and maintenance hard enough without unnecessary overhead being introduced into the product by various individuals.
KISS is a mindset that should be drilled into everyone working on the project. Many or even most people do not have a true appreciation for complexity and often greatly underestimate the negative impact that small amounts of complexity can have on a product over time.
A few example questions showing where KISS could be applied:
- Why are we implementing this design pattern? Is there a simpler pattern that would be more efficient and easier to maintain?
- Is there a simpler way to implement this bit of code?
- Does every part of our process make sense or are there ways to make it more efficient?
- Are there parts of the code or process that we tend to repeat over and over that could be simplified?
PILLAR 2: YAGNI – YOU AREN'T GOING TO NEED IT
From the world of Extreme Programming (link) comes the YAGNI, or the “You Aren't Going to Need It” rule. As the name implies, when designing and coding, really think if the bit of functionality you are adding is definitely going to be added or are you just putting it in ‘just in case’. More times than not, these ‘just in case’ additions end up never being used and simply add to the maintenance overhead of the product.
If you keep the code as simple as possible and if you end up needing a bit of functionality later, it is usually no big deal to insert new functionality because the code is very simple and you have good test coverage, giving you confidence that you won't break anything at a later date.
The XP/Test Driven Design community takes a harder line than I tend to – they claim that even if you KNOW functionality will be needed in the near future but not at this immediate moment, don't put it in. I tend to go with the idea that if I know for a fact that functionality will be needed and I'm already in that bit of code or designing that part of the system, go ahead and put it in.
YAGNI example questions:
- Is this bit of functionality I'm implementing absolutely needed right now?
- Is this bit of functionality that I'm implementing highly likely to be needed in the future or am I doing a ‘just in case’ that has a decent chance of never being utilized?
PILLAR 3: DRY - DON'T REPEAT YOURSELF
DRY is a rule that actually drives a lot of design patterns and refactoring recommendations. One of the biggest maintenance problems is when you have code repeated throughout the project. What tends to occur in these cases is when one of these code copies needs updating, developers need to search throughout the code base and update all the copies. Sooner or later one or more copies ends up not getting updated and you get bugs introduced. Additionally, copies of logic adds to the sheer volume of code need to be maintained which makes for a more confusing product in general.
So in short, when you see a piece of code that you are copying/pasting, extract it into its own method or module. It will be much less bug-prone and easier to maintain in the future.
PILLAR 4: STAY ORGANIZED
Stay organized in every part of the project; from where you place documentation on the company server, to how you lay out your code files, to how you name your classes, to how your product is being installed, even to making sure you refer to various concepts in a consistent manner when speaking and writing about them.
I find that proper organization is often under-stressed in software projects, which is a shame because poor organization can decrease maintainability as well as the chances of long term project success. When things aren't organized, it means that the team members need to employ raw memorization of random bits of information. This memorization overhead takes away from having a clear head to solve problems and muddles communication between team members. Therefore, poor organization can lead to the introduction of ‘dumb’ bugs and can even indirectly cause project schedules to slip.
Ensuring that all parts of the project are organized cuts down on ramp-up time of newly hired individuals as well. This is because when a project is properly organized, the company isn't as reliant on the tribal knowledge of existing members. New members will be able to more easily figure out how things work and where information is, simply by following consistent patterns.
It’s All About a Mindset
The pillars may seem obvious and even a bit mundane, however they are intended to reinforce a mindset of simplicity which leads directly to the creation of maintainable, quality software. In addition to hiring talented individuals, shops have to ensure that the culture reinforces good software development. The culture can't be just about pushing deadlines, giving lip service to code quality and stating that if we only implement patterns x, y and z that all will be OK. The mindset encouraged by the project is critical to the production of maintainable software.
- 30th June, 2009: Initial post