Sunday, April 13, 2008

Language Comparison Series

I needed something to do at the last SuperHappyDevHouse event, so I decided to start learning Python. I need something to use for some projects outside of work, and I've wanted to check it out for a while since so many people seem so committed to it, so it seems like as good a time as any. I've read through the pickaxe book and done a few small projects in Ruby at work, but it was a while back and I've not forgotten it all, so I figured it was worth trying something different. So I've been working through Dive Into Python, installed andLinux so I have a better dev environment locally (though we'll see how that goes; I may try VMWare, create a real Linux partition, or just switch back to using the Windows toolchain, as painful as it is), and now I'm working through the Django tutorial.

Of course, part of my motivation is also that we have our own programming language, currently called GScript, and it's good to learn about other languages so you can see how yours compares and so you can borrow the best ideas that are out there. The same applies to frameworks too, which is one reason I'm going to try out Django; we have our own ORM layer and web layer, so it's good to see what cool directions other people have gone with those.

Honestly, it's not worth it to me to check out any Java frameworks in those regards: everyone uses Hibernate, so I really should learn more about it, but Java just doesn't lend itself to great frameworks due to its lack of metaprogramming. No matter how clever you are, it's really a pretty fatal flaw in my opinion; the gscript interface to our ORM layer is all dynamic even though GScript is strongly-typed, thanks to the magic of our open type system, but on the Java side we have to do massive amounts of code generation that should be totally unnecessary. Thankfully pretty much our entire interface to the web layer is through gscript, so we don't have to do any Java code generation there. There are a lot of reasons why I think our web framework is better than anything else out there for the sort of work that we do, but the open typesystem in gscript really makes it untouchable. I think that it would take people some time to understand what we've done with our latest "smoke tests," but I think that if people really understand what we were doing it would blow their minds a bit, since it really is a total game-changer as far as our ability to reliably test our entire application from the UI on down.

But I digress . . . my point here is that I've started putting up a series of articles on the Guidewire Development Blog comparing GScript with Java, Ruby, and Python. I chose those because they're the languages I know best (or at least are freshest in my head) and because those are, for a lot of people, the main choices for a modern web development platform. I didn't include PHP because . . . well, because PHP code is always eye-bleedingly ugly. I'd certainly consider it for web development due to its sheer practicality, scapability, and rapid development model, but as a language designer it should really serve as a cautionary tale of how not to do things.

So if you want to see how GScript stacks up, head on over the dev blog and check it out. The first two are up, and I'll probably be adding one or two comparisons a week.

Sunday, April 06, 2008

Why Java Needs Closures

(Note: This has been cross-posted to the Guidewire Development Blog)

There was a post by Bruce Eckel on Artima this week that asked the question of whether or not closures would make Java less verbose, so it seemed like an apt time to put this up.

People tout closures as cure-alls for all sorts of things: because they like functional programming or because it’s better suited to certain tasks, or maybe because they want to use it for control structures (so they don’t forget to close a file after reading it, say). Honestly, I’m just sick of writing this same block of code over and over again:

Map> claimsByUser = new HashMap>();

for (Claim claim : someListOfClaims) {
List claims = someListOfClaims.get(claim.getUser());
if (claims == null) {
claims = new ArrayList();
claimsByUser.put(claim.getUser(), claims);
}
claimsByUser.put(claim.getUser())
}

I’d much rather write something like:

var claimsByUser = someListOfClaims.partition(\claim-> claim.User)

Sometimes I feel like all my Java code devolves into a morass of for loops and angle brackets (I like generics, mostly, but without type inference they’re exceedingly painful). Even worse, it’s the same few for loops over and over again. You can write helper classes and methods to do things, and you can simulate closures using anonymous inner classes, but even then your code looks like:

Map> claimsByUser = ListUtils.partition(someListOfClaims, new Partitioner() {
public User partition(Claim c) {
return c.getUser();
}
});

Hardly the most elegant code on the planet. If you had to read or modify the code, hopefully it’s obvious which one is easier to understand and easier to change.

There have been multiple closure proposals floated for inclusion in Java 7, and the one that looks like it’ll make it in is, like the generics implementation, a bit too complicated in the wrong ways. The arguments over exception and return handling within closures, along with debates about the scoping rules, have not (in my opinion) ended well, mainly (from what I can tell) due to a desire to be able to use closures to allow programmers to create new language-level control constructs, like the for loop added in Java 1.5. From my viewpoint, they’re silly questions to ask in the first place: a closure is a function, so a return statement within a closure just returns from that function. Returning from the containing scope just seems like madness and an invitation to serious confusion. Yes, it lets you define new control structures, and yes, new control structures can also simplify code, but I really think they should be two completely different features. Keep closures simple and understandable, with simple, consistent rules about scoping, return values, and exception handling. If people still demand better control structures, then make that a separate effort and implement those cleanly and simply.

While nothing’s been officially decided yet, I’m guessing that the two most likely outcomes are either 1) a confusing, over-engineered closures implementation or 2) no closures at all. And that’s just unfortunate; even some simple form of closures allows for a major simplification of routine data structure manipulations that both reduces code and makes code more clear. And of course, closures are far more concise and usable if you add type inference in as well, but that’s another post. Just yet another reason why the world needs a language like GScript.

