1253
Classes are currently the best way for programmers to achieve modularity. But
1254
modularity is a big topic, and it extends beyond classes. Over the past several
1255
decades, software development has advanced in large part by increasing the
1256
granularity of the aggregations that we have to work with. The first aggregation
1257
we had was the statement, which at the time seemed like a big step up from
1258
machine instructions. Then came subroutines, and later came classes.
1259
It’s evident that we could better support the goals of abstraction and
1260
encapsulation if we had good tools for aggregating groups of objects. Ada
1261
supported the notion of packages more than a decade ago, and Java supports
1262
packages today.
1263
C++’s and C#’s namespaces are a good step in the right direction, though
1264
creating packages with them is a little bit like writing web pages directly in html.
1265
If you’re programming in a language that doesn’t support packages directly, you
1266
can create your own poor-programmer’s version of a package and enforce it
1267
through programming standards that include
1268
● naming conventions that differentiate which classes are public and which are
1269
for the package’s private use
1270
● naming conventions, code-organization conventions (project structure), or
1271
both that identify which package each class belongs to
1272
● Rules that define which packages are allowed to use which other packages,
1273
including whether the usage can be inheritance, containment, or both
1274
These workaround are good examples of the distinction between programming in 1275
a language vs. programming into a language. For more on this distinction, see 1276
Section 34.4, “Program Into Your Language, Not In It.”
1277
CROSS-REFERENCE This is a checklist of considerations about the quality of the class. For 1278
a list of the steps used to build a class, see the checklist “The Pseudocode Programming
1279
Process” in Chapter 9, page 000.
1280
CHECKLIST: Class Quality
1281
Abstract Data Types
1282
Have you thought of the classes in your program as Abstract Data Types and
1283
evaluated their interfaces from that point of view?
1284
CROSS-REFERENCE For
more on the distinction between classes and packages, see “Levels of Design” in Section 5.2.
Abstraction
1285
Does the class have a central purpose?
1286
Is the class well named, and does its name describe its central purpose?
1287
Does the class’s interface present a consistent abstraction?
1288
Does the class’s interface make obvious how you should use the class?
1289
Is the class’s interface abstract enough that you don’t have to think about
1290
how its services are implemented? Can you treat the class as a black box?
1291
Are the class’s services complete enough that other classes don’t have to
1292
meddle with its internal data?
1293
Has unrelated information been moved out of the class?
1294
Have you thought about subdividing the class into component classes, and
1295
have you subdivided it as much as you can?
1296
Are you preserving the integrity of the class’s interface as you modify the
1297
class?
1298
Encapsulation
1299
Does the class minimize accessibility to its members?
1300
Does the class avoid exposing member data?
1301
Does the class hide its implementation details from other classes as much as
1302
the programming language permits?
1303
Does the class avoid making assumptions about its users, including its
1304
derived classes?
1305
Is the class independent of other classes? Is it loosely coupled?
1306
Inheritance
1307
Is inheritance used only to model “is a” relationships?
1308
Does the class documentation describe the inheritance strategy?
1309
Do derived classes adhere to the Liskov Substitution Principle?
1310
Do derived classes avoid “overriding” non overridable routines?
1311
Are common interfaces, data, and behavior as high as possible in the
1312
inheritance tree?
1313
Are inheritance trees fairly shallow?
1314
Are all data members in the base class private rather than protected?
1315
Other Implementation Issues
1316
Does the class contain about seven data members or fewer?
1317
Does the class minimize direct and indirect routine calls to other classes?
Does the class collaborate with other classes only to the extent absolutely
1319
necessary?
1320
Is all member data initialized in the constructor?
1321
Is the class designed to be used as deep copies rather than shallow copies
1322
unless there’s a measured reason to create shallow copies?
1323
Language-Specific Issues
1324
Have you investigated the language-specific issues for classes in your
1325
specific programming language?
1326 1327
Additional Resources
1328Classes in General
1329Meyer, Bertrand. Object-Oriented Software Construction, 2d Ed. New York: 1330
Prentice Hall PTR, 1997. This book contains an in-depth discussion of Abstract
1331
Data Types and explains how they form the basis for classes. Chapters 14-16
1332
discuss inheritance in depth. Meyer provides a strong argument in favor of
1333
multiple inheritance in Chapter 15.
1334
Riel, Arthur J. Object-Oriented Design Heuristics, Reading, Mass.: Addison 1335
Wesley, 1996. This book contains numerous suggestions for improving program
1336
design, mostly at the class level. I avoided the book for several years because it
1337
appeared to be too big (talk about people in glass houses!). However, the body of
1338
the book is only about 200 pages long. Riel’s writing is accessible and enjoyable.
1339
The content is focused and practical.
1340
C++
1341Meyers, Scott. Effective C++: 50 Specific Ways to Improve Your Programs and 1342
Designs, 2d Ed, Reading, Mass.: Addison Wesley, 1998. 1343
Meyers, Scott, 1996, More Effective C++: 35 New Ways to Improve Your 1344
Programs and Designs, Reading, Mass.: Addison Wesley, 1996. Both of 1345
Meyers’ books are canonical references for C++ programmers. The books are
1346
entertaining and help to instill a language-lawyer’s appreciation for the nuances
1347
of C++.
1348
Java
1349Bloch, Joshua. Effective Java Programming Language Guide, Boston, Mass.: 1350
Addison Wesley, 2001. Bloch’s book provides much good Java-specific advice
1351
as well as introducing more general, good object-oriented practices.
1352
CC2E.COM/ 0679
CC2E.COM/ 0686
Visual Basic
1353The following books are good references on classes in Visual Basic:
1354
Foxall, James. Practical Standards for Microsoft Visual Basic .NET, Redmond, 1355
WA: Microsoft Press, 2003.
1356
Cornell, Gary and Jonathan Morrison. Programming VB .NET: A Guide for 1357
Experienced Programmers, Berkeley, Calif.: Apress, 2002. 1358
Barwell, Fred, et al. Professional VB.NET, 2d Ed., Wrox, 2002. 1359
Key Points
1360
● Class interfaces should provide a consistent abstraction. Many problems
1361
arise from violating this single principle.
1362
● A class interface should hide something—a system interface, a design
1363
decision, or an implementation detail.
1364
● Containment is usually preferable to inheritance unless you’re modeling an
1365
“is a” relationship.
1366
● Inheritance is a useful tool, but it adds complexity, which is counter to the
1367
Primary Technical Imperative of minimizing complexity.
1368
● Classes are your primary tool for managing complexity. Give their design as
1369
much attention as needed to accomplish that objective.
1370
7
1High-Quality Routines
2 Contents 37.1 Valid Reasons to Create a Routine
4
7.2 Design at the Routine Level
5
7.3 Good Routine Names
6
7.4 How Long Can a Routine Be?
7
7.5 How to Use Routine Parameters
8
7.6 Special Considerations in the Use of Functions
9
7.7 Macro Routines and Inline Routines
10
Related Topics
11
Steps in routine construction: Section 9.3
12
Characteristics of high-quality classes: Chapter 6
13
General design techniques: Chapter 5
14
Software architecture: Section 3.5
15
CHAPTER 6 DESCRIBED DETAILS of creating classes. This chapter zooms in
16
on routines, on the characteristics that make the difference between a good
17
routine and a bad one. If you’d rather read about high-level design issues before
18
wading into the nitty-gritty details of individual routines, be sure to read Chapter
19
5, “High-Level Design in Construction” first and come back to this chapter later.
20
If you’re more interested in reading about steps to create routines (and classes),
21
Chapter 9, “The Pseudocode Programming Process” might be a better place to
22
start.
23
Before jumping into the details of high-quality routines, it will be useful to nail
24
down two basic terms. What is a “routine?” A routine is an individual method or
25
procedure invocable for a single purpose. Examples include a function in C++, a
26
method in Java, a function or sub procedure in Visual Basic. For some uses,
27
macros in C and C++ can also be thought of as routines. You can apply many of
28
the techniques for creating a high-quality routine to these variants.
29
What is a high-quality routine? That’s a harder question. Perhaps the easiest 30
answer is to show what a high-quality routine is not. Here’s an example of a low-
31
quality routine:
32
C++ Example Of a Low-Quality Routine
33
void HandleStuff( CORP_DATA & inputRec, int crntQtr, EMP_DATA empRec, double
34
& estimRevenue, double ytdRevenue, int screenX, int screenY, COLOR_TYPE &
35
newColor, COLOR_TYPE & prevColor, StatusType & status, int expenseType )
36 { 37 int i; 38 for ( i = 0; i < 100; i++ ) { 39 inputRec.revenue[i] = 0; 40 inputRec.expense[i] = corpExpense[ crntQtr ][ i ]; 41 } 42 UpdateCorpDatabase( empRec ); 43
estimRevenue = ytdRevenue * 4.0 / (double) crntQtr;
44 newColor = prevColor; 45 status = SUCCESS; 46 if ( expenseType == 1 ) { 47 for ( i = 0; i < 12; i++ ) 48
profit[i] = revenue[i] - expense.type1[i];
49
}
50
else if ( expenseType == 2 ) {
51
profit[i] = revenue[i] - expense.type2[i];
52
}
53
else if ( expenseType == 3 )
54
profit[i] = revenue[i] - expense.type3[i];
55
}
56
What’s wrong with this routine? Here’s a hint: You should be able to find at
57
least 10 different problems with it. Once you’ve come up with your own list,
58
look at the list below:
59
● The routine has a bad name. HandleStuff() tells you nothing about what the 60
routine does.
61
● The routine isn’t documented. (The subject of documentation extends
62
beyond the boundaries of individual routines and is discussed in Chapter 19,
63
“Self-Documenting Code.”)
64
● The routine has a bad layout. The physical organization of the code on the
65
page gives few hints about its logical organization. Layout strategies are
66
used haphazardly, with different styles in different parts of the routine.
67
Compare the styles where expenseType == 2 and expenseType == 3. 68
(Layout is discussed in Chapter 18, “Layout and Style.”)
69
● The routine’s input variable, inputRec, is changed. If it’s an input variable, 70
its value should not be modified. If the value of the variable is supposed to
71
be modified, the variable should not be called inputRec. 72
● The routine reads and writes global variables. It reads from corpExpense and 73
writes to profit. It should communicate with other routines more directly 74
than by reading and writing global variables.
75
● The routine doesn’t have a single purpose. It initializes some variables,
76
writes to a database, does some calculations—none of which seem to be
77
related to each other in any way. A routine should have a single, clearly
78
defined purpose.
79
● The routine doesn’t defend itself against bad data. If crntQtr equals 0, then 80
the expression ytdRevenue * 4.0 / (double) crntQtr causes a divide-by-zero 81
error.
82
● The routine uses several magic numbers: 100, 4.0,12, 2, and 3. Magic 83
numbers are discussed in Section 11.1, “Numbers in General.”
84
● The routine uses only two fields of the CORP_DATA type of parameter. If 85
only two fields are used, the specific fields rather than the whole structured
86
variable should probably be passed in.
87
● Some of the routine’s parameters are unused. screenX and screenY are not 88
referenced within the routine.
89
● One of the routine’s parameters is mislabeled. prevColor is labeled as a 90
reference parameter (&) even though it isn’t assigned a value within the 91
routine.
92
● The routine has too many parameters. The upper limit for an understandable
93
number of parameters is about 7. This routine has 11. The parameters are
94
laid out in such an unreadable way that most people wouldn’t try to examine
95
them closely or even count them.
96
● The routine’s parameters are poorly ordered and are not documented.
97
(Parameter ordering is discussed in this chapter. Documentation is discussed
98
in Chapter 20.)
99
Aside from the computer itself, the routine is the single greatest invention in
100
computer science. The routine makes programs easier to read and easier to
101
understand than any other feature of any programming language. It’s a crime to
102
abuse this senior statesman of computer science with code like that shown in the
103
example above.
104
The routine is also the greatest technique ever invented for saving space and
105
improving performance. Imagine how much larger your code would be if you
106
had to repeat the code for every call to a routine instead of branching to the
107
CROSS-REFERENCE The
class is also a good contender for the single greatest invention in computer science. For details on how to use classes effectively, See Chapter 6, “Working Classes.”
routine. Imagine how hard it would be to make performance improvements in
108
the same code used in a dozen places instead of making them all in one routine.
109
The routine makes modern programming possible.
110
“OK,” you say, “I already know that routines are great, and I program with them
111
all the time. This discussion seems kind of remedial, so what do you want me to
112
do about it?”
113
I want you to understand that there are many valid reasons to create a routine and
114
that there are right ways and wrong ways to go about it. As an undergraduate
115
computer-science student, I thought that the main reason to create a routine was
116
to avoid duplicate code. The introductory textbook I used said that routines were
117
good because the avoidance of duplication made a program easier to develop,
118
debug, document, and maintain. Period. Aside from syntactic details about how
119
to use parameters and local variables, that was the total extent of the textbook’s
120
description of the theory and practice of routines. It was not a good or complete
121
explanation. The following sections contain a much better explanation.
122