Re: implementing roles in OOP......

From: H. S. Lahman (h.lahman_at_verizon.net)
Date: 04/19/04


Date: Mon, 19 Apr 2004 18:58:37 GMT

Responding to Nicholls...

On "walking" the real requirements into a model:

>>>Messages.
>>>Something that defines what needs to be done to a message i.e.
>>>processing (but this may mean sending down a worm holes like a queuing
>>>system)
>>
>>(1) I assume this mean that the same Message may be processed
>>differently based on some context. If so, that sounds like Strategy or
>>State:
>
>
> 1st thing most of this is an attempt to capture and extend some of the
> ideas put forward in "Enterprise integration patterns" - which I can
> heartily recommend - I am at best a plagurist.
>> * invokes 1
>>[Message] ------------------ [RoleContext]
>> R1 A
>> | R2
>> +-------------+--------...
>> | |
>> [ContextA] [ContextB]
>>
>>Somebody needs to instantiate the R1 relationship for a particular
>>context. That would probably be whoever initially accepts the message
>>(e.g., it checks the message identifier or some state variable). Who in
>>your problem space would that be?
>>
>>Some other open questions... What are the contexts? And what is the
>>processing being defined? (E.g., is it so complex it can't be
>>encapsulated in a single ContextX object?)
>
>
> Not sure what you mean by contexts - there is some sort of
> encapsulation of something that transforms a message (by value) I
> think this is something like a strategy and would potentially;

One possibility: ContextA => DataMessage and ContextB => CommandMessage.
  That assumes the behaviors for each type of message are rather
different. Then Message would only handle responsibilities that were
not dependent on the type of message. IOW,

>
> consume
> transform

[RoleContext] would provide an interface for consume and transform that
would be implemented differently depending upon whether the message
identifier indicated the it was a data message or a command message.

> direct i.e. decide which of the next nodes the message should be sent
> - a bit like if/else

While this might be a Message responsibility, I would bet that it should
really be a responsibility of someone else (e.g., Router). [Of course
I'm applying my own understanding of network messaging systems for lack
of more detailed requirements. Still, I would expect the algorithms to
be sufficiently complex to warrant encapsulation in an class dedicated
to that subject matter.]

>>>Something that defines how the net of nodes is traversed.
>>
>>(3) Sounds good, especially if Leafs are shared by Composites. IOW, a
>>smart collection class.
>
>
> hmmm, I'd prefer to externalise it, there potentially could be
> different ones at run time i.e. depth 1st, width 1st, sychnronous,
> asyncronous (see below).

It is already externalized from the Composite structure! That's kind of
the point of postulating such an entity -- to encapsulate the traversal
algorithm outside of the actual structure. One reason for doing that is
so that one can provide different traversal algorithms (e.g.,
subclassing whoever this is or providing it with its own Strategy)
without touching the network representation itself.

>
> So for me (currently) it's a strategy of a visitor (though I'm using
> visitor in the loosest possible sense).

I see no evidence so far of a Visitor. So far we only have:

- Message and some set of associated behaviors that may need to be split
out as roles in a State of Strategy pattern.

- A Composite network structure that may have one or more traversal
algorithms externalized from the structure.

At best that are three relatively simple GoF patterns (Composite and two
State/Strategy) that are completely independent (i.e., no interaction
between Message and Node has been defined yet).

>
>
>>>Something that defines how the processing is dispatched this can be
>>>asynchoronously.
>>
>>(4) I'm not sure what you mean by 'dispatched'. What processing is
>>being dispatched? Who logically owns it? Node? Someone else not
>>mentioned? What are the rules and policies for dispatch?
>>
>>You can get asynchronous for free if you use object state machines for
>>behavior.
>
>
> I'm in 3GL world (C#) where dispatching synchronously and
> asynchronously is explicit.

