Over the more than five years I have founded and managed a start-up software company, we have implemented processes and tools that enabled our company to release high quality, fast performing code quickly and efficiently. Many CEO's that I have met have done an incredible job with their company's strategy, sales, marketing, and product ideas. But some don't quite get the software engineering side of the organization. It is possible to be a CEO of a software company and not have a software background. This is not as rare of an occurrence as you might think among early stage software companies. It's important that these CEO's and their engineering staff understand what it takes for their organization to write quality and efficient code.
The concepts that I talk about apply to a software company using any development environment, but the tools that I'm discussing in this article are specific to Microsoft .NET technologies. This is not an inclusive list of all available tools; just the ones I'm familiar with.
There are many other sources on the Internet that talk about these concepts, including the Joel Test. I'm not posing anything new or revolutionary here. These concepts have helped Atalasoft become a market leader in .NET Imaging Toolkits amongst a number of incumbents in a relatively short amount of time.
1. Source Control
I believe that having a good source control system is the most important system that should be in-place in a software development shop. A good source control system tracks the history of all changes to code, and allows more than one developer to work on the same code base by managing files with check-in/check-out policies. There are free systems such as the open-source subversion, based on CVS. There are also some great commercial choices including Vault from SourceGear, and Team Foundation Server from Microsoft.
Even if you have only a single developer writing code, a source control system will manage all history important when overwriting that important piece of code that hasn't been backed up. It will also enable a developer to work on different branches of the same code-base. For a single developer, the tools available from SourceGear are free. If you are a Microsoft Certified Partner, Team Foundation Server (TFS) for up to 5 users is free. A Microsoft Gold Certified Partner with an ISV competency has the benefit of 25 licenses of TFS.
2. Bug Tracking System
A system for tracking bugs is very important. It can be a simple excel spreadsheet located at a central location, but for more than one or two developers, you'll want to invest in a commercial product. We use FogBugz, but there are many others, including work item tracking built into TFS. A bug tracking system should have the capability of assigning items to specific users, various priority levels, tracking time estimates, and differentiate between a bug and a feature.
3. Unit Tests
By now, unit testing should be incorporated into any software shop, no matter what the size. A unit test is a small isolated bit of code that verifies the logic of some production code usually written by the same developer. Generally, for every class that's written, an associated test class located in a separate test assembly should be created to verify all of the business rules and logic. The unit test can then be run to verify the results of the test. If in the future, a change is inadvertently made to the tested code that invalidates the business logic, the unit test will fail allowing the developer to fix the issue before it is released to the customer. Having unit tested code gives the developers more confidence to improve their code design by re-factoring, or to add features and fix bugs with confidence that new bugs will not be introduced.
We use NUnit which is an open source testing framework for .NET. However some of our newer projects that are built with Visual Studio 2005 use the testing framework built into Visual Studio 2005 Professional (sometimes referred to as MSTest). Both are about equivalent in functionality. The advantage of MSTest is the ability to easily test non-publicly accessible code., and the built in code coverage tools. In either case, we use TestDriven.NET to debug our code from the unit tests directly. When a customer reports what might be a bug in our code, we simply write a unit test and debug the code directly from the test. Once the bug is fixed, the passing unit test is checked-in along with the bug fix. We can be confident that the same bug will NEVER occur again.
If you already have a giant code-base that is not unit tested, it can be overwhelming to start to add unit tests. If that's the case, make sure that any new code has associated tests, and try to allocate time to write tests for the core business logic of your existing code. It can be expensive, and might delay the introduction of new feature, but the stability and quality improvements will almost always outweigh the costs.
4. Repeatable Build
For a simple software product, sent to just a few customers, a build might be as simple as launching Visual Studio, Getting the latest source code, Performing a rebuild, zipping up the release folder, then copying to a shared folder for QA or the customer. Packaged software with an installer, help files, and multiple binaries can be much more complicated than this. In either case, you're going to want to automate this process as much as possible. Most importantly, you always want your unit tests to run AND PASS before the build makes it to the customer.
We use NAnt for build automation, but Microsoft now has a similar product called MSBuild with Visual Studio 2005. Either of these build systems are very powerful and can integrate with most source control systems. You will need to allocate time into your schedule to build and maintain a build script. For complicated projects, it might even require a dedicated resource.
Once the build is repeatable, you can setup a schedule to run it every night, or better yet use a continuous integration server. More on that later. If you've made it to this step, congratulations. I promise, if you're not doing this now it will be worth it as it can revolutionize your development. Without these 4 steps in-place, your company is at a serious disadvantage from your competitors.
5. An Agile Development Process
Some process is needed before any code is written. But if your team is just one or two developers, it might have been ad-hoc to this point. Ad-hoc is not going to cut it as your team grows. There are also non-agile processes such as CMMI. Generally this approach is divided into 3 even blocks of time. The first step is the design and spec writing. The second step is the coding, and the third step is the testing. This process can work, and some companies have had many successes with this approach, but it's very difficult to keep to a schedule when unexpected problems arise or when using new technology. An agile approach is more iterative. It enables a development team to make changes (such as removing low priority features) without impacting the schedule.
There are many resources on various forms of Agile Development. We have adopted a process called SCRUM at Atalasoft, and it has worked great. With SCRUM, we have a set of prioritized requirements that sometimes do change over a development cycle of many iterations called Sprints. At the beginning of each sprint, the highest priority items are estimated and allocated to the sprint. At the end of each sprint, we have a deliverable product that is presented to the management team. Because the iterations are short (generally a month or less) we know very soon if our time estimates are correct, and are able to adapt to a possibly slipping schedule by removing lower priority features. Requirements also can change during the development process but these requirements never impact the current sprint. This process has enabled us to release major versions of our product more than once a year.
6. Continuous Integration
The definition of Continuous Integration from it's best evangelist, Martin Fowler is:
Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly.
I suggest you read Martin Fowler's essay on Continuous Integration for a better understanding of the concept. We use CruiseControl.NET, developed by Fowler's company, for continuous integration. It's easy to setup, free, and fun to use. We can now be assured that our code-base is stable (or not) at any time of the day. Problems with the build are reported to the developers almost immediately, and usually can be fixed right away.
7. Static Code Analysis
Static Code Analysis is very useful at enforcing design patterns, catching performance problems, and finding other problems by analyzing the source code without executing the application. If you are using Visual Studio Team System, use the Code Analysis tools built-in. If not, FXCop is the same as the code analysis included in Team System, but without some Visual Studio integrations such as the ability to annotate your code to ignore exceptions.
8. Code Profiling
We use code profilers to help find performance issues, memory leaks, and other problems in our code by instrumenting executing code. AQTime from Automated QA makes a great product. Visual Studio Team System also has some profiling tools, but those tools do not profile unmanaged code. We've been able to quickly optimize our algorithms and code paths by running code profilers on our code-base to find bottlenecks.
9. Code Coverage
Code Coverage is great in determining what percentage of your code-base is unit tested. Visual Studio Team System has some good code coverage tools. We also use AQTime. Our goal is to achieve 85% coverage with any new code we write, but admittedly that is sometimes hard to obtain.