Wednesday, May 7, 2008

Why Groovy as a service layer

I've spent the last week working on getting an Axis2 and Groovy based web service up and running. Getting Groovy to work as an Axis2 service class was incredibly simple... the Groovy scripts compile to class files and then it's just dropping the Groovy jar in the classpath.

So the implementation is finished. Now comes the hard part: convincing my co-workers in a Java shop that Groovy is the right choice for a service layer. Everyone knows it's my pet technology, and so far my demos have resulted in a lot of eye rolling. But darn it, I think it's the right choice, and I'm using this post to explain why.

The design has the service layer interacting with the Java-based business logic facades. My intent was to have the service layer's concern be strictly focused. It moves incoming requests from untyped primitives (Strings and XML blocks) into typed Java objects consumable by the facade, and it moves typed Java objects produced by the facade back into untyped primitives (Plain Old XML) consumable by the client. (I'm pretty sure this is not proprietary information at this point, but don't ask for more details).

Groovy's Java integration makes it well-suited to do this. My service class just instantiates the Java objects it needs almost exactly like it would in Java. As a result, the impedance mismatch between a Java and Groovy service class is very low. Context switching languages can be tough, but this is one of the easier cases.

But that explanation answers the question, "Which dynamic language?" rather than the question, "Should we even use a dynamic language?", which is the real decision.

In my career I've spent an inordinate amount of time at type system boundaries. Most my time has been spent in C++ and Java, statically typed languages enforced with a compiler. And at the same time, most of my career has been spent working with untyped data: primitive types coming from the database, byte streams coming from sockets, character data coming from files. I've spent a lot of time writing code like this:

String name = resultSet.getValue("name")

char* name = resultSet[4]

I'm not saying my projects are littered with code like this. I'm saying the projects contain code like this, and this type of code is where I've spent too much time. It's error prone because the compiler can't check it for you. It's hard to test because you usually need an integration test to really check it. And it's hard to read because the offset 4 and the entire getValue() call are mostly just noise in the signal.

The statically typed languages I've used simply don't support untyped data very well. This is why a lot of the frameworks exist. Hibernate makes working with untyped databases easier. XPath and Castor make consuming untyped XML easier. But using a dynamic language like Groovy makes working with untyped data natural.

For instance, consuming XML is trivial with XMLSlurper:
def records = new XmlSlurper().parseText(CAR_RECORDS)
def carRecords = records.car
def allNodes = carRecords.depthFirst().collect{ it }

The signal to noise ratio here is much higher than the Java equivalent. There is no getValue() or getChilden() cruft to obscure the intent. In my experience, this is easier to read, a little easier to write once you're over the learning curve, and about the same to debug. Before the IDEA/Eclipse Groovy plugins it was harder to debug, but now I believe it is about the same.

Producing XML is trivial too, using the built-in MarkupBuilder:
def writer = new StringWriter()
new MarkupBuilder(writer).records() {
car(make:'Holden') {
country('Australia')
}
car(make:'Peel') {
country('Isle of Man')
}
}

I find this easy to read because, even in more complicated examples, the structure of the builder calls mirror the structure of the XML produced. This is also very easy to write. So easy that I've yet had to debug it. Overall, I've been really satisfied with the ability of Groovy to produce XML without additional libraries.

Back to my service layer... remember it's sole purpose is to move data back and forth between Java types and XML primitives. When choosing a language for this layer, we have to ask, "How well does it support untyped data? (Moving data in and out of XML)" The Groovy language has Java beat here. We also have to ask, "How well does it support typed data? (Moving data in and out of Java classes)" Groovy probably has Java beat here again, with its support for builders and identity blocks. Once you concerns are isolated to a single layer, it seems that Groovy is the clear winner for implementation language.

The decision to use Groovy has not yet been made... so what do you think? What are your reasons to use Groovy?

11 comments:

Steve Mayzak said...

My experience with Groovy started with Grails. Since then, I have been using Groovy a lot more for prototyping ideas, writing scripts to handle mundane manual tasks, etc... I love it! As a consultant I will be pitching the use of Groovy and Grails more and more. I am just so much more productive with it than with Java!

Les said...

I did. I wanted to carve off part of grails. Unfortunately it is too tightly coupled. So, I wrote my own. It has saved us a ton of development time.

Anonymous said...

