Introduction
Probably one of the most difficult things about maintaining a development shop is that you can't always be around to make sure that (1) all your company's projects are bug-free, and (2) that the morale of your development team(s) remains at the highest levels. In practice, this situation can often become a nightmare if your development team is scattered across multiple off-site locations and don't even share the same time zone. To make matters worse, you have to ensure that every line of code in your company's code base is fully tested, commented, and documented so that you can promptly deliver it yesterday in time for the release deadline.
With that much chaos in mind, one might even think that we'd be in some sort of a code quality crisis here at CodeLean; however, our code metrics for our projects show a completely different story:
Average Cyclomatic Complexity | 1.81 (StdDev 1.96) |
Average Test Coverage Rate | 95.9% |
Average FxCop Errors | Zero |
Average StyleCop Errors | Zero |
Code Documentation Coverage | 100% |
Now, if you're not familiar with some of the metrics above, the table just means that we can keep our code quality extremely high with only a minimal amount of effort, regardless of project size or scope. In other words, our projects can be composed of several hundred thousand lines of code, and we can still guarantee the same level of quality. In this post, I'll show you a few things you can do with your development process and your development team to make your projects just as efficient.
Inhumanly Possible?
At first, this might seem impossible--after all, one might be dealing with thousands (or even hundreds of thousands) of lines of code per project, and it's hard to go through line by line of
that much code and ensure that everything works just as advertised. So the next question that you might be asking is "How can you guarantee that your code meets the standards above if it's not humanly possible to inspect that much code, and still meet the client deadlines?"
QA Specialists to the Rescue?
Indeed, such code quality inspections can be done by an army of quality assurance specialists, but there's no guarantee that they will be able to catch every QA issue from your development team. The problem with this approach is that it can't scale, because the ability to inspect your code base largely depends on the number of people that you have available that can inspect it. In other words, it's a huge bottleneck, and that's where build automation can come in handy.
Automating Code Inspections
The best way to ensure the quality of your code is to use automated code inspection tools (such as StyleCop, FxCop, and Gendarme) to catch QA violations during your application build process. These tools can eliminate the tedium that is often associated with having your QA teams manually inspect each line of code in your code base. Furthermore, automated code inspection tools can typically inspect code bases of any size, making it easier to inspect your systems without having to pay an entire QA team to perform the same task.
Add Code Quality Metrics
Beauty in Objectivity
One of the best parts about having code quality metrics calculated during each build is that it forces all your developers to adhere to a single set of standards without any form of bias from the code reviewer (or in this case, the automated code inspection process). Secondly, it eliminates many of the conflicts that arise between developers during the course of multiple code reviews since the automated code metrics will force all your developers to follow a single standard. This will allow your developers to work in tandem without stepping on each other's egos, and at the same time, it will also ensure that your code metrics never fall below a certain threshold.
Fail Any Build That Does Not Meet Your Company's Standards
If your developers write code that fails to meet the threshold, however, then your build process should automatically fail itself in order to prevent your developers from adding substandard code into your projects. At first, this approach might seem a bit too stringent, but in practice, it forces developers to fix the quality of their code before committing the changes back to the code repository. This particular approach also teaches developers to think about the design of their code before making any unnecessary changes, and it also prevents developers from hastily committing unrefactored code that might have otherwise been overlooked in a manual code inspection.
Automate Your Deployment Tasks
Application deployment is arguably one of the most critical and mundane tasks that any developer team can undertake. More often than not, a single configuration error can mean the difference between a company shipping a well-designed product website or having the same company display a "404 - Page Not Found" error within a few minutes of having their Web site go live into production. Since many deployment tasks (such database deployment) are repetitive, the best way to eliminate such last-minute deployment problems is to put all the deployment tasks into automated deployment scripts. Automated deployment scripts eliminate the chronic tedium associated with manual deployment, especially when it comes to deploying database applications and deploying Web applications.
Database Deployment
Setting up and tearing down databases during manual deployment can potentially cause version conflicts between the production code and previous database versions. Suffice to say, it can be difficult for developers to synchronize the application code with the database code over the course of the application's lifetime. In many cases, it's far too easy for developers to forget to deploy the correct SQL script or ensure that the application code writes to the correct version of the database. Indeed, there must be a better way to reduce the errors in deployment, and the most efficient way to do this is to use automated build tools like NAnt (for .NET) or Ant (for Java) to tear down and redeploy the database whenever the application needs to be updated or installed. Automated database deployment often reduces many of the errors associated with deployment by simplifying the database deployment down to a very few small steps. This allows nearly anyone on the development team to deploy the database schema without having to know everything about the deployment process, and that might come in handy if the application needs to be deployed immediately and the principal developers or DBAs are unavailable at the time of deployment.
Web Deployment
Web deployment, on the other hand, suffers some of the same drawbacks associated with database deployment. With manual Web deployment, it can be very easy to overlook or omit critical files (such as configuration files) when a Web project is being deployed to a Web server. Futhermore, manual Web configuration and deployment can also become quite tedious when your team is dealing with more than one Web server and it can easily get more complicated once your team starts dealing with multiple Web servers or Web farms. Like database deployment, most (if not all) Web deployment tasks can be automated, and this can save your development team some precious time if you're running on a tight schedule and can't afford to miss the project deadline.
Automate Your Web Acceptance Tests
Automated Web acceptance tools such as WaitiN and WaitiR eliminate the need for Web testers to manually check the features of your Web site. These tools allow you to take control of Web browsers such as FireFox, Chrome, and Internet Explorer, and let your tests interact with nearly any Web site without forcing anyone on your team to sit at the keyboard and perform the same steps over and over to see if they work as advertised. It might seem a bit unsettling at first, but watching these automated Web acceptance tests test your site by themselves (and without any form of human intervention) is practically a miracle unto itself. More importantly, automated Web acceptance tests can save you a lot time and money since nobody has to be at the keyboard when those tests run. Lastly, automated Web acceptance tools allow you to quickly find errors within your Web site in a matter of minutes. In contrast, it could take a Web testing team anywhere from a few hours to a few days to manually isolate the same bug if your team had made changes to their code. Speed is one of the benefits that automated tests provide, and needless to say, speed is one of the critical factors that can either make or break a deadline.
Make a One-Step Build
Allowing your developers to build your applications in a single step is one of the best ways to make your team more productive. This means that anyone on the development team (regardless of their skill level) will be able to automatically build, test, and even deploy your applications within a matter of minutes. You can use build automation tools (such as NAnt and Ant) to script the entire process. Although there is a slight learning curve in adopting these tools, there's no better feeling than knowing that you can roll out your entire app in a single step without slowing down the rest of your development team.
Use Continuous Integration
Continuous Integration is possibly one of the best investments that any company can undertake to ensure that their software is always in a releasable state. CI servers (such as TeamCity and CruiseControl) force developers to integrate their code changes on a daily basis, and they can easily help the upper management keep track of the overall health of the company's software development projects. Having your developers integrate their code changes on a daily basis means that more bugs can be found during these daily integrations instead of waiting until the end of the project to merge all the changes together. In other words, Continuous Integration can save your team an inordinate amount of headaches because it forces bugs to be fixed ahead of time instead of having them wait until the end of the project to resolve those same issues.
Go Green, or Don't Go Home
A CI server is typically in one of two possible states. It can be in a "green" state, which means that the current project builds itself properly and that all of its unit tests are in a passing state; or it can be in a "red" state, which means that the current project cannot be built or at least one of its unit tests have failed. One of the simplest ways to maintain or improve your company's software quality is to make sure that nobody on the development team goes home until the CI server is in a "green" state. Since the goal of Continuous Integration is to be able to create software that can be released on a daily basis, forcing the team to always leave the CI server in the "green" state ensures that your software can be released at the end of any given work day.
Use Source Control
Source control is undoubtedly one of the best inventions in software engineering because it allows developers to branch, undo, revert, restore, and merge changes in their source code that might have otherwise been impossible to perform if they were to use a standard file system to manage their source code. Source control makes it practically effortless to manage multiple versions of the same project at the same time. Source control management tools such as GIT, Subversion, and CVS all have the ability to branch multiple source files in any given project, and most (if not all) of these tools have the ability to track multiple file revisions to any given project during the course of its lifetime. Such tools can be a godsend when dealing with projects with thousands of source files because those tools make it easy to undo changes to an almost infinite number of files. In many cases, it only takes a single command or a single right mouse button click to revert a project back to the previous working revision.
Use Test-Driven Development
What if it were possible to perform regression tests on your entire application in less than five minutes? What if the same application could automatically tell you which parts of itself are broken, right after a developer makes changes to the source code? And what if it only takes a single person to execute a single step to run all these tests? How much would that be worth to your company? At first, this might sound too good to be true, but indeed, it's real, and it's called Test-Driven Development.
Needless to say, any project that can regressively test itself will be easy to maintain and debug since bugs can be detected during every five-minute test run. Since the tests only take five minutes to run, it's practically trivial for every member of the development team to test your application dozens of times per day before (and after) making changes to your source code. TDD allows developers to discover bugs faster than other more traditional development approaches, and more importantly, it forces developers to write their unit tests first so that the unit tests ultimately "drive" the design of the system. A passing test is often equivalent to one functional requirement, and since tests must be written before the actual code is written, every functional requirement that is implemented using TDD will automatically have a test that verifies its behavior even before the code is written.
Refactor Early, and Refactor Often
In many ways, it's easier to prepare for a disaster than be forced to experience it unprepared, and incrementally refactoring your company's code base is no exception. Refactoring allows developers to improve the quality and design of their code so that they will be prepared to handle any "disastrous" requirements that would normally wreak havoc on any reasonably sized code base. Refactoring preserves the original functionality of a code base without adding new features or subtracting any functionality. At first, refactoring might seem like an unnecessary task given that most clients don't care (or pay for) you to refactor their code. In fact, it's entirely possible for a company to work several years without having to refactor their code, so why should developers even refactor?
The answer is that as your code quality will inevitably plummet as your code base grows larger and larger. The longer you wait before you refactor your code, the more difficult it will be to add new features to the system without causing some other feature to break. In essence, every time the development team decides not to refactor their code, they incur a certain amount of technical debt. Much like financial debt, technical debt seems to have no initial cost, but technical debt can eventually lead a team's progress to a complete standstill if the debt is not repaid with refactoring. The easiest way to avoid technical debt altogether is to have your developers refactor their code as soon as they write it, and have them refactor it as often as possible.
Conclusion
A company that implements all these concepts under one roof will be well on their way to ensuring that they can deliver the world-class quality code that their clients rightfully deserve. The road to excellence definitely won't be an easy journey, but no matter where you go on this globe, we at Codelean will be there to help your company reach its full potential, so please don't hesitate to contact us if you have any questions.
--Philip Laureano
Codelean Lead Developer
Codelean Lead Developer