« October 2005 | Main | December 2005 »

November 25, 2005

Ruby on Rails: 100,000 morons can't be wrong

Listen to this articleListen to this article

So I have to admit that not only am I a cardpod-carrying member of the apple cult, but lately I've been dabbling in a bit of voodoRuby-on-Rails as well and so-far, me likey. I think it's one of those tools that people will either get or not. If they do, it'll be fantastic; if not...

Rather than give you my personal take on this, I thought I'd take a slightly different approach and get in touch with one of my inner-morons for a more balanced perspective.

Ahem...

I'd like to start by saying outright that I think RoR will be a good fit for most large corporate development shops. I can see it delivering 20x, 30x maybe even 50x improvements in efficiency however I do see some short-comings, probably due to it's relative immaturity when compared with Java.

If you look at most of the projects that are using Rails and Ruby at the moment, the code-base consists of dozens, maybe hundreds or possibly even a few thousand lines-of-code at most; Certainly nothing that compares to the size of projects we are used to working on which are in the order of tens if not hundreds-of-thousands of lines-of-code. But fear not, we have a plan to ensure it's readiness for enterprise use.

We have two choices: develop applications and components on an as-needs basis; or try to build some common infrastructure that all projects can use.

The first option sounds dangerous as it will no doubt lead to everyone doing it slightly differently which in turn leads to lots of unnecessary duplication of effort. So as part of the next project, we plan to produce a framework (Ruts?) that will sit on top of RoR upon which all the teams can build. This way we will have better management and control over the infrastructure.

We'll start by checking the source code for Ruby and Rails into our repository so we can patch them whenever we need to. This means we don't have to wait for patches to become available in production versions. It also has the added benefit that when the API's change our code won't need to be re-factored as a consequence. Isn't open-source great!

Next we'll address configuration. There really needs to be a way to place all the configuration in XML files. XML is, after all, THE standard; we've been using XML successfully in Java for years and everyone understand it. We'll start with database connection details, then move on to other areas. One area of particular interest will be database schema generation. At the moment Rails only supports coding the SQL directly. Unfortunately this doesn't allow us to write database agnostic DDL; enter XML. If we create an XML-based language for defining the schema, we can then generate the SQL for each desired database; heck we can also generate the appropriate Rails model classes as well including relationships, etc.

We'll also need clustering—every enterprise application needs clustering. To this end we'll extend rails—we have the source—to support transparent clustering by sending session state to a master controller server that will then send it to all the nodes in the cluster. This will require serialisation and class version management which ruby already has built-in.

We see other improvements in efficiency in terms of testing. We find that due to the very slow turn-around time of Java web applications, our developers spend a great deal of their time writing tests. Rails on-the-other-hand has such a quick development cycle time that we can dispense with much of the automated testing in favour of manual testing.

Having said that, we have noticed that each time the database schema or configuration changes we have to stop and start the server so we will also include an extension to Rails that looks for changes in the configuration and automatically refreshes rails. Again, once implemented in the framework, each project will benefit.

Another limitation in Rails is the MVC implementation. Again, it's pretty good but it could still be improved. We've known through years of experience now that trying to put all that code into one controller class just doesn't work. Instead we will create command objects, wired together using XML and a generic AbstractController that will read the configuration file and work out what to do. This will be much simpler and we envisage huge time savings as a result.

Also the active-record stuff might be a good starting-point but it will need to be enhanced a bit for real enterpise applications. For a start, what it needs are DAO's, one for each table in the database. Again a few classes in this respect would do wonders for productivity. We might even write some code that could generate DAO's from the schema XML configuration discussed earlier.

Come to think of it, if we had some kind of container, then it could manage all this for us and more including transaction management, dependency injection based off an XML file, etc.

We've also been looking at the query language. It's pretty good but it's not very rich and it's basically just SQL injected into your source. What Rails really needs is some kind of Object Query Language along the lines of hibernate. In fact, because hibernate is open-source, we might want to consider replacing active-record with a hibernate re-write (Rhibernate?)

So, as you can see, with a few little tweaks here and there, Ruby-on-Rails might just be what we need to get our enterprise development teams moving towards Web 2.0. We just need to work out how to get Rational Rose and ClearQuest integrated to generate all the code for us and we're set to go.

November 15, 2005

Thank-God for Wireless

Listen to this articleListen to this article

When I arrived home I realised I didn't have my keys with me and my brother had (selfishly I might add) gone out somewhere. But, thanks to the wonders of modern technology here I am, sitting on the steps of my apartment building, chatting on IM, checking my email, reading RSS feeds and of course, authoring a blog entry.

