|
Prev: Call for Papers with Extended Deadline: 2007 International Conference on Multimedia Systems and Applications (MSA'07), June 25-28, 2007, USA
Next: learning OOD with C++, good idea ?
From: kk_oop on 1 Mar 2007 07:42 Hi. I'm working on an architecture consisting of a group of interacting components. By a component, I mean a cohesive group of classes that offer their behavior to other components through a well defined interface. Aside from the interface, all other details are hidden from external components. I'm defining an approach to make the component interfaces "well defined." To do this, I'm using "design by contract" ideas. The contracts are being defining in terms preconditions and postconditions. These are defined in terms of a notional domain model for each component. It's essentially the technique described in Craig Larman's Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development. For instance, a Widget Factory component may offer an allocateWidget service. To define the behavior of allocateWidget, I'd create a class diagram with a notional domain class called Widget and one called Widget Factory. I'd show a relationship between these classes. Then, taking Craig Larman's approach, I'd define an allocateWidget post condition stating that a Widget instance was created and an instance of the relationship between WidgetFactory and Widget was created. This contract and the domain class diagram would be made available as part of the component's "black box" documentation. So that's the general approach. My question is this. Should I be defining contracts for a component's periodic behavior if it impacts the domain model? Technically, a periodic is not visible to a client, so it can be seen as an implementation detail. However, if that periodic is changing the domain model in such a way that it can impact other services' preconditions, it seems to me that the periodic contract should be made visible to clients. For instance, in the example component above, if a periodic were deleting a Widget under certain conditions, it seems to me that this should be made visible to clients, and a way to make it visible would be to make the periodic's contract visible to the clients. Any opinions would be greatly appreciated! Thanks, Ken
From: H. S. Lahman on 1 Mar 2007 12:20 Responding to Kk_oop... > My question is this. Should I be defining contracts for a component's > periodic behavior if it impacts the domain model? Technically, a > periodic is not visible to a client, so it can be seen as an > implementation detail. However, if that periodic is changing the > domain model in such a way that it can impact other services' > preconditions, it seems to me that the periodic contract should be > made visible to clients. For instance, in the example component > above, if a periodic were deleting a Widget under certain conditions, > it seems to me that this should be made visible to clients, and a way > to make it visible would be to make the periodic's contract visible to > the clients. I'm not quite sure what you mean by "a periodic". Do you mean some object is doing things concurrently according to a fixed time schedule? Assuming that is the case, then how does that object delete the Widget? Surely it must use the same Facade interface the other objects use to interact with the encapsulated objects. If so, then there may be a dependency between the interface methods. For example, one might not be able to invoke allocateWidget if there is already one there so one must wait until after deleteWidget is invoked. If that is the case you will have to somehow define that contract constraint for the Facade class you are using as an interface. That gets tricky because the precondition will be based on the internals (i.e., whether a Widget exists) that the client is not supposed to know anything about. So what one needs to do is convert the constraint into semantics that is meaningful in the client context. IOW, there must already be some conditions in the external context that determine when deleteWidget and allocateWidget need to be invoked. One needs to define a condition for the external context that captures the sequencing constraint. That might be as simple as an isWidgetAvailable attribute in an object outside the Facade that is set when allocateWidget is called and reset when deleteWidget is called (i.e., the precondition on calling allocateWidget becomes "isWidgetAvailable = FALSE"). ************* There is nothing wrong with me that could not be cured by a capful of Drano. H. S. Lahman hsl(a)pathfindermda.com Pathfinder Solutions http://www.pathfindermda.com blog: http://pathfinderpeople.blogs.com/hslahman "Model-Based Translation: The Next Step in Agile Development". Email info(a)pathfindermda.com for your copy. Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php. (888)OOA-PATH
From: kk_oop on 1 Mar 2007 20:38 On Mar 1, 12:20 pm, "H. S. Lahman" <h.lah...(a)verizon.net> wrote: > Responding toKk_oop... > <snip> > > I'm not quite sure what you mean by "a periodic". Do you mean some > object is doing things concurrently according to a fixed time schedule? > Thanks for you response! Here's what I mean. A component service like allocateWidget starts a timer and gives it a callback method. The callback method is not a blackbox component service. It is a method on an implementation class inside the component. Eventually when the timer expires (long after allocateWidget has completed), the callback method checks some condition then, based on that condition, deletes the Widget. Now let me distinguish between the domain class Widget from the implementation class Widget. In the implementation, Widget may be implemented by a number of classes, especially if a state pattern or something like that is being used. The domain class Widget is purely notional. It is only meant to represent the concept of Widget and its possible states (shown as notional attributes). It and the rest of the domain model exists just to represent the main concepts manipulated by the component--and thus to be referenced by the component's service's contracts. As Larman recommends, a postcondition is deletion/creation of a domain class instance, deletion/creation of a relationship between two domain class instances, or the change of state of a domain class instance. So let's say that allocateWidget has a precondition that no Widgets exist. That means that the behavior of the periodic is significant because it will delete the Widget domain instance. In reality, that may mean that 10 classes got deleted (if the state pattern was used and the Widget had 8 states). But from an external component client point of view, he only cares that the Widget domain instance got deleted, since that now means he can call allocateWidget. Now, as you suggest, if the component offered a doesWidgetExist() service, the client could just check that before calling allocateWidget, but it just seems like good practice to let clients now what events may lead to a change in a component's domain model. Based on all that, do you think the periodic's postcondition should be exposed to the client? <snip> Thanks in advance! Ken
From: H. S. Lahman on 2 Mar 2007 12:48
Responding to Kk_oop... > Here's what I mean. A component service like allocateWidget starts a > timer and gives it a callback method. The callback method is not a > blackbox component service. It is a method on an implementation class > inside the component. Eventually when the timer expires (long after > allocateWidget has completed), the callback method checks some > condition then, based on that condition, deletes the Widget. > > Now let me distinguish between the domain class Widget from the > implementation class Widget. In the implementation, Widget may be > implemented by a number of classes, especially if a state pattern or > something like that is being used. The domain class Widget is purely > notional. It is only meant to represent the concept of Widget and its > possible states (shown as notional attributes). It and the rest of > the domain model exists just to represent the main concepts > manipulated by the component--and thus to be referenced by the > component's service's contracts. As Larman recommends, a > postcondition is deletion/creation of a domain class instance, > deletion/creation of a relationship between two domain class > instances, or the change of state of a domain class instance. Alas, I am confused about what you mean by "domain class". It seems like we are talking about objects here and they are either instantiated or they are not. What you seem to be describing is a GoF Facade pattern where some group of objects (your implementation objects for the Widget functionality) is encapsulated behind a Facade "wrapper" object (the public Widget). So external clients talk to Widget and Widget re-dispatches to its "internal" implementation objects. But in that scenario Widget and all the rest of the objects have concrete instantiations. So... > > So let's say that allocateWidget has a precondition that no Widgets > exist. That means that the behavior of the periodic is significant > because it will delete the Widget domain instance. In reality, that > may mean that 10 classes got deleted (if the state pattern was used > and the Widget had 8 states). But from an external component client > point of view, he only cares that the Widget domain instance got > deleted, since that now means he can call allocateWidget. Also, who owns allocateWidget? If allocateWidget creates a Widget object (and the "contained" implementation classes), then it has to be owned by an object outside Widget. Or is this just intended to be a 3GL constructor for Widget? Or does one instantiate Widget and then invoke allocateWidget to create the implementation objects? I don't like the last because it opens opportunities for referential integrity problems, especially in a concurrent environment. I would make sure Widget and its implementation objects were all instantiated in the same method scope to make life easier for managing referential integrity. I don't like it as a constructor if it also instantiates the implementation objects. Constructors are inherently fragile and should be kept as simple as possible. Who owns the callback? Is it one of the implementation objects, Widget itself, of some external object? It sounds like the Widget Facade object gets deleted by the callback, which also deletes all of the implementation objects. If so, then any relationships between external clients and Widget will have to be removed at that time to ensure referential integrity. So.... > Now, as you suggest, if the component offered a doesWidgetExist() > service, the client could just check that before calling > allocateWidget, but it just seems like good practice to let clients > now what events may lead to a change in a component's domain model. I'm afraid that was not what I suggested. In a concurrent environment that just opens up the possibility of race conditions. I argued that the callback provided should not be an internal implementation. It should be a responsibility of the domain Widget so it is visible to external clients. That's because the timer /is/ an external client. If one does that, then one has a "visible" dependency between public behaviors and one can define a precondition contract to enforce it. But in this case I think there is an obvious state variable to access for the precondition: the existence of a relationship to Widget. IOW, the precondition for allocateWidget is that the relationship is not instantiated. > Based on all that, do you think the periodic's postcondition should be > exposed to the client? I think it is necessarily exposed because the relationships to Widget must be de-instantiated and that will affect the potential clients. BTW, the only exception I can think of would be a Singleton pattern. There might be a business rule that no more than one Widget can exist at a time so the client /always/ invokes allocateWidget as a static class method. The Singleton pattern then actually creates only when necessary because it knows <internally> if there is one yet. (The implementation objects just have their life cycles tied to the Widget Singleton.) Then the callback is just a static class method of Widget. If that is the case, then it is a matter of private implementation of the pattern so, consequently, its postcondition is not relevant to clients. ************* There is nothing wrong with me that could not be cured by a capful of Drano. H. S. Lahman hsl(a)pathfindermda.com Pathfinder Solutions http://www.pathfindermda.com blog: http://pathfinderpeople.blogs.com/hslahman "Model-Based Translation: The Next Step in Agile Development". Email info(a)pathfindermda.com for your copy. Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php. (888)OOA-PATH |