Asynchronous dispatch is never explicit in the 3GL world; 3GLs only
support <synchronous> procedural message passing. But you can emulate
it fairly trivially with state machines and event queue managers in any
3GL. I would think that would be highly desirable in such an
application where one has to deal with things like handshaking protocols
and time-outs that are inherently asynchronous.

>
> But yes dispatching is the encapsulation of this decision (and
> possibly the traversal strategy).

You have to put more words around 'dispatching'. Those requirements
will be crucial to correctly modeling how Message and Node interact.

>
>
>>>Something like a 'thread' which orchistrates the above two (actually
>>>this is a visitor and they are a strategy) and gives 'return' events
>>>and 'error' events with the nodes.
>>>Something that creates 'threads'.
>>
>>(5) Until I know what 'dispatch' is about, I can't comment on this.
>>However, I can say that threads are an implementation issue for
>>nonfunctional requirements (i.e., concurrency) so they don't affect the
>>OOA solution for functional requirements that determines whether Visitor
>>is needed.
>>
>
>
> Currently the 'thread' is a visitor, it has a strategy which is the
> dispatcher which decides how a given message is sent to a given set of
> nodes i.e. async, sync, depth, wdith.

That is neither a thread or a Visitor. It is a selection algorithm.
That is, it is the sort of code that would be executed to instantiate a
relationship between Message and either DataMessage of CommandMessage.
Or such code would be executed to instantiate the relationship between
the root (or entry) Node in the network structure and a particular
traversal algorithm.

There is nothing so far to indicate whether one can achieve better
performance by placing that algorithm in a thread and creating multiple
instances of the thread. Nor is there any indication so far that there
exists the special sort of inclusive *:* relationship among two sets of
subclasses where one would use Visitor.

BTW, I would steer way clear of thinking about threads in this context.
  They are not even remotely analogous. The use of Visitor is a high
level design decision for resolving functional requirements. Threads
are a low level implementation decision for resolving nonfunctional
requirements.

>
>
>>>Some nodes pick up messages from worm holes (like a external queuing
>>>system).
>>
>>(6) Fine; routine in R-T/E.
>>
>
>
> This could be files, db's, queues but there are outised the system,
> messages pop into existence or pop out of existence down these nodes.

What do you mean by "down these nodes"? A Message has to come from
somewhere. If that source is external to your application, then it is
simply an interface message and the immediate source is irrelevant.
[Routing history information may be useful for other reasons (e.g.,
diagnostics) but that is driven by other requirements than those around
"popping into existence".] If it is internal to your application,
someone has to create it and that someone will understand its context.

>
>
>>>There are two types of nodes in the context of a visiting thread - a
>>>processing node and a return node i.e. 2 visit methods.
>>
>>(7) Why not each flavor of Node has a different implementation of the
>>same method? Does the behavior for each type of node change with the
>>context of collaboration? If so, how?
>
>
> Not sure what you mean.
>
> Here I'm trying to draw on the analogy of procedural code...i.e. we
> have ;
> variables
> atomic processes
> composire processes i.e. calls (which may well go off somewhere else
> invisibly to use) - but invisibly to us in a sense.
> return
>
> return doesn't do anything, but is does something to the context i.e.
> clear up all the rubbish and pass something on to something else
> OUTSIDE the current context.

I am asking about requirements for the problem you are trying to solve.
  Analogies in other problem spaces are not useful for that. You
indicated there are different types of Nodes, which suggests they have
different responsibilities. I am trying to establish the problem
context that determines those differences. For example,

(1) Does a particular Node have the same responsibilities throughout the
execution?

(2) Does a particular Node take on different responsibilities during the
execution? If so,

(2a) Do the responsibilities for a Node depend solely upon Message type?

(2b) Do the responsibilities for a Node depend upon the state of
processing of a particular message?

(2c) Do the responsibilities of a Node depend on something other than a
particular message type and/or processing?