What else would a geek do under the circumstances I ask?! ;-)

November 06, 2005

Mocking my Visitors

Listen to this articleListen to this article

I mentioned in a comment earlier this week that I like Builders as they allow me to separate out the ickyness involved with construction from my nice pristine objects. Besides anything else, it allows me to layer on functionality: first implement the domain objects, assembled by hand for testing purposes; then create another layer—the builder—that will automate the construction process.

Of course being the good little TDD weenie that I aspire to be, at some point I want to test that the builders are generating the correct structure.

IMHO, the utterly evil-broken-and-wrong approach is to expose all the properties on all the nodes in the graph—I use the terms node and graph generically here to refer to objects related in some fashion—for reasons I've harped on about more than enough.

Another approach—that maintains encapsulation—is to implement equals() for all the nodes in the graph. The idea for testing then is to create the expected structure by hand (just as I had already been doing) then use the builder to create another and assert that the two are identical. I have actually used this approach before and while it worked just fine, it never really felt Good™. I'm not sure why; just an intuitive ookyness.

More recently though I tried a different approach: using a visitor. Again the approach was similar: constructed the expected structure by hand; then use the builder to make another; and finally assert that the two are identical. This time however, the idea was to traverse the expected structure and match, node-for-node, with the actual. The neat thing about this approach though was that because my visitor class was an interface, it was trivial to use EasyMock to do all the grunt-work for me. (EasyMock also allows mocking classes however I still prefer interfaces.)

The idea is to create a mock visitor using EasyMock and pass that to the accept() method of the structure I had created by hand to set-up the expectation. Once that was done, I could then simply pass the same mock to the accept() method of the structure constructed by the builder:

public void testBuilderMakesIdenticalStructureToOneBuiltByHand() {
    // Create the two structures
    Node createdByHand = createByHand();
    Node createdByBuilder = createByBuilder();

    // Visit the one created by hand to set-up the expectations
    NodeVisitor visitor = EasyMock.createStrictMock(NodeVisitor.class);
    createdByHand.accept(visitor);
    EasyMock.replay(visitor);

    // Visit the one created by the builder to verify
    createdByBuilder.accept(visitor);
    EasyMock.verify(visitor);
}

private Node createByHand() {...}

private Node createByBuilder {...}

Note: I'm using the latest version of EasyMock that supporst JDK 1.5 generics however I'm not (nor will I ever be) using static imports as suggested in the documentation!

This time, it felt Good™. I could use the same visitor for testing, reporting and persistence, all without the need to break encapsulation.

Now while I'm really not keen on igniting a religious flame-war over mock objects in general nor mock object libraries in particular, the fact that EasyMock works against the real interfaces—as opposed to using string descriptions ala JMock— was a huge advantage in this case.

November 03, 2005

Sufferin' Sukertash

Listen to this articleListen to this article

Wouldn't you know it! A week after The Book leaves the warehouse, I find a mistake in the very first figure! I'll never criticise another book EVER again. Ok, I'll criticise the book but not the author(s).

Thankfully there's an errata page; not that I've ever visited one for a book that I've bought mind you but still, it's somewhat comforting to know.

What's particularly amusing is that the first error submitted was by me, a co-author LOL.

November 02, 2005

Constraining Design in Search of Elegance

Listen to this articleListen to this article

Rather than play with the latest shiny new framework, language, etc. my vice is continually trying new and/or whacky—for me at least— programming/design techniques. To be fair, I don't tend to thrust these upon unsuspecting clients as the new way of doing things. Rather, I'll start a new pet project of some kind and try to push the paradigm as far as possible and see where it—or I—break down.

Most of the time these "techniques" manifest themselves as a set of constraints or rules for coding; something akin to a manual Checkstyle or PMD for design rather than coding conventions. So just like constraining method lengths and Cyclomatic complexity help shape a design by forcing me to actually think about what I'm trying to achieve, I like to play with other types of constraints.

For example, James and I had a go at 100% TDD for a Swing application many, many moons ago. Again not so much because we think 100% TDD is necessarily a good (or bad) thing but more in attempt to push the idea as far as possible, just to see how it and we would react under pressure so to speak. The results were actually very interesting and made me want to find someone prepared to pay me money to build a rich-client application (Not using Eclipse RCP!)

After I started doing some Objective-C some months back, I was forced to deal with the fact that there was no such thing as a private method—everything in Objective-C is effectively public. I then started to think about what it might be like to apply the same thing to my Java code; what if I was forced to make every method public? How would that affect my design.

