![]() |
Dr. Carlo Pescio Systematic Object Oriented Design |
Published in IEEE Computer, Vol. 30 No. 9, September 1997.
Over two decades ago, expert systems were one of the most promising
technologies. Then researchers rapidly stumbled into what's called
the Feigenbaum Bottleneck: as the complexity of the domain
grows, it becomes very difficult for human experts to formulate
their knowledge as practical strategies (human say-how).
It is reasonably easier to demonstrate knowledge by doing something
(human show-how); most peoples can also make good choices
between alternatives (human say-what).
Not much attention has been paid to the Feigenbaum Bottleneck
outside the domain of artificial intelligence. This is unfortunate,
because the bottleneck hints at the inner nature of human beings.
To see the depth of its effects, we have to look no further than
the current state of software systems design.
Principles, principles everywhere
Early in the history of programming, brilliant peoples realized
that every good software system has some desirable properties:
It should be extendible; parts of it should be modifiable without
major impact on other parts; and so on.
Because of the Feigenbaum bottleneck, it is very hard to find
precise, step-by-step instructions to build systems with such
properties. It is easier to articulate the desirable properties
under the form of design principles.
Over the years, the wealth of knowledge accumulated as design
principles has reached a critical mass. Entire books are now dedicated
to the subject. Still, despite of this body of knowledge, design
remains difficult. A major problem in principles-driven design
is the ambiguous and non-constructive nature of most principles.
Ambiguity comes from the use of natural language, but also from
the desire to capture a large number of cases under a single principle.
As a consequence, adherence to a principle is often non-measurable.
Words like "abstraction", "detail", "extensible",
"open" are very expressive, but lack the necessary precision.
Being non-constructive means that a principle often provides no
guidance toward a design which respects the principle itself.
This is also common in mathematics: a theorem may guarantee that
something exists, but may not give any hint about how to find
it.
Together, these two problems make principles-driven design somewhat
hard to practice with success without a considerable experience.
The revenge of practice
In more recent times, design patterns have emerged as a valid
alternative to the principles-driven approach. The introductory
chapter of the GoF book is adamant: "One thing expert designers
know not to do is solve every problem from first principles.
Rather, they reuse solutions that have worked for them in the
past".
If principles represent the "say-what" approach
to design, patterns are the "show-how" way. You
look for recurring design problems, find the solutions that worked
better, and capture their essence in a pattern.
The biggest problem with patterns is that they rely on previous
experience, so when the available knowledge does not cover your
problem, you are out of luck. Sure, human beings are fairly flexible;
they can come up with some workable solution anyway. But obviously,
there is a limit to how far you can go with patterns alone. Also,
patterns leave a lot of details unspecified, so they are independent
from each instance. As a consequence, the designer must be able
to fill in the blank, usually backing up with its own experience,
which is hard for inexperienced designers.
Finally, there is a "disregard for originality" in the
pattern movement. Stop and think about how those clever solutions
have been devised the first time. Because in absence of previous
experience, the original, bright designer didn't use patterns,
but some other approach which is now intentionally neglected.
Patterns are a great way to encode knowledge, but as a design
technique they are necessarily incomplete: they leverage existing
solutions but cannot generate completely new ones.
Systematic Design
It is recognized that we lack a systematic approach to design.
Assuming we have done a good analysis job, we are still largely
left at the mercy of experience. Our own experience, to disentangle
ourselves in the jungle of principles, and other people's experience,
under the form of patterns. This being the same in all the other
disciplines, we may conclude that it is an unfortunate fact of
life, shrug our shoulders, and go back to our high-paying design
jobs. But this is not generally true. Electrical engineering,
for instance, has a large theoretical background but also a comprehensive
body of heuristic techniques that can be systematically applied
to solve problems. The same holds for other fields as well. And
here we close the circle: the Feigenbaum bottleneck notwithstanding,
we have to bite the bullet and try to articulate a "say-how"
approach to software design.
A transformational approach
Trivial design is easy. After all, is just a matter of laying
down a solution, and most peoples can even skip this step altogether
and jump to coding. In both cases, the result is often less than
optimal.
However, if we have a systematic method to recognize and solve
common problems in the initial, trivial design, we have a much
higher chance of ending up with a better result. Also, if the
problem-solving approach is constructive, we can gradually learn
how to avoid problems up front, applying the techniques on the
fly as expert designers do.
Here I describe an approach to design based on transformation
techniques, which I've used with success in the development of
large systems.
To find a transformation technique, you start with an informal
design principle. Then, you try to distillate some necessary
conditions which are unambiguous and amenable to formal
verification. It is not necessary to capture the whole essence
of the principle in a single rule: in some cases, that's simply
not possible. However, we can settle for a small number of necessary
conditions, provided that they can be conceptually ascribed to
the principle, and that they are formally verifiable.
The next step is to identify a set of transformations which can
be used to enforce the observance of a rule. Each transformation
technique, when applied to an interoperating set of classes that
violate a design rule, should lead to an equivalent structure
that respects the rule. Patterns are a good source of inspiration
for atomic transformation techniques, because most patterns are
based on a combination of several simpler techniques. That's why
patterns aren't always easy to understand "in depth".
Consider the informal principle "abstractions should not
depend upon details". I have taken this principle and identified
a formal necessary condition and some transformation techniques
[Pes98]. Using those techniques, I derive the Observer and the
Mediator patterns from two trivial designs.
Here, I briefly consider a simpler case, the "I'm Alive!"
principle [CN93]. This principle is usually spoken as "an
object should expose services, not data". This is a fundamental
OOP principle, but unfortunately is not based on measurable semantics.
However, in many practical cases a violation of the principle
follows this scheme: object A asks object B for one of its parts
(C), then does something with C (see fig. 1).
For instance, B may be a Book, C a Chapter, and A may iterate
over the pages and print them. If we consider only this scheme,
it's much easier to come up with a good design rule which can
be automatically verified. In fact, we don't even have to invent
the rule, as it already exists. It's called the Demeter Law [LH89]
and it states that "any method M of a class C should use
only the immediate part of the object, the parameters of M, objects
that are directly created in M or global objects" (other
formulations are more amenable to automatic checking). Basically,
the Demeter Law prevents from taking a part of another object
and doing something with it. Any program can be modified to conform
with the Demeter Law, but automatic transformations rarely yield
good code. What we want is to find a set of transformations which
respect the spirit of the rules, not only the letter. Our job
is to find the verifiable condition, and to provide a set of transformations
to the designer. The designer picks the best suited transformation.
Figure 2 gives an example of a (simple) transformation: now A
asks B to do something, and B gets its own part and asks it to
do it. Instead of asking for a chapter and then print it, now
A asks to print a certain chapter. Each object exposes only services,
not data (the "get" becomes "do").
Although trivial once exposed, this transformation rule is useful
in a large number of cases, and is used instinctively by experienced
designers. Naturally, there are several other transformation techniques
which may be used to enforce the Demeter Law, as well as other
measurable, necessary conditions that subsume the "I'm Alive!"
principle. If you know some interesting techniques, I'll be glad
to hear from you.
Conclusions
Over the years, I've identified a small (but continuously growing)
set of verifiable rules and transformation techniques. I've applied
them during the design of large, real-world critical systems,
and taught them to developers. I've found that they are very easy
to grasp and that people end up paying more attention to design
principles once they know how to verify and make correction to
their works. Obviously, many rules and techniques are yet to be
found. Interestingly, verifiable rules may lead to some true
object oriented CASE tools, beyond glorified drawing systems.
Bibliography
[CN93] Peter Coad, Jill Nicola, "Object Oriented Programming",
Yourdon Press, 1993.
[LH89] K. J. Lieberherr and I. M. Holland, "Assuring Good
Style for Object-Oriented Programs," IEEE Software, September
1989.
[Pes98] Carlo Pescio, "Deriving Patterns from Design Principles",
Journal of Object Oriented Programming, October 1998.
Biography
Carlo Pescio holds a doctoral degree in Computer
Science and is a consultant and mentor for various European companies
and corporations, including the Directorate of the European Commission.
He specializes in object oriented technologies and is a member
of IEEE Computer Society, the ACM, and the New York Academy of
Sciences. He lives in Savona, Italy and can be contacted at pescio@eptacom.net.