I think that you've laid out the case nicely in your blog post, but I just wanted to echo how nice it is to work with XML slurper/parser when dealing with XML. The syntax is much more natural and much easier to read than what you'd get in Java.

As you know, groovy is (mostly) a superset of Java and I've seen a number of people with only Java experience adapt to working in groovy very quickly.

The recent speed improvements made by the groovy team render most of the speed issues moot, but you've still got the option of diving back into Java for any areas that aren't performant.

I think it's also good for your team to get exposure to groovy as there are other areas beyond this project where it's very useful to know (quick scripts, unit testing, and potentially grails work for prototypes or actual projects when people get comfortable enough).

Unknown said...

I couldn't agree more with your position. I'll admit, until recently I viewed Groovy as somewhat of a novelty language. I have completely changed my view of it and have REALLY come to appreciate its elegance and value. With the joint compiler in 1.5x and the incredible support provided by IDEA, I think it would be a great fit.

Ricky Clarkson said...

Now if only Groovy supported static typing, and its Closure type were typable.

Hamlet D'Arcy said...

Ricky, you're more of an expert on type system than me, but it seems like a static type system would get in your way here. Not in the general case, but in this specific example, my entire app is focused on moving data back and forth between a structured layout (XML) and a typed layout (Java). The conciseness and simplicity Groovy offers is due to its dynamic typing (which is what enables the metaprogramming tricks behind XMLSlurper and MarkupBuilder). I can't imagine having that nice XMLSlurper syntax in a statically typed language. And I don't see how static typing would help with using the MarkupBuilder either. (I'm guessing it's a lack of imagination though)

Does Haskell have some of these same capabilities while also offering a modern type system?

Peter Pascale said...

Some thoughts on topics that may come up in the review:

Performance:
The classic gripe against dynamic languages. The recent groovy news highlights their focus on performance improvement. If the service layer is stateless, the performance-risk-mitigation approach could be to run more instances. But there is a limit to this - let's say XML processing performance was really bad (I haven't checked the Language Shootout tests they are selecting for their improvements - are they including XML processing?). You wouldn't want the groovy introduction to be stained by this. My suggestion - be willing to prototype the relative performance of this vs. a java approach.

Separation of Concerns:
This example hinges on using groovy for one thing - the transformation. Will there be temptation to slide in other concerns/business logic in this layer? I suspect not - since all the logic is behind the facade, but this may come up. The separation should be clearly defined, and ideally, enforcable. This is not a slam on groovy though - people have proven they can quickly have the same creep with other technologies (like business logic churned into stored procedures).

Multi-Language:
*whine* but now our developers will have to know two languages when one could suffice. I don't buy this - I agree that groovy over other dynamic languages best alleviates this. This could be a good way to introduce groovy, with the natural side effects Ted noted. But it will come up. Beyond the above arguments, there is the fact that even if you don't know groovy - this code should be easier to read and grok than the java alternative.

Alternatives:
What alternatives exist, particularly - can an xml binding framework fill the same gap? If not - you should be clear as to why - you want this to be a rejectable alternative. If yes - then I think this could be the strongest argument against groovy, because xml binding is a common need. Using the same approach adheres to the 'follow one way of doing a common task'.

Unknown said...

@hamlet d'arcy:
"but it seems like a static type system would get in your way here."

Not all type systems get in your way. A typical example is Scala, and it has a very strong support for XML literals ..

Hamlet D'Arcy said...

It does seem Scala supports a lot of the same XML parsing stuff Groovy does.
Creating XML looks pretty trivial: http://www.scala-lang.org/intro/xml.html
And there are a lot of references for reading XML, and not all are binding based:
http://burak.emir.googlepages.com/scalaxbook.docbk.html

Ricky Clarkson said...

Hamlet,

I was actually going to look into Scala's XML support (which looks good) just to answer your question, but didn't. I'm glad you did. :)

Ricky.

Unknown said...

@peter and @hamlet-

"but now our developers will have to know two languages when one could suffice."

there is in-house knowledge of ColdFusion, which is another dynamically-typed language that offers excellent xml parsing (and writing), "speaks" java natively, and oh yeah - can return data in multiple formats by changing an attribute of your web service (see the documentation for the returnFormat attribute at http://www.cfquickdocs.com/cf8/?getDoc=cffunction, or you can build up other return value formats yourself as long as it "looks" like a string).

Just some food for thought... :D