The Challenge of Configurability

(Note: This has been cross-posted to the Guidewire Development Blog).

Every kind of software development has its own unique set of challenges: embedded software, desktop software, games, operating systems, and web applications all have their own difficulties and problems. Enterprise software is no different, and one of the main challenges there is making that software configurable.

Of course, not all enterprise software vendors try to do this; some of them go the route of essentially requiring you to fit your business to how their software works, while others basically bring in a small army of consultants to essentially do a complete custom build based loosely on some pre-existing components that they have. One of the things that sets Guidewire apart from our competitors in the insurance software market, and (I’d argue) from most enterprise vendors in general, is the level of configurability that we provide with our software. And after having worked on configurable, enterprise systems for close to six years now, I can be fully confident in telling you that the reason no one else does it to the degree that we do is that it’s really, really hard.

Why is it so hard? For one, it turns everything into a meta-problem. Think about the problem of assigning claims to users. If you were just building out a system for in-house use, you’d probably just hardcode the logic in Java (or whatever language you’re using): assign glass claims to the group with this name, injury claims to that group, etc. In our system, that’s implemented via a ruleset, where we call out to business rules that are set up to do that assignment. That means we have to think about where those callouts should occur, what the API should be for them, and what sorts of methods the person writing the business rules will need available: maybe they need to do round-robin assignments, maybe they need to do location-based assignments, or maybe they want to balance assignments based on adjuster workloads. Instead of coming across those problems and solving them as we need to, we have to think about what the API should be up front and try to provide the right amount of flexibility for our customers.

Programming that way is just harder than normal code because you’re working at another level of abstraction; instead of writing an expression like 1 + 1 in the language, you’re writing the language itself (numeric literals, additive expressions, etc.). The code for implementing a language is rarely straightforward when compared to the code written in that language.

There are other challenges too. We need good tools to ease the configuration work and help discover problems. Testing an entire framework is harder than testing code in that framework, both because of the combinatorial explosion of configuration options and because the surface area of our API is much larger than what our default application configuration actually uses. Upgrade is another challenge we always have to think about, as we don’t always know what sorts of configurations customers have performed and have to be careful to keep those configurations working as much as we can and/or to provide upgrade tools when we change the frameworks. Getting feedback from customers is more difficult than it otherwise would be, since customers have to configure the application a non-trivial amount before they can realistically use the features we want feedback on, meaning they’re less likely to give us that feedback and that it takes longer to get it. And lastly, there’s constant pressure to release early versions of the software so that customer projects can get underway with their configuration and integration work, but that means customers will start configuring on partially-complete systems, which can force us to be locked into APIs (or at least provide an upgrade path) for things we haven’t fully completed and thus need the freedom to change.

If it’s so hard, you might be thinking, then why do it? The most obvious reason is that it better serves our customers’ needs, and as a software vendor that’s obviously our top priority. Relative to minimally configurable systems, highly configurable software results in a product that (once configured) more closely matches how our customers do business. Relative to custom-built systems, configurable systems can be implemented faster and the end product can be owned and maintained by the customers rather than requiring vendor patches or consultants for any future changes. Even relative to in-house built systems, configurable software like ours will allow future changes to be made much faster and more safely.

The second reason is less obvious, and that’s that in many ways forcing us to think hard about configurability makes us write better, more flexible software. We’ve developed a huge array of tools (our scripting language, our metadata layer, our web framework, etc.) that would help us even if the end result was something that would never be configured by a customer. For example our web framework, while built with customer configuration in mind, lets us build new pages, modify existing pages, and find and fix bugs far faster than we ever could with our old struts/jsp-based web framework. Just like doing test-driven development can often lead to better-decomposed code, making things configurable and flexible often results in better tools and better frameworks that benefit application development generally.

With great challenges come great rewards. What we’re doing might be incredibly difficult, but that’s why our systems are the best ones on the market.