[comp.object] How do you evaluate objects?

schultz@grebyn.com (Ronald Schultz) (11/29/90)

WHAT IS A "GOOD" OBJECT ?

The following are some brief notes on how we evaluate objects in
our environment.  Any additional comments or suggestions would be
appreciated.

Designing objects is not easy.  Design is a complex task.  But
determining whether or not a design is good or appropriate is
crucial to being successful.  Our review review process for
objects consists of the following checks:

     o    Model Correspondence
     o    Mapping
     o    Constraints
     o    Visibility
     o    Feedback

(Please note that while our development is conducted in
Smalltalk/V 286 and any specific examples are provided in this
enviroment these notes should be appropriate to an OO development
effort.)

Model Correspondence:
          
It should go without saying that the naming of an object is
extremely important, particularly if issues of reuse are
involved.  Associated with any name is a user's conceptual model
of what the object is.  When the object, as designed by the
designer, corresponds closely to the user's mental model of the
object, we have defined a "good" object.  When the user's mental
model of the object conflicts with the object as designed is, we
will have problems.  Designers of objects, and the users of the
objects, are often not the same people.  Object designers must
pay particular attention to their customers (object users) and
listen and respond to the needs of their customer.  Object users
must be willing to specify and present to the designers
situations where differences exist between their mental model and
the actual object.  Communication between designer and user is
the key to ensuring that model correspondence is accurate and
complete.  

Mapping:

This evaluation involves determining if the mapping between
operations, and what they operate on, is clear and unambiguous. 
The assignment of operations (methods if you wish) to objects is
a critical analysis and design consideration.  

In particular we look for the following.  If the number of
possible behaviors/states exceeds the number of operations, there
is apt to be difficulty in the use of the object.  In general,
operations that perform more than one action are apt to be
difficult to remember.  When the number of operations equals the
number of actions, each operation can be specialized and labeled
specific to its task.  In this case the operations are visible
through the name of the operation.

In addition we look for instances of object blindness during the
mapping evaluation.  AN EXAMPLE OF OBJECT BLINDNESS.  A power
drill and a block of wood are the objects of interest.  One
wishes to drill a hole in the wood block.  Where does one assign
the operation "drill hole"; to the wood block or to the drill? 
What is missing here is a "person" object.  A "person" drills the
hole, not the drill or the block of wood.  The mapping of "drill
hole" to wood block or power drill does not make "real world"
sense, and hence serves as a clue to a mapping problem.

Visibility:    

Necessary operations should be visible. This ensures that the
interface is understandable and usable.  Visibility of operations
not essential to the use of the object must be restricted from
view.  Public operations should be visible to the object user,
private ones should not.

Visibility acts as a good reminder of what can be done with the
object.  A good relationship between the name of an operation and
what it does makes it easy to find the appropriate operation for
a task.  As a result, there is little to remember.

For an example of a "bad" operation one can look in the Smalltalk
ClassHierarchyBrowser Class for an operation named "hierarchy". 
As an operation name this particular operation suffers because
(a) the name of the operation is not a verb and (b) it is
difficult to discern the action that this operation performs.

Constraints:

The appropriate use of constraints in object design can help in
ensuring the proper use of objects.  First there are physical
constraints.  The development environment itself can be used to
physically restrict what a user of an object can see about the
object itself.  Restricting source code viewing to the object
interface and public methods is one way.  Typing provides another
mechanism.

Next there are semantic constraints.  The names of objects and
operations provide a great deal of semantic information to the
user of the object.  Appropriately naming objects and operations
provides in many cases sufficient information to the user to
ensure that his use of objects is appropriate.  If your
development environment supports associating graphics with your
objects, the appropriate selection of icons, and even colors, can
be used to provide cues to the user as to how to use the object. 
In these cases semantic information provides a constraint to the
user that assists the user is rationally using the object.

