QualityCode.com Essay: What Is Code Quality?
Quality is actually quite difficult to define. We can talk about “external” quality, which really comes down to customer satisfaction, or we can focus on “internal” quality, which only affects the customer indirectly. Both are important, and fortunately they do not need to conflict with each other.
External quality is really about communicating with your customer(s), getting frequent honest feedback, and responding to their requests. If they change their minds (and they will), work with them instead of against them. Choose a process that is focused on their requirements, not on the tools and technologies that will be used.
Most of the material on this site is directed at improving the internal quality of software projects. Too many projects end up with code that is so complex and unclear that it is virtually impossible to maintain. Even a small change can break an unrelated feature. Adding a small feature can take forever. Most projects seem to hit this point after one to three years.
One of the best ways to avoid this “code rot” is to refactor the code. That doesn’t mean rewrite it. It means to improve the existing design without changing the functionality. Don’t wait until the code is a big mess, and then take weeks to completely refactor it. Instead, do a little refactoring each day.
Choose excellent names for your classes, methods, and variables. And don’t be afraid to rename them if you think of a better name later. Keep your method signatures clean (for example, avoid passing extra parameters), and be sure each method is a member of the right class. Keep your methods reasonably short, and your classes small. Extract complex formulas so you can give them meaningful names. Avoid global variables, and use singletons only when absolutely necessary. Above all else, avoid any code duplication.
Another trick to avoiding unmaintainable code is to keep the design as simple as possible. Don’t add hooks for future features that may never be needed. Don’t handle every general case if you only really need to handle one specific set of parameters. There are times where you have to over-generalize, such as if you’re about to publish your API to the world. But in many cases you can do the absolute minimum, and it will work just fine. In most cases, “you aren’t going to need it” (YAGNI).
One last tool that helps keep your code modular (and modular code tends to be highly maintainable and extensible) is to create your code using Test-Driven Development (TDD). Before you write any code, write a simple test that shows how that code would be used. It might be as simple as writing a single “assert” statement. Then, after you’ve seen the test fail, write just enough code to get it to pass. Repeat the process until your code does everything it needs to.
At that point, you’ll have code that you know works (because all the tests pass), is modular (testability generally forces modularity), and has a suite of tests that approaches 100% coverage. From then on, keep your tests updated and always write a failing test before adding functionality. Each time you make a change, you can quickly run the test suite, and be confident that you didn’t break anything.
This allows you to refactor aggressively, which allows you to keep the code clean (or actually improve the design over time), and avoid code rot. You will be able to continue to quickly, inexpensively and safely improve that code indefinitely.
Basically, I have just described an agile approach to software development, along the lines of Extreme Programming (XP). I encourage you to learn more about XP, and other agile methodologies.