I love programming, and I'm usually very proud of my code.
Except when it comes to applications that have a GUI. I think the GUI
applications I've written are so incompetently coded that I ought to
be fired on the spot for them. Not that I don't try. When it comes
to coding GUI apps I work twice as hard and twice as long as with any
other type of programming, constantly testing and refactoring, but the
resulting code is invariably impenetrable, impossible to debug and
modify, far worse than reams of goto-infested FORTRAN code. In short,
my GUI code represents gross programming malpractice.
I suspect the roots of my problem are the event-driven and MVC
paradigms. I just don't know how to write under these paradigms
without producing spaghetti code! Maybe the problem goes deeper,
maybe the problem is with the whole message-passing paradigm,
i.e. with OOP itself. This is particularly true for multithreaded
programs (i.e. multithread = multiple strands of spaghetti). (I
thought I once came accross an anti-OOP rant by EW Dijkstra, but I
can't find the citation...)
I really want to get better at writing GUI apps, but I don't know what
to do. Books? Go back to school for some re-training?
When I posted substantially the same post in comp.lang.java.gui, the
only potential useful reply I got was the suggestion to read the GoF
book. I've read this book already. Thanks to it I have a better
grasp of how one codes for a pluggable L&F than I had before reading
the book. But it has not helped my coding GUI apps much.
I emphasize that my query here is not about learning those principles
of GUI design that matter from the user's perspective. What I need is
coding principles and guidelines to keep my event-driven
message-passing programs from slowly degenerate into spaghetti code.
Any advice you can give on this me would be most helpful!
Thanks!
bill
>In short,
>my GUI code represents gross programming malpractice.
One of the most powerful techniques for organizing GUI code is to
separate it into two components. The first controls the API of the
GUI and is utterly brain-dead. It makes no decisions on its own.
There are no loops or if statements in it. The second module does
not know anything about the GUI API, but does know about the GUI
module, and sends it messages. It is responsible for manipulating all
the data and controlling the enabling of menus, buttons, etc. It
manages the selection state of list boxes, etc. etc.
These two modules are written to be independent of each other. Call
the first the "Dialog", and the second the "Model". The independence
needs to be such that you can replace the Dialog with a Text UI, and
the Model won't know the difference. They need to be so independent
that you could move the dialog to a different machine and efficiently
use RMI to bind them together. They need to be so completely isolated
that you can write unit tests for either without affecting the other.
I'm currently writing a book entitled "UML for Java Programmers". In
this book is an example of a Java UI that is separated in the above
manner. I've attached that example to this message.
If you can't read the attachement, let me know and I'll put it in a
URL you can get to.
Robert C. Martin | "Uncle Bob"
Object Mentor Inc.| unclebob @ objectmentor . com
PO Box 5757 | Tel: (800) 338-6716
565 Lakeview Pkwy | Fax: (847) 573-1658 | www.objectmentor.com
Suite 135 | | www.XProgramming.com
Vernon Hills, IL, | Training and Mentoring | www.junit.org
60061 | OO, XP, Java, C++, Python |
You and I can enjoy the experience of not always seeing
eye-to-eye, but we can also respect each other, even when
you might find some idea of mine totally ludicrous.
-- Richard Riehle
>In short,
>my GUI code represents gross programming malpractice.
One of the most powerful techniques for organizing GUI code is to
separate it into two components. The first controls the API of the
GUI and is utterly brain-dead. It makes no decisions on its own.
There are no loops or if statements in it. The second module does
not know anything about the GUI API, but does know about the GUI
module, and sends it messages. It is responsible for manipulating all
the data and controlling the enabling of menus, buttons, etc. It
manages the selection state of list boxes, etc. etc.
These two modules are written to be independent of each other. Call
the first the "Dialog", and the second the "Model". The independence
needs to be such that you can replace the Dialog with a Text UI, and
the Model won't know the difference. They need to be so independent
that you could move the dialog to a different machine and efficiently
use RMI to bind them together. They need to be so completely isolated
that you can write unit tests for either without affecting the other.
I'm currently writing a book entitled "UML for Java Programmers". In
this book is an example of a Java UI that is separated in the above
manner. Here is an excerpt from that chapter that shows the example:
www.objectmentor.com/resources/articles/EmployeeTerminatorTestFirstGUIExample.pdf
> I really want to get better at writing GUI apps, but I don't know what
> to do. Books? Go back to school for some re-training?
Simply sit down with a tutorial for a well-designed OO GUI. I suggest
Mac OS X. Objective-C would be a good thing to learn for that system,
but it does have Java bindings as well.
Thanks, Bob. This is just the kind of thing I'm looking for.
In <g56qeu4nj9k2hvmh8...@4ax.com> Robert C. Martin <u.n.c.l.e.b.o.b.@.o.b.j.e.c.t.m.e.n.t.o.r.d.o.t.c.o.m> writes:
>On Thu, 23 May 2002 14:01:52 +0000 (UTC), bill <bill...@hotmail.com>
>wrote:
>>In short,
>>my GUI code represents gross programming malpractice.
(The employee termination theme of the example is a nice--if somewhat
unsettling--touch given the context of my original post!)
>One of the most powerful techniques for organizing GUI code is to
>separate it into two components. The first controls the API of the
>GUI and is utterly brain-dead. It makes no decisions on its own.
>There are no loops or if statements in it. The second module does
>not know anything about the GUI API, but does know about the GUI
>module, and sends it messages.
This last sentence confused me, because I couldn't see how the second
module could possibly send messages to the first without "knowing"
about its API, or at least some of it... (Though, after reading the
EmployeeTerminator example I think I have the gist of what you mean.)
>I'm currently writing a book entitled "UML for Java Programmers". In
>this book is an example of a Java UI that is separated in the above
>manner. Here is an excerpt from that chapter that shows the example:
>www.objectmentor.com/resources/articles/EmployeeTerminatorTestFirstGUIExample.pdf
I look forward to getting this book! When is it scheduled for
release?
I do have one question about the example. You write
One might ask why terminate and selectionChanged are separate
functions of EmployeeTerminatorController. Why not just have
terminate take the employee argument? I did this because I didn't
want the EmployeeTerminatorDialog making assumptions about what it
means when the user clicks the terminate button.
But this just prompts the new question: "Why didn't you want the
EmployeeTerminatorDialog making assumptions about what it means when
the user clicks the terminate button?"
Thanks for your advice!
bill
>
>
I suffer from the same problem. I do not believe the problem is with
event-driven, MVC paradigms or multi-threading. I do believe the
problem is because we are "crossing the chasm" between two different
layers and this is inherently problematic. We can make our GUI View
clean. We can make our Model clean. We cannot expect to link our Model
and View together, throw a User into the mix, and have anything but an
ongoing battle to minimize the spaghetti. IMHO, its a fact of life.
Actually, I posted a note on this exact topic a few weeks ago. One
person responded and that one person agreed :-)
>
>
>Thanks, Bob. This is just the kind of thing I'm looking for.
>
>In <g56qeu4nj9k2hvmh8...@4ax.com> Robert C. Martin <u.n.c.l.e.b.o.b.@.o.b.j.e.c.t.m.e.n.t.o.r.d.o.t.c.o.m> writes:
>
>>On Thu, 23 May 2002 14:01:52 +0000 (UTC), bill <bill...@hotmail.com>
>>wrote:
>
>>>In short,
>>>my GUI code represents gross programming malpractice.
>
>(The employee termination theme of the example is a nice--if somewhat
>unsettling--touch given the context of my original post!)
>
>>One of the most powerful techniques for organizing GUI code is to
>>separate it into two components. The first controls the API of the
>>GUI and is utterly brain-dead. It makes no decisions on its own.
>>There are no loops or if statements in it. The second module does
>>not know anything about the GUI API, but does know about the GUI
>>module, and sends it messages.
>
>This last sentence confused me, because I couldn't see how the second
>module could possibly send messages to the first without "knowing"
>about its API, or at least some of it... (Though, after reading the
>EmployeeTerminator example I think I have the gist of what you mean.)
Sorry, the API I was referring to was javax.swing, not the API of the
EmployeeTerminationDialog.
>>I'm currently writing a book entitled "UML for Java Programmers". In
>>this book is an example of a Java UI that is separated in the above
>>manner. Here is an excerpt from that chapter that shows the example:
>
>>www.objectmentor.com/resources/articles/EmployeeTerminatorTestFirstGUIExample.pdf
>
>I look forward to getting this book! When is it scheduled for
>release?
Production has already begun. It'll be in the bookstores in
September.
>I do have one question about the example. You write
>
> One might ask why terminate and selectionChanged are separate
> functions of EmployeeTerminatorController. Why not just have
> terminate take the employee argument? I did this because I didn't
> want the EmployeeTerminatorDialog making assumptions about what it
> means when the user clicks the terminate button.
>
>But this just prompts the new question: "Why didn't you want the
>EmployeeTerminatorDialog making assumptions about what it means when
>the user clicks the terminate button?"
I don't want EmployeeTerminatorDialog making any assumptions about
business rules. I don't even what it to know that there *are*
business rules. The dialog is a GUI, it knows nothing of business
rules. The Model holds business rules, I don't want it to know
anything about javax.swing, or GUI's in general.
> I love programming, and I'm usually very proud of my code.
>
> Except when it comes to applications that have a GUI. I think the GUI
> applications I've written are so incompetently coded that I ought to
> be fired on the spot for them. Not that I don't try. When it comes
> to coding GUI apps I work twice as hard and twice as long as with any
> other type of programming, constantly testing and refactoring, but the
> resulting code is invariably impenetrable, impossible to debug and
> modify, far worse than reams of goto-infested FORTRAN code. In short,
> my GUI code represents gross programming malpractice.
Basically my advice is a variation on Martin's. The crucial thing to
realize is that the GUI is a low level service the application uses to
communicate with the user. That communication is based upon very simple
messages and data transfers. The problem solution does not care whether
it is communicating with the user via GUI, command line, programmatic
API, or optical recognition of smoke signals.
So the key thing to do is encapsulate the GUI in one (or two)
subsystems. Let the problem solution dictate what message and data
transfers are required to/from the user and design the subsystem
interfaces accordingly. That is, the problem solution defines the
necessary message and data transfers. Then design the GUI subsystem to
translate the messages in that interface into messages to the OS window
manager. The important mind set is that the application controls the
GUI service; the windows message loop does not run the application.
[There is a chicken and egg thing here. Typically the GUI definition is
part of the functional specification of the system. Keep in mind there
is an iteration. If data or instructions are required to solve the
problem that the initial GUI does not provide then the GUI changes, not
the solution. In reality this is rarely a problem if the GUI design has
been properly reviewed.]
> I suspect the roots of my problem are the event-driven and MVC
> paradigms. I just don't know how to write under these paradigms
> without producing spaghetti code! Maybe the problem goes deeper,
> maybe the problem is with the whole message-passing paradigm,
> i.e. with OOP itself. This is particularly true for multithreaded
> programs (i.e. multithread = multiple strands of spaghetti). (I
> thought I once came accross an anti-OOP rant by EW Dijkstra, but I
> can't find the citation...)
As it happens, I always do event-based communications because it is the
True Path. B-) But your application does not have to if you have
properly encapsulated the GUI. The window message loop will live within
that subsystem and, as one alternative, you can simply enqueue the
events the application cares about there until the application requests
them (i.e., the application sends the What's New, Pussycat? message when
it gets bored).
Note that the encapsulation separates concerns. A lot of the
asynchronous message processing in the GUI can be handled in the GUI
subsystem. Often the classes there are dumb data holders that buffer
information until the user decides to do something like Save. So the
GUI subsystem mostly just converts OS window messages into attribute
data and periodically shovels it off to the application.
That subsystem has very little notion of the problem semantics of the
data and messages that it handles. It has objects like Window and
Control where the problem semantics is reflected mostly in things like
text values for labels and titles. Its <very limited> mission in life
is to relate the screen data and controls with messages to/from the rest
of the application. Generally that does not require a whole lot of
state machines for event-based processing.
So typically there is only one thread in the GUI subsystem because it is
just managing the OS window messages and the OS window manager is kind
enough to wait until asked for the next message. If the application has
a limited attention span it will send I'm Busy to the GUI and the GUI
will map than into an hourglass request to the OS window manager.
If the application has juggling as a avocation, it will deal with
dispatching messages from the GUI subsystem based upon message type and
its own rules for solving the problem in a multi-threaded manner. That
is, the application defines the multi-threaded strategy and then one
constructs the interface to the GUI so that it can keep things straight
(i.e. provide a consistent GUI Control instance -> message type ->
thread mapping). However, if one treats the GUI as a pretty dumb
decoding of user information, that mapping is usually pretty straight
forward. (More precisely, the GUI is pretty limited and there isn't a
lot of room to distinguish thread context, so most of the thread
intelligence will be determined by non-GUI factors.)
BTW, it is sometimes helpful to have two subsystems for a GUI,
especially when not using a window builder tool for automatic code
generation. This provides two levels of abstraction. The higher one is
much as I described above. The classes will be instantiated with some
application semantics and will usually be very easily mapped into the
application's problem space (e.g., the application's Account class maps
to the GUI's AccountWindow and its attributes map to a collection of
Control objects associated with AccountWindow). Though the semantics is
limited, it is still application specific. It is essentially a step
stone between the application and the next subsystem that makes the
developer's life easier.
The other subsystem provides a low level service to the high level GUI
subsystem. This subsystem lives to commune directly with the OS window
manager (e.g., at the MFC or Win32 API level). The actual message loop
code lives here. Here there is no application semantics at all; one
just has multiple instances of generic Window. This sort of subsystem
is completely reusable across applications because it has no application
semantics as all; it just manipulates data values.
Essentially it provides a more generic API for the OS window manager.
Because most of the things it does are pretty tedious, the world is full
of window builder tools that handle this automatically. If you use a
window builder, the higher level GUI subsystem will implement the
callbacks the builder wants in methods.
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
h...@pathfindersol.com
Pathfinder Solutions -- We Make UML Work
http://www.pathfindersol.com
(888)-OOA-PATH
I think MVC is flawed, and MVP is better. Maybe that would help.
I also think there comes a point where a kind of spaghetti is appropriate.
The application-specific part of the UI consists of instantiating a bunch
of pre-written classes and connecting them together. The code consists of
"wire output A to input B" without much deeper structure. Such deeper
structure as there is mostly consists of entire sub-triads encapsulated
within another Presenter - which is part of why MVP helps, I suppose.
Anyway, once you reach this point, the programming becomes declarative,
perhaps even table-driven, rather than conventional OO. It just takes a
lot of OO to get there.
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
bran...@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
Are you certain you understand the GUI design principles that a user
sees? Would you like to give your top three GUI design rules?
I know I participated in some threads about UI recently, here and/or
elsewhere. I went looking for books on the topic about a year ago,
and found little of use -- a few wordy books about UI design, but
nothing very close to applied.
Do you have use cases mapped out for the interactions? That's for the
interaction, not the underlying domain objects.
Joshua Stern
> On Thu, 23 May 2002 14:01:52 +0000 (UTC), bill <bill...@hotmail.com>
> wrote:
>>I really want to get better at writing GUI apps, but I don't know what
>>to do. Books? Go back to school for some re-training?
> ...
>>I emphasize that my query here is not about learning those principles
>>of GUI design that matter from the user's perspective. What I need is
>>coding principles and guidelines to keep my event-driven
>>message-passing programs from slowly degenerate into spaghetti code.
>>
>>Any advice you can give on this me would be most helpful!
>
> Are you certain you understand the GUI design principles that a user
> sees? Would you like to give your top three GUI design rules?
I suspect bill is not stating the user's experience is unimportant, only
that's not where he finds the spaghetti. So if he was trying to direct the
thread away from this topic...
--
Tokomar
I don't think it's just you. Based on a number of code-bases I've
seen, the ugliest code is often GUI code. I attribute this to two
things: 1) The GUI development process is often much less
structured/more susceptible to feature requests/modifications/etc.,
and 2) GUI code often has the added burden of often having to be built
upon a series of third-party libraries/components/etc.
That said, on a rare occassion I have seen GUI code that appeared to
be quite clean. It would be interesting to try to compile a list of
those things that SPECIFICALLY apply to writing clean GUI code (as
opposed to general "good programming" practices.)
J
bill <bill...@hotmail.com> wrote in message news:<acisof$5f0$1...@reader1.panix.com>...
Yeah, but there are some specific practices, design strategies, that
make GUIs virtually impossible to program.
Small design changes can simplify implementation by huge amounts. A
complex, modeless form quickly suffers from combinatoric explosion, if
the fields need to be cross-checked against each other and a database.
A bad design is pretty much impossible to code correctly, with or
without spaghetti. Hence, my raising the issue against an attempted
dismissal. I give it at least 80% odds that that's the real issue.
J.
<ears perk up>
Table-driven? Did I hear you right?
http://www.geocities.com/tablizer/guitable.htm
I just added a new section with a nifty little diagram.
>
> Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
> bran...@cix.co.uk | And close your eyes with holy dread,
> | For he on honey dew hath fed
> http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
>
-T-
I am puzzled by this. In my experience with event driven GUI, you end up
with a set of small functions each responding to a single type of event. For
example if you have a Delete button in a dialog you would have an
OnDeleteButtonPress function. In effect you are being pushed towards good
design in as much as you have small functions each with a single
responsibility.
John
<picky> So, is this a bad time to mention that 'example' has an 'm' in it?
(page 1, line 5) ;-) </picky>
If I understand you right then I think this is exactly what we do
in Smalltalk (and what I do in Java, having put hours of work into
building the appropriate framework).
The first sub-system you mention corresponds to smalltalk's
"ApplicationModel". It's job is to create a number of adaptors
linked to the underlying domain. Each adapter provides a
one way "get" channel for protected display items, or a two
way "get/set" channel for editable display items, or encapsulates
an action. It does not specify presentation at all.
You can build and test this layer independently of the GUI
presentation .. then build one or more GUIs onto it later on.
That's the second subsystem you mention.
The advantage is that not only do
you get the separation of concerns, but by using adaptors you
produce a predictable API as a result of building the high
level abstraction. Now your other subsystem, with low level
presentation details, can simply be an aggregation of
widgets connected to adaptors. They do not need to be
subclassed, and do not need to be handled with any special
code at all. Simply create the widgets attached to Application
Model adaptors, and assemble them into a tree.
In smalltalk we don't even need code to do this. An
auto-generated descriptor is stored as static data and
used at run time to build and connect the widgets.
--------
Or maybe don't even build a gui at all! Just use the
ApplicationModel as a facade for the domain app and write
servlets or command line interpreters that use it.
-------------+ http://www.mk.dmu.ac.uk/~gperkins/
I would be very interested to hear your reasoning on this.
There must surely be advantages and disadvantages to each?
-------------+ http://www.mk.dmu.ac.uk/~gperkins/
Please see the earlier notes from myself and Lahman. If you use
or build the right architecture and framework, there won't be any
GUI code. So the problem disappears.
-------------+ http://www.mk.dmu.ac.uk/~gperkins/
It depends how good your framework is. The original poster probably
had not worked with properly layered system with clear in-out channels
and change notification.
Suppose you have an address-book style frame somewhere in your
application. Click on name in a big list, and rest of frame
fills with the details of that person. What should happen when
you click on the delete button?
Obviously, the currently selected person should be removed
from the domain data. But much screen updating needs doing to.
You might well end up with something like
on personDelete
// find selected index
// work out which Person object it renders
// tell app. domain to remove that Person object
// remove selected item from the display list
// clear out all the detail fields and labels on the screen
Each of which requires several lines of code.
The trouble here is that every event handler has to know
the exact knock-on effects of obeying a command. Then
it has to go round refreshing all parts of the frame (and
possibly other frames) that may be affected by those
knock-on effects.
It seems spaghetti-like because you build up massive
dependencies between all the event handlers. And it
gets hard to separate them. You might like to build
one module of event handlers per frame on the screen.
But some frames will edit underlying domain objects
which then cause refreshes on ALL the other frames!
The handler in one module has to ask another module
for all of its active frames, and go through them
to refresh them all. Any tiny change to the presentation
details forces you to edit almost every event handler
in the system. Frames cannot be developed separately
as their handlers need to be interacting with each
other all the time.
-----------------------
With the right architecture, you get something more
like:
peopleSelector = new Selector( People.singleton )
...
on personDelete
p = peopleSelector.selection()
if (p != null) People.singleton.remove(p)
Any widgets rendering the Selector (eg lists, pop-ups,
drop-downs, radios) onto any frame in the application
will refresh themselves automatically when the "remove"
method fires change notification. Any fields attached
to the Selector's current selection will go blank,
'cos the Selector itself will notify loss of selection.
No need to decode the GUI to see what was selected,
and no need to synch. other parts of the GUI.
-------------+ http://www.mk.dmu.ac.uk/~gperkins/
Buttons are easy.
The problems are typically when you have dozens of data fields that
need to be cross-checked, you want to check each field on completion
(not wait for the whole page to be submitted), and you don't know in
what order they're going to be filled.
But even on a batch submission, the combinatoric explosion of which
fields have been filled in, can be a bugger.
J.
Why must there?
As for the reasoning, I don't have anything to add to the existing
literature, eg:
http://www.object-arts.com/EducationCentre/Overviews/MVC.htm
http://www.object-arts.com/Papers/TwistingTheTriad.pdf
I hadn't thought of it that way, but I see your point. Where can I
learn about the GUI design issues you describe?
bill
Ooops. Sorry, I was talking about the wrong book. The 'UML for Java
Programmers' title will be in the stores by the end of the year.
I'm thinking of setting up a yahoo group to discuss the book and
posting the current state of the manuscript every week or so. I'll
let you know if and when that happens.
> If I understand you right then I think this is exactly what we do
> in Smalltalk (and what I do in Java, having put hours of work into
> building the appropriate framework).
It sounds like it. I don't know enough about Smalltalk to know how much
is Smalltalk implementation and how much is methodology. When I last
looked at Smalltalk ('80s), I don't recall it having that sort of
infrastructure. It would seem, though, that...
> <snip>
>
> In smalltalk we don't even need code to do this. An
> auto-generated descriptor is stored as static data and
> used at run time to build and connect the widgets.
it exists today.
>
> --------
>
> Or maybe don't even build a gui at all! Just use the
> ApplicationModel as a facade for the domain app and write
> servlets or command line interpreters that use it.
Actually I think this is fairly common, even without a builder. Once
the GUI concerns are encapsulated often the only OOA/D necessary is a
Class Diagram. Since the subsystem lives to translate messages from one
interface to another, the processing is pretty simple minded for most
GUIs and the subsystem objects tend to be dumb data holders. So one can
Just Do It by having methods in one interface simply invoke methods in
the other interface, possibly with a little data gathering from dumb
objects.
IME it is unusual to have GUI objects with significant behavior unless
one is doing fancy graphics rendering. Of course if the GUI starts to
get fancy (e.g., complicated Undo rules across multiple windows), then a
little more A&D is necessary. B-)
I found Robert Martin's example very useful. It reminded me of stuff
I have read before, and sharpened them. But as I think about my own
code, I realize that there's much more to the problem than drawing a
sharp line between model and presentation. Graham Perkins writes
about this in one of his posts. In my application, I have several
closely interrelated models. For example, in a GUI I have a mutable
tree, from which users can select nodes (by clicking on them). Upon
selecting a node the user can operate on it. For example, s/he can
delete it from the tree; or s/he can append it (or rather, a string
corresponding to the node's content) to a list of chosen items. This
list of chosen items is displayed using a standard widget for lists.
(The user can add items to this list in other ways besides selecting
nodes from the tree, but I won't get into this). The user can then
use the items in this list to generate a standarized query, which
results in another list being produced. And on, and on, and on. So
above I have at least: 1) the tree model; 2) the tree selection model;
3) the model for the list of selected items; 4) the list corresponding
to the result of the query. (1) and (2) must know about each other;
(3) must know about (2); other components I have mentioned must know
about (4)...
My point is that, I need more principles for dealing with this
creeping interconnectivity, in which ultimately every model (and their
views) must know about every other model/view... I think this is what
Graham Perkins is alluding to, but I can't quite follow him:
>With the right architecture, you get something more
>like:
> peopleSelector = new Selector( People.singleton )
> ...
> on personDelete
> p = peopleSelector.selection()
> if (p != null) People.singleton.remove(p)
>Any widgets rendering the Selector (eg lists, pop-ups,
>drop-downs, radios) onto any frame in the application
>will refresh themselves automatically when the "remove"
>method fires change notification. Any fields attached
>to the Selector's current selection will go blank,
>'cos the Selector itself will notify loss of selection.
>No need to decode the GUI to see what was selected,
>and no need to synch. other parts of the GUI.
This touches precisely upon the kind of situation I find bewildering,
but unfortunately, I can't follow the (pseudo?)-code:
> peopleSelector = new Selector( People.singleton )
> ...
> on personDelete
> p = peopleSelector.selection()
> if (p != null) People.singleton.remove(p)
Is this Python? At any rate, I don't understand what it means. What
is the Selector object? What is People.singleton? If someone could
spell it out for me, I'd be most grateful.
Thanks,
bill
Pardon my ignorance, but what does A&D mean? Architecture and Design?
Alcohol and Drugs?
Thanks,
bill
I don't know of anything.
There's probably mention of it in any GUI book, but none that I've
seen has made a major point of it.
Maybe I should spit out a page or two and post it someplace.
Longer term, for the last year I've been considering writing a book on
GUI design, and the proper use of modality to decouple internal logics
(and, not coincidentally, to make the design idiot-proof at the user
level) would be a major topic.
I only worked out my own view of this fully about three years ago, but
as I said somewhere, I've dabbled in the theory and practice of GUI
design for ** years.
(The basic idea is to split the GUI into blocks, only one of which is
enabled at any one time. A use case should lead to a state diagram
for the blocks, and the logic inside of the blocks is not only
combinatorically much more limited than it would be for the whole form
at once, but usually the app logic is such that logic within a block
is quite simple and straightforward, ... and then so is the code to
implement it. HOWEVER, some people would say that this is bad design,
they prefer a modeless, direct-manipulation model. I used to believe
in that, sort of, until I saw what a mess Microsoft made of things in
using it, and when I tried to program the same kind of stuff myself.
There, a whole book chapter in one paragraph!)
(the kind of stateless logic you have to work under for web forms is
similar to the kind of stateless architecture mainframes have used for
forty years for CICS and the like, those are other reference points
for modality, but not for GUI specifically)
Joshua Stern
Close enough (Analysis & Design)
> Alcohol and Drugs?
That too....depending on how onerous the project is....
R.
--
He that breaks a thing to find out what it is has left the path of wisdom.
-- Gandalf the Grey
>(The basic idea is to split the GUI into blocks, only one of which is
>enabled at any one time. A use case should lead to a state diagram
>for the blocks, and the logic inside of the blocks is not only
>combinatorically much more limited than it would be for the whole form
>at once, but usually the app logic is such that logic within a block
>is quite simple and straightforward, ... and then so is the code to
>implement it.
This sounds *very* interesting. I presume that what you describe
above is not just the wizard approach of popping up a new dialog box
every time you hit the 'next' button.
I've had an idea running around my brain for awhile, but I can't quite
put my finger on it. It's more of a feeling than an idea. You're
paragraph above resonated with that feeling. Please say more.
>In my application, I have several
>closely interrelated models. For example, in a GUI I have a mutable
>tree, from which users can select nodes (by clicking on them). Upon
>selecting a node the user can operate on it. For example, s/he can
>delete it from the tree; or s/he can append it (or rather, a string
>corresponding to the node's content) to a list of chosen items. This
>list of chosen items is displayed using a standard widget for lists.
>(The user can add items to this list in other ways besides selecting
>nodes from the tree, but I won't get into this). The user can then
>use the items in this list to generate a standarized query, which
>results in another list being produced. And on, and on, and on. So
>above I have at least: 1) the tree model; 2) the tree selection model;
>3) the model for the list of selected items; 4) the list corresponding
>to the result of the query. (1) and (2) must know about each other;
>(3) must know about (2); other components I have mentioned must know
>about (4)...
It seems to me you have multiples separations to perform. The first
is the separation between the actual data and behavior of the
application, and the data and behavior you need to control the UI.
Second is the seperation between the data and behavior you need to
control the UI, and the actual GUI.
This is precisely the Model-Presenter-View split. (If I read the MVP
docs correctly (which is hard because there aren't many (but isn't
that always the way with good ieas))).
So, first make the models work without *any* UI. Make a nice API for
the models and write unit tests that demonstrate that they can be
manipulated appropriately, and that they do the right things.
Next, make the presenter. Gather all the data and manipulations you
will need together. That includes the trees, lists, buttons, other
lists, etc. But don't mention the GUI. In fact, make it possible to
manipulate the Presenter from a textual UI. Write unit tests that
demonstrate that you can select items in the tree, put them into
lists, build queries, etc. Also test that the presenter and models
work correctly together. You still haven't written *any* GUI code.
Finally, write the GUI. Put no intelligence in it. Keep it stupid,
stupid, stupid. Make sure all the GUI control comes from the
Presenter in abstract terms.
Pop-ups and tabbed wizards suck because you the user is denied
immediate view of all the data. The presentation style favored these
days is the "explorer", with some kind of separate navigation control
always in sight, usually on the left, with generally scrollable large
areas (scroll being the lowest cognitive load for accessing extra
data) to the right.
This is not different in kind from the earliest menu/MDI designs, but
it is different in detail, and generally a good thing, I believe.
These matters are orthogonal to the protocol used to guide users
through complex data domains (with special emphasis on data entry).
In some ancient CICS kinds of systems, you simply had separate
programs / forms for each CRUD function. That enforced modality. A
simple form appears asking for key fields. You press enter. Another
form appears with key fields locked, and data fields displayed. Kewl.
You want to modify the data, you select a line and a third form
appears with just that data unlocked for modification. OK, this is
all rather crude by modern standards, but it shows the idea.
Generally, I believe you will find that this corresponds to a use case
in which the user is guided through a navigation path across the
application domain. True, it does not leave the user free to choose
any of what might otherwise be possible paths, but that is not
necessarily a bad thing. When going from place to place we tend to
use the highways, and if we're banned from taking side-streets on a
journey from Chicago to New Orleans, well, we'll probably make the
trip faster for all of that.
I don't know how you will take this, Robert, you already took issue a
couple of weeks back with some other stuff I posted regarding linkages
between application domain, classes, and GUI. But you're welcome to
it, FWIW.
Joshua Stern
OK, this is clear.
>Next, make the presenter. Gather all the data and manipulations you
>will need together. That includes the trees, lists, buttons, other
>lists, etc. But don't mention the GUI.
This part baffles me (I have *much* to learn), because when you write,
e.g., "buttons" or "tree" I think "GUI", which is clearly not what you
mean. In Java Swing, for example, I would use JButtons or
JTrees--which I think of as GUI--for those... I know that these
components can be given different L&Fs, but I don't think this is what
you mean by GUI either.
I think a concrete example of MVP (preferably in Java Swing) would
make everything clear. My initial Google search for this did not turn
up anything useful. Do you know where I can find an example and/or
tutorial of MVP?
>In fact, make it possible to
>manipulate the Presenter from a textual UI.
Do you mean something with a text-based shell, and a typical session
like:
myapp<11> load "mydata"
myapp<12> delete 5415
myapp<13> select 43221
myapp<14> select 981
myapp<15> select 2794
myapp<16> crunch
results_line_1
results_line_2
results_line_3
.
.
.
results_line_24972
myapp<17> deselect 43221
myapp<18> select 2398
myapp<19> crunch
results_line_1
results_line_2
results_line_3
.
.
.
results_line_24972
myapp<20>
Many many thanks!
bill
thanx,
max.
>This touches precisely upon the kind of situation I find bewildering,
>but unfortunately, I can't follow the (pseudo?)-code:
>> peopleSelector = new Selector( People.singleton )
>> ...
>> on personDelete
>> p = peopleSelector.selection()
>> if (p != null) People.singleton.remove(p)
>Is this Python? At any rate, I don't understand what it means. What
>is the Selector object? What is People.singleton? If someone could
>spell it out for me, I'd be most grateful.
OK, I'm beginning to understand: Person is the model class and
Selector is (I think) the presenter class? But in what class does
this code reside? Some overarching main class that talks to both the
model and the presenter?
bill
>gper...@gperkins.co.uk (Graham Perkins) wrote (abridged):
>> > I think MVC is flawed, and MVP is better. Maybe that would help.
>>
>> I would be very interested to hear your reasoning on this.
>> There must surely be advantages and disadvantages to each?
>
>Why must there?
>
>As for the reasoning, I don't have anything to add to the existing
>literature, eg:
> http://www.object-arts.com/EducationCentre/Overviews/MVC.htm
> http://www.object-arts.com/Papers/TwistingTheTriad.pdf
>
Hmm. Can you sy 404?
(I'm not sure why the first reference but in the second pdf is
capitolized ( I didn't think that makes a difference).
The first one works for me - I just tried it again. The second one
failed; sorry; it looks like the extension should be capitalised too:
http://www.object-arts.com/Papers/TwistingTheTriad.PDF
The PDF file is the more useful. If that link doesn't work, try using
google to search for "Twisting the Triad".
I also recommend the original Taligent paper, "MVP: Model-View-Presenter
The Taligent Programming Model for C++", which I think is at:
ftp.mayn.de/pub/unix/devel/MIRROR.docs/mvp.pdf
Again, search for the title if the link doesn't work. This paper talks
about reusable support objects, some of which take on the role of device
drivers or "controllers" in MVC-speak.
Part of the problem of MVC is that nowadays device drivers are usually
provided by the OS. More seriously, a controller is often coupled to a
view (eg mouse gestures only make sense with a window open) so there
needs to be something which represents the combination, ie what MVP
calls a Presenter. Presenters should be reusable, pluggable modules.
(I think the notion of decomposing a UI into hierarchical, reusable
Presenters may connect to JRStern's notion of splitting the UI into
independent, mutually exclusive blocks. Only better.)
>> If you can't read the attachement, let me know and I'll put it in a
>> URL you can get to.
>Robert, please post the URL, I would really appreciate it.
www.objectmentor.com/resources/articles/EmployeeTerminatorTestFirstGUIExample.pdf
> I found Robert Martin's example very useful. It reminded me of stuff
> I have read before, and sharpened them. But as I think about my own
> code, I realize that there's much more to the problem than drawing a
> sharp line between model and presentation. Graham Perkins writes
> about this in one of his posts. In my application, I have several
> closely interrelated models. For example, in a GUI I have a mutable
> tree, from which users can select nodes (by clicking on them). Upon
> selecting a node the user can operate on it. For example, s/he can
> delete it from the tree; or s/he can append it (or rather, a string
> corresponding to the node's content) to a list of chosen items. This
> list of chosen items is displayed using a standard widget for lists.
> (The user can add items to this list in other ways besides selecting
> nodes from the tree, but I won't get into this). The user can then
> use the items in this list to generate a standarized query, which
> results in another list being produced. And on, and on, and on. So
> above I have at least: 1) the tree model; 2) the tree selection model;
> 3) the model for the list of selected items; 4) the list corresponding
> to the result of the query. (1) and (2) must know about each other;
> (3) must know about (2); other components I have mentioned must know
> about (4)...
There is a problem being solved by the application. The GUI operations
you describe above are just reflections of what the real problem is --
dancing shadows on the wall of Plato's cave and all that. What needs to
be described is the problem being solved by the application. Until we
know what that problem is, we can't determine the level of intelligence
actually required by the GUI.
So far, though, it sounds like the GUI is not very bright. Thus far it
just seems to be a bunch of nested collections (tree nodes and list
widgets). The membership in the collections is dynamic so that main
activity seems to be dynamically instantiating a bunch of 1:*
relationships. Without more knowledge of the problem this is pure
speculation, but it might look something like:
1 1
Tree --------- RootNode
| 0..1
|
|
parent of 0..* | 0..*
+---------- TreeNode ------------- List -------- NodeText
| 0..1 | 1 0..1 1 *
| |
| | child of
| |
+---------------+
This set of classes and relationships captures the basic structure of
the described display and that structure probably maps pretty closely to
some structure in the problem solution.
Operations like drag & drop on the screen will translate into
instantiation of new relationships (collection membership). When those
relationships change the application will have to be notified so it can
Do The Right Thing in the problem context. That is pretty straight
forward; whoever instantiates/deinstantiates a relationship just sends
the application a message at the same time.
Drag & drop is driven by OS window manager messages and will depend on
the level of abstraction your GUI subsystem talks to the OS. Let's keep
things simple and assume you used a high level GUI builder that provides
the cursor image code transparently (i.e., the icon outline that moves
with the cursor after click-and-hold).
The window builder code will need a couple of callback methods: say,
DragSelected() and NewPosition(IconID). Let's put them in TreeNode.
DragSelected() is probably a no-op unless the application needs to know
when the user is screwing around (e.g., to open a DB transaction).
NewPosition, though, needs to update the relationships. Assuming this
works like Windows Explorer (i.e., the drop is only legal if it lands on
a specific icon), that will be pretty easy because IconID will map to an
icon handle attribute in either RootNode or some TreeNode in the
hierarchy. So NewPosition does the following:
1. navigates the tree to find the new parent (IconID match),
2. removes the existing parent relationship,
3. instantiates a new one to the new parent,
4. sends a message to the application about the change,
5. sends a message to the OS to clear the screen,
6. sends a message to Tree so it can write itself to the window manager.
Tree just navigates the relationships and pumps them out to the OS
window manager to be displayed (obtaining the IconID handle as each new
icon is instantiated). [Notice how Explorer blinks when you drag & drop
a directory? It is probably just rewriting the whole pane because that
is the easiest thing to do.]
There are lots of variations in details like window builder callbacks
that depend upon the specific tools and level of abstraction for
communing with the OS window manager. But as described thus far the GUI
problem seems to be a fairly simple manipulation of collection
relationships. If a much lower level of detail is necessary to talk to
the window manager, then that should probably be placed in a separate
service subsystem (as I suggested in a previous message) since it is at
a much lower level of abstraction (pixels, icon bitmaps, and WM_xxx
messages) than this view.
[BTW, the model I drew above is an OOA model. (I am a translationist so
I don't do code.) In the OOD and/or OOP one would likely provide
additional collection classes to implement the 1:* relationships. Those
classes would have the appropriate Add, Remove, Next, Find, etc. methods
for managing membership and tree relationship navigation.]
I would probably have the GUI act to drag-n-drop by returning a reference
or ID of the "from" widget or node and the "to" widget/node. If a "drop"
event is registered in the event table (list) for that widget, then the
referenced code that is registered would be activated. The parameters
could be passed as an associative array with whatever event-specific
peices of info are needed (such as FromID and ToID). Of course, OO fans
would probably want to pass an object instead of an associative array
(dictionary). To each their own.
-T-
> Regarding drag-n-drop,
>
> I would probably have the GUI act to drag-n-drop by returning a reference
> or ID of the "from" widget or node and the "to" widget/node. If a "drop"
> event is registered in the event table (list) for that widget, then the
> referenced code that is registered would be activated. The parameters
> could be passed as an associative array with whatever event-specific
> peices of info are needed (such as FromID and ToID).
That is a detailed implementation issue and, as I indicated, there are
lots of variations. However, including "from" in the drop message is,
at best, a convenience. A separate message should still be sent to
announce when the drag starts (if one is providing general purpose
window builder code) and that is the logical place for the "from".
> Of course, OO fans
> would probably want to pass an object instead of an associative array
> (dictionary). To each their own.
Nonsense. In my world passing object references is recognized as the
worst form of coupling and we employ pure event-based communications
(message type and data-by-value data packet).
A general-purpose GUI framework that included *everything* would
probably be too overwhelming for most uses.
Besides, I am defining a "drop" event,
and not a "drag" event here. I would
suggest that one use or have a "startDrag" event to get what
you are asking here. There is no reason that a "drop" event
cannot *also* supply the "from" reference/ID. It does not
have to be mutually exclusive. I would suspect that
most uses would *not* use a "startDrag" event anyhow,
unless perhaps the GUI engine does not provide its own
indicator cursor and/or movement animation.
"Convenience"? Perhaps. But that is what good software
is all about.
>
> > Of course, OO fans
> > would probably want to pass an object instead of an associative array
> > (dictionary). To each their own.
>
>
> Nonsense. In my world passing object references is recognized as the
> worst form of coupling and we employ pure event-based communications
> (message type and data-by-value data packet).
What is a specific case example where such alleged bad coupling
would break down and show its ugliness?
>
> *************
> There is nothing wrong with me that could
> not be cured by a capful of Drano.
>
> H. S. Lahman
-T-
A general-purpose GUI framework that included *everything* would
probably be too overwhelming for most uses.
Besides, I am defining a "drop" event,
and not a "drag" event here. I would
suggest that one use or have a "startDrag" event to get what
you are asking here. There is no reason that a "drop" event
cannot *also* supply the "from" reference/ID. It does not
have to be mutually exclusive. I would suspect that
most uses would *not* use a "startDrag" event anyhow,
unless perhaps the GUI engine does not provide its own
indicator cursor and/or movement animation.
"Convenience"? Perhaps. But that is what good software
is all about.
>
> > Of course, OO fans
> > would probably want to pass an object instead of an associative array
> > (dictionary). To each their own.
>
>
> Nonsense. In my world passing object references is recognized as the
> worst form of coupling and we employ pure event-based communications
> (message type and data-by-value data packet).
What is a specific case example where such alleged bad coupling
would break down and show its maintenance ugliness?
>
> *************
> There is nothing wrong with me that could
> not be cured by a capful of Drano.
>
> H. S. Lahman
-T-
This is meant to be in an intermediate layer, below the
very top "presentation" layer which contains the actual
widget tree and event handlers.
This intermediate layer should basically provide an
application-oriented facade for the underlying domain,
to which we can attach GUIs or servers.
I'm assuming all domain Person instances are in a domain
singleton class People, whose sole instance is stored
in a static read-only variable "singleton".
My intermediate layer here is adding the ability to select
a person. A Selector simply needs to be a data structure
which holds a list and a current selection. In java, you'd
use any class which implements javax.swing.ListSelectionModel
> > ...
> > on personDelete
> > p = peopleSelector.selection()
> > if (p != null) People.singleton.remove(p)
I've written "on personDelete" to indicate that this is
the code to be executed when somebody selects a person
and presses the delete button. How you connect the actual
button widget to this particular piece of code depends
on your language and libraries.
The next two lines of code are crucial to untangling
your spaghetti ..
> > p = peopleSelector.selection()
find out which person has been selected by asking the
Selector structure to tell you what the current selection
is. Who cares what is on the screen? There may be two
selection list widgets attached to this particular Selector
structure. Or a selection list widget, a drop-down list
widget, and a radio-button widget. Maybe from different
frames. Or maybe the Selector structure got updated from
a server that just read incoming commands over the network.
Or it got changed by a test program that you're running
just to exercise this particular use case.
The key is that the presentation widgets themselves should
be working directly with the Selector and synchronising
with it. You middle layer code does not need to know
anything about the screen, or even that it exists. Absolutely
NO messing about with JList selection index etc!
> > if (p != null) ...
If it's a good Selector structure, then it will allow
de-selection, so we better make sure we've actually got
a selection. (or you might do this with pre-conditions
or exceptions)
> > ... People.singleton.remove(p)
now remove the Person object from the domain's collection
of all people .. causing CHANGE NOTIFICATION!
The change notification comes back to the Selector,
which passes it on. Any list/drop/radio widgets connected
to that Selector then know they have to refresh. Any
individual field widgets connected to that Selectors current
selection also know they have to refresh. Any other
Selectors and Adaptors in the middle layer also pass on
change notification, causing all widgets which displayed
anything to do with the People.singleton or the deleted
"p" to refresh if necessary.
------------------------
Personally I've found it convenient to wrap the middle
layer "actions" up as command models, as per Command
Pattern. Each one knows how to deal with a fine grain
use case, but doesn't know or care how it was invoked.
Elsewhere, a small library of generic event listeners
can be used to connect buttons, menu options, keypresses
etc. to middle-layer actions.
-------------+ http://www.mk.dmu.ac.uk/~gperkins/
I've said *that* a thousand times!
-------------+ http://www.mk.dmu.ac.uk/~gperkins/
>>That is a detailed implementation issue and, as I indicated, there are
>>lots of variations. However, including "from" in the drop message is,
>>at best, a convenience. A separate message should still be sent to
>>announce when the drag starts (if one is providing general purpose
>>window builder code) and that is the logical place for the "from".
>>
>
>
> A general-purpose GUI framework that included *everything* would
> probably be too overwhelming for most uses.
>
> Besides, I am defining a "drop" event,
> and not a "drag" event here. I would
> suggest that one use or have a "startDrag" event to get what
> you are asking here. There is no reason that a "drop" event
> cannot *also* supply the "from" reference/ID. It does not
> have to be mutually exclusive. I would suspect that
> most uses would *not* use a "startDrag" event anyhow,
> unless perhaps the GUI engine does not provide its own
> indicator cursor and/or movement animation.
Drag & drop is a single, continuous operation from the user's viewpoint.
If one decides to provide a low level event like Drop, then one has to
have the corresponding Drag event. That is a necessity for a client
that may be interested in concurrent processing because the operation
takes physical time.
>
> "Convenience"? Perhaps. But that is what good software
> is all about.
The convenience is that if the client isn't doing concurrent processing
it can ignore the Drag message because the "from" instance is also
included the Drop message as well as the Drag message. However, in
supporting that convenience one is providing unnecessary features and
that sort of thing leads to a framework that may "be too overwhelming
for most users". (Though the user really don't care what the messages
are; it is a developer convenience, which is even worse.)
>>>Of course, OO fans
>>>would probably want to pass an object instead of an associative array
>>>(dictionary). To each their own.
>>>
>>
>>Nonsense. In my world passing object references is recognized as the
>>worst form of coupling and we employ pure event-based communications
>>(message type and data-by-value data packet).
>>
>
>
> What is a specific case example where such alleged bad coupling
> would break down and show its maintenance ugliness?
Any time an object reference is passed (that isn't a copy) is an
example. In general the degree of coupling can be classified as, in
increasing order of coupling:
pure message: No data can be modified and no behavior invoked. The only
potential coupling problem is the timing of delivery of the message.
by-value data: The sender's implementation still can't be harmed. In
addition to timing, though, there is a data integrity issue in that the
data may no longer be valid (up to date) when it is processed.
by-reference data: Now the sender's data can be modified without its
knowledge.
independent behavior (e.g., a Java applet): Though the applet is not
part of the sender's implementation there can still be substantial side
effects when invoking it that may affect the sender. In particular,
there is no guarantee when or by whom it will eventually invoked.
object reference: Now the receiver can invoke any of the behaviors and
modify any its knowledge with complete impunity. This opens up an
unlimited potential for side effects on the sender.
Caveat: the context is references to objects that the sender itself
depends upon in its own implementation. An obvious example is passing a
reference to an object embedded in the sender's implementation, but
there are more subtle dependencies through associations. That is, the
sender rarely dispatches a semantically dependent reference with an
expectation of unlimited access. But since the receiver has no explicit
way to know what the sender's constraints are that comprises a
particularly fragile form of coupling.
At the low level of OOP, passing object references as a mechanism for
relationship navigation when addressing messages is a routine
performance enhancement. But relationship navigation is independent of
the semantics of the "sending" object and such enhancements should
appear as aspects orthogonal to class semantics.
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
Like I keep saying, having an event X is NOT mutually exclusive
to having an event Y. I described a possible interface for
a "drop" event. This does NOT exclude other event types
such as Drag_move or whatever else you envision.
There seems to be a communications gap here.
>
>
> >
> > "Convenience"? Perhaps. But that is what good software
> > is all about.
>
>
> The convenience is that if the client isn't doing concurrent processing
> it can ignore the Drag message because the "from" instance is also
> included the Drop message as well as the Drag message. However, in
> supporting that convenience one is providing unnecessary features and
> that sort of thing leads to a framework that may "be too overwhelming
> for most users". (Though the user really don't care what the messages
> are; it is a developer convenience, which is even worse.)
>
Like I said, my estimate is that a Drop event with the attributes
I described would be the most commonly used. Any others would
just be icing for fancy pants stuff.
>
> >>>Of course, OO fans
> >>>would probably want to pass an object instead of an associative array
> >>>(dictionary). To each their own.
> >>>
> >>
> >>Nonsense. In my world passing object references is recognized as the
> >>worst form of coupling and we employ pure event-based communications
> >>(message type and data-by-value data packet).
> >>
> >
> >
> > What is a specific case example where such alleged bad coupling
> > would break down and show its maintenance ugliness?
>
>
> Any time an object reference is passed (that isn't a copy) is an
> example. In general the degree of coupling can be classified as, in
> increasing order of coupling:
>
> pure message: No data can be modified and no behavior invoked. The only
> potential coupling problem is the timing of delivery of the message.
>
> by-value data: The sender's implementation still can't be harmed. In
> addition to timing, though, there is a data integrity issue in that the
> data may no longer be valid (up to date) when it is processed.
>
> by-reference data: Now the sender's data can be modified without its
> knowledge.
So you are saying that by providing the ID of the "From" thingy,
it is creating a risk of some sort?
What is the alternative? You can't just copy the object/record
of the From thingy (and others) every
single time because the event framework
cannot know what is going to be done with the information.
You would end up with a huge chain of possible things
to copy.
Also, the event behavior may want to even *change* the From thingy.
By passing a reference (the ID), the developer has sufficient
information to carry out such a task *if needed*.
Again, if you want to implement some sort of security scheme
to keep A from changing B, then ACL's are a more generic solution
than class interfaces.
>
> independent behavior (e.g., a Java applet): Though the applet is not
> part of the sender's implementation there can still be substantial side
> effects when invoking it that may affect the sender. In particular,
> there is no guarantee when or by whom it will eventually invoked.
>
How about we stick with one example at a time (drag-n-drop).
I don't see a need to introduce another example just yet.
> object reference: Now the receiver can invoke any of the behaviors and
> modify any its knowledge with complete impunity. This opens up an
> unlimited potential for side effects on the sender.
>
> Caveat: the context is references to objects that the sender itself
> depends upon in its own implementation. An obvious example is passing a
> reference to an object embedded in the sender's implementation, but
> there are more subtle dependencies through associations. That is, the
> sender rarely dispatches a semantically dependent reference with an
> expectation of unlimited access. But since the receiver has no explicit
> way to know what the sender's constraints are that comprises a
> particularly fragile form of coupling.
>
> At the low level of OOP, passing object references as a mechanism for
> relationship navigation when addressing messages is a routine
> performance enhancement. But relationship navigation is independent of
> the semantics of the "sending" object and such enhancements should
> appear as aspects orthogonal to class semantics.
>
> *************
> There is nothing wrong with me that could
> not be cured by a capful of Drano.
>
> H. S. Lahman
> h...@pathfindersol.com
> Pathfinder Solutions -- We Make UML Work
> http://www.pathfindersol.com
> (888)-OOA-PATH
>
>
-T-
OK, so let me feed this back to you to see if we are talking about the
same thing.
Assume I am a user working on an HR system. To the left is a tree
that has all the different departments in it. I click on department
1704 and a subtree appears that has managers, employees, conference
rooms, labs, telephones, etc, etc. I click on Employees, and a
subtree of the employees in that department appears. I click on Bob
Martin and his employee record appears in the area to the right.
I need to change Bob Martin's area code from 708 to 847. So I click
on his phone number. But instead of letting me edit the phone number
in-situ, the system pops up a dialog that has lots of inter-related
contact information. It has his phone number, fax number, mobile
number, and addresses. This allows two things. First, as the user I
can see all the fields that might be impacted by the change. After
all, if the area code for his home number changed, his fax number
probably changed too. Secondly, it provides a convenient software
module for cross-checking the data. For example, if I mistype the
area code, the module can easily discover that the employee's address
does not lie in the area code. Putting this code is a relatively
small dialog gives it a home. Putting it in a huge edit window for
teh whole employee could lead to spaghetti.
Is this what you were getting at? It has the advantage of binding
associated data into simple modules, and of controlling the way that
data is editted. It has the disadvantage of an extra step, but I
don't see that as a huge problem. Actually, the technique is an
extension of the tree metaphor being used over at the left. It's just
that the leaves of the tree are encapulated groups of data editted by
special dialog boxes. Sounds like a pretty reasonable scheme to me.
>I don't know how you will take this, Robert, you already took issue a
>couple of weeks back with some other stuff I posted regarding linkages
>between application domain, classes, and GUI. But you're welcome to
>it, FWIW.
We agree on some things, we disagree on others. Anything else would
be scary. ;^) Cordial diagreement is an effective teacher and I
value it.
>In <m15teu89c6h864g16...@4ax.com> Robert C. Martin <u.n.c.l.e.b.o.b.@.o.b.j.e.c.t.m.e.n.t.o.r.d.o.t.c.o.m> writes:
>>Next, make the presenter. Gather all the data and manipulations you
>>will need together. That includes the trees, lists, buttons, other
>>lists, etc. But don't mention the GUI.
>
>This part baffles me (I have *much* to learn), because when you write,
>e.g., "buttons" or "tree" I think "GUI", which is clearly not what you
>mean. In Java Swing, for example, I would use JButtons or
>JTrees--which I think of as GUI--for those... I know that these
>components can be given different L&Fs, but I don't think this is what
>you mean by GUI either.
The software can be aware that a button exists, without knowing
anything about JButton. Don't think of it as a button -- think of it
as a control point for a command.
Remember the EmployeeTerminatorModel? This class managed the
enable/disable state of the "Terminate" control point. It also
received a callback when the Teminate command was invoked. From the
EMployeeTerminatorModel's point of view, it didn't know anything at
all about JButton, but still managed to control the important bits of
it.
So, write your presenter so that it knows about the control points for
each command, and can manipulate those control points nicely, without
having to know the actual form of the GUI widget that the control
point is controlling.
>
>>In fact, make it possible to
>>manipulate the Presenter from a textual UI.
>
>Do you mean something with a text-based shell, and a typical session
>like:
Yes, like that. You might even want to write the text-based shell the
first few times you do this. It'll help you to ensure that you are
getting your separation right. After you do it a few times, though,
your unit tests ought to be sufficient to guarantee the appropriate
separation.
Robert C. Martin | "Uncle Bob"
Fine so far, we're just navigating.
>I need to change Bob Martin's area code from 708 to 847. So I click
>on his phone number. But instead of letting me edit the phone number
>in-situ, the system pops up a dialog that has lots of inter-related
>contact information.
No pop ups. Ever.
> It has his phone number, fax number, mobile
>number, and addresses. This allows two things. First, as the user I
>can see all the fields that might be impacted by the change. After
>all, if the area code for his home number changed, his fax number
>probably changed too. Secondly, it provides a convenient software
>module for cross-checking the data. For example, if I mistype the
>area code, the module can easily discover that the employee's address
>does not lie in the area code. Putting this code is a relatively
>small dialog gives it a home. Putting it in a huge edit window for
>teh whole employee could lead to spaghetti.
Well, the software modularity is about right, but I would expect that
(a) all these fields were already displayed without any extra pop-up,
and (b) they should be edited in place. So, the question is how to
display the same modularity on the "flat" presentation. Basically,
you might have a contact frame on the flat, that contains voice and
fax numbers (not really a great example, but let's stay with it).
Generally, I like to (1) keep all data displayed but locked on a
browse screen, (2) click a button (or something) to unlock the data -
to enter edit _mode_, (3) click another button (or something) to
explicitly commit the data or to cancel the edit, in either case
returning back to mode (1). This is only a standard design for
character-mode screen designs circa 1985.
>Is this what you were getting at? It has the advantage of binding
>associated data into simple modules, and of controlling the way that
>data is editted. It has the disadvantage of an extra step, but I
>don't see that as a huge problem. Actually, the technique is an
>extension of the tree metaphor being used over at the left. It's just
>that the leaves of the tree are encapulated groups of data editted by
>special dialog boxes. Sounds like a pretty reasonable scheme to me.
I don't mind the extra step, in fact, I think the explicit mode-change
clicks are a very positive advantage, both for the programmer and for
the user.
You assumed a very powerful navigation tree. For large datasets, this
is not generally possible -- the tree would probably bring up a form
with several search parameters, which would return a pick list, from
which you would finally arrive at an individual record. Tree plus or
minus narrower search -- both are in fact enforcing modality, either
you are in navigation mode, or in search mode, or in view mode, or in
edit mode, or in update mode (for a second!)
But you don't want to have dozens of buttons all over a flat
presentation to enable editing of these three or those four fields.
Instead, you might have the interface watch for the first field to be
modified. On that keystroke, you could re-lock all unrelated frames
(fields) and logically bind the form's update button to just the
edited frame/fields.
(Actually, this whole example is a little misleading at this point,
from my general design, but maybe the gist is clear)
>>I don't know how you will take this, Robert, you already took issue a
>>couple of weeks back with some other stuff I posted regarding linkages
>>between application domain, classes, and GUI. But you're welcome to
>>it, FWIW.
>
>We agree on some things, we disagree on others. Anything else would
>be scary. ;^) Cordial diagreement is an effective teacher and I
>value it.
Well, let's not scare the horses.
Just remember, my position is lots of modality, and no pop-ups.
Joshua Stern
>>Drag & drop is a single, continuous operation from the user's viewpoint.
>> If one decides to provide a low level event like Drop, then one has to
>>have the corresponding Drag event. That is a necessity for a client
>>that may be interested in concurrent processing because the operation
>>takes physical time.
>>
>
>
> Like I keep saying, having an event X is NOT mutually exclusive
> to having an event Y. I described a possible interface for
> a "drop" event. This does NOT exclude other event types
> such as Drag_move or whatever else you envision.
>
> There seems to be a communications gap here.
It is not about precluding a Drag. The issue is that concurrency
demands that one *must* have a Drag (or equivalent) in a general service
interface. That is important because...
>>>"Convenience"? Perhaps. But that is what good software
>>>is all about.
>>>
>>
>>The convenience is that if the client isn't doing concurrent processing
>>it can ignore the Drag message because the "from" instance is also
>>included the Drop message as well as the Drag message. However, in
>>supporting that convenience one is providing unnecessary features and
>>that sort of thing leads to a framework that may "be too overwhelming
>>for most users". (Though the user really don't care what the messages
>>are; it is a developer convenience, which is even worse.)
>>
>>
>
> Like I said, my estimate is that a Drop event with the attributes
> I described would be the most commonly used. Any others would
> just be icing for fancy pants stuff.
The Drag will already have provided the "from" identity. Therefore
having the "from" in the Drop is redundant. It is icing on the cake
provided as a convenience for a subset of the functionality.
>>>>>Of course, OO fans
>>>>>would probably want to pass an object instead of an associative array
>>>>>(dictionary). To each their own.
>>>>>
>>>>>
>>>>Nonsense. In my world passing object references is recognized as the
>>>>worst form of coupling and we employ pure event-based communications
>>>>(message type and data-by-value data packet).
>>>>
>>>>
>>>
>>>What is a specific case example where such alleged bad coupling
>>>would break down and show its maintenance ugliness?
>>>
>>
>>Any time an object reference is passed (that isn't a copy) is an
>>example. In general the degree of coupling can be classified as, in
>>increasing order of coupling:
>>
>>pure message: No data can be modified and no behavior invoked. The only
>>potential coupling problem is the timing of delivery of the message.
>>
>>by-value data: The sender's implementation still can't be harmed. In
>>addition to timing, though, there is a data integrity issue in that the
>>data may no longer be valid (up to date) when it is processed.
>>
>>by-reference data: Now the sender's data can be modified without its
>>knowledge.
>>
>
>
> So you are saying that by providing the ID of the "From" thingy,
> it is creating a risk of some sort?
I am saying that there is more coupling when passing data by reference
than when passing it by value. More relevant, providing the "from" ID
would normally be a data-by-value communication, so it would be a less
risky coupling than this.
>>independent behavior (e.g., a Java applet): Though the applet is not
>>part of the sender's implementation there can still be substantial side
>>effects when invoking it that may affect the sender. In particular,
>>there is no guarantee when or by whom it will eventually invoked.
>>
>>
>
> How about we stick with one example at a time (drag-n-drop).
> I don't see a need to introduce another example just yet.
This has nothing to do with Drag & Drop. This sub thread stems from
your assertion about OO people passing object references around. The
Drag & Drop subthread stems from a completely different context. You
are hauling out forensic ploys again (deflecting with non sequiturs).
Since I am not in a patient mood today due to a root canal, you only get
one strike before being out. Ta-ta.
Serious?
What about if a field asks for an employee number? Either the
user has to leave the half-finished form to go look for it,
or some kind of pop-up is available to assist in the look-up.
You might suggest that they can search for the employee
number *before* getting to that form. However, what if
there are other similar items, like vehicle ID?
(For example, associating an employee to a given
company truck.)
-T-
Ya got me.
Yes, I still use pop-ups for finders.
At least, I have done so traditionally. What I'd prefer is to
dynamically rearrange the presentation to put the modal finder dialog
onto the form, but that's a lot more work.
But the topic was GUI spaghetti, which is mostly about data entry and
modification, not navigation or browsing, ... so I (over)simplified my
answer (actually typed then erased these very qualifications).
Also I'll do a pop-up for system-level error messages that basically
say CALL SUPPORT IMMEDIATELY!
J.
The advantage of a pop-up is that you can have almost unlimited
space for entering search criteria, displaying close matches,
etc. I see no advantage to trying to jam it all onto
one screen. Screen real-estate is often a precious
enuf resource. The only advantage may be that the
most commonly-used search techniques can be accessed
without opening a pop-up. But, this is not satisfactory
for a full-blown lookup, which one may need if the common
routes don't work.
>
> But the topic was GUI spaghetti, which is mostly about data entry and
> modification, not navigation or browsing,
Data entry may involve lookup up information that you don't
have on hand at the moment due to typos or whatever.
> ... so I (over)simplified my
> answer (actually typed then erased these very qualifications).
>
> Also I'll do a pop-up for system-level error messages that basically
> say CALL SUPPORT IMMEDIATELY!
>
> J.
-T-
I am not understanding you here. What does "it" refer to?
Redundancy of information provided *is* justifed if
there is a big usage quantity descrepancy between
one supplier and another. For example, your ISP could
also fax you usenet messages if it really wanted to.
However, it also provides it via its NTTP (sp?) protocol
(electronically). There are duplicate paths
to the same bits of info because one is more
convenient for certain things. It is also why
your car has a rear view mirror. You *could* get
the same info by turning your head.
>
> >>>>>Of course, OO fans
> >>>>>would probably want to pass an object instead of an associative array
> >>>>>(dictionary). To each their own.
> >>>>>
> >>>>>
> >>>>Nonsense. In my world passing object references is recognized as the
> >>>>worst form of coupling and we employ pure event-based communications
> >>>>(message type and data-by-value data packet).
> >>>>
> >>>>
> >>>
> >>>What is a specific case example where such alleged bad coupling
> >>>would break down and show its maintenance ugliness?
> >>>
> >>
> >>Any time an object reference is passed (that isn't a copy) is an
> >>example. In general the degree of coupling can be classified as, in
> >>increasing order of coupling:
> >>
> >>pure message: No data can be modified and no behavior invoked. The only
> >>potential coupling problem is the timing of delivery of the message.
> >>
> >>by-value data: The sender's implementation still can't be harmed. In
> >>addition to timing, though, there is a data integrity issue in that the
> >>data may no longer be valid (up to date) when it is processed.
> >>
> >>by-reference data: Now the sender's data can be modified without its
> >>knowledge.
> >>
> >
> >
> > So you are saying that by providing the ID of the "From" thingy,
> > it is creating a risk of some sort?
>
>
> I am saying that there is more coupling when passing data by reference
> than when passing it by value. More relevant, providing the "from" ID
> would normally be a data-by-value communication, so it would be a less
> risky coupling than this.
>
>
Again, your use of "it" is confusing me here. You appear to
be agreeing with me being that an ID is a "value".
Data access level is a minor issue anyhow. During
any given event handling, what may need to be read or modified
could be just about anything. If you need to flip
bit X to get the job done, then you need to do it.
That is life. If the biz rules say you need to
delete 30,000 records when drag and drop is
done/triggered, then you need to do it. The job
of the Drop event is to provide sufficient information
to the event logic to carry out what it needs to.
(Usually this by itself does not change anything, but
simply gives info to the app.)
>
> >>independent behavior (e.g., a Java applet): Though the applet is not
> >>part of the sender's implementation there can still be substantial side
> >>effects when invoking it that may affect the sender. In particular,
> >>there is no guarantee when or by whom it will eventually invoked.
> >>
> >>
> >
> > How about we stick with one example at a time (drag-n-drop).
> > I don't see a need to introduce another example just yet.
>
>
> This has nothing to do with Drag & Drop. This sub thread stems from
> your assertion about OO people passing object references around. The
> Drag & Drop subthread stems from a completely different context. You
> are hauling out forensic ploys again (deflecting with non sequiturs).
I swear I have no (conscious) alterior motives. I honestly did
not understand the (appearent) change in topic.
There is no smoke in the grassy knole.
> Since I am not in a patient mood today due to a root canal, you only get
> one strike before being out. Ta-ta.
>
>
I suggest you stay out of the teaching profession. An intolerance
for communication gaps will likely get you fired.
>
>
> *************
> There is nothing wrong with me that could
> not be cured by a capful of Drano.
>
> H. S. Lahman
> h...@pathfindersol.com
And marketing also
> Pathfinder Solutions -- We Make UML Work
> http://www.pathfindersol.com
> (888)-OOA-PATH
-T-
Sorry to SPAM this news group, but you may want to have a look at our
SansGUI product which allows scientists and engineers to develop and
deploy their simulation programs without writing a single line of GUI
code (yes, Fortran is supported :-):
http://protodesign-inc.com/sansgui.htm
Forget about hundreds or thousands of API function calls, message
maps, multi-thread handling, mouse event processing, model and view
synchronization, dynamic charting, etc. All you need is one data
object format and one API function prototype. Please follow the
example links on the page to see a variety of sample projects, screen
shots, and source code:
http://protodesign-inc.com/sg_examples.htm
Cheers,
Greg Chien
http://protodesign-inc.com