This post is mostly thinking out loud about the dev processes we have or will have at TalentSpring.
Tools
- Source Control - We use Subversion
- Bug Database - We use Trac
- Documentation - We use a combination of rdoc inline code documentation and Trac's wiki.
- Planning / Schedule - Again, Trac.
- Deployment - Capistrano works great for this.
- Code Coverage - rcov in the RoR world.
Planning the Work
The first obvious thing is to figure out what you're working on. This isn't dev specific, everyone in the company (at least in a startup) should be involved in figuring what is needed, how to prioritize it, how it fits into the product and the user's needs, etc.
Feature Milestones
Once a feature is decided on, unless it is absolutely trivial the work should be done in a separate branch. Along with that is a milestone to coordinate the work, even by a single developer. In Trac we create a milestone and create tickets for work items and issues.
Those tickets should be detailed enough that once they are all resolved you should be ready to deploy the feature to the live site.
Branches
You gotta have source code control, and you gotta use branches.
Live Site Branch
In Subversion-land this is the 'trunk' branch. This should have the same contents as the production site at all times. There are only two things that should be checked in directly to this branch: ASAP bug fixes, and branch integrations. Once the checkin is done and verified it should be deployed to the live site to maintain the relationship that everything in trunk is on the live site and vice versa.
Working Branch
Each feature being worked on should have its own branch (in Trac usually under branches/featurename). This allows it to be developed on its own schedule, be delayed without affecting other features or bug fixes, and canceled without more problems than needed. It also allows people to try it out, test it, and iterate on it in isolation.
Bugfixing Branch
This branch (for us called branches/bugfixes) is created from the trunk and the purpose is to collect small fixes for bugs that occur on the live site (that is, that exist in the trunk branch) but are not high enough priority to warrant an ASAP fix. This branch should be integrated back into the trunk (and then deployed) on a regular, predictable heartbeat.
Iterating
Once the developer has a feature in a good enough state it should be used by other people in the company to find bugs, issues, and concerns early. These should be turned into bugs/tickets and assigned to the feature's milestone. The feature is then iterated on until all the tickets are resolved and everyone involved agrees that it is ready for the live site.
Automated Tests
Unit, functional, and integration tests serve multiple purposes in this world.
- Defense - When you write code you need to be worrying about not just getting it working correctly now, but how to keep it working in the future as you and others change code around it. By writing a solid set of automated tests and having everyone run them before they commit their own changes, you are protecting your code from future changes.
- Finishing Faster - The more tests you write that exercise code paths the more you can depend on things you've gotten working continuing to do so while you get the next thing up and running. You don't have to manually verify that what you just changed didn't cause problems with stuff you got working an hour ago.
- Compiler Substitute - We use Ruby on Rails, which is wonderful for development speed but awful in the same way that all interpreted and not compiled languages are: If your code is syntactically parse-able it is assumed to be correct until it runs. Having full code coverage is a must in this environment, because any code you can't verify that you've run is a ticking time bomb of bugs waiting to be discovered. You're using the tests as a replacement for the work that compiler checks do in other languages.
Finalizing
Integrating Into the Trunk
Now the contents of the feature branch are integrated back into the trunk branch. This may involve some resolution of conflicts between changes made for the feature and for other features or bug fixes. One way to mitigate this problem is to integrate changes from the trunk branch into the feature branch on a regular basis so they're in sync as much as possible.
Deploying
There's always risk that something won't work properly on the live site that does on a developer machine, so it is worth having a small environment set up that mirrors (although likely at a much smaller scale) the production one. Deploy there first and verify that the tests still pass and the feature works as expected.
Once you're confident that the feature is verified as best it can be without actual deployment, deploy it to the live servers and once again verify that things are working as expected. Monitor for a while afterward and be ready to rollback the deployment if something goes significantly wrong.
Fixing
Even then the likelihood of catching every problem and having no bugs once the feature goes live is low. As reports come in from customers or employees, they need to be triaged.
Regression Testing
A regression suite is a set of tests that verify a product has not regressed in functionality due to recent changes. We don't have such a thing, but we can actually do one better.
To make sure that the site doesn't regress (there's nothing more frustrating than seeing the same bug pop up over and over for whatever reason), create a unit, functional, or integration test (or more than one if the bug is complex) that reproduces the bug you're fixing. Once you've fixed it, the test should pass.
If someone later makes a change that would cause that bug to happen again, instead of that going live and a user rightly wondering why you can't seem to fix the bug for good, the test will fail and the developer who caused the failure will have to address it to pass the automated tests (which should be a requirement to checkin).
ASAP Bugs
These are bugs that are causing significant pain on the live site. The developer should drop whatever they're working on to fix it up immediately. This causes disruption to other work so it should only be done for bugs that really warrant that treatment. In a sense all bugs should be fixed "as soon as possible", these are the ones that need to be fixed immediately for the site to work right and the users to be happy.
Non-ASAP Bugs
Most bugs won't be that serious, and they need to be fixed in priority order. Set that priority and a heartbeat milestone, the higher priority bugs should be done before feature work and the lower ones after. The features should also have a priority to make that decision more straightforward, if a feature has a higher priority than all the known bugs it should be worked on first, etc.
Heartbeat Release Milestones
We have a milestone every week to integrate all the fixes in the bugfixes branch and deploys them live. It gives a nice rhythm of updates that everyone can count on, and you know that even if your fix didn't make it this week it should be ready for next.
Comments