Monday, January 22, 2007

Uh-Oh, He Went There

Of course with a title like that, you're going to get some traffic; unfortunately, just like Pat Maddox's blog post today, Java People Must Be Stupid, a title which draws in traffic doesn't always necessarily draw in a whole lot of thoughtful comments as well. Must be some astrological thing, it's a good day for provocative titles that result in minimally thoughtful discussions.

The big theme in the dumber comments on Ramon's post was that Rails is obviously better than Seaside, because you can generate HTML programmatically in Rails too. The thing is, Seaside's advantage is not the ability to generate HTML programmatically. That's like, you're packing for a trip, so you compare a black sweater and a white spacesuit, and you say the sweater's better because it's hard to keep white clothes clean. These are completely different things. The sweater might be easier to wear on the plane, but if your destination is above the atmosphere, the spacesuit is going to be your only option.

Seaside doesn't generate HTML programmatically because that approach has some inherent superiority. Seaside generates HTML programmatically because it's necessary in the context of Seaside's design, and Seaside's design is the interesting part. Seaside uses a completely distinct paradigm for Web applications, and it's a paradigm where template files are much less useful. You could add templates to Seaside very, very easily, but it would be a bad idea.

Here's why. Think about named routes. Jamis Buck praised these today, and his praise certainly had some merit. Jamis Buck is, of course, a very, very smart programmer. But think about named routes. What is a named route, exactly? If your Web application could be conveniently and comprehensibly viewed as a single codebase, what would a named route be?

Named routes would be labels, the last relic of goto still surviving in Java and Perl -- and probably many other places as well -- like a Loch Ness icthyosaur lurking somewhere in Scotland, millions of years after the extinction of all its cousins. There's a reason that the guy who created Seaside calls his blog HREF Considered Harmful. An explicit, hard-coded href is completely identical to a goto. It is the same thing. And although the implementation of named routes is beautiful, the basic idea is only slightly more elegant than the basic idea of a named goto.

Say you've got an app which you're building first without Ajax, and then with Ajax. This is a very common development practice, because Ajax is often a pain in the ass to debug. Assume you're building such an app, and assume further that all the hard stuff happens on the server side, and the Ajax stuff is just cosmetic. If you build this app first without Ajax, you get to code all the hard parts in the context of standard Rails error messages -- in effect using your server and browser almost as a de facto IDE. Then when you do the last little Ajax bit, the cosmetic bit, all you're really doing is changing the views and a few controller render calls.

If you were in Seaside, you wouldn't have to do that. Seaside views HTML as a stream, and the same component can generate the same HTML on the stream whether the stream's sent out as a complete page load or an incomplete page load. Different divs in the page can come from different objects in Smalltalk, and the same set of objects can be used for rendering as Ajax or in the original Web 1.0 style. It makes no difference at all. You have complete control. And while you can emulate that kind of componentized system in Rails, with multiple levels of nested partials, it isn't elegant at all. In fact it's so heinously inelegant that you can really only do it for trivial cases. It's kind of like the way you can really only do trivial flow control if you're using goto.

But let's take it even further. Say something changes. You have a series of steps to fill out, in a form. If Pat Maddox is working for you, you can already fill out those steps in any random order, and it's not going to matter. But in most cases, you'll have to revise your system. Like say you've got a form, and the form has twenty fields, and those fields all live inside one form which you display to the user with a render call. And suddenly you want the user to be able to enter the form fields in any order, and have them saved immediately. And further, you want these form fields to be accessible at any point, anywhere in the application, where before they were only accessible at specific points, on specific pages.

To transform a code base this way, it might be possible in Rails, if you have a good team. In fact I think that's the whole point of the restful approach, and if I understand correctly, that's why people are so excited about it.

But to transform a code base this way, in Seaside? There is no transformation. You get all that for free. It's built in. That's the whole point of Seaside. Dismantling your entire design just to save form fields in a different order isn't necessary if you aren't using the 2007 goto anywhere in your code base.

At best, a Web application framework built on URLs gives you a command-line interface in the "Location" box. At worst, you get a tangled nest of gotos. But with a continuation server, you get an entire app on every page load. Everything you need is right there. The type of flexibility and detailed control which users take for granted in desktop apps is absolutely achievable in Web apps -- but it might not be achievable with Rails.

That is the question that makes Seaside interesting. Is what Seaside does without breaking a sweat even possible with Rails?

I still work with Rails. I love Rails. I'm just saying all this to offset the stupidity of the comments in Ramon's blog about Rails being able to generate HTML programmatically. It's not about being able to generate HTML programmatically. It's about being able to generate Web apps programmatically.

9 comments:

Seaside is certainly an excellent framework, much for the same reasons as Rails — it's opinionated in the way a web-application should be built. It's opinions are, however, very different.

That being said, your comparison of URLs to goto statements isn't just wrong, it's dangerous. Using a goto statement to jump to a label in your code is considered bad form because it encourages unstructured programming and spaghetti code. The program is still just as powerful, but much more difficult for people to maintain and build on because it's no longer grouped into some sort of logical structure.

A URL on the other hand is a name. In the case of the web, it references a resource. If I give you a URL, you should be able to dereference it and retrieve a representation of that resource. What's more, it's not good style to change that URL. On the web, URLs aren't part of the implementation — their part of the interface. URLs are one of the primary reasons the web has succeeded to the extent is has today.

