Re: OO Principle - reference needed



Responding to Sanford...

I have a question about setting up collaborations. Let me give a trivial
example. Say an object uses a timer. It doesn't create the timer itself,
rather the timer is passed to it when it is created. The object that
uses the timer stops and starts the timer as it pleases and consumes
"tick" events generated by the timer. My question is whose
responsibility is it to ensure the integrity of the relationship between
the two object?

First, some background to make sure we are on the same page. We have:

[SomeObject]
| *
| provides timer notifications to
|
| R1
|
| initializes
| 1
[Timer]

There are three ways to implement the OOA/D's R1 relationship.

(1) One can pass a Timer reference to a method of SomeObject as a argument. That creates a temporary relationship for the scope of method. That is usually a bad idea for two reasons. Passing object references is the worst form of coupling. In this context, though, the problem is that whoever invokes the SomeObject method must understand the rules and policies of the R1 instantiation (i.e., which Timer to use) _in the course of its primary collaboration with SomeObject_. It is quite possible that the reason that object is collaborating with SomeObject is completely unrelated to time-outs so that object should have no clue about [Timer].

(2) One can provide a referential attribute in SomeObject that is assigned the identifier of a Timer object. To navigate the relationship SomeObject then employs a Find on the set of all [Timer] objects using the identifier. This is the RDB style of implementing the relational model.

(3) One can provide a referential attribute in SomeObject that is assigned a reference to a Timer that can be navigated directly. This is the normal OO style of implementing the relational data model.

When you say the timer is passed to SomeObject when it is created I assume you mean as a constructor argument. (A simple knowledge setter would be used if the assignment is dynamic after the creation of SomeObject.) That is essentially applying the implementation approach of (3). So far, so good.

The integrity of the R1 relationship is then the responsibility of whoever invokes the constructor of SomeObject. IOW, the rules and policies of instantiation normally includes instantiation of the object's relationships. When SomeObject is created there is a context and that context will determine which Timer should participate in the relationship. Thus the instantiation context includes the object's relational environment in the same way that it includes the initialization of its state for the context.

My point in the quoted paragraph was that the rules and policies that govern the context of object creation are usually quite different than the rules and policies that govern object collaboration.

To continue with the example, the consumer, i.e. the object that uses
the timer, makes certain assumptions. It assumes that when it starts the
timer, it's not already running. And when it stops the timer no one else
will start it again. In other words, it's in control of the timer.

This is a much broader issue that is related to the fundamental way the OO paradigm approaches collaborations.

In fact, SomeOBject has no expectations about Timer; its implementation should not even know that a Timer exists. The whole point of the OO paradigm is to eliminate the hierarchical implementation dependencies implicit in the Do This approach of traditional functional decomposition where the message sender /expects/ something to be done.