Interestingly it had a largely positive effect: I started making smaller classes with well defined behaviour that made sense to be public. In a way, I was forced to make my class behaviour more cohesive. The problem was of course that, as with anything that is approached in such a strict and unforgiving manner, there are times when it just makes more sense to have a private method that can be re-used or more often, helps to make the code more readable.

So for the most part, I was happy with the outcome: assuming behaviour is public yet not wishing to expose all of that behaviour forces me to compose large classes from smaller ones thereby hiding "private" implementation detail in public methods on other, re-usable, classes.

More recently I decided to try a couple of other things out on a project. These were:

  • No if's;
  • No casting to expose "conditional" behaviour; and
  • No getters & setters—i.e. tell don't ask.

Nothing special here really, but I wanted to see how far I could push the ideas and what effect that had on my design and productivity.

The first—no if's— is relatively simple to address through the use of polymorphism and Maps as jump-vector tables; techniques most people probably use anyway.

The second—No casting to expose "conditional" behaviour—is a little harder. To completely eradicate. Firstly, I was using Java 5 with "generics" to remove the need to cast items in collections—although if you're not careful, the code can get quite messy with all the "devils horns"—however, the real problem comes when you have a group of classes all related via an interface where some of the implementations provide certain behaviour and others don't. This was most noticeable when implementing anything that resembled a Composite Pattern.

Enter the Courtesy Implementation. In every case where I ended up needing to implement a method that didn't "make sense" it would have been a programmatic error to have called the method on an instance of that particular class anyway so I simply threw an UnsupportedOperationException. At this point I wished that would happen by default; that by implementing an interface you could somehow say you weren't going to support certain methods. A pretty stupid thing to want really, given I'm working in a strictly-typed language.

And finally, tell don't ask. The code—comprising 50 main classes and slightly fewer test classes (tsk tsk)—has zero (0) getters and setters. Admittedly I wasn't implementing a CRUD application so that made things easier but there were times when I thought I would need a getter but managed to get around that need quite elegantly (IMHO) through diligent use of simple call-backs (no real closures in Java unfortunately); more complex Visitors; implementing Comparable; etc. In other words, lots of interfaces.

One thing that did arise though was the constant fight against cyclic-dependencies. One example where this is particularly obvious is with visitor. The "standard" way to write a visitor is something along the lines of:

public interface Visitor {
    public void visitX(X x);
    public void visitY(Y y);
}

public class X {
    public void accept(Visitor visitor) {...}
}

public class Y {
    public void accept(Visitor visitor) {...}
}

The problem with this is that the Visitor depends on X and Y yet the classes X and Y both depend on Visitor: cyclic dependence.

Interestingly, the "usual" way to implement the visitor would probably look something like this:

public class PrintingVisitor implements Visitor {
    public void visitX(X x) {
        out.println("X:" + x.getName());
    }

    public void visitY(Y y) {
        out.println("Y: " + y.getTotal());
    }
}

But recall that I had imposed the constraint of no getters so instead re-worked it like this:

public interface Visitor {
    public void visitX(String name);
    public void visitY(int total);
}

public class PrintingVisitor implements Visitor {
    public void visitX(String name) {
        out.println("X:" + name);
    }

    public void visitY(int total) {
        out.println("Y: " + total);
    }
}

Like anything, this is open to abuse, but there are no longer any cyclic dependencies and the only time the guts of X and Y are exposed is when calling on the visitor.

The example just shown is very simple and won't work in all cases of course but it does highlight how a bit of extra thinking can lead to interesting, and hopefully richer and more useful, designs; the constraints I had imposed seemed to force me to think more about the behaviour and less about the data. For some of you freaks who find that very easy to do I'm very happy, but for mere mortals such as myself, having a few rules-of-thumb to know when I'm being "dumb" makes life that much easier.

Another really interesting thing for me in all of this is that statically-typed languages such as Java force me to make all my interfaces explicit. That is, I need to create physical interfaces so as to remove the cyclic-dependencies between concrete classes. However, with languages such as Ruby, Smalltalk etc, the interfaces are implicit. In a sense, Ruby and Smalltalk allow me to define interfaces at the method level; a much smaller level of granularity than is practical with Java. When I asked a old smalltalker friend of mine about how he would have dealt with cyclic-dependencies, he replied "we never worried about it; if the object responded to a message that's all that mattered." I repeated this answer to another non-smalltalk friend of mine to which he mused "and they probably created a lot of spaghetti!"

So, while many people are clamouring for more-and-more functionality from their programming language, API's etc. I think sometimes I'd actually prefer less; so long as long as it's the right set of course ;-)