>
>
>>>These structures need to be able to be nested i.e. I should be able to
>>>embed a a network within 'owning' node.
>>
>>(8) This gets interesting. Is the following correct?
>>
>> * connects
>> [Node] -----------------------+
>> A |
>> | R3 | R4
>> +----------+-----------+ |
>> | | | |
>>[Processor] [Return] [Network] <>--------+
>>
>
>
> Yep as above.
>
>
>>>The structure nodes may not actually define the processing themselves
>>>but may create processing objects - not sure - it guantees stateless
>>>behaviour so I like it.
>>
>>(9) Stateless is a low level OOD or OOP performance issue. The context
>>here is the OOA decision of whether Visitor is needed.
>
>
> OK, but I want a 'execution' of a network to be completely decoupled
> from any other 'execution' of the same or any other network (unless
> someone has gone to the bother of not doing this.
>
> In the same way that given executions of a piece of software is
> independent of any other (within reason) unless the software
> explicitly tries to communicate with other software outside it's
> control.

Converting stateful objects to stateless objects is usually a pretty
mechanical change at the OOP level. [Automatic code generators can do
this for a subsystem by simply setting a switch. However, it may
require re-negotiating external interfaces if the state information
can't be stored in the DB. That is, if state information must be stored
in the subsystem's client, it will have to be passed to the subsystem
via the interface (e.g., XML strings).]

>
>
>>>There seems to be about a billion ways of stringing these things
>>>together.
>>
>>(10) One step at a time. B-)
>>
>>How does [Message] fit in the picture vis a vis [Node]? I assume there
>>is some direct relationship between [Message] from (1) to [Node] from
>>(8). But it might be to [Processor] or even [Return]; can't say without
>>more information on processing.
>
>
> Hmmm - again to use the procedural software analogy - we have a
> function in code as a definition or plan, we can execute that function
> and data will pass through the processes defined by our function - in
> that sense the network is like a function and the nodes are like
> statement, but they are a little like factories i.e. they define the
> process and the dependencies but they aren't the processes themselves.

Again, I am asking for /your/ requirements for /your/ problem. What is
the problem space connection (if any) between Message and Node?

>
>
>>Next is the traversal issue from (3). My guess is that the traversal is
>>really a routing algorithm for messages:
>>
>> * connects
>> [Node] -----------------------+
>> A |
>> | R3 | R4
>> +----------+-----------+ |
>> | | | |
>>[Processor] [Return] [Network] <>--------+
>> A
>> | R5
>> +-------+-------+
>> | |
>> [LAN] [RootHome]
>> | 1
>> | routes through
>> |
>> | R6
>> |
>> | 1
>> [RoutingAlgorithm]
>>
>>[Caveat. I am already speculating like crazy because there are too many
>>open questions. I am simply trying to demonstrate how I would chase an
>>OO solution without any preconceptions about Visitor or composition.]
>>
>
>
> You are....
>
> fair enough. Nodes are objects and connected together in networks and
> these networks explicitly define the temporal dependencies between
> implied processes.
>
> The route through the network (like in software) is defined by the the
> statements (and variables - note there are no varaibles and there
> doesn't need to be) and conditions - so the route for a given thread
> is statically defined by the network and dynamically by 'if' nodes.
>
> Note that the thead analogy breaks because messages are not
> conceptually executed in series.

Enough with the analogies! B-) What are the requirements? What
temporal dependencies? What implied processes?

IOW, tell me where my diagram fails to correctly capture your problem
space. [Aside from the fact that there is no Visitor. B-)]

>
>
>>Then one has to work out how the dispatching in (4) fits with (1) and
>>(8). My guess would be that [RoleContext] stuff is pretty cosmetic
>>(e.g., formatting data packets, putting routing information in a header,
>>etc.). Given that the routing algorithm is in [RoutingAlgorithm], that
>>pretty much leaves the processing from (4) as protocol stuff. I would
>>expect that to be handled via [Processor] and [Return].
>
>
> hmmm routing behaviour can implicitly or explicity be enbedded in
> messages but I would handle that by getting some nodes to consume
> their messages in "message filters" or by embedding conditional
> behaviour in 'message routers".

