Friday, 8 May 2009

When to use a Seaside Component?

A recent StackOverflow question asked "When to use Seaside components, and when to use simple render objects?". This is a common challenge for new Seaside users (with the additional wrinkle of whether they should be implement a Brush thrown in for extra confusion).

To some extent these decision end up being subjective design decisions but there are some pretty compelling reasons why you might need to use a Component. I took a crack at answering the question but I encourage you to post or look for alternate answers there if you think mine is wrong in some way. I think the question is an excellent one so I'd also encourage you to upvote the question and/or answer if you think it is appropriate.

First of all, you are correct that you do not need to use a Component in order to access the Session. Seaside 2.9 moves #session up to a new class WAObject which makes it accessible to almost all Seaside objects (including Components) but you can definitely refer to WACurrentSession yourself for now in 2.8.

Components provide roughly the following functionality in 2.8:

#renderContentOn: is called with an instance of whatever renderer class you specify in #rendererClass (instead of whatever renderer is in use when your object is asked to render itself)

A hook (#updateUrl:) to allow updating the URL used by the renderer to generate links

Hooks (#updateRoot:, #style, #script) to allow updating the HEAD section of the HTML document

The ability to be the root of an Application

Hooks (#updateStates:, #states) to make state backtracking easier

A hook (#initialRequest:) to allow initialization based on the request that caused the Session to be created

A facility (#children) to make sure all components below you will also have the above hooks called on them

The ability to add Decorations

The ability to show/answer/call (uses Decorations)

Some convenience methods (#inform:, #isolate:, etc)

If you don't need any of the above, you don't need a Component. If you need any of the above, you pretty much do need a Component unless you want to implement the equivalent functionality on your own class.

The simplest metric is probably: if you intend to keep the object around between HTTP requests it should be a Component; if you intend to throw the object away and create it on each rendering pass it probably doesn't need to be. If you imagine an application that was displaying blog pages, you'd probably have Components for a menu, a blog roll, the blog body, each comment, and so on. You might want to factor out the reading of the blog's markup and generation of its HTML so that you could support different markups or different renderers and so that the comment Components could support the same markup. This could be done with a non-Component class that implements #renderOn: and could be created and used by other Components as needed.

Seaside 2.9 currently splits up the above functionality by making WAPresenter concrete and introducing WAPainter as its superclass. 1-3 above are implemented on WAPainter and 4-7 on WAPresenter so you have your choice of what to subclass depending on your needs. It also removes a lot of methods from WAPresenter and WAComponent in an effort to make them easier for end users to understand.

3 comments:

Robert Sirois
said...

Is there a good source (besides class comments) that explain the use of the new classes (Painter, etc.)? I would be very interested in reading an article that compared the different rendering classes (coming from perspective of a new Seaside developer). I use WAComponent for virtually everything :)

Actually, I've been working on a sort of design document for 2.9 which will discuss the implementation of each layer. That might provide what you're looking for but I need to get it finished... it's been stalled for the past few months. I keep telling myself I'll find time this summer before ESUG but so far it isn't happening. I know people want it though - I'll keep trying.