As a result, messages in the OOA/D are supposed to be announcements (I'm Done) and they are peer-to-peer to avoid hierarchies. To provide an announcement the object only needs to understand itself and not its context.

It is the job of the developer to connect the dots of the OO solution in the OOA/D by mapping announcement messages to objects that care what is being announced. In UML one does that in an Interaction Diagram that is at a higher level of abstraction than individual object methods. So, in theory, one can define collaborations after all of the object methods have been defined and implemented.

One rigorous way to do that mapping is through DbC. There is a precondition in the state of the overall problem solution that must prevail for the Timer.start method to be invoked. That precondition will exactly match the postcondition of some method of SomeObject. IOW, SomeObject does something that makes it appropriate to start the Timer in the overall solution. Therefore one generates a message in that method to announce that postcondition and one addresses that message to the right Timer. (Hold that thought about "right" Timer for a moment.)

A similar logic chains applies to the method of SomeOBject that responds to the Timer event. It has a precondition that must prevail for it to execute at that point in the overall solution. That precondition maps to the postcondition of whatever Timer method tracks the elapsed time. So the Timer announces the postcondition that the time has elapsed and the developer maps that announcement to the method of SomeObject that cares.

Thus in the OO paradigm, both SomeObject and Timer are defined around doing their own thing (i.e., intrinsic, atomic behaviors) without regard to context. So their implementations have no clue about even the existence of the other object. It is the developer that must provide the sequencing of peer-to-peer announcement messages and a mechanism for addressing them. That addressing mechanism brings us full circle back to who is responsible for ensuring the right Timer is used.

You are correct that some object must own that responsibility by making sure the referential attribute in (3) is the right one. That, though, is based upon context and that context will be defined somehow in the problem space. That is, there is some way to determine which SomeObject needs to be paired with which Timer _in the problem space_. It is those problem space rules and policies that the developer needs to encapsulate in the object that assigns the referential attribute.

In this case the relationship is fixed when SomeObject is created. So the logical place to encapsulate those rules and policies is in the object that creates SomeObject. [Among other things, referential integrity for unconditional relationships is most easily managed when the object instantiation and relationship instantiation is within the same method scope. That makes life /much/ easier when dealing with things like concurrency at OOP time.]

Is it whoever set up the collaboration responsibility to make sure that
these assumptions are met? How far should the consumer go in making sure
that its assumptions are true, e.g. that the timer is running when it
should be or not?

Whoever instantiates the R1 relationship only needs to understand the addressing side of collaboration. That object only needs to understand enough of the context to know who /participates/ in collaborations with a given SomeObject. That will be defined in the large when the developer identifies relationships in the Class Model. It will be defined in the small when the developer actually instantiates the relationship.

That participation is the same regardless of how many times SomeOBject and Timer collaborate or even When they collaborate in the overall solution context. More important, it does not depend on Why they collaborate or What they do when the collaborate. The developer defines When, Why, and What for collaboration in other ways in the design.

Thus What is defined by the individual object responsibilities that are abstracted from the problem space as necessary to solve the problem in hand. OO encapsulation and problem space abstraction ensures those are self-contained, cohesive, and logically indivisible (i.e., they are connectable dots). If done properly those actions can be expressed in terms of DbC preconditions and postconditions.

The Why is captured in the developer's vision of the way the solution works and the problem space itself. In this case the problem space dictates that SomeObject needs to do something a fixed amount of time after doing something else.

The When is managed through the developer connecting the dots of collaboration announcement messages by mapping solution sequencing preconditions to method postconditions _after all the methods have been defined_.

The point is that, unlike the OOPLs, OOA/D and UML provide explicit support for the developer to separate the concerns of Who, When, Why, and What when forming collaborations. So there is no simple answer to your questions, other than a cop-out that the developer is responsible. The developer addresses those issues individually in different ways in the design.

Does a typical OO developer think explicitly about things like DbC daisy chains? Not usually. However, the proper methodological mindset for OOA/D needs to be there and that mindset recognizes that Who, When, What, and Why are different issues that can be managed independently.

That, in turn, is manifested is more maintainable applications. For example, suppose one decides the context of instantiating R1 needs to be more dynamic and different Timers will be selected from a pool throughout SomeObject's life. Now we need to assign the R1 referential attribute dynamically via a setter and that setter needs to be invoked whenever the context of selection arises.

No big deal. The requirements change will necessarily somehow define the nature of substitution. The developer may map that into a different object that manages the pool for available [Timer] objects as simply finding an unoccupied Timer. That object will logically invoke the SomeObject setter. That object's behavior will be triggered by the need for a Timer, which can be synchronized in solution time by the same sort of DbC analysis as above. All of that stuff will be unavoidable when dealing with the new requirements.

But what happens to [SomeObject] and [Timer] to accommodate the new requirements? Nothing. One doesn't to touch them at all and they will continue to collaborate correctly.


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

H. S. Lahman
hsl@xxxxxxxxxxxxxxxxx
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info@xxxxxxxxxxxxxxxxx for your copy.
Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH



.



Relevant Pages

  • Re: Thread and Timer
    ... The timer is associated with the thread that calls the SetTimer API. ... The code is executed in the context of the thread that calls the ... and everything that code calls executes in the context of that ... If the secondary thread is a UI ...
    (microsoft.public.vc.mfc)
  • Re: patch tulip-natsemi-dp83840a-phy-fix.patch added to -mm tree
    ... called from timer context, ... The first case can be fixed by moved all the timer code to a workqueue. ... send the line "unsubscribe linux-kernel" in ...
    (Linux-Kernel)
  • Re: Waiting until timer without cpu crash?
    ... just schedule a TimerTask and then let the main ... be very cautious about using Thread.sleep in a GUI ... you almost certainly want some kind of timer ... execute your code in a context where it is safe to interact with GUI ...
    (comp.lang.java.programmer)
  • Re: How to set Timer IST?
    ... That's not high level enough. ... What do you mean by Set up a timer with 5ms ... However we don't have any context so can only ... Steve Maillet ...
    (microsoft.public.windowsce.embedded.vc)