workaround for generating gui tools

Jeremy Bowers jerf at jerf.org
Sun Apr 10 13:09:15 EDT 2005


On Sun, 10 Apr 2005 13:57:26 +0200, Diez B. Roggisch wrote:

>> Domain-specific abstractions do that *faster* than GUI designers, not
>> slower. And better, too, since every iteration tends to be fully
>> functional and not just a "let's see what this looks like" prototype.
> 
> Can you show me some working, in-use example for that?  I _seriously_ doubt
> that the process of rearranging and tuning the layout can be done faster in
> the text-world than with a good designer like qt-designer. But I'm all ears
> for better solutions.

Regrettably, no. I have them but they are all unsharable, either because
the real owner would consider them proprietary, or because they are an
unreleased and at the moment unfinished product I can't give the code out
for.

But I can help some.

Part of the problem is the incredible cognitive disconnect between the
"layout" system of design and the system I'm advocating. You're looking at
your designer and saying something like, "well, if I want to re-order
these two options, it's three drags, even less if there's an 'exchange'
option, how can anything possibly be any easier?" (At least, that's my
guess.) But that is not where the advantage lies.

One of the things I can't show you at the moment is actually written as a
web application using Javascript and mod_perl. It's a bog-standard GUI app
that edits databases, from the surface. SOP for the forms designer
approach is to create a form for each thing that will be edited; in this
case in HTML, but that's not particularly different and you can get form
editors for that, too, if you try.

But even now, we have at least 20 different types of things to edit, and
the full power of databases is at play here; we have foreign keys that may
have an arbitrary number of certain things (customers may have an
arbitrary number of phone numbers, for instance; in practice of course you
won't have 20, but they may have "home", the may have "home + work", the
may have "work + fax", etc.), and a customer's address may actually be in
an Address table, rather than directly in their record. Add up all the
little pieces and at the moment we've got around 100 different types of
things that might need editing, many of which can have arbitrary links to
other things. (Some of these 100 things are just "link tables", SQL tables
that link an ID in one table to an ID in another for many-to-many
relationships and these will not directly be edited, but still there's a
lot of "things" in play here.)

