[TransWarp] peak.web.forms (was re: State of the Onion)

Phillip J. Eby pje at telecommunity.com
Sat Aug 9 17:32:28 EDT 2003


At 08:18 PM 8/9/03 +0200, Roché Compaan wrote:
>* Phillip J. Eby <pje at telecommunity.com> [2003-08-09 17:43]:
> > >During our
> > >discussion I thought that we don't really need "field" and that widgets
> > >can do all that you propose a field should do. I am still not convinced
> > >this is necessary separation, but I'll have to think about it some more.
> >
> > Widgets shouldn't be mutable, but a widget class by itself will not 
> contain
> > sufficient parameterization for its instances.  Therefore, there are two
> > different objects at runtime: an object that describes the fixed 
> properties
> > of the widget, and one that describes its state with respect to its 
> current
> > usage within the web hit.
>
>Why can't widgets manage state or why must they be immutable? They are
>not really loaded with services. In my mind they have to do very little:
>render a value and *maybe* store a value. In fact why do they have to
>keep any state at all - the values they need for rendering come from
>either the request or an object.

If they don't have state, then every method called has to have additional 
parameters passed in, *and* there is a tighter coupling to the external 
objects.  If a widget looks at the request and the object, it is coupled to 
both.  Let's say we had a new data source we wanted to load a form from: to 
do this would require changing every single widget.

Using the form-and-field approach, the form can have methods like 
'loadFromRequest()' or 'loadFromObject()', or you can write external 
functions that manipulate a form and its data.  This is a greatly reduced 
coupling.

In general, I prefer to introduce more objects, and have each object 
responsible for a distinct role.  Such objects are usually much more 
flexible, reusable, and maintainable.  For example, the model I've 
described so far could readily be adapted to a non-web GUI.  One would 
simply replace the "field" class with one that would also hold an actual 
GUI widget, and would get/set the data from the GUI widget instance, rather 
than keeping the data in itself.  (Yes, of course there'd be more to such a 
port than that, but it would still be better than having to rewrite all the 
widgets so they don't expect to have a REQUEST object!)

In short, it's my "design sense" that asserts it be done this way.  There 
are many logical justifications, as you can see, but I don't actually think 
about such "background" reasons for things when I design, I just "know" how 
it should be, and can (sometimes) explain my reasons later.  Such 
horizontal concerns (things that apply to more than one kind of 
application) are "background" thoughts for me.


> > >precisely because there may be differences between "modes". Sometimes
> > >you just want to remove widgets on the edit form that are visible on the
> > >add form. If the differences are overwhelming then create another form.
> >
> > I'd prefer the objects to control their own destinies here.  If there are
> > things that should be different, this should be specified by the form or
> > widget definitions, not by application code at runtime.
>
>If it is allowed to manipulate a form instance then I see no problem

Really, I don't want this to be the normal circumstance.  Writing the last 
email made it clear to me that forms want to drive the application, not the 
other way around.  E.g. an edit method should look more like:

def edit(self, CONTEXT):
     form = self.editForm.forContext(CONTEXT, self.subject)
     if form.isComplete():
         form.updateObject(self.subject)
         # render success template
     else:
         # render previous template, using 'form'

And the above code should work perfectly whether editForm is a single 
screen or multi-page form, whether it opens other windows to do searches, 
or whether the object whose edit method this is, is being displayed as part 
of a larger template.

And this construction as I've shown it is still too awkward, really.  What 
this should *really* do is have the *form* itself be the object posted to, 
with this 'edit' being more like an 'on_Submit' operation.

Hmm.  All this makes me want to take a look at XForms again, even though 
XForms is designed for an XML data model on the back-end.  Anyway, I'm 
beginning to see that the high-level vision here is that you could actually 
design the framework so that common GUI functions (add, edit, view) might 
be accomplished without writing any app-level code at all; just create the 
form design, and specify what it should do.


>with adding a widget to or removing a widget from a form instance at
>runtime. This would fall under changing their *state*, not?

Right, but this doesn't move us towards having full GUI separation.



>In PEAK however, I think we should code forms in python so that we can
>visualise them in UML and that is probably the page you are on already.

Well, I don't know about the UML bit; my "Web Extensions for UML" knowledge 
is more than a little rusty.  But definitely the framework should be able 
to be driven by metadata, ala the "Naked Objects" approach.  The dream here 
is that if you should be able to go straight from a UML model to a default 
(if perhaps ugly) GUI for it.  If you could add a few stereotypes or tagged 
values to the UML model to control initial widget selection, etc., however, 
you might be able to very rapidly prototype new applications.


>I imagine you see an addForm as:
>
>     class AddForm(Form):
>
>         class Name(model.Attribute):
>             referencedType = widget.TextWidget
>             css_class = 'field_input'
>             size = 20
>
>         class Age(model.Attribute):
>             referencedType = widget.TextWidget

Something like that, yes, but perhaps also very different.  Up until now, I 
hadn't really been thinking as much about using Python code to specify form 
definitions, as I'd been focusing on very data-driven aspects.  Now, I'm 
realizing that you probably want some code that goes with this, maybe some 
methods that manipulate form data in some way, or at least the option of 
having some.

Ideally, it would be possible to have this code be limited, however, to 
"form domain" matters, and not necessarily related to GUI matters, except 
at an abstract level that would be applicable to multiple implementations 
(e.g. wxPython vs. HTML).

Maybe I want too much.  :)  But I generally find it better to know what 
direction I'd like to go, because I can always scale down the vision if the 
budget doesn't allow it, but it's harder to change something that's already 
built with a more limited scope in mind.  Of course, this has to be 
balanced against YAGNI-ism, but adaptation offers a powerful YAGNI weapon.

For example, suppose we made classes that corresponded to "abstract" 
widgets, and then used adaptation to turn them into HTML widgets, wxPython 
widgets, etc.?  Not only that, but we could make the adaptation specific to 
an individual form, using protocols.Variation.  Anyway, one reason I want 
to look at XForms again, is that they had a specification/model for a set 
of abstract widgets that could then be mapped to specific widget 
implementations using CSS and the like.  I think that in our case we could 
use pwt:define's in place of CSS.

An interesting thought - many GUI systems these days use XML as a 
basis...  besides HTML, there's also wxPython's XML resource format, and 
Mozilla's XUL.  All of these can be rendered with peak.web.templates, so 
there do seem to be some intriguing possibilities for future GUIs.


>I think I should just make a prototype so that we have something
>concrete to work from. I find it difficult and frustrating to only talk
>about this.

Feel free.  I, on the other hand, don't know enough yet about what I want, 
to make anything.  From my POV, this is all still far-off brainstorming, 
similar to where the existing peak.web stuff was a few months ago.  What we 
ended up with in developing the existing peak.web tools looks *very* 
different from any of the things Ty and I first talked about, so I'm glad I 
didn't rush to build any of the things we first talked about.

But, if you want a forms framework *now*, rather than possibly waiting a 
few months, then rolling your own is indeed a good plan.  Meanwhile, I've 
been wondering when XForms might become important/relevant to 
peak.web.  Now that I've realized I'm trying to reinvent it, perhaps I 
should just go see if we can port it instead.  :)




More information about the PEAK mailing list