in reply to Re: OT: Design question
in thread OT: Design question

It's actually even more complicated than that. There are, say, 5 different widget properties. (It's actually more like 20, and some aren't actually widget properties, but are based on widget properties.) Every widget will have a value for every property. The handlers trigger based on the values for the widget properties, not if the widget has a given property. So, I really need to have a way to ask a given handler if it needs to fire based on a given widget and the values for all the properties. And, the issue is how to maintain in a human-readable fashion all these mappings.

I do appreciate the fact that you've helped refine the problem for me. It's not about the architecture of triggering events and event handlers. It's really about how to make this system accessible by humans. I need to abstract out the complexity and put it in one place. The complexity is going to be there and I can't wish it away. What I need to do is concentrate it so that it's not spread throughout the code.

Being right, does not endow the right to be rude; politeness costs nothing.
Being unknowing, is not the same as being stupid.
Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Replies are listed 'Best First'.
Re^3: OT: Design question
by graff (Chancellor) on Oct 01, 2004 at 02:11 UTC
    It's not about the architecture of triggering events and event handlers. It's really about how to make this system accessible by humans.

    Amen.

    Since you need build the app to support ongoing adaptability / expandability, the first thing to do is think about how to optimize, from the perspective of the people who will be doing this, the task of adding / modifying app behaviors.

    That means working out a conceptual model for controlling the app that is easy to explain and understand, and then working out a set of cookbook steps that involve the minimum possible amount of input from the person doing the task -- i.e. if the task is structured so that any single piece of information or logic needs to be supplied in more than once place by a human, you probably haven't got the right design yet.

    That said, I like BrowserUK's take on the matter, which seems to go in the same direction as tmoertel's notion: capture the relations as data rather than as blocks / objects / classes of code. That will generally mean less code, and less work for the humans who handle the "behavior modifications"; those are both good things.

Re^3: OT: Design question
by tmoertel (Chaplain) on Oct 01, 2004 at 17:51 UTC
    It's actually even more complicated than that.
    Still, I wouldn't change the approach: Create an external specification that is tailored to capture your application's complicated relationships in a way that is intuitive to humans; then, translate the specification into the desired code, either at run time or during a pre-processing step.
    There are (about 20) different widget properties..., and some aren't actually widget properties, but are based on widget properties.) Every widget will have a value for every property.
    This is important information that will help us design our specification.
    The handlers trigger based on the values for the widget properties, ....
    This, too, is good stuff to know. (Maybe you could tell us what you're really doing?)
    So, I really need to have a way to ask a given handler if it needs to fire based on a given widget and the values for all the properties.
    Not necessarily. You might, for example, be better served by having an object of specialized type whose responsibility it is to manage widget property–to–handler relationships. Then you would ask it what handlers ought to be fired, not the handlers themselves. But that's a decision to be made later. For now, let's just figure out how to specify the relationships.

    If I'm reading your new constraints correctly, the relationship we're concerned with is that between widget properties and handlers, not widgets and handlers. So, let's start out with a simple matrix that enumerates all of the possible points of intersection:

    Property Handler 1 2 3 4 ... ======== =========== A a b B C c ...
    This looks much like what I suggested before, but now we have a new interpretation. Each a or b in the matrix represents a set of conditions that govern whether the associated handler (given by column) may fire for the current widget based on its current value of the associated property (given by row). In other words, we can interpret the column under Handler 3 as saying, Handler 3 will fire for the current widget if the current widget's A property satisfies condition b and its C property satisfies condition c. Our rule, for now, is that all associated conditions must be satisfied in order to fire the handler.

    If that's all the more complicated your relationships are, then we're done. But maybe the all-or-none rule is too limiting. Maybe Handler 3 ought to fire if b(A) or if c(C) is satisfied. Then, a simple matrix will not suffice; we'll need a way of specifying expressions:

    Handler Firing condition ======= ================ 1 a(A) 2 ... 3 b(A) || c(C) ...
    If we filled out this two-column table for all of your handlers, we would have a lot of redundancy because, in your original question, you said that, "there's only really about 4-5 different types of events, just with different parameters." So, let's allow the handlers and conditions to be parameterized (and we'll give the handlers names, while we're at it):
    Handler Firing condition ======= =================== Page("Jim") a(A) Email("foo-alert@...") b(A) || c(C, "foo") Email("bar-alert@...") b(A) || c(C, "bar")
    At this point, we have to be careful that our specification doesn't devolve into a bunch of if-statement equivalents. But I'm going to stop here because I'm just guessing about what you really need and don't know which refinement to make next. I don't have enough information to know whether it would be better, for example, to factor out redundancy in our specification or to leave it in. This is where knowing about what you're really doing would be helpful.

    Depending on your needs, reasonable refinements might include factoring out common subexpressions, adding environmental context, or adding a related specification table. Each involves trading one kind of complexity for another, and whether it makes sense for you depends on the costs of managing different kinds of complexity in your application and programming culture. Only you know enough to make these decisions at this point.

    Cheers,
    Tom