Sunday, October 17, 2010

Mercurial is Good for You

Foreword: this story talks about our use of a Version Control System (VCS), and does not aim at presenting them. Therefore, if it's a new concept for you, you should read some documentation (and you should really do it, because one can't live without knowing it!).

Well, everyone in the team already knows SVN, but it seems that Distributed VCSs (Mercurial, Git...) are here to stay, baby. In other words, DVCSs seem to solve regular VCS problems, in a very effective and clean way. And as a proof, the amount of projects using DVCSs is always increasing.

So we'd decided to give Mercurial a try during the Impulse project. Since the project should test methods and workflows, we would see whether it is an appropriate tool, and whether we would keep it for further projects.

Spoiler alert: we are definitely going to keep it. Let's see why.

Our Mercurial architecture

A big difference between Mercurial and SVN is the meaning of repository. In SVN, a firm could have a single repository, or at best, one for each of its projects. And if the guys are good enough, they could use several branches within the repository. In Mercurial, a firm could have hundreds of repositories, because they act like branches. Mercurial still has the concept of branch inside repositories, but it's not a good way to use it. Whenever someone wants to create a new branch out of a repository, he has to clone it on his local computer. Once the changes are OK, he pushes the new repository into its parent, otherwise he may delete the repository (it's a simple directory). This philosophy may sounds a bit disappointing, but it is learned very quickly and is really worth it.

We spent hours to choose the architecture we would use. The main requirements were that:
  • It had to allow us to do code reviews and testing ;
  • It had to be lightweight.
Here is the result:

Our Mercurial architecture. The yellow boxes are repositories.
The principles are:
  • Each module has its own repository, namely dev-xxx. The Impulse project has three modules: engine, scene and game, so there are three repositories: dev-engine, dev-scene and dev-game.
  • Each developer may clone a repository on its computer, to code the module. It is shown as user-xxx on the above image. Since it is local to the developer, he may also use several clones... it is up to the developers.
  • Modules have their own unit tests. So code tests have to pass (i.e. yield only successes) before the user repositories to be pushed into the dev ones. A build server then tests again each push, because problems may appear (e.g. platform-compatibility, or missing files).
  • When a module is ready, it is pushed into the testing repository. In this repository, the QA tests the modules. Developers may code in this repository (mainly to fix bugs), but they should not add new features to the code.
  • When the game being tested is cool enough, we release it by pushing it into the stable repository.
You might see some similarity with Linux (at least Debian) distribution organizations. It's no accident: with this architecture, we can test the game, without releasing it, while development still continues.

Publishing code

Another main difference between Mercurial and SVN is the release of changes. In SVN, when someone commits some changes, it is instantaneously available to other developers. Therefore, we tend to commit only files in their final revisions, because we are afraid of committing them while still working on them. Sometimes with reason! - as the committing may break other people's work, thus making the telephone ring withing the minute! A better way is to develop in a branch, and then to merge it into the trunk. This is exactly the philosophy of Mercurial: committing changes and publishing them are two different actions. That way, we commit more often, thus making us able to keep track of more changes, even if they break compilation. This is indeed the real use of any versioning system.

Terminology in Mercurial.
Since everyone develops on its own computer, the changes may be committed into the local repositories, but they are only published whenever the developer wants, by pushing it into a dev-xxx repository. This is why the code in server repositories should always compile, and have quite stable features.

So far, our team isn't a firm. We are almost all students, either in France, Sweden or Germany. We develop on our computers, behind several proxies standing between us... But we believe that Mercurial's philosophy is particularly well suited for firms. Every computer should be accessible on a private LAN. Thus Alice could ask Bob about the changes she just made: Bob creates a clone of Alice's repository and can see the changes, while they are not published. He can even write some lines and push them back to Alice. This is an exciting workflow to test, as soon as we get into a firm :)
Bob clones Alice's repository and pushes into it back.
By chance, Alice and Bob work at the same firm.

Working with code reviews

I won't tell you again how fabulous the code reviews are. Just that I made a mistake recently. Well, nothing serious, thanks. But embarassing.

I requested a code review for some classes I had to write. But I also continued to develop them, locally. The bad thing came: developers made comments on my code. Well, the very bad thing came: I had to change some functions. So these changes were committed after that I committed new features. And a principle of the code review is that we may change some part of the code, but introduce no new feature. I failed.

Let's say that you have our architecture, i.e. a central repository, somewhere on a server, and a local clone of it. There are two ways - nearly the sames - to avoid this error:
  1. Create a clone of the parent repository, since it doesn't have the new features you introduced in your local repository.
    When you have to modify focused code, make your change in this new repository, commit the changes, and push it back into the parent. Indeed, this is the way our testing repository works. Since you no longer need the new repository, simply delete it. You will also have to pull the changes into your old repository to avoid multiple heads.
  2. Create a clone of your local repository when you request a code review, and continue development in this new repository while the code review focuses on the older ones.
    When you have to modify focused code, make your change in the old repository, commit the changes, push it into the parent, and here again, pull the changes into your new repository. When the code review is over, push the changes from your new repository into the older, and delete it.
Two ways to work with code reviews.
Of course, I didn't think about any of them. Awful.

Adopt Mercurial today

As pointed out by Joel Spolsky, changing from SVN to Mercurial is not so easy. They look the same, but they are not. It's a new philosophy to learn.

SVN works well, but it seems that Mercurial does better. So far, our project has shown it. As explained, Mercurial allow us to have a flexible repository architecture. The developers learned very quickly how to use it, since 10% of the commands are used 90% of the time. They are now used to coding with it, and everything works fine. Great idea to give Mercurial a try!

1 comment:

  1. Nice post ! Here is a useful website which helped me to switch from SVN to distributed DVCSs (in my case, git).

    http://hginit.com/

    ReplyDelete