Posts Tagged ‘Agile’

Groovy Builders: A Pair Programming Experience

Tuesday, June 17th, 2008

So I’ve been meaning to write up a post on my experience with Groovy’s Builder support.  Rather than actually do this though, I thought it would be more insightful to enclose the transcript from my latest Pair Programming session, which revolved around writing a custom Groovy Builder and integrating it into our application.

Let’s have a look, shall we?

—————————————–

me: Ready for another day of Pair Programming, Doug?

doug: Ugh. Yeah, sure. Did you think about how to address our DSL design issue since our last session?

me: Um.  Yeah, I totally did…  What is the design issue again?

doug: Good grief, we go over this every morning!  It’s our job to take all of the line item budget data, organize it by department and produce a budget book.  The budget book is made up of Book Sections.  Book Sections contain other Book Sections and Page Elements. Book Sections map to Departments, while Page Elements map to budget line items.  So it’s our task to map from one structure, a list of departments with budget data, to another structure, a list of book sections with page elements.

me: Oh right, of course.  I remember now.

doug: So,  I’m afraid to ask, did you come up with any ideas?

me: Sure did!

doug: Great, let’s hear them.

me:  Um. You first.

doug: That’s a big surprise.  Ok, I’ve been reading up on Groovy Builders and-

me: I was thinking Groovy Builders too–I just forgot that I had thought of that until you just said it now.

doug:  I’m sure.  Anyway, thanks to Groovy’s closure and dynamic method support, notably pretended methods, it has this very useful Builder pattern.

me: Right, I know all of this already.

doug:  Really?  By all means, please take it from here.

me: …um…interface…implements…er…class…abstract–

doug: Are you just stuttering keywords again?  Honestly, how did you even get this job? Ok, so let’s take the use case where we already have the organizational hierarchy loaded up.  Remember, Departments are made up of Organizations, which are made up of Bureaus, and bureaus have budget line items. So it looks like this (takes the keyboard):

class Department {
  List<Organization> orgs;
}
class Organization {
  List<Bureau> bureaus;
}
class Bureau {
  List<BudgetLine> budgetLines;
}
class BudgetLine {
  long amountRequested;
  long amountApproved;
 ...
}

So we need to map this hierarchical structure to the BookSection and PageElement world.

class BookSection {
  String name;
  Style style;
  List<BookSection> subsections;
  List<PageElement> pageElements;
}
class PageElement {
  String content;
}

So each Department/Org/Bureau needs to map to a BookSection, and each BudgetLine maps to a PageElement, and we need to preserve the structure.  Using Java we could do something like:

BookSection rootSection = new BookSection("root");
for (Department dept : departments) {
  BookSection deptSection = new BookSection(dept.getName());
  rootSection.add(deptSection);
  for (Organization org : dept.getOrganizations()) {
    BookSection orgSection = new BookSection(org.getName());   

    deptSection.add(orgSection);
    for (Bureau b : org.getBureaus()) {
      BookSection bureauSection = new BookSection(bureau.getName());   

      orgSection.add(bureauSection);
      for (BudgetLine line : b.getBudgetLines()) {
        PageElement element = new PageElement(line);
        bureauSection.addPageElement(element);
      }
    }
  }
}

me: Wow, that’s really verbose!

doug: Finally a relevant, however uninsightful, comment.  But using a custom Groovy builder, we can turn it into–

me: I think I know where you’re going, here let me take a crack at it. (grabs keyboard)

class Doug extends Nerd

doug:  Give me the keyboard!  It wasn’t funny yesterday either.

me: Yesterday “Nerd” was an interface.  I refactored it.

doug: Anyway, using a custom Groovy Builder, the code now looks like this:

BookSection root = builder.bookSection(name:"root", style:default) {
  departments.each { dept ->
    bookSection(name:dept.getName(), style:deptStyle) {
      dept.getOrganizations().each { org ->
        bookSection(name:org.getName()) {
          org.getBureaus().each { bureau ->
            bookSection(name:bureau.getName()) {
              bureau.getBudgetLines().each { line ->
                pageElement(line)
              }
            }
          }
        }
      }
    }
  }
}

me: Well, that’s slightly more readable, I guess.

doug:  What are you talking about?!  It’s much better!  It much more closely captures the budget domain as a DSL.  The “builder” object that kicks that all off is a subclass of FactoryBuilderSupport, the same superclass of the popular SwingBuilder.  We’ve just adapted the idea from making graphical widgets to making BookSections and PageElements. The FactoryBuilderSupport handles  the associations, so we don’t have to worry about wiring the BookSections up to each other like we did in the Java version.  The structure is implicit in the code.

me: Oh!  I think I have the hang of this now.  Oh wait.  What version of Mozilla do we have to support for this application?

doug:  What?  That doesn’t make any sense.  First of all this is desktop application.

me: IE 3 then?  No IE 4, I think.  Yeah, IE 4.  I mean, if you haven’t upgraded by now, you’re out of luck, right?  Can I have the keyboard to update my Facebook profile now?

doug:  Sure…I’ve had enough for now anyway.