Why wouldn't the Node ask the Message for any embedded routing
information? It is reasonable for a Message to know its ultimate
destination. It is also reasonable for it to know where it has already
been.

Note that the level of abstraction of the latter is open to negotiation.
  Message doesn't need to understand anything about the semantics of
networks to keep track of an ordered list of generic "routing entries".
  That allows Node or Network or the traversal algorithm to interpret
and process a Routing Entry in more detailed terms.

That makes (in this respect) Message a dumb data holder while Node,
Network, or the traversal algorithm has all the smarts about network
connections and navigation.

>
>
>>However, to keep them cohesive there has to be someone else in the
>>picture that they talk to. IOW, I would expect objects that would be
>>surrogates for the hardware, like [Router]. Then [Processor] and
>>[Return] don't really do anything except provide state machines for the
>>protocol hand-shaking. Their state actions might well provide
>>dispatching (e.g., processing a time-out) by sending a message to
>>someone who cares.
>
>
> Again I am in 3GL world I don't want to explicitly queue messages
> inside the framework, a message pops into existence and we should be
> able to 'run' that message through the network without queueing them
> explicitly.

The problem is that network processing is inherently asynchronous.
Layered models serialize the processing by hiding the event-based
processing in the infrastructure. But in doing so they hide the entire
network behind CORBA or DCOM. But you don't have that option; the
network is necessarily explicitly exposed in your problem.

IOW, if you are going to mess around with networks at the message level,
you would be well-advised to employ and asynchronous model from the
outset. A synchronous solution will be unnecessarily complicated and
fragile.

To respond more directly, what happens when the final destination Node
disappears temporarily while multiple Messages to it are being
processed? You could have a single thread per Message and pause all
those routing to the Node until it comes back. That's a lot of overhead
(thread processing isn't free and you have to find the threads both to
pause them and to release them) compared to pausing the pop function for
a single Node event queue.

[There are even more exotic problems with race conditions in pausing the
threads (e.g., while you are pausing thread 1, thread 2 completes and
sends its message the the Big Bit Dump in the Sky). With the queue
approach one can never lose a message. With concurrent threads one
opens a whole new vista of foot-shooting.]

*************
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
hsl@pathfindermda.com
Pathfinder Solutions -- Put MDA to Work
http://www.pathfindermda.com
(888)-OOA-PATH



Relevant Pages

  • Re: implementing roles in OOP......
    ... Then Message would only handle responsibilities that were ... passing a message through the a network. ... It is at a lower level of abstraction, ... It is a selection algorithm. ...
    (comp.object)
  • Re: JUnit FAQ suggests private methods bad design?
    ... > Testing private methods may be an indication that those methods should ... the relevant public responsibilities, one has also tested the private ... algorithm may be implemented with thousands of realized LOC but the ... selected, [Network] can invoked FlowAlgorithm.Solve. ...
    (comp.object)
  • Re: Attaching a behavior only to multiple classes.
    ... responsibilities are important to the problem, ... specific solution context. ... The point is that GoF uses delegation to separate the behavior from ... >>concerns of instantiation, implementation, and navigation. ...
    (comp.object)
  • Re: Design advice needed
    ... describing a graph and the other is executing some behavior that is dependent on context not directly expressible in terms of the graph. ... Loading/saving from/to persistence is one suite of responsibilities. ...
    (comp.object)
  • Re: A Design Problem
    ... there are a flock of reasons why one should be worried about the overall design and should look for another way to allocate responsibilities and/or implement relationships when managing collaborations. ... then the client needs to navigate a relationship that is directly to the ... In an OOPL that would be enforced in the type system by making the pointer type be specifically a Button type rather than a Control type. ... But to make that decision the sender method must understand its context in the overall solution. ...
    (comp.object)