Bottom-Up Design and this Thing called an 'Object'

Alan F. Blackwell

December 1993

.EXE Magazine 8(7), pp. 28-32

(pre-publication title: "When an Object is not a Thing")

I was at a loss for words recently when my neighbour on the Tube
noticed the logo on a promotional satchel I was carrying. He asked
me: what exactly is Object Technology?' What could I say between
Leicester Square and Piccadilly? My problem is that object
orientation (OO) is starting to invade our speech with some of the
worst examples yet of computer jargon. 'Object' is a useful concept
in English; not commonly used, but widely understood. It is certainly
a more everyday item than jargon terms such as 'entity'. Now the
computer industry is appropriating a useful word and giving it a
completely new meaning.

It is not only the computer-innocent that are suffering from the
redefinition of the word 'object'. Software developers starting to
design an OO system and faced with the first blank sheet, often fall
into the trap of believing that an 'object' is a 'thing'. This is
true in everyday language (unless you are a philosopher), and
promoters of OO often imply it in their sales pitches. Be careful,
though. For an OO developer, an object is not a thing.

The sales pitch

When vendors are selling object-orientation, they try to describe
the benefits in terms that your manager will understand. Lets face
it, this means over-simplifying. This is no problem for you, until
your project is behind schedule and the sales talk comes back to
haunt you. It sounds impressive to a manager, but how would you like
to be told, after working on a system for a year, that the analysis
should have involved no more than underlining the nouns in the
specification, and making each one an object? Or that designing an OO
system is as natural as speaking English, because describing the
relationship between two things is as good as specifying their
interfaces? Or that the coding part of an OO project consists of
writing down the behaviour of an object as the analyst describes it?

Claims like this were once more accurate. Object orientation (in
the form of the Simula language) was first used for simulation work,
where the goals were - to model the behaviour of real world objects.
In a simulation program, an object really does represent a thing: in
the systems that most of us work on, it usually does not.

When hype fades away

The naive idea that nouns in the specification become the objects
in the design can be abandoned as soon as the system boundary is
drawn. Most structured design methods start by drawing a system
boundary - it is surprising how often people forget that initial step
on their first OO project. There is little point in designing an
object unless it corresponds to something inside the system, but it
is very tempting, for example, to make an object called 'User'. Talk
about the user as an object if you like, but remember the user is not
inside the system.

As important is the fact that many of the objects in an OO design
do not correspond to any thing in the real world. A mouse button
click is not a thing; neither is a transaction. What about a print
buffer, an event dispatcher or an interaction mode?

In fact when you look at the structure of most completed OO
software, you find that the majority of the objects represent
concepts in computer science rather than real-world things. As with
most advances in programming languages, the ultimate benefit of
object orientation is that it helps us to define the behaviour of a
system at a higher level of abstraction.

One of the great advances to come with block structured
programming languages was the introduction of record data types such
as the C struct - these allowed several pieces of data to be
treated as a single abstraction. OO extends this concept to include
operations on the data as part of the record abstraction. The
extension of the record abstraction is often reflected in the
language implementation, as in the case of C++, where class
is just an extension of struct.

If advances in software come from greater abstraction, then OO
designers should concentrate on designing classes that are good
abstractions. Some OO languages allow you to treat your abstractions
in the same way as the base data types of the language, so that a
well designed class can be treated directly as a language element. If
you can achieve this, the program code becomes an elegant tool for
expressing the function of your system, rather than the usual
rats-nest of data and control.

An excuse for having fun

When you look at the most elegant software designs - systems like
GNU EMACS or TEX - they succeed because they provide powerful
building blocks that can be combined in simple ways by relative
novices. The writers of these systems are software geniuses, so we
mortals can only aspire to the same elegance. But OO does give us
tools that make the job a lot easier. If you can write a decent set
of classes, providing building block abstractions for your
application, analysis and design will be straightforward. You may
have spotted my hidden agenda here. I want to justify what
programmers always liked to do best - bottom-up design.

Bottom-up has been frowned on ever since top-down became
politically correct in the Structured Seventies. What we all secretly
know is that bottom-up is more fun! What half-decent programmer would
waste a day working on some functional decomposition user-view
data-flow analysis specification when he could be hacking away at
code? I don't want to imply that it is a bad thing to think first
about what you are doing. Remember that those building blocks have
got to be well-designed. That means brainwork, even if it is Monday
morning, and you would rather just sit back with your copy of .EXE
magazine. What I do want to emphasise is that a good OO design takes
the code into account right from the beginning. The non-technical
analyst can be even more of a problem than usual on an OO project,
because an arbitrary set of functional specs does not necessarily
break down into an elegant set of building blocks.

Don't shoot the analyst