In this respect, comparing URLs to goto's doesn't make much sense. URLs are much more like messages being passed to a webserver, possibly with other arguments (in the query string or body.) I'll agree that Rails dispatching using labels could be improved, there'd be advantages to dispatching to the controller / action you're referencing and decoupling that for URL generation (much like Camping does.)

Yea, I went there, I couldn't resist. They're both awesome frameworks, why shouldn't they be compared.

If you like REST, use Rails, but if you think manually binding pages together with manually passed parameters sucks and can be improved upon, use Seaside.

Justin, using a URL is also a jump to a label, and also encourages unstructured programming and spaghetti web sites where pages are all bound together and tightly coupled to the next in the work flow. His comparison is quite accurate.

REST is "an" answer, it's not "the" answer. Stateless apps have their place, so do stateful ones like Seaside apps. Web sites benefit from statelessness, but real hardcore complex applications, benefit from state.

Justin: Perhaps some of your concerns stem from Giles' comparison to goto, which programmers basically consider trash. URIs really are like gotos, conceptually, but that's where the similarity ends - it doesn't mean that URIs are a bad idea like gotos. Far from it, because as you pointed out, they're responsible for the web's success.

To me, Giles is saying that you can't directly compare Rails with Seaside. Yeah they both help you create web applications, but they answer the question "What exactly is a web application anyway?" differently.

I still haven't played with Seaside (shame on me!), so I might be entirely wrong about it. It seems though that the difference is a level of abstraction. Rails encourages you to think of your application in terms of resources. Indeed DHH himself has said "We don't abstract away standards," with the relevant standard here being URIs and web resources. Seaside, on the other hand, seems to be more about writing application code without caring about the exposed resources, and letting the framework handle that transformation.

So it's really not an either/or...just because in Seaside you don't actively expose and link resources doesn't mean they're not exposed and linked to the world. It just means that you don't really have to think about it, whereas in Rails you're encouraged to think about it.

Of course, a hybrid approach probably provides the most power and simplicity... ;)h

Hey, that was a great article. Thank you. (I must admit I didn't read it all the way through though. The white-on-black theme is just a little too hard to read after a long day of driving. You definitely piqued my interest with the bit about named routes as a goto.)

Doesn't Seaside stores state in the URL itself, making it impossible to bookmark your progress through the webapp?

I'm sure you can get a RESTful Seaside webapp, it's just you'd be working against the whole continuation-based foundation of it. Similarly with Rails, you need to do extra work if you start to go outside its target area.

If URIs are part of your application's interface to the world then it is impossible to NOT think about them and still expect a quality interface to emerge "magically". You have to decide what resources should be referencable and bookmarkable. This is exactly what the routes file does.

Ramon does not claim that Seaside is magical: he says that "REST" and "statelessness" (i.e. Web Architecture) is "an answer" not "the answer". Which implies that he accepts that there are tradeoffs.

On the other hand, recent posts from the seaside guys have started to pull back from the whole ubiquitous-continuations thing, so I'm not convinced that Ramon represents the party line.

Continuations aren't entirely ubiquitous in Seaside, it's true, but using explicit hrefs sure seems to carry the exact same risk as explicit gotos, for the exact same reasons, and I don't see why anybody would rather read a W3 spec than create something useful. Obviously exposing URIs to other applications is very useful, but if you want sophistication comparable to desktop apps, you need a system free of URLs for the same reason you need a language free of gotos.

href is less harmful than goto, because it's incredibly useful for text links, but for application links, it's almost exactly the same thing as goto.

Rails is a fantastic system for creating what people think of as Web apps. Seaside gives you the ability to maintain state in a way you previously couldn't do with Web apps. It's definitely **an** answer, not **the** answer, but the last thing in the world I want on my blog is language war. Language wars are for programmers who are insecure in their own abilities and identify with what a language can do instead of what they can do.

And honestly, it's not just that it's an answer rather than the answer -- Seaside and Rails might also be answers to utterly distinct questions.

Anyway, as to the idea that my comparison of URLs to goto is not just wrong, but dangerous, first of all, it's not my comparison, it's Avi Bryant's. Second, I'm never wrong; and third, I'm always dangerous.

And with that I'll jump into my helicopter and go skiing in the Alps while shooting Nazis and snapping a bullwhip.

Seriously, of course it's a dangerous idea. "Dangerous idea" is a redundant phrase. If it's not dangerous, it isn't an idea. But the dangerous idea comes from Avi Bryant, not me.

Hi, nice screencast. You commented that Seaside should support REST. I'm not so up on REST but further to a previous comment Seaside does actually support bookmarks. It is maybe not so integral or obvious in the framework as many of the other features but it is reasonably easy to make permanent URLs.

The way you do this is to hook into #updateURL: so a component can modify the contents of the URL before the state information gets added.

You can then define what happens when you navigate to this URL by hooking into the #start method of a customised render loop. It's then up to you how you configure the app.

I wrote a simple document server in Seaside that used this technique for categories and search. If someone bookmarks the whole of a permanent URL that contains the session state, it doesn't matter because if the session has timed out, you still have enough information to configure the application based on the bookmark.

I'm not sure that's a good description of the REST features in Seaside, a screencast would be much better!

Checkout Lukas Renglii's Seaside pages. I'm sure this appears in one of his tutorials/ESUG presentations.