Another constraint is the logical constraint.  In this case logic
dictates how the use of an object should occur.  Adding an
integer object to an icon object does not make sense logically. 
Providing cues to the user as to what the logical constraints are
in the object's use helps ensure the appropriate use of the
object.


Feedback:

Objects should "feedback" to the user appropriate information
about their state, and their response to a particular operation. 
Error handling and exceptional processing should be well
understood and detailed.  If an exception condition occurs, the
object should provide details back to the user in manner that
allows the user to respond quickly, with a minimum of research. 
Unformatted dumps of an object's state is not an appropriate
feedback mechanism.  

Any comments or suggestions as to additional evaluation criteria?

Ron Schultz
schultz@grebyn.com
614-759-3127

Piersol@Apple.com (Kurt Piersol) (11/30/90)

I'd suggest some other evaluation criteria, based on experience building 
scalable systems with Smalltalk-80. Thus, I'll use Smalltalk-80 terms to 
describe them. These are:

1. Abstraction - Where possible, the object should never refer explicitly 
to any other class. Any dependencies on other objects should be strictly 
protocol based, to assure as strong an encapsulation as possible. If you 
do this, as time passes, you'll find that you spend less time on 
algorithmic details and more on understanding the transformations and 
movement of your data.

2. Parsimony - Not only is it important to have necessary operations 
visible, but it is important to have only operations appropos to the 
particular object located there. Although it may be tempting, for 
instance, to take a specialized transformation and locate its code in the 
originator of the transformation, it's better to locate it in the 
recipient. If you need to build a ROT13 transform for your mail reader, 
put the operation on class String, rather than class MailReader. That way, 
other programmers can find the capability and make use of it in 
serendipitous ways.

3. Expressiveness - Designing the methods of a class is like defining a 
language for manipulating objects of that class. Make sure your message 
set is expressive, and you have a big win. There is no good way of 
measuring expressiveness that I've ever seen, but some thought about ways 
you might wish to refer to the object as a generic construct will often 
give you insights into ways to make its message set expressive. Approach 
each class design as an exercise in language design.

4. Consistency - Does your class have messages which resemble messages 
used for similar operations in your class library. Obviously, a more 
consistent system is more comprehensible. This postpones the inevitable 
point where your system becomes too large for anyone to master, and you 
must implement cumbersome bureaucratic controls to attempt to maintain 
system integrity.

5. Relevance - How much does your class take advantage of existing classes 
in its operation. If you are not making extensive use of the class 
library, you are giving yourself unneeded headaches with maintenance and 
integrity. Examine classes for use of common algorithms and structures, 
and decide if another object class can be either used or generated to 
centralize the needed functionality. Remember the Abstraction criterion, 
though, and rely on protocol instead of explicit class reference!

Hope these are of some use to you!

Kurt

Kurt Piersol                                           Apple Computer ,Inc.
arpa: Piersol@Apple.com                                  20525 Mariani Ave.
uucp: ...!apple!piersol                                Cupertino, CA 95014
ALink: PIERSOL.K                                              408/974-1201

Disclaimer: My opinions are my own, NOT Apple's. So There.

bryan@sierra.STANFORD.EDU (bryan) (11/30/90)

Ron's notes, IMHO, are far too informal.  Too many goods, shoulds, and
nices.  Notes like this often add to the confusion of ``what is an
object'' rather than explain it.  I'd recommend reading:

    ``Assessing the Quality of Abstract Data Types Written in Ada'',
    D.W. Embley and S.N. Woodfield (Brigham Young University),
    Proceedings of the 10th International Conference on Software
    Engineering, April 1988, Singapore, pp. 144-153, IEE Computer
    Society Order Nuber 849, ISBN 0270-5257, ACM Order Number 592880,
    ISBN 0-89791-258-6.

Embley and Woodfield present a straightforward, machine-checkable
method of measuring the coupling and cohesion of a module (in this
case, Ada package).

