For a few years I ran an open source simulator project, which was used for a number of competitions each year. This put some pretty strict deadlines on the project as not only did in need to be ready for the competitions, the participants had to have it pretty far in advance in order to adapt their code to work with the newer versions of the simulator. Here are some of the things I learnt along the way.

  1. Make your first release as soon as possible.

    It doesn't matter how many features need to be implemented or how many bugs there are. Get a
    version out there so other people can start playing with it and you can start building a community.

  2. Break you project into phases.

    Pretty much any project can benefit from being broken down into phases. You may have a whole heap of features you want in the final product, but not everyone in your community will need all those features, nor want to wait for all those features. Pick a small subset and make that the target of your first phase. Some projects (especially in the commercial world) like the big bang approach, and while it can be impressive when it works, more often than not the big bang results in a Big Bang and a whole heap of collateral damage (usually involving injuries the Project Manager and the development team, albeit usually at a political level, though that's never a guarantee).

    Also (as you'll see recommended further down) bug fixing only occurs when a phase is feature complete. If your phases are too big, then you community will suffer by having to put up with buggy software for a longer period of time.

  3. Tell people when you think the current phase will be feature complete.

    If people like your software, then they'll want to know when they can expect it to be ready. Ideally you want to under promise and over deliver, so make your estimates generous. Keep your community informed and keep updating your estimate. Let me stress that one, keep updating your estimate. No-one expects your estimate to be right, or even close to right, but as the phase progresses and you get closer and closer to being feature complete, the more and more accurate your estimate will become.

    Updating the estimate will give your community confidence. When they see each new estimate, they can get a feel for when they think you'll be ready (as opposed to when you think you'll be ready). For example, if they see at each update that the phase will be feature complete in another month, then they'll know that no progress is being made. If however you're reducing the estimate by 1 week every 4 weeks (e.g. in January you estimate it'll be ready in 8 weeks, then in Feb you estimate it'll be ready in 7 weeks), then even though you're running late, at least your community can extrapolate and figure out when they think you'll be ready.

  4. Automate the release process and make regular releases.

    As with all projects, unless you are really disciplined you'll be surprised at where all the time went. By releasing often you'll force yourself into making progress and have a greater chance of meeting the estimates you've. You'll also keep your community interested and attract more members because they can see the progress being made and can benefit regularly from new features.

    By automating as much of the release process as possible, regular releases become a real possibility and not just wistful thinking. If making a release is painful or a chore, then you'll avoid it to spend more time working on new features. The lack of releases will result in lost of contact with your community and the project could go off in a direction they are not interested in, or worse you could.

    In one of my projects, I could make a release and upload it to SourceForge by running four commands,
    make release
    cd foobar-1.3.4
    ./configure
    make upload

    This would run all the unit tests, tag the release in CVS, checkout the tagged version into a directory, cd into that directory, build all the source and binary distributions and then upload them to SourceForge. The most laborious part of the whole process, was actually going to SourceForge to claim the uploaded files and release them to the public.

  5. Pick meaningful version numbers.

    Version numbers should to mean something to the people using your software, this is especially important if you are making lots of releases. It doesn't matter what the version means, just so long it makes sense and there is some sort of constancy. Personally I prefer the triplet, X.Y.Z. X gets incremented for each phase of the project and Y and Z get set to zero. Y gets incremented for each release that has a new feature and Z gets set to 0. Z gets incremented for each release that fixes some bug. So, for a new project, I would start with 0.0.0, then 0.1.0, 0.2.0 … 0.12.0 until I'm feature complete. Then when I'm feature complete for the phase and working on bugs the version numbers would go to 0.12.1, 0.12.2 … 0.12.9, etc. Yeah, it's not as pretty as saying something is version 1.0, or 2.6, but at least my community can look at 3.6.0 and know that it's the 4th phase of the project, it has at least 6 new features over version 2.x and those new feature probably have a few bugs here and there.

    Some projects like to put a build number somewhere in there as well, in case the resulting binary is somehow corrupted during the build. In my mind the build code is part of the project code, so a bug in the build is a bug in the project. Thus the fixed build will have the third number in the triplet incremented.

  6. Automate you unit tests and run them often.

    Unit tests are a developer's GPS. They tell you if you are on course, heading for the rocks or going in circles. Each new piece of code has the potential to break some other piece of code. As you project gets bigger, testing each feature manually (and all the border conditions) will become too laborious and will not happen. This is when your project will start to head down the toilet as existing functionality that your community is used to (and possibly relying on) starts to break.

    Unit tests are good. Automated unit tests are better. There is no point having unit tests unless they are easy to run and are run regularly. You should be able run all your unit tests with a single simple command line or with a few clicks in your favourite IDE. Like releases, if running the unit tests becomes a chore, then you'll be less likely to do it. If this becomes the case then when you do eventually run them, you'll find you've broken a whole heap of tests and much of the work you've done since you last ran them has been in vain.

    In the project mentioned earlier, I could run all the unit tests by running make check
    That being said, one of the projects I'm currently working on is a WordPress theme and I'll admit I have no idea how I can even start to unit test it, let alone make it automated. I'm open to suggestions.

  7. Don't fix bugs until you are feature complete.

    This may seam strange at first and it will alienate some members of your community, but you don't want to fix bugs because fixing bugs will distract you from working on new features and push back your schedule. This becomes an issue of doing the greater good for your community. Do you fix a bug that affects 10% of your community, or add a new feature that affects 90% of your community? I recommend the latter.

    Part of the reason I recommend working on new features over bugs is that you have no idea what the code is going to look like when the phase is feature complete. You have no idea what bugs that are here today, may be gone or no longer relevant tomorrow. What's the point of spending time investigating and fixing a bug that would have been fixed by some refactor anyway? Keep you focus on new features and your schedule and make sure you have appropriate unit tests so that you can be confident that the completed features are actually working.

    I would even go as far as suggesting to be very careful about accepting bug fixes from your community during this stage of the project for the same reasons mentioned above. I've never seen a bug fix that was accompanied by a unit test, so to incorporate a bug fix, you need to create the unit test, merge the fix into your code (they don't always match the version you currently have) and possibly refactor the fix if it doesn't match your standards for code quality. A possible compromise would be to host the patch with the version it is for in your download section or in your bug tracker if its available online. When you are feature complete, if the bug fix still works and is still relevant, you can incorporate it then.

  8. Once you are feature complete, have a celebration. You deserve it :)

    You've been working hard on your project, releasing regularly, adding new features and trying to keep to your schedule. It's time to reward yourself for all that effort. Go out and have some fun. Take a break from the project for a couple of weeks; it'll still be there when you get back. You don't want to burn yourself out.

  9. Fix bugs and do nothing else.

    The phase is feature complete and now if the time to look at those pesky bugs. Don't be tempted to start on some of the next phase's features. If you have a good community then they will have been patient with minor bugs up until this point. Don't try to push the friendship. Fix the bugs and keep releasing often.

    You'll probably find you'll get bug reports through all sorts of channels such as email, forums, mailing-lists, SMS (how the hell did they get my number?), etc. None of these are any good for keeping track of bugs or their current status. Either use some sort of bug tracker (like the one on SourceForge or Bugzilla), an easily editable web page or even a file on your computer. It doesn't matter how you keep track of them, you just need somewhere where you can quickly find out what has and hasn't been fixed and how urgent you think each bug is.

    The best method I've found for fixing bugs and making sure they stay fixed is to create unit test or tests that reproduce the bug. Then you can go about fixing the bug until the unit tests pass. Not only does this give you confidence that the bug is fixed, it stops the same bug from reoccurring in some future release. For every bug, there should be at least one unit test.

  10. Make a stable release and have a large celebration. You deserve it :)

    I've never had a firm rule for when exactly to make a stable release, it's always down to a gut feel. Generally speaking, there should be no known bugs and the bug reports should have dried up. Make this release with as much fanfare as it deserves, go out and celebrate and revel in the fact that only a very small fraction of all software projects come even close to making it this far.

  11. Be amused by Murphy's law and a whole heap of new bugs.

    It doesn't matter how long you wait to make your stable release, it will always be followed by a fresh wave of bugs. That's just the way life is. Keep fixing defects and making regular releases until the bugs dry up again. At the same time you can start looking at the next phase. Just make sure you can easily fix bugs for phase 1 without having to include any phase 2 code.

Conclusion

You can't take any of these rules a gospel, some are more important than others and sometimes it's just not possible to apply some of these rules. Just use you common sense and apply them where you can and use them as a general guide, then your project will have a far greater chance of success.