Friday, May 9, 2008

On Navigable Owned Ends...

OK, it’s time for me to get a little bit technical (and to try out JBuilder 2008) for a change. While working on the E/R metamodel as a member of the IMM submission team, I ran into an “interesting” scenario recently involving associations with one end type. Consider the class diagram below (the names have been changed to protect the innocent).


Can you see what’s wrong with this picture? The intent of the modeler was to express the fact that a bicycle has two wheels, one of which is the ‘front’ wheel (from the perspective of the rear) and one of which is the ‘rear’ wheel (from the perspective of the front). If you think about what an instance of this model might look like if it were mapped directly to classes and fields in a programming language like Java (using EMF, for example), you’ll realize that each instance of the 'BicycleWheel' class would need a reference to the bicycle’s other wheel, but also to itself – in order to satisfy the multiplicities (both association ends are required, i.e. they have a lower bound of 1), each wheel must reference both the front wheel and the rear wheel of the bicycle; obviously not a desirable result. In fact, it’s currently impossible to create a valid instance of this model using Java code generated by EMF, since an attempt to set a reference from the front wheel to itself (to satisfy the multiplicity) would result in its reference to the rear wheel being discarded.


What’s interesting (at least to a modeling geek like me) is that this redundancy could, in theory, be eliminated simply by making the association ends (the 'frontWheel' and 'rearWheel' properties) navigable owned ends. What does that mean? Well, in UML 2.x, it’s possible to designate a navigable association end as being owned either by the end type (as in the diagram above) or by the association itself. In the latter case, a mapping to Java would require a class to represent the association; now, in addition to there being an instance of the 'Bicycle' class and two instances of the 'BicycleWheel' class, there would be (at a minimum) an instance of the class representing the association which, in turn, would only need to reference each of the wheels once to satisfy the multiplicities. Ed and I have been giving some thought as to how owned association ends might be mapped to Java using EMF, but this special case makes me think that we still don’t have it quite right – see below.


I think there would still be an issue here with respect to navigability, because given a bicycle wheel, it's supposed to be possible to navigate to both the front wheel and the rear wheel (according to the model). Would this require redundant entries in the maps? What if a front wheel is passed as an argument to the 'getFrontWheel(BicycleWheel)' method? What if the owner of the bicycle rotates its wheels every season? I’m starting to wonder whether it should be considered valid at all to model a bidirectional association with required member ends and one end type. In the absence of an answer to that question and/or EMF support for mapping navigable owned ends to Java, there are a number of ways the model could be changed and still (or better) express the original intent. The model we ended up going with (or, rather, a reasonable facsimile thereof) is below. What might you have done differently?


10 comments:

Greg said...

You've got my mind twisting here Kenior Hussey, but why wouldn't you use an intersection/association class here to allow for a unique instance of a bicycle and a wheel of specific type (e.g. of type front or of type rear)?

Maybe this would be a way to solve the data problem but it seems like it;s just the conceptual way to solve this...

Ian Bull said...

Another option, "Sir Kenior", it to model the front and rear wheel as two different classes (possibly extending Wheel). This way, the front wheel would have a reference to the rear, and the rear to the front. The rear may also have other attributes, such as number of gears, etc...

Ed Merks said...

It doesn't make sense for the front wheel to reference itself as the front wheel since the opposite of that referenced wheel is required to refer back to that starting wheel as the rear wheel, which, as you point out, it is a contradiction. So it seems to me that the model is simply incoherent; the lack of coherence is demonstrated by the inability to create a valid instance.

Isn't it just the multiplicity that makes creating a valid instance impossible, and not just the fact that it's a bidirectional reference with only one end type? After all, a directed graph of nodes would use bidirectional references with only one end type and I don't think you'd suggest this isn't valid...

citylights said...

Ken,

This scenario provides a good example of why UML 2 introduced the notion of composition and composite structures as class diagrams do not adequately address the different ways in which things get assembled. In this case a parts [wheel] role [position] in relation to its composite element. As Ed suggests the model itself is rather non-sensical at least in the sense that you are requiring a wheel to both know its position and its relationship to other positions. This should more logically be the responsibility of the composite rather than its parts. Hence the need for parts, connectors and composite structures...

Kenn Hussey said...

Greg, I considered using an intersection entity here, but in the absence of other properties qualifying the association between a bicycle and its wheel(s), I figured it was better to keep the number of entities to a minimum.

Another, more "UMLish", way to do this would have been to use a property qualifier, e.g. to define a "PositionKind" enumeration (with literals 'front' and 'rear') and declare a 'position' property as a qualifier on the 'wheels' association end...

Kenn Hussey said...

Ian, if there was something intrinsic about a bicycle wheel that made it either a front or a rear wheel (which, in hindsight, I realize might be the case here, but wasn't the case with the original E/R metamodel), then this would make sense.

Kenn Hussey said...

Ed, as you pointed out, the issue could be resolved by changing the lower bound one or both of the problematic association ends to 0... I meant to qualify my doubt about the validity of bidirectional associations with one end type accordingly (and will do so now).

There is an interesting difference between a model of a directed graph and this one; in the former, the references between the nodes make sense as a characteristic of the nodes, whereas in the latter, the notion of whether a bicycle wheel is in the front or rear position is really only meaningful in the context of a bicycle (and so should be modeled that way, IMHO).

Kenn Hussey said...

Shaun, I agree that knowledge of whether a wheel is in the front or rear position should be a responsibility of the bicycle; indeed, if a wheel were not attached to a bicycle at all, it would not have a reference to another wheel. The original segment of the E/R metamodel did involve a composition between the two types, but I've used a shared aggregation here to reflect the fact that a bicycle wheel can, in fact, exist independently of a bicycle.

Ian Crawford said...

Warning: I'm more practical than academic when it comes to modeling. There's almost certainly something general, deep, and useful in this hypothetical example that's lost on me. ;)

One thing I would do differently in your last example is lose the "otherWheel" association as I don't see what value it provides. You need to navigate back to the Bicycle to determine front from rear, anyway.

Second, why is wheels a collection? A Bicycle is related to exactly 2 instances of BicycleWheel, each with a distinct role. Why not model it as such? (Unless you foresee a Cycle/Unicycle/Bicycle/Tricycle hierarchy, but this, I suppose, is besides the point.) We're not talking about a pool of interchangeable wheels here.

If it's important to maintain direct navigability between wheels, Ian's Wheel/FrontWheel/RearWheel hierarchy has my vote.

Kenn Hussey said...

Ian, I agree that the link between the wheels is somewhat redundant, given that the same information can be obtained from the bicycle itself - that's why I made the 'otherWheel' property derived (i.e. its value would be calculated by navigating to the bicycle and obtaining the other wheel from the 'wheels' property).

The 'wheels' property is a collection because the example is contrived. ;) In the original model, there is actually a more general association, say between "Vehicle" and "Wheel" which has an unlimited upper bound; the association is specialized for bicycles in this context by constraining the upper bound to 2.