Hiding XSLT Tag Soup

The ever-interesting Jeff Atwood correctly points out that many frameworks force you to create tag soup – a horrible mess of executable code and HTML markup. Commenters suggest a number of solutions but none are really satisfying.

Our in-house framework started back in the bad old days with Java emitting HTML directly – surely the worst of all worlds. We figured out early on that it was better to create XML first, and transform with XSLT; for instance, this reduced the pain of generating reports from our screens, since we can transform the XML to flat files and PDFs.

However, even XSLT can be pretty soupy:

  <xsl:when test="@current">
    <b><xsl:value-of select="@number"/></b>
    <span style="cursor: hand;">
      <xsl:attribute name="onClick">
        <xsl:value-of select="@number"/>
      <u><xsl:value-of select="@number"/></u>

This implements page numbers with links to all but the current page, similar to Google’s Goooooooooogle:
1 2 3 4
Not only do we have lots of XSLT logic with smatterings of HTML thrown in, we even have some inline JavaScript at lines 8-10, which is code inside markup inside code!

We could clean up this particular example but it’s way too easy to create a mess like this. So we’ve gradually introduced more and more generic templates that take XML of a certain form and produce the corresponding HTML – including all the messy bits like JavaScript. For instance, here’s how we render a table of data with headings, column selection, and sorting:

<xsl:call-template name="chunk-multiple">
  <xsl:with-param name="node" select="data/content/section/dataset[@name='TABLE']"/>

Yes, it’s cheating because the template code is still tasty tag gumbo. But we have only a few templates, and we can concentrate on making them as readable as possible with comments and careful layout, while each individual application screen is defined in just one language – XSLT.

There’s a lot more cleaning up we could do with templates for our buttons and forms, but at least it’s more broth than chowder. Bon appétit!

My New Favorite Extreme OO Rule

Two code dojos ago, we tried using three Object Calisthenics rules (aka “Extreme OO” rules) in our kata exercise. The “Object Calisthenics” essay was published in The Thoughtworks Anthology. Since then, I have checked out the anthology from the YD library. After reading the original essay, I decided to apply these rules to the refactoring that I was doing.

The rule that stuck with me the most this time around was:

8. Use first-class collections. In other words, any class that contains a collection should contain no other member variables. The idea is an extension of primitive obsession. If you need a class that’s a subsumes the collection, then write it that way.

I had a class that I was refactoring (mostly for clarity) that among other things held a cache of data. For simplicity sake, let’s say the cache was held in a Map<Foo, Bar>. The class then went on to get, put, iterate, and remove from that map.

So, I applied Rule #8 and created a FooBarLookup class that encapsulated the Map<Foo, Bar>. I then had the freedom to only add the methods to it that I needed like Bar get(foo) and void add(Foo, Bar).

The most important thing that I realized is that I could abstract more powerful methods. For example, when I was done with a given Bar, I removed it from the FooBarLookup. In this Map, I had many Foo‘s mapping to the same Bar. So, previously, I had wrote code that iterated through the Map.entrySet() and removed entries that had matching Bar‘s. Now, I could now hide this iteration in a new method on FooBarLookup: boolean remove(Bar).

Big whoop, you say.

Well, one nice thing about this encapsulation is if I decided later that I needed to speed up this new remove(Bar) method, I could maybe add a Multimap reverse lookup to feed the keys to remove into the main Map. Then, I can manage the bidirectional map setup with the same add(Foo, Bar) method that I had defined before.

This new FooBarLookup class also gave me the ability to write some high-order-function-esque methods that map or filter the Foo‘s and Bar‘s in the Lookup. Happily, all of this iteration noise is hidden inside the encapsulated collection, and away from my business logic.

ICFP Contest 2008

This year’s ICFP programming contest was this past weekend. This year’s contest was to write a program to control a simulated Mars rover and get it to its home base. While avoiding Martians. 🙂

Before the contest, we (my ‘team’) were planning on working in D. A mate of mine had wanted an excuse to learn it, and he figured since in past contests we had to drop back into C for various things, we should use something closer to the metal. But when it came time for the contest, he flaked out, so I went with Python. It’s kind of my default if-all-else-is-equal thing, as it makes life easy.

I got off to a bit of a slow start – couldn’t get their test server running on my machine. After tinkering with video drivers and setting up a quick hack to just send ‘forward’ commands, I had my little rover running quickly into craters. Progress! To be fair to the organizers, they had a LiveCD in which everything ran fine. But I wanted to develop in my environment, and I was having trouble running it in VMWare on my really-in-need-of-replacing home laptop.

Then came the hours (late Friday night my time) of trying to remember math I hadn’t really needed to use in a decade. TDD was really nice when it came to the “get the angle I need to be aimed at to get home” bit – I could come up with test cases where I knew the answer, but I kept messing up the formula (you shouldn’t code while sleepy). But at least I knew when I was done.

I had the basics working ok on Saturday, but then I migraine took me out for a bit, and a bunch of stuff came up on Sunday, and by Monday I just needed a break. Oh well, there’s always next year. 🙂

I didn’t have quite as much fun with it as past years. Mostly because the people I was going to work on it with didn’t have time. But also there were a lot of details that you needed to get under control but which didn’t really excite me. I think about the point I read the bit about needed to change TCP/IP settings to get it to run fast enough I started getting a sinking feeling about it all. Didn’t have the same completely-unlike-my-normal routine that past ones did. Also, the past few years had a way to upload things as you went along and see how you were doing on a scoreboard. I can understand why they didn’t this year (they are going to have a tournament at the end), but I think having a scoreboard of how teams were doing against some hidden, fixed set of maps would have been a lot of fun and more motivating.

Not that I didn’t have any fun with it. It was fun to see the little guy go. The visualization was a nice touch. In past years, I’ve often wanted some sort of visualization, but it always fell lower in the priority list than other things and never got done. It’s very motivating to *see* things.

I also loved that it got me doing things I don’t normally do, remembering things I haven’t used in a while. And I look forward to reading the write-ups. I often learn new-to-me data structures and algorithms (like Ropes), which is really one of my favorite parts.

Extreme Ironing in Visual Basic

Extreme ironing looks like fun: take an ordinary activity and do it in strange places or under strange conditions or both.

I felt a bit like an extreme ironist this week as I wrote a plugin for Excel in Visual Basic, surely one of the more unit-test-unfriendly languages out there. I’ve sworn never to write code without a unit test again, but how the heck am I supposed to write test-first when the language is designed for accidental programmers who don’t know what an object is, much less a unit test?

Yes, there is VBAUnit but it looks abandoned. You can forget about mocking or refactoring, of course.

I did find it was possible to write working unit tests for each of my non-interactive procedures once I embraced the notion of using Excel itself as the interface. The outputs go into cells and Excel formulas check whether they match the expected values. The plugin generates random strings so there’s a simple randomness check for a roughly even distribution – hardly the Diehard tests but it works.

There’s one procedure (I guess it’s called a SUB procedure in the VBA world) that I can’t test from within Excel, because it’s the one that actually opens forms and interacts with the user. If this were a commercial product, I’d use WinRunner to simulate a user clicking and typing data, or try to find an open-source alternative, but since we’re just using the plugin internally I’m happy with a manual test carefully documented in one of the Excel sheets.

I don’t think I’m going to be adopting VBA programming (or extreme ironing!) as a hobby anytime soon, but it was a fun experiment – a little like our last code dojo, where we imposed some severe restrictions to see how far we could push ourselves.

Happy ironing!

Crazy guy dangles from rope over canyon while happily ironing

Crazy guy dangles from rope over canyon while happily ironing