We could try to create a form for each one, and in fact earlier versions
of the system did just that. But that solution sucked, for all of the
reasons I typically rant against these solutions; they rapidly got out of
sync with the database schema, a bug fix in one was a bug fix in no others
(copy and paste code tends to run rampant in this situation, though
technically that's just a tendency, not a requirement), and any but the
most critical enhancements are out of the question because they only
affect a small part of the system.

So, instead, with this new system (note I wasn't involved with the old
system), I do everything with metadata. (Credit where credit is due, the
other programmer was starting to do some of this, though he couldn't quite
take it down to the interface and there are some things I had to add
later.) Every "thing" (class) has a description of what it's made out of,
and what type each of those things are. When I go to edit an instance, the
Javascript pulls down that description, and a description of the instance
(and all of its associated sub-instances), and instead *generates* a form
to edit the object based on what it is made of.

Right now, I'm emulating the old two col approach, labels on the left,
values on the right, but I'll be changing that later. For now, though,
that makes it easy (and like I said, as nice as forms are, having to do
that many they bailed out and went with a standard design). And since I'm
putting these things in by hand, I can also create custom widget types and
use them. (For that, I'm using my XBLinJS library, so you can actually
think of the HTML widgets as having capabilities much like Tkinter
widgets, in that I can subclass from them and make them do domain-specific
things just like Tk.)

Integer value types get integer text boxes; these do not allow you to type
anything but numbers. Floating point is the same way, but adds the .
(although only one). All numeric fields do math within themselves, which
is something that should have been standard for a decade now but
programmers had to actually do something special in their forms to get
it; I get it for the same price as anything else, once I wrote the
code. (By that I mean, type "1+4" in and it will resolve itself to
"5".) That's one of the reasons I rant about this; there is *so much*
functionality like that that ought to be standard because done correctly
it's trivial to plunk the right text widget subclass down if you're
generating the screen, but form designers make this a lot of extra work.

How do I decide the order to create the fields? Classes carry a metadata
field called "order" that lists the fields it wants in order, the
remainder will by default be tacked on the end. What if I don't want a
certain field to display? There's a metadata field that lists the ones we
want to display for editing, there's another I can use to just filter a
couple out if the first isn't present. What if I want a particular widget
to do something special like be a certain width? I've created a metadata
"escape hatch" that lets me pass parameters directly to the <input> node;
it's "bad style", but sometimes useful. Everything I use is backed by a
database which has limited typing abilities, so I have a field called
"humantype" that declares the human type of the data, so I can then create
intelligent widgets for that, too. One of the things we can do, for
instance, is create an "image" widget that specifies a URL for an image,
and as validation, shows it there in the browser. We could also make it
accept uploads. Then, just by labelling a field as an "htmlImage", we get
the image editor, no form redesign, no muss, no fuss.

Form designers give you small parts of this; you can create a text node,
say it's an int, and get automatic min/max, although... they don't pull it
from the database, they don't have any understanding of what's going on,
etc. In my design, every is some sort of intelligent field, not a
bog-standard text box, and the idea of a "field" includes the ability to
validate the value inside of it, depending on what kind it is. (Here, the
number fields for instance have a bit of code to check min and max. Other
fields make sure they reference something real in the database.)

By making smarter widgets, and intelligently assembling them in code
instead of plopping down stupid (in the programming sense, not the
derogatory sense) text widgets here and checkbox widgets there, I can
(and have) created entirely *new* objects, and the editor *just works*.

Semi-weakness: Vast, labyrinthine preferences dialogs can be a pain, if
your "core app" doesn't itself look like one. Still, you'd be surprised in
practice how that tends not to come up, especially if your app can already
support that sort of thing, in which case it's just another data source.
(All the prefs we have in this app fit right into the same model without
any hassle, so this isn't a stopper.)

The true and major weakness: You can't hire a guy off the street to draw
boxes in his designer, connect a couple of events, and call the form done.
(Although in practice it's rarely that easy...) You have to be a
programmer that can handle a level of abstraction above the raw fields.
But the benefits are...

...ultimately, *exactly* the same benefits you obtain from any other layer
of abstraction, and with exactly the same tradeoffs and costs, with
exactly the same result that *typically* the abstraction is a good thing
but every once in a while, mostly on small jobs, it's a loss. Indeed I see
this entire argument as isomorphic to "Why would I want to do OO when my
procedural code works just fine?", right down to the different programming
style it engenders, the difficulty of crossing the understanding gulf, and
the initial difficulties. (Regrettably, this style is unpopular and not
immediately supported by frameworks or anything, so initially you end up
constructing your own.) It even *feels* the same, with the way I don't
want to work on forms-based apps anymore because they feel so static and
concrete and immobile, just as non-OO procedural does, and the way it
takes so much work to do the same thing, over and over again.

If this thread is still going in a couple of days, I'll post a screenshot
with some labels on it so I can gesture a little more concretely, and I
might post some of the source data files, too, if it seems like it would
help. The screenshot won't help much, though, because it is in the
*behavior* of the resulting app that the true difference is felt.

I wish I could point at a consumer app to download, but I think this has
not penetrated the general consciousness yet, because in C or C++ this is
a *god awful nightmare*. The function signatures necessary to pull this
off would put most C programmers off their feed, and would challenge even
C++ programmers (God help you if you tried to template any of this...),
and the memory management becomes quite exciting. This is going to follow
behind the dynamic languages, which actually make it possible, by a few
years, and those are only now beginning to penetrate the mainstream
consciousness. I would expect that at least among the good programmers,
this will be SOP in about five to ten years, with better framework
support, but at the moment all I can say is the benefits in the code I
can't show you yet (sorry) are overwhelming, and the obvious problems
fully overcomable, once you get into the paradigm.

Cue the smalltalk "I did this in the 80's and it's been all downhill since
then" replies... 



More information about the Python-list mailing list