The majority of useful classes will fall into one of three basic
categories: data objects, user interface components, controllers or
building blocks. Data objects are easy to find. Any database record
or similar collection of information that will hang around together
should become a data object. From the old-style analyst's point of
view, these look like the centre of the design. They are easy to
spot. A library system, for example, is pretty likely to contain a
'book' object. The data members of this object will include 'author'
and 'title'. The operations on the object will include 'withdraw' and
'lost'. It is hard to believe that people get paid for this kind of
work, isn't it?

User interface components are easy to identify as well. The
simplest are designed as one object per dialog window (or per screen,
if you are still building systems for dumb terminals). The data items
that appear on a single window are all related to one another, or at
least should be, unless the analyst really messed up. It makes sense
to design a class for each window.

The more interesting user interface components are groups of
fields or widgets that always appear together or behave in a certain
way. Consider a customer service system in which there are several
different reasons for making a cash transaction. Each of these
appears on a different dialog window, but each includes a display
field for amount due, an entry field for amount tendered, and another
display field for change. These three fields always work the same way
and the relationships between them are fixed. The analyst probably
won't spot that these can be combined into a single class, but if you
code them together they can save you a lot of duplicated effort. They
only need to be coded once and debugged once. What's more, when the
analyst springs on you the fact that the customer is actually Greek,
and all the cash transactions should be displayed in Drachma, you can
fix up the user interface with a single change.

Controller objects are the difficult part. These are the objects
that only live inside the program and never show themselves to the
outside world. You have to be a real programmer to design the
architecture of the system at this level. If the analysts don't know
what they are doing, don't let them near controllers. A truly bad
analyst won't even notice that controllers are needed - they will
just draw a bubble called 'system', or a line labelled 'operate', to
represent something that you know will take 70% of the effort on the
project.

You can recognise a controller object by the fact that it is
transient. If the system user doesn't see it and it is not stored in
the database, it is probably a controller. Things like transaction
queues should be implemented as controller classes; real time or
embedded systems tend to have a lot more of this kind of thing. The
average data processing application (if you are lucky) is composed
mostly of data objects and user interface objects, but if the system
is doing something clever, you will probably have to get your hands
dirty with controller objects.

Abstractions

Good abstractions are the building blocks of OO design. The more
of these basic building blocks you have, the more you can get the
real benefits of OO. Unfortunately, there is no quick and easy way to
learn how to design a good set of building blocks. You'll learn to
recognise them more easily with experience.

I can offer some advice for spotting when you haven't got good
building blocks. Look out for anywhere that basic language types are
being used for parameters or variables - if the same operations are
being repeated on those values in different places, they should
possibly be turned into a class. If there are several basic values
that are always used together, they should almost certainly be a
class.

Consider filenames in C++ as a simple example. All the system
calls expect a filename to be a char*, and C programmers are
used to thinking of a filename as being a char*. You can
store them in this form and pass them around the system in the same
way. Think how convenient it would be, though, if you never had to
write code to check for valid construction, or to concatenate to
paths, or to allow for portability between UNIX and MS-DOS format
path separators. If you define a filename class, it might still
contain the same char* data, but you can build in checks to
make sure that there are no spaces in the middle, and that the last
character is not a path separator. Making system calls can be just as
easy as it was with a char*, because you can define a type
conversion operator that passes the char* to the system
call.

Even better, you can build in the system calls as operators on the
filename class itself. The type checking of the compiler now starts
to work for you (rather than against you, as it normally seems to);
you will not mix up filenames with other string data such as user
names. You can distinguish in advance between a directory path and a
file path. Perhaps 'directory' should inherit from 'filename'? You
can start to define operators on these classes to do useful things.
What would you expect to happen when you assign a filename to a
directory? Should you get the directory path? How about adding a
string to a directory? Maybe that should concatenate them and return
a filename?

As you can see, defining building blocks opens up a whole spectrum
of possibilities at the bottom levels of your design. You can see
some good examples of building block design by reading through the
source code for class libraries. Eventually, we might all have access
to class libraries that do everything we want at this level. In the
meantime, we have to design many of our own building block classes
and good abstractions, like the filename class, which can simplify
the design of a whole system. If you are careful you can use a lot of
the same building blocks in your next project and get some real
improvements in productivity.

The bottom-up manifesto

In this article I have argued for more bottom-up design; the main
benefits of using an OO language come only when you have a working
set of building blocks. This means that a good programmer using an OO
language can work better, even using old-style analysis methods: the
building blocks should be designed as a separate exercise from the
analysis. Don't confuse what I am saying with OO analysis. That is a
completely different field, which can be used either in conjunction
with an OO language, or with a conventional language. OO analysis is
not much like programming, but you may find it entertaining

What you need to avoid are the people who think they are OO
analysts, but who do not really understand OO programming. They are
rather too common. If you aren't careful, analysis objects can
pose as software objects and take over your design - like the
killer vegetables in Invasion of the Body Snatchers. If you
are under attack from analysis objects, just quote the design creed
of the bottom-up manifesto: 'a class is an abstraction; an object is
not a thing.'