Newsgroups: comp.lang.c++,comp.object,comp.lang.smalltalk
Path: cantaloupe.srv.cs.cmu.edu!das-news2.harvard.edu!news2.near.net!howland.reston.ans.net!swrinde!pipex!uunet!rcm!rmartin
From: rmartin@rcmcon.com (Robert Martin)
Subject: Re: Teaching OO
References: <1994Dec26.162401.6570@rcmcon.com> <RFR0lOfN33q2071yn@IIA> <AKV.95Jan8184845@srl03.usl.edu> <3ettm9$rj3@seralph9.essex.ac.uk> <3evfec$5ah@nova.umd.edu> <3evjp1$13fg@news-s01.ny.us.ibm.net> <1995Jan11.143449.24323@rcmcon.com> <3f10h3$1c4@crchh917.bnr.ca>
Organization: R. C. M. Consulting Inc. 708-918-1004
Date: Mon, 16 Jan 1995 20:09:08 GMT
Message-ID: <1995Jan16.200908.2541@rcmcon.com>
Lines: 169
Xref: glinda.oz.cs.cmu.edu comp.lang.c++:107729 comp.object:25123 comp.lang.smalltalk:19583

ethridge@bnr.ca (Allen Ethridge) writes:

>Having worked on projects where a lot of effort was placed on planning
>for possible future needs, OO and structured, i agree with Bill.
>Somewhere in some OO journal i read a statement to the effect that we
>are in general very bad at predicting future requirements.  Good OO
>design satisfies the existing needs. Reuse is not an objective of OO
>design.  It is instead a benefit of good OO design.

I agree with the sentiment, but not the statement.  Design for "use"
is, of course, paramount.  However, neglecting reuse would be
unfortunate.

More importantly, designing for "use" does not simply mean "make the
application work".  It also means "Ensure that the application is
maintainable throughout its lifecycle, and is easy to adapt and expand
as its environment and market change."  Satisfying these needs
requires the same kind of thought and activities as designing for
reuse.  

As engineers, we must make a trade off.  Although maximal reusability
would be wonderful, it will be expensive.  On the otherhand, minmal
reusability will create applications that cannot be maintained or
enhanced.  We must strike a balance in the middle.  We must (as poor
as we are at it) attempt to predict the most likely forces that will
cause the software to change, and then design for reusability within
that context so that the architecture of the product is not affected
by those changes.

>If you design for reuse you are likely to end up with a lot of very
>general and poorly defined objects that sort of work for most people
>but don't really adequately satisfy anyone's particular needs.  

This is only if you go mad with reuse and try to create classes which
are all things to all people.  But if you narrow your scope and try to
make objects that are reusable in the most likely context, you are
more likely to succeed.

>In a
>good OO design the objects defined meet the needs of that particular
>set of requirements.  The reuse appears afterword, on its own,
>unplanned for.

No.  Unequivocally, No.  Accidental reuse is very rare, and is
generally unsatisfactory.  Simply writing code in an OOPL does not
guarantee any kind of reuse.  If reuse (and that included
maintainability and enhancability, since that is just reuse in place)
is to be achieved, it must be designed in.  The dependencies that
would thwart it, must be managed.


>> Remember, maintenance is a form of reuse, since you are changing the
>> application and then asserting that all the unchanged code can be
>> reused in the changed context.
>> 

>Seeing maintenance as reuse is, i think, an overly broad definition of
>reuse and not an entirely accurate definition of maintenance.

Maintenance, and reuse have this in common, that they are both
thwarted by source code dependencies, and that they are both enhanced
by the management of those dependencies.  

>A class is reusable if it can be inherited from to meet the needs of
>similar, but not necessarily identical, environments.  But that reuse
>can only be determined by the later development, not by the original
>development of the class.  Not all classes need to be reused and a class
>should not be designed for reuse until there is a demonstrated need.

I would change this to "an anticipated need", rather than "a
demonstrated need".  And generally this means that you separate the
classes into base classes which capture the abstraction, and derived
classes which capture the detail.  Then you write the clients such
that they use the base class interface rather than the derived class.
This is a *relatively* cheap procedure.

>> >However, given the existence of bounded contexts, there is no such
>> >thing as "pure" or 'abstract' interface with no dependance whatsoever
>> >on implementation.  
>> 
>> Of course there is.  
>> 
>> class AbstractB
>> {
>>   public:
>>    virtual void X() = 0;
>> };
>> 
>> The class AbstractB has utterly no dependency at all upon any
>> potential implementation of X in a derived class.
>> 

>Not being knowledgeable in C++ i have to ask - what use does this
>class serve?  I get the feeling that, by your definitions, a perfect
>class would define objects that provided no services - how is it possible
>for an object to provide services without those services being needed
>in and determined by the context where the object lives?

The class Abstract B provides a service X.  Nothing more is known.  

Lets make this a little more real:

class Modem
{
  public:
    virtual void Dial(PhoneNumber) = 0;
    virtual void OffHook() = 0;
    virtual void OnHook() = 0;
    virtual void SendChar(char) = 0;
    virutal char GetChar() = 0;
};

Here is an abstract interface for a modem.  None of the functions are
implemented, the interfaces are pure.

I can now write functions which manipulate modems in terms of this
abstract interface.  I can also derive HayesModem from Modem such that
those programs can manipulate HayesModems through the Modem interface.
Thus those programs do not even know that HayesModem exists.

>> We can use Structured Analysis and Design to create modules that can
>> be "used".  But, as history has shown, we need something more.  Not
>> only must modules be usable, they must be maintainable.  They must
>> survive their lifecycle.  And this means that we have to design the
>> modules for survivability.  One very important criterion is the
>> management of dependencies between modules.  A module with very few
>> dependencies is more robust than a module with many dependencies.  
>> 

>Yes, encapsulation is good, but this does not require that the
>object be designed for reuse.  It simply requires that the object
>be well-defined.

I am not talking simply about encapsulation.  Morever, encapsulation
without a strategy is only marginally useful.  The stragegy requires
that we examine the collaborations of many objects and then attempt to
define interfaces that can be abstracted such that the dependencies
between the collaborators are broken.  *Then* we can encapsulate the
resulting interfaces.

>> >>What is
>> >>the goal of OOD?  What benefits are we trying to gain.  
>> 
>> >How to design useful objects.  
>> 
>> Why objects?  Why not just useful code?
>> 
>> >The benefits of encapsulation,
>> 
>> What are the benefits of encapsulation, if not the management of
>> dependency?
>> 
>> >inheritance, polymorphism, 
>> 

>Inheritance and polymorphism are where the reuse comes from,
>not from the "management of dependencies between modules."

Inheritance and polymorphism are the tools that allow dependencies to
be managed.  Such management affords reuse and maintainability.

It is quite easy to write code that is rife with inheritance and
polymorphism, and yet is not reusable or maintainable.

-- 
Robert Martin       | Design Consulting   | Training courses offered:
Object Mentor Assoc.| rmartin@rcmcon.com  |   Object Oriented Analysis
2080 Cranbrook Rd.  | Tel: (708) 918-1004 |   Object Oriented Design
Green Oaks IL 60048 | Fax: (708) 918-1023 |   C++
