Links

Patrick Mueller elsewhere: muellerware.org, twitter.com/pmuellr

Thursday, September 20, 2007

which flavor do you favor

A question: if you had to provide a client library to wrapper your RESTful web services, would you rather expose it as a set of resources (urls) with the valid methods (request verbs) associated with it, or provide a flat 'function library' that exposed the resources and methods in a more human-friendly fashion?

Example. Say you want to create a to-do application, which exposes two resources: a list of to-do items, and a to-do item itself. A spin on the "Gregorio table" might look like this:

resource URL template HTTP VERB description
to-do items /todo-items GET return a list of to-do items
to-do items /todo-items POST create a new to-do item
to-do item /todo-items/{id} GET return a single to-do item
to-do item /todo-items/{id} PUT update a to-do item
to-do item /todo-items/{id} DELETE delete a to-do item

(Please note: the examples below are painfully simple, exposing just the functional parameters (presumably uri template variables and HTTP request content) and return values (presumably HTTP response content), and not contextual information like HTTP headers, status codes, caches, socket pools, etc. A great simplification. Also note that while I'm describing this in Java code, the ideas are applicable to other languages.)

If you were going to convert this, mechanically, to a Java interface, it might look something like this:

For the first two rows of the table, you use the following interface:

1: public interface ToDoItems {
2:     public ToDo[] GET();
3:     public ToDo POST(ToDo item);
4: }

For the last three rows of the table, you use the following interface:

1: public interface ToDoItem {
2:     public ToDo GET(String id);
3:     public ToDo PUT(String id, ToDo item);
4:     public void DELETE(String id);
5: }

I'll call this the 'pure' flavor.

A different way of thinking about this is to think about the table as a flat list of functions. In that flavor, add another column to the table, named "function", where the value in the table will be unique across all rows. Presumably the function names are arbitrary, but sensible, like ToDoList() for the /todo-items - GET operation.

Here's our new table:

function resource URL template HTTP VERB description
ToDoList to-do items /todo-items GET return a list of to-do items
ToDoCreate to-do items /todo-items POST create a new to-do item
ToDoGet to-do item /todo-items/{id} GET return a single to-do item
ToDoUpdate to-do item /todo-items/{id} PUT update a to-do item
ToDoDelete to-do item /todo-items/{id} DELETE delete a to-do item

This flavor might yield the following sort of interface:

1: public interface ToDoService {
2:     public ToDo[] ToDoList();
3:     public ToDo   ToDoCreate(ToDo item);
4:     public ToDo   ToDoGet(String id);
5:     public ToDo   ToDoUpdate(String id, ToDo item);
6:     public void   ToDoDelete(String id);
7: }

I'll call this the 'applied' flavor.

Now, if you look at the combination of the two 'pure' interfaces, compared with the 'applied' interface, there's really no difference in function. In fact, the code to implement all these methods across both flavors would be exactly the same.

The only difference is how they're organized.

Now, the question is, which one is better?

Now, you might say I'm crazy, who would ever choose the 'pure' story over the 'applied' story? And my gut tells me you're right. The 'applied' story seems to be a better fit for humans, who are largely going to be the clients of these interfaces, writing programs to use them.

But this flies in the face of transparency, where we don't want to hide stuff so much from the user. HTTP is in your face, and all that. At what point do we hide HTTP-ness? If you don't want to hide stuff from your users, you might choose 'pure'.

And I wonder, are there other advantages of the 'pure' interface? You might imagine some higher-level programming capabilities (mashup builders, or even meta-programming facilities if your programming language can deal with functions/methods as first class objects) that would like to take advantage of the benefits of uniform interface (as in the 'pure' interface).

And of course, there's always the option of supporting both interfaces, as in something like this:

01: public interface ToDoService2 {
02:     public ToDo[] ToDoList();
03:     public ToDo   ToDoCreate(ToDo item);
04:     public ToDo   ToDoGet(String id);
05:     public ToDo   ToDoUpdate(String id, ToDo item);
06:     public void   ToDoDelete(String id);
07: 
08:     static public interface ToDoItems {
09:         public ToDo[] GET();
10:         public ToDo POST(ToDo item);
11:     }
12: 
13:     static public interface ToDoItem {
14:         public ToDo GET(String id);
15:         public ToDo PUT(String id, ToDo item);
16:         public void DELETE(String id);
17:     }
18: }

Even though you have 10 methods to implement, each real 'operation' is duplicated, in both the 'pure' and 'applied' flavors, so you really only have 5 methods to implement. No additional code for you to write (relatively), but double the number of ways people can interact with your service.

Wednesday, September 19, 2007

NetBeans 6.0 Beta 1

Shiver me timbers, yes, I'm blogging a bit about NetBeans. After hearing such gushing reviews of it, I figured I'd take a look. It's been at least a year, and probably more, since I last looked at it. And I should note, I'm just looking at the Ruby bits.

Thought I'd provide some quick notes on NetBeans 6.0 Beta 1 as a confirmed Eclipse user. I'd give the history of my usage of Eclipse, but then Smalltalk enters the picture around pre-Eclipse VisualAge Java time-frame, and you don't want me to go there, do ya matey? That would just make me sad anyway, remembering the good old days.

I've also used the RDT functionality available in Aptana, and will make comparisons as appropriate.

cons:

  • On the mac, uses a package installer, instead of just a droppable .app file.

  • Mysterious 150% cpu usage after setting my Ruby VM to be my MacPorts installed ruby. I didn't see any mention in the IDE of what it was doing, but I figured it was probably indexing the ruby files in my newly-pointed-to runtime. Only lasted a minute or so. If it had lasted much longer, I might have killed it, and then uninstalled it.

  • Can only have a single Ruby VM installed; Eclipse language support usually allows multiple runtimes to be configured, one as default, but overrideable on a per-project, or per-launch basis. What do JRuby folks do, who want to run on JRuby or MRI alternatively?

  • Plenty of "uncanny valley" effects going on, because Swing is in use. Of course, Eclipse also has a lot of custom ui elements; I'm becoming immune to the uncanny valley; and FireFox on the mac doesn't help there either.

pros:

  • I see the Mac .app icon changed from the sharp-cornered version to a kinder, gentler version (see the image at the top), but I think I can still validly compare Eclipse and NetBeans to two of my favorite sci-fi franchises, given their logo choices. But it's certainly less Borg-ish than older versions.

  • Install now ships as a .dmg for the Mac (disk image file) instead of an embedded zip file in a shell script.

  • Debugging works great. Same as Eclipse with the RDT.

  • I can set Eclipse key-bindings.

  • F3 works most of the time ("find the definition") like in Eclipse. In fact, this is cool: F3 on a 'builtin' like Time, and NetBeans generates a 'dummy' source file showing you what the source would look like, sans method bodies, but with comments, and the method navigator populated. Nice!

  • A Mercurial plugin is available for easy installation through the menus, and CVS and SVN support is built-in. I played a bit with the Mercurial plugin in a previous milestone build, and it was easy enough to use, but I never could figure out how to 'push' back to my repo. Why Eclipse doesn't ship SVN support, built-in, in this day and age, is a mystery to me.

  • Don't need to add the "Ruby project nature" to a project just to edit a ruby file in the project. How I despise Eclipse's project natures.

  • Provides great competition for Eclipse.

Quite usable, overall. Hat's off to the NetBeans folks! I'll probably start using it for one-off-ish Ruby work I do.