xmonad: a success for pure functional data and QuickCheck

So, after 2 months of activity:

From a whole bunch of developers, and unabated growth in the code base ..

;) Actually, unabated growth in comments in the code base:

xmonad 0.2 is released! Yay, a proper tiling window manager in Haskell, ready to use. It’s been a lot of fun working on this project, and I think it’s been a real success so far. We’ve been able to develop very quickly and apply good Haskell methodologies, such as strong typing, QuickCheck, and Neil’s cool `catch’ pattern verifier, to a real-world program.

In fact, it has been remarkable how several times that, after large refactoring and rewrites have taken place, once the code type checks and the QuickChecks pass, the application hums along as if nothing changed. We rewrote the entire core over a weekend a little while ago, and the code just worked. It was scary!

There are lessons here, I think, for `agile’ development. We spent a bit of time early on building up a large set of generic window manager properties, stated as QuickCheck predicates. Once this was in place, it gave us the confidence to try out experimental changes, because as long as the types check, and the QC properties hold, things seem to just work. Making code experiments safe really improves the development experience. You feel more comfortable playing with the code, and pushing it in unusual or radical directions. With strong types, and automated testing, you have the machine support to move the code faster and further..

We’ve been able to use a lot of automated testing because, although xmonad would appear to be a very eventful, imperative program — a window manager — it all runs on top of a purely functional core (the xmonad `zipper’ data structure). The imperative layer of the window manager — that part that talks to the X server — is just a skin over a referentially transparent core (which models the desktop state). And with such a core, we can do a lot of automated testing. The core window manager can be tested without even needing an X server (so we run automated tests on each darcs commit). Keep your code pure, so you can test harder, and the bugs will stay far away.

Another interesting point: once we found the right data structure — a zipper of workspaces (an xmonad workspace is a one hole context of a window list) — the code got far simpler (see the drop in the lines of code count around patch 300), the QC properties got stronger, and more invariants were determined statically by the data structure itself. Pick a data structure that embeds the semantics of the domain you’re modelling and your life will be easier.

I doubt we would have attempted such a radical experiment as the zipper rewrite, without the QC properties in place first — and for purely political reasons: with the QC tests it is easier to gain the trust of the other developers that the wacky idea of a complete rewrite, would be safe. Other devs need not trust you, they can look at the QC properties, and check for themselves that the code is ok. QuickCheck helps you win friends and influence people ;-).

So, I think xmonad is now a serious, highly usable tiling window manager. If you like dwm-style tiling, but need proper full screen, or Xinerama support (or just like hacking Haskell), xmonad is the logical choice, in this area. And weighing in at 1/40th the size of the Ion window manager is a bonus.

And now, thanks to Jason Creighton, xmonad supports a true floating layer per-workspace, as well:

The future looks pretty bright for xmonad, I think. Its remarkably stable, small and simple. And becoming quite well documented. You can now tile your windows, purely functionally!