Now I know that Ada is not OO, and that data abstraction is but one
aspect of OO, but it's a good start.  If anybody knows of other
published measuring techniques (i.e., metrics) that do take into
account other aspects of OO, please post references.

doug

johnson@m.cs.uiuc.edu (11/30/90)

I think that any discussion of what is a "good" object should
recoginize that objects should not be designed in isolation.
Instead, a system is made up of many objects, and they must
be designed to work together.  Thus, it is important to have
a few very flexible interfaces, and most of your objects should
fit into one or more of the interfaces.  

The suggestion that a method should do one thing is important,
and is a special case of the general system design rule that
each component should do one thing.  Of course, since an object
has many methods, it might seem impossible for an object to do
one thing and for its methods to also do one thing, but "one"
is relative.  The phrase "do one thing" really means that it
should be possible to describe what the component does in a short
sentence and that you should never have to use just half of the
component.  A Button might be able to display itself and to react
to a mouse click, but it still embodies one main idea.

Another thing to remember is that some of the objects are part
of the problem domain, while others are part of the solution domain.
You should not expect users to understand (or even care) about the
objects that are in the solution domain.  In fact, it is best to
hide their existence from the users as much as possible.

Ralph Johnson -- University of Illinois at Urbana-Champaign

grp@Unify.com (Greg Pasquariello) (11/30/90)

I just have two comments that may be meaningful.  Then again, they may
not :-)

In article <11379@goofy.Apple.COM>, Piersol@Apple.com (Kurt Piersol) writes:
> 
> I'd suggest some other evaluation criteria, based on experience building 
> scalable systems with Smalltalk-80. Thus, I'll use Smalltalk-80 terms to 
> describe them. These are:
> 
> 1. Abstraction - Where possible, the object should never refer explicitly 
> to any other class. Any dependencies on other objects should be strictly 
> protocol based, to assure as strong an encapsulation as possible. If you 
> do this, as time passes, you'll find that you spend less time on 
> algorithmic details and more on understanding the transformations and 
> movement of your data.
> 

One comment I have about your abstraction criteria, is that it may not be
quite broad enough.  I believe there are two kinds of objects, "dumb" 
objects, and "sentient" objects.  Dumb objects do not know about other
objects, and provide the strong encapsulation.  Sentient objects however,
are aware of other objects (most notably, dumb objects), and know how to 
make use of and interact with them.  Using the example from Ronald Schultz,
the block of wood and the drill are the dumb objects;  they do not know
about each other, and provide highly encapsulated classes.  The person,
on the other hand, is aware of both the drill and the block of wood, and
knows exactly how the two can interact, but provides only a weak encapsulation.
As in life, if a new kind of drill comes along (i.e. drillPress), the
person needs to get new instruction; he needs to be subclassed to 
drillPressOperator, maintaining the knowledge of how to use a drill on
a block of wood, but with the new knowledge of how to use the drill press
to manipulate the drill.

> 2. Parsimony - Not only is it important to have necessary operations 
> visible, but it is important to have only operations appropos to the 
> particular object located there. Although it may be tempting, for 
> instance, to take a specialized transformation and locate its code in the 
> originator of the transformation, it's better to locate it in the 
> recipient. If you need to build a ROT13 transform for your mail reader, 
> put the operation on class String, rather than class MailReader. That way, 
> other programmers can find the capability and make use of it in 
> serendipitous ways.

My only comment here, is based on the last sentence.  Object designers must
be careful to include only operations on the class (as you mention), and
not include gratuitious operations that someone may find serendipitous
later.

> Kurt
> Kurt Piersol                                           Apple Computer ,Inc.
> arpa: Piersol@Apple.com                                  20525 Mariani Ave.
> uucp: ...!apple!piersol                                Cupertino, CA 95014
> ALink: PIERSOL.K                                              408/974-1201
--

---
Greg Pasquariello	
Unify Corporation 	grp@Unify.Com