Sucking Less: Checking In More Often
I'm fairly fearless when coding, which means that about once a week, I delete a huge chunk of something I should've kept, or change something into something unrecognizable, thereby inadvertently breaking a dozen unit tests. When I discover the problem, usually about 4 hours later, I no longer have any idea what I did that made the bad thing happen. Then I spend another 2 or 3 hours figuring out what I broke and fixing it. Ugly.
On my personal projects, I check in code every time I get a unit test working. My checkins are something like 15-20 minutes apart. On projects I get paid for, though, checking in means running the whole unit test suite, and that can take 10 minutes (on a good project) or 2 hours (on a bad one)--so I don't do it very often. That's when I get into trouble. I've been meaning to solve that problem for some time, and Joel Spolsky's blog topic last Wednesday (Joel on Software) finally kicked me in the pants. It took 15 minutes to solve the problem; here's how I did it.
The new breed of source code control systems, distributed systems like Git and Mercurial, have had my attention for awhile, as I usually work with a team that's spread out geographically. I regularly need to share code that's not quite ready to be delivered with another developer, and that developer is very likely in a different city. Typically we're reduced to emailing files to each other. A distributed SCC system would resolve this, as we could sync changes between our personal development repositories, but I assumed setting up and learning a new SCC would be painful, as it has been in the past, so I never got around to it. Joel's article on Mercurial, however, got me to thinking about it seriously, and since I had a few hours on my hands, I figured I'd give it a try. What I didn't expect was that I'd be up and functional in 10 minutes.
I
downloaded Mercurial and installed it on my main dev box, which is a
Windows laptop (I know, I suck). That took about 2 minutes, including
googling for the Mercurial web site (http://mercurial.selenic.com/).
Then I changed to the main development directory of my current project,
and typed (per Joel's tutorial at http://hginit.com/):
hg init
hg add
The first impressive thing is these commands 'just worked'. The second
is that's all that's required to set up a local repository and add an
entire project to it. Really. I'm so psyched!
The "add" command was naive, because it added everything,
including build output and subversion control directories (**/.svn/**).
I spent the next 10 minutes reverting my add, ("hg revert --all"), then building
an "ignore" file, then adding again, and finally committing. To
shorten your search (Mercurial has great documentation, by the way--it
only took me a few minutes to figure this stuff out), here's what I
ended up doing.
1. I created an .hhrc file in my home directory (C:\Documents and
Settings\Jerry) with the following content:
[ui]
username=jerry
editor=C:/bin/vim/vim71/gvim
The "username" entry preempts a request by the "commit" command for a
username, and I prefer vi to the default editor, which is notepad.
2. In the root of my project directory, I created a .hgignore file with
the following content:
syntax: glob
.svn
*.class
*.log
.hgignore
antbuild/*
build.properties
This tells Mercurial to ignore all files or directories named .svn
(which is where subversion stores its status), all .class and .log
files, the .hgignore file itself, the build.properties file, and
anything in the antbuild directory (or its subdirectories). Mercurial
ignore files support at least 3 different syntaxes for specifying files;
the documentation is available on the Mercurial wiki and it's quite
complete.
Finally:
hg add
hg commit
Now I'm in a position to check in locally every few minutes, but when I
have a small feature complete, I can deliver via svn to the project's
repository. That's right: I'm using Mercurial locally, and SVN for the
project.
On my next project, I hope to have a chance to specify that the whole
team uses Mercurial for the whole project; working with another
programmer who's not physically nearby just got a whole lot easier; we
can exchange our updates directly with Mercurial, then push them up to a
central repository independently. Sweet!
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)





Comments
Ricky Clarkson replied on Mon, 2010/03/22 - 7:52am
Josh Marotti replied on Mon, 2010/03/22 - 11:55am
10 minutes -> 2 hours to run unit tests? Why is it taking so long? Sounds like you are running integration tests (hitting the db, going through multiple layers of code, need an app-server loaded, etc?).
I've had over 250 unit tests that ran under 10 seconds.
So if you are working on a piece of, say, the business layer, you should be able to just run the business layer unit tests, everything passes, and push the code in. If it breaks anything else, there is a missing unit test for that layer that you will need to add.
The point of unit tests are quick feedback. If it takes more than 20 seconds, it isn't something that will be run by developers quickly which will lead to problems like what you are seeing!
Jay Spring replied on Mon, 2010/03/22 - 2:32pm
Ricky Clarkson replied on Mon, 2010/03/22 - 11:53pm
Konstantin Scheglov replied on Tue, 2010/03/23 - 2:52pm
in response to:
Josh Marotti
Problem is that your users don't care about your unit tests, they want to see that at their level all things work. So, you should run high level tests - call them as you want - integration or functional, I don't care about names.
So, while you can run unit tests to see if something is broken, you still have to run high level tests to have some confidence that at user level things still work as before, plus new implemented features.
Allen Geer replied on Tue, 2010/03/23 - 10:02pm
County Line Nissan replied on Mon, 2011/08/01 - 11:08am
Nabeel Manara replied on Fri, 2012/01/27 - 9:06am