Re: How to model decoupled hierarchies?
- From: "H. S. Lahman" <h.lahman@xxxxxxxxxxx>
- Date: Mon, 20 Nov 2006 17:42:13 GMT
Responding to Kowalski...
Since I'm not familiar with the problem space, the thing I am missing is
how the first structure maps into the second.
The "mapping" is the whole "business logic" and the main purpose of the
software. Basically the class surface has a methode "void reconstruct(
Object &obj)" which creates the surface sections and then delegates to
their reconstruct method. The most important class is the surface
section (abstract class and concrete implementations) since it
encapsulates the actual algorithm for reconstruction.
Sorry, but I'm still confused. Below you agreed with my speculation that [Surface] and its components were used to solve some customer problem like 3D graphic display rendering. I would regard that as being the main purpose of the software, which would make creating [Surface] and its components from [Object] a peripheral problem for setting up the main solution.
The notion here of creating [Surface] being the whole business logic and main purpose seems more appropriate for a particular subsystem whose subject matter was explicitly that construction. IOW, whoever actually uses the [Surface] once it is constructed would be in another subsystem or another application. I'll assume we are really talking about a subsystem whose purpose in life is to create a [Surface] and that subject matter is encapsulated because it is so complex.
Since reconstruction happens between two consecutive slices of the
object (triangles are generated between the vertices of (the contours
of) two slices), the section holds references to the slices. After
construction of the surface sections, during the reconstruction phase,
temporaries have to be created. This temporaries are based on the
objects slices and contours and therefore can be shared between to
sectors (one slice is part of two sectors, once as upper once as lower
slice).
Creating this temporaries is quite time-consuming. Althougth these
temporaries are constructed using slices and contours, they logically
don't belong together.
But I suspect that I might get performance gains if I make them part of
the contours ans slices. That's why I had the idea to "wrap" them into
the analogous "PerSliceElements". Since the PerSliceElements concrete
type depends on the type of the surface sections and methodes creating
them belong to the surface sector base class, this design is not really
convenient (the pointer to the shared slice elements have to be casted
on each query, which lucky don't happen too often).
So to rephrase the question: "Is there a better solution with
equivalent or better performance?"
I am guessing that is algorithmically well-defined but tedious.
Very right.
This is what I am pushing back about. If the algorithm is well-defined in some context beyond the specific problem space, such as mathematics, one can make the argument that it isn't a proper target for an OO solution. IOW, if one can describe the algorithm abstractly in terms of structure elements themselves (e.g., section, slices, vertices, etc.) without reference to what the structure represents in the problem space (i.e., the semantics the user attaches to the 3D image), then one probably doesn't want to use OO for the construction.
A <simplistic> analogy is a Quicksort algorithm. One can identify objects to use, such as Partition and Pivot, but one wouldn't do that because the algorithm is defined outside any particular sorting context. The reason is that one uses the OO paradigm to provide maintainable software in the face of volatile requirements. But the Quicksort algorithm is not going to change over the product life cycle. [One might employ a better algorithm in the future, so one would use OO techniques to encapsulate the algorithm to facilitate replacement. But one wouldn't do the algorithm itself using OO.]
Alas, there is no free lunch. There are three prices one pays for that maintainability in OO applications: they take longer to develop because they are not intuitive in computing space terms; they are verbose so the applications are larger; and they tend to have overhead for abstraction that slows them down. Generally traditional procedural implementations of algorithms will be faster, smaller, and more intuitive at the 3GL level. So one does not address algorithms like Quicksort with OO techniques; instead they are encapsulated and implemented with other techniques in "realized" code. One only addresses algorithms with OO technique that are unique to the problem in hand and, consequently, can change over the life of the software product as the problem definition changes.
[FWIW, I've worked with OO applications where as much a 60% of the code was realized in languages like C or FORTRAN. In such applications the OO code essentially just provides the glue for tying things together. This is quite common in scientific arenas, fairly common in R-T/E, but rather rare in IT.]
So what I am pushing back on here is whether those "temporaries" need to be described with objects at all. I think that depends on whether the construction algorithm is unique to the problem space. If it isn't, then I would be inclined to leave the temporaries as internal implementation elements (arrays, structs, whatever) of a realized construction algorithm that is accessed from Surface.reconstructor.
OTOH, if the basic structures of [Object] and [Surface] and their constituents are likely to change over the life of the application in ways that would trigger changes to the algorithm, I would be inclined to break out objects for the intermediate construction elements just as you have. To make your question relevant, I will assume that's the case...
Alas, I can't answer the question because I still don't have enough information about what actually goes on in the transformation of [Object] to [Surface]. However, I can make a couple of points that may be helpful.
If you isolate the problem to simply constructing one structure from the other, the abstractions you choose for intermediate objects can be based on the invariants of that problem rather than the structures themselves. IOW, the intermediate objects can be viewed as enabling getting from A to B rather than as intrinsic elements of either A or B. To stretch the Quicksort analogy even further, objects like Pivot and Partition exist because of the /way/ one sorts rather than either the input or output arrays or sort orders. Capturing invariants from that perspective may simplify the solution.
I am suspicious of [Surface] and its constituents owning the 'reconstruct' behavior. [Surface] is the output of the construction process. Since someone else will actually use [Surface], it becomes a dumb data holder with respect to the construction process. All one cares about is that the constituent elements are instantiated, initialized properly, and have the correct structural relationships. Any behaviors [Surface] and its constituents may have are only relevant to the context where is is used (e.g., actual display rendering).
From another perspective, the important thing in the construction is the /structure/ that relates [Surface] and its constituents. That structure transcends any particular object or class in the structure. In addition, to actually do the construction, one must "walk" the [Object] structure. That all requires context knowledge that I doubt is intrinsic to [Surface] in the overall problem context.
So I would still push for one or more factory objects that encapsulate the construction rules and policies in isolation from both [Surface] and [Object]. That dovetails with the notion of the intermediate objects existing to support the way the mapping is done. That is, those objects just temporarily hold information (or provide a base for relationships) that the factory will need later. I would bet that perspective would result in objects that are easier to optimize for performance at the 3GL level.
For a <purely speculative> example, let's suppose you need a [PerSliceElements] collection class. If you only need that collection for the current [Slice] being processed, then you don't need the heap overhead of creating and deleting it as each Slice is processed; you just provide a fast reset() method to clear it and start adding elements for the new Slice. IOW, one takes advantage of the scope in the algorithm context to provide optimization and that is enabled because the class is tied to the way the algorithm works.
My final suggestion is to rise above the OOPL view and do a full OOA/D Class Model and Sequence Diagram of the construction, even if it is just a temporary whiteboard version that is not kept for posterity. I think the key here is properly abstracting objects for the invariants of the mapping function, which is fairly complex. Due to the apparent complexity and the high level of abstraction, I think you need to do that without the distractions of 3GL coding and type systems. Once you have captured the essentials of the solution in an OOA/D model, you can find the proper tricks, like reusing objects above, to enhance performance at the 3GL level. IOW, the OOA/D provides the necessary structure one needs to solve the problem that is optimized in OOP, so one needs to get the skeleton right before worrying about optimization.
<snip>[Caveat. I am making an assumption that you need the [Surface]
structure to solve some customer problem (e.g., it is a basic part of
some sort of 3D display rendering).
That's is true. But the main purpose of the surface is calling the
"reconstruction" method. Everything else is just "nice to have".
If one can eliminate
intermediate objects like PerSliceElements, then one could have
substantial performance gains in both context switches and heap operations.
That is also a reason, they I consider my design at hand as not very
well.
A downside of delegation of responsibilities is performance when the
number of objects is large. Ultimately one could delegate
responsibilities down to the point where each bit was an object and one
could have children in the time the program executes. So at some point
one needs to find abstractions where one can substitute algorithmic
processing for static structure even though static structure is the
basis of high maintainability in the OO paradigm.
In the OO paradigm the criteria for that cut-bait point is whether the
algorithm is unique to the problem in hand. IOW, one does not want to
"hide" flow of control that is important to solving the particular
problem. But if an algorithm exists outside the scope of the particular
problem, it is fair game for encapsulation in a single method. (I have
seen an entire linear programming package encoded in FORTRAN
encapsulated as a single object method.)
I think encapsulating an Object "walker" algorithm to build a [Surface]
structure is a good compromise. That's because such an algorithm really
doesn't affect or depend on anything you actually do with the [Surface]
to solve the application problem. It is simply a mapping function for
the invariants of structures that exists beyond the scope of the
particular problem (i.e., the algorithm can be abstractly specified in
structure terms rather than specific problem terms). IOW, it's not
going to change unless you make fundamental changes to the structures
themselves, so maintainability is probably not a major issue.
I am not quite sure what exactly you mean by that. Maybe you could give
an example.
Hopefully the discussion of the Quicksort analogy above will clear this up. If not, let me know and I'll take another shot at it. (Here I am basically arguing for making the construction algorithm realized code.)
*************
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
.
- References:
- Howto model decoupled hierarchies?
- From: Thomas Kowalski
- Re: Howto model decoupled hierarchies?
- From: H. S. Lahman
- Re: How to model decoupled hierarchies?
- From: Thomas Kowalski
- Re: How to model decoupled hierarchies?
- From: H. S. Lahman
- Re: How to model decoupled hierarchies?
- From: Thomas Kowalski
- Re: How to model decoupled hierarchies?
- From: H. S. Lahman
- Re: How to model decoupled hierarchies?
- From: Thomas Kowalski
- Howto model decoupled hierarchies?
- Prev by Date: Re: Howto model decoupled hierarchies?
- Next by Date: Re: Orthogonal requirements
- Previous by thread: Re: How to model decoupled hierarchies?
- Next by thread: Re: Howto model decoupled hierarchies?
- Index(es):