I’ve talked about this a couple of times when asked what recommendation I’d give to people starting to release their own software, but a quick search of my site seems to indicate I never actually blogged this. I’m going to postulate something that will seem utterly nuts and over-engineered to some. But it’s true:
Even Solo Developers should use version control.
Marcus Zarra started a great saying that has become commonly accepted among programmers (I’ve mentioned it in my previous posting): You always program as a group of three programmers: Past You, who is a moron, Present You, who is average, and Future You, who is a genius. While this is generally used as a rationale to write readable, self-documenting code and detailed comments instead of just assuming you’ll remember what you were thinking a month ago in two years when you get back to this code, it also helps explain why you need version control.
What is Version Control?
There are many version control systems, or VCSes: Subversion is a well-known one, as are Perforce and SourceSafe, and others popular these days are Git, Bazaar and Mercurial. There also used to be one called CVS, which was kind of the great-granddaddy of most systems used today. They all have a general principle in common:
- There is a repository in which you put your code, and that keeps track of every new version of a file, and lets you rewind to any previous version of a single file or the whole project.
- You specify small explanation messages whenever you add a new version of your project to the repository (called “committing” the changes), so you can later go through the code and see what a particular change was for.
- They handle access by multiple users and make it easy to merge changes to the same file by two users without one user’s changes accidentally overwriting the other.
What does version control get me?
An Additional Backup
As software developers, our most important asset is usually our source code. If we lose that, we can close our shop. Since most version control systems keep the repository on a separate machine, usually a server (either a Mac mini in your cupboard, or one hosted on Versionshelf or a similar service on the ‘net), one thing you get is an additional backup. You can never have too many backups of your most important asset.
Even if you just install the server software on your work Mac or use one of the distributed version control systems like Bazaar and keep the repository on your local hard disk, you still get the version history. Now why would you need to be able to go back to an older version of your application? One word: Bugs.
Face it, software has bugs. And the insidious part about bugs is that they don’t always show right away. You may have released new versions for over a year, and suddenly you find that an old version of your app did something just fine, but the one you have now does it wrong. With version control, you can just get the old version of your application out of the repository. Even better: You can let the version control system show you the differences between the code of these two versions. Just for one file, or for all files.
Yes, you could just duplicate your code folder in Finder when you release a version, but not only does that use a lot of disk space (version control only remembers the bits that actually changed, so is much more efficient), but since you label each change with a commit message, you can keep a copy of much smaller sets of changes. There’s not just one for each version you released, there is one for pretty much each work session, or each small bug in your list of bugs. That makes it much easier to isolate the changes to that particular feature that broke a year ago from the hundreds of other changes to unrelated files.
Freedom to Radically Change your Code
Since you always have a backup of your working code, you can easily experiment with your code. If the experiment doesn’t work out, just don’t commit it to the repository. Or if you already committed it, you can simply copy the working code from an older version of that file and use it to replace the experimental code to get back to a working application.
Also, since version control keeps track of individual changes, you can do experiments “on the side”. Not sure whether you can pull off porting your old Carbon application to Cocoa? You can tell the version control to make a copy of everything (remember, copies in version control are cheap, as version control only keeps track of changes, and a copy is 100% identical to the original, just in a different spot). Then you can start porting this copy to Cocoa. The original is still Carbon, and you can make releases from the original copy. Once the Cocoa-version is finished, you just tell your version control program to “merge” the changes made to the copy into the original.
Version control knows the exact lines that changed, so it can often automatically insert all the changes in the right spots of the original. You’ll manually need to adjust some spots, e.g. where you added a new Carbon window that the new version didn’t have, or where you changed the same line both in the original and in the copy after the copy was made, and that’s it. You have been able to simultaneously pull off a huge change to your application, while still releasing new updates. Your users don’t even notice how involved it was to replace the entire UI.
This technique of making an experimental copy and editing that, then reintegrating it, is called making a “branch”, as the single change history suddenly branches out into two separate lines until it is merged back in again. The same technique can be used for other big changes. Writing a version 2.0? Find a bug in 1.9 that needs to be fixed ASAP? Retroactively create a branch that goes off at the point where 1.9 was released, and fix the bug there, and release it, without having to deactivate, test and debug a lot of new code you added for 2.0.
Documentation for Obscure/Contradictory Bug Fixes
Sometimes, a bug is kind of obscure or incomprehensible, and by fixing it, you inadvertently break something else. Version control can not only show you each line that changed, but it can even show you an annotated version of any source file, mentioning who changed what, where, and what commit message it contained. So, if you find a spot where you need to change a time-out parameter on a function call, and you wonder why it is so insanely high, you can look at the commit message and see that there’s some bug in some router hardware that causes timeouts to return 10 seconds early, about which you’d completely forgotten since you fixed this a year ago.
Now, this can be the last line left over from that fix, you can have accidentally deleted the comment in the source file that said the same thing. Still, version control doesn’t forget. It still knows that this single line is left over from that fix. So you dig out that router, and make sure that your new fix doesn’t break this old one.
Safe Collaboration in a Team
Ages ago, I did web site backend programming together with a CSS guy. We had no version control. Since the source code generated parts of the HTML, the CSS maven would often have to drop into the source code files and change the id or class of this or that element, or add other design-related attributes directly to the HTML to work around omissions in the CSS implementation of certain browsers. Sometimes I added something new and needed to quickly add some simple CSS to be able to see whether my code worked. Every time one of us made such a change to the other’s files, he had to call across the room and ask if he “could have listgenerator.cgi” or whatever.
Sometimes one of us forgot. What happened then was that one would download the file from the development server and start work on his changes. Meanwhile, the other would download the same file, make a change and upload it back to the server again. Then the first would be finished and upload his changed version again, which didn’t have the newest changes, because he’d downloaded it earlier, and suddenly some changes were gone.
This couldn’t have happened with version control. Whenever you commit changes to a file, your version control program checks whether the version on the server is still the same as the one you downloaded when you made the change. If it isn’t, it will complain and offer to merge your changes. Once it has done that, you make sure everything went well, and then commit again.
That last example shows us the main philosophy behind version control: Never lose any data. In fact, in most version control systems, it is impossible to delete a file. You see, you can delete a file on your disk and commit, and that will make it not show up in the newest revision, but since all older revisions on the server still contain that file, you can always rewind to get the file back.
But then, that’s exactly the point of version control: You want to be able to go back to any version of your project, undo any change, no matter whether it is adding text to a file, or actually deleting it.
I hope my incessant rambling has helped those of you who were unaware of the necessity that is version control. As a programmer who ships software to others (particularly paid software), you simply can’t afford to trust your important code and your livelihood to your ability to remember to make copies of a folder and slowly burn them to DVDs. I don’t care what system you use, just use one.