| 6 |
Ensure that every
object is meaningful, either in terms of the subject matter, or in
terms of the implementation platform or as a powerful metaphor. |
| 6 |
All application
functionality should be carried out by objects; not by ordinary functions;
not by class methods (statics); only by methods (member functions). |
| 7 |
If the code doesn't
work, you've failed. If you haven't done enough testing, you won't
know if the code works. If you haven't found out about the problem,
you don't know what numbers to put in the tests (Kent Beck). |
| 28 |
Don't write programs
if you can use good frameworks instead. Don't use frameworks if you
can use tools instead. Don't use tools if you can buy packages instead. |
| 30 |
Postpone the
inventive and the speculative as long as you can (but no longer than
that). Stick to facts and the definitive in the early stages (in the
requirements and in the subject matter model). |
| 31 |
Trust the state
of the subject matter, in all its manifestations, to guide you. Be
suspicious about all other aspects of the subject matter. |
| 33 |
If it has been
decreed that the development process must be linear (or "waterfall")
and you don't feel like lying about what you're doing, consider another
project. |
| 34 |
Given the choice
between being class-oriented and object-oriented, go for being object-oriented. |
| 36 |
Design objects
from the outside in: messages, then methods and then instance variables
(and inheritance). Don't design objects from the inside out: instance
variables, then methods and then poor, happenstantial interfaces. |
| 40 |
Superclasses
should be abstract. Don't instantiate superclasses even if you could.
Only instantiate leaf-node, concrete classes. |
| 41 |
Ensure that there
is a very pressing reason if you ever use a superclass (base class)
as a type. Stick to interfaces (pABCs) and the occasional attribute
(value) object's concrete class for your types. |
| 46 |
Don't carry out
activities whose payoffs haven't been identified. |
| 46 |
There are many
diagram types and symbols in the UML. Know which ones you intend the
project to use, how you intend them to be used and how much you intend
to use them. |
| 47 |
Be guided by
use cases in your drive toward a good architecture, but don't let
use cases drive the whole process. A good architecture is crucial.
Use cases are important but are only on an indirect path to a good
architecture. |
| 53 |
Everybody must
know, and pay respect to, whether UML is being used informally (sketch)
or formally (blueprint). Avoid, at all costs, even the faintest possibility
that a sketch might be interpreted as a blueprint. |
| 54 |
Get diagrams
as close as you can to "comprehensible at a glance"; certainly
not "comprehension only after many hours effort". |
| 54 |
Ensure that any
diagram serves a purpose. Put in a comment saying what that purpose
is. |
| 56 |
Only use prefixes
in names when there is a very good reason. |
| 56 |
If you can write
an honest mission statement for a package, in a paragraph, it's probably
a reasonable package. If you can write an honest mission statement
for a class or type, in a sentence, then it's probably a reasonable
class or type. |
| 69 |
If a document
title contains the word "requirements", ensure that it also says
what it is that has these requirements, and of what. |
| 69 |
If you haven't
got clearly expressed (and preferably quantitatively expressed) requirements,
then you haven't got a contract. Personally, I'd be very wary of working
without a contract. |
| 69 |
Requirements
control is one of your main opportunities to gain project control.
Don't waste the opportunity. |
| 69 |
Ensure that someone
is keeping, and controlling, a risk schedule; and that vague or challenging
requirements are on it, and monitored. |
| 69 |
Requirements
capture is your opportunity to be factual, to be definitive and not
speculative, to make the best start you could ask for. Don't waste
the opportunity and don't pollute the facts with analysis or design
speculation; it'll be too early. |
| 70 |
Ensure that your
input requirements concern themselves with observables - inputs and
outputs - and the relationships between them. |
| 71 |
Check that your
requirements are implementation-independent. Any requirement that
would disappear if the technology changed, isn't a requirement. |
| 79 |
Don't call prototypes
prototypes; call them mock-ups. Computer people forget to throw prototypes
away. They have forgotten what the word means. Make sure mock-ups
are clearly broken and dysfunctional outside of the reason for their
creation. |
| 90 |
Never be tempted
to skip the analysis phase because you are already subject matter
experts. You need a written down consensus model to move forward from. |
| 93 |
It all boils
down to componentization, high cohesion and low coupling. So make
sure everyone understands these things, and make sure everyone pays
full respect to them and not just lip service. |
| 94 |
Ensure that all
names (types, classes, methods, parameters, etc.) are precise (honest,
complete, unambiguous), colorful (rather than gray) and concise (but
not at the expense of the other qualities). |
| 99 |
Ensure you keep
use cases and actors in their place - in the requirements. Actors
only coincidentally become entities. Many actors would be poor entities.
Many entities will never have been actors. |
| 99 |
Many good entities
come to us via nouns; but there are other routes like noun phrases,
verbs and verb phrases. |
| 100 |
Distinguish "pure"
events from events remembered. An event remembered is a candidate
entity. A pure event hints, tangentially, at a message. |
| 101 |
Don't let pronouns,
possessive pronouns or passive verbs hide important entities. |
| 101 |
Have a good dictionary
and a good thesaurus within arm's reach of any software development
activity. |
| 102 |
Name entities
with good, strong names; no processors, handlers or managers. Use
singular names. Avoid terms from the implementation technology. |
| 103 |
High-level, single-instance
entities are OK. (But don't let them become "god" objects.) |
| 104 |
Include relevant
entities, but err on the side of generosity. Design will follow "if
in doubt, leave it out"; analysis will follow the opposite. A
rich entities list is more important. |
| 107 |
Keep attributes
simple and scalar. If it can't easily be measured against some kind
of scale (including enumerations like {up, down} or, as a last resort,
text), then it isn't an attribute, it's an entity. |
| 108 |
Understand identity.
Entities have identity; attributes do not. Use the "point or
measure" ("how much/how many") test to distinguish them. |
| 109 |
One-to-one associations
are perfectly acceptable. Don't be tempted to collapse two such associated
entities into one. |
| 110 |
If you see entity
boxes with activities (operations) or visibility marks, ensure there
is good reason (I can't think of one!) |
| 112 |
Subject matter
entities give ideas for objects, not classes. |
| 112 |
Subject matter
attributes don't predict object instance variables; they predict query
services that might, but only might, be supported by an instance variable. |
| 114 |
Check that all
your association and aggregation relationships are characterizing.
Any use-only relationship might be useful in the design but they won't
be useful in the analysis. |
| 116 |
Don't rely on
default multiplicity values. Put all multiplicities in explicitly |
| 119 |
Be relentless
in making many-to-many associations prove that they are correct and
necessary. Prove that there isn't a missing entity. Prove that there
aren't really a pair of one-to-many associations in opposing directions. |
| 122 |
You don't really
know your entities until you have 95% of their attributes, all with
good, strong names and until you have all of their associations roles
strongly named. |
| 123 |
Consider allowing
role name tenses to indicate their nature over time. "-ing"
names can often correctly indicate current associations; "-ed"
or "-es" names can often correctly indicate accumulating associations. |
| 124 |
You must not
assume that all associations are bidirectional by default. You will
open up an unnecessary chasm between models and code. Make bidirectional
association prove themselves to be so. And even then keep an eye on
them as new entities emerge. |
| 128 |
Treat n-ary associations
as mistakes. Investigate them thoroughly and replace them with something
better. |
| 128 |
Overlooked entities
are not only a problem in their own right, they exacerbate other problems. |
| 129 |
Ensure that everyone
on a project has, and uses, a consistent, sensible and useful interpretation
of aggregation. |
| 131 |
Unless your interpretation
of the aggregation relationship is an unusual one, avoid "has"
or its many synonyms as role names. |
| 136 |
Modelers can
occasionally get a little too fanciful or exotic. To keep oneself
grounded, it helps to imagine yourself explaining a feature in a training
session with the users. |
| 141 |
Be wary of status
attributes. They often imply and suppress model elements that should
be included in the model. |
| 142 |
It can be difficult
to distinguish subject matter from solution. Something is subject
matter if a) it's relevant and b) it's not up for replacement by the
system-to-be. |
| 150 |
Don't think like
a programmer; think like an object. Through a programmer with a good,
anthropic imagination, an object should design its own implementation
and the interfaces of the other objects. |
| 153 |
Pounce on any
hint of a conflict in a model. It often tells you that something -
an entity, an association, etc. - is missing. |
| 168 |
Respect the principle
of substitutability. Don't use generalization, implementation or inheritance
where you couldn't validly say that an instance of the specializing
type can act as ("substitute for") an expectation of the general. |
| 173 |
Don't go over
the top looking for generalizations. If they're there, fine. But don't
risk inventing ones that are not going to be useful. Generalizations
are not particularly good predictors of inheritance or implementation
relationships, for example. |
| 174 |
When considering
generalization relationships, start with the facts and determine the
commonality. Start with the special rather than the general. Don't
assume similarity. |
| 176 |
Don't confuse
the carrying of multiple types (OK) with multiple inheritance of implementation
(not OK). |
| 191 |
Think very carefully
about how many state machines you are going to need. Expend the greatest
care in ensuring that each state machine really says what you think
it says and ought to say. |
| 197 |
Ensure that you
have and share an interpretation of events in state machines. I suggested
that in analysis they are significant happenings, and that it isn't
worth asking how the entity was "notified"; and that in design
they are messages. |
| 199 |
Try never to
have state machines that specialize more general state machines, either
directly or because their context objects are in a generalization
relationship. |
| 200 |
Don't think of
composite states as states. Think of them as groups of real states.
Ensure that if these groups were ungrouped - if the machine were "flattened
out" - no information would be lost even if the thing did become
unreadable. |
| 208 |
State machine
outputs (activities in UML 2) have very little promise and very great
peril. You almost certainly don't need them. If you use them, have
the project standards carefully say how and why. Alternative phrasing:
stick to protocol state machines. |
| 248 |
You will almost
certainly need a CASE tool. Whichever you choose it will almost certainly
infuriate you in some way or other. Ensure it serves you and that
you don't end up serving it. Ensure everyone uses it consistently. |
| 249 |
Design is not
an end in its own right. Design provides a good home for good code. |
| 251 |
You will budget
for testing, of course. But don't budget on the assumption that all
the tests will be passed. Don't forget to budget for debug, fix and
re-test. |
| 252 |
Program in the
future tense. Foresee the inevitability of having to change and extend
tomorrow what you are writing today. |
| 255 |
There are no
reasons to have global variables or global functions. For example,
instead of making Planck's constant a global, have a universe, or
standard model (physics) object and ask it for Planck's constant. |
| 262 |
You can expect
your subject matter to lead you to good ideas for objects; you can't
expect it to lead you to good ideas for classes. So, plan your object
first. Then you'll have some of the evidence to plan the classes. |
| 263 |
An object should
be cohesive. It should represent one thing, all of that thing and
nothing but that thing. It should have a good, focused mission statement. |
| 263 |
Respect the need-to-know
principle: be happy not to know if you don't need to know. The US
Military says: "Need-to-know" is one of the most fundamental
security principles. It limits the damage that can be done by a trusted
insider who goes bad. |
| 265 |
Avoid the overly
complex, thinly disguised data structure masquerading as an object.
Design objects, and design them from the outside in. |
| 266 |
Watch out for
pronouns. Never say I'll do this, if you are being the programmer.
Never say we'll do that; they'll do the other. Never say you - meaning
one - will do this or do that. (And if one does say "one", never
say one will do this and then that.) |
| 266 |
If you don't
do CRC, you will have to find another, equally good way of coming
at your objects via the messages they can expect to receive. |
| 273 |
The CRC chapter
bristles with dos and don'ts which are not duplicated here. They would
be worth re-reading for the first few CRC workshops. |
| 278 |
Don't confuse
use cases and object interaction. Use cases are for requirements and
an external perception. Object interaction is a design activity, an
internal perception, and validates that your classes' instances can
enact the use cases. |
| 289 |
Object type boxes
will tend to have a single substantive compartment listing message
signatures. Visibility symbols would be unusual and their significance
would require careful definition. |
| 296 |
The subject matter
model will tell you about the query services. You will need something
other than the muses to tell you about the rest of the services (and
CRC is a good candidate). |
| 320 |
Names of interface
and pABCs should be "broader" and speak of role; names of
concrete classes should be "narrower" and speak of realization. |
| 320 |
Variables have
types; objects have classes. That's the pithy version. The slightly
more informative and accurate version is: a variable (or parameter
or return) has a type; an object has a class and carries several types. |
| 321 |
After one has
realized that the program is no longer the deliverable, and has acknowledged
the importance of class design, one must then go on to realize that
designing the type system is equally important. |
| 325 |
main( ) isn't
run by an object. An object-oriented piece of software would not,
therefore, have application logic in main( ). |
| 329 |
When design time
arrives, get the abstract types and concrete classes right first.
Put abstract superclasses (base classes) between the abstract types
and the concrete classes, later. |
| 329 |
And all that
happens as you get more experienced is you realize that this guideline
is correct; the ability to guess what to inherit doesn't improve. |
| 331 |
Ensure you know
how your object-oriented programming language achieves polymorphism
(and thus, probably, late binding) while retaining strong type checking.
Otherwise you are wasting a significant part of your investment in
object technology. |
| 331 |
In Java and
C# you must understand interfaces; in C++ you must understand best
practice use of abstract and pure abstract classes. |
| 337 |
Service perceptions
(interfaces, pABCs, non-private method signatures) should use names
that talk of the role or service provided; not of how things work,
not of implementation. |
| 338 |
Apportion your
time wisely. Type names and public signatures require ten times more
thought than private instance variable names |
| 339 |
Interface boxes
will tend to have a single substantive compartment listing message
signatures. Visibility symbols would be unusual and their significance
would require careful definition. |
| 340 |
Let change cases
help you test the likely longevity of your type (interface and pABC)
names. |
| 345 |
Object-orientation
remains important even when designing classes. Keep in mind that the
aim is good objects, and classes are a means to that end. Think outside-in.
Use sequence diagrams as well as class diagrams. Do CRC. |
| 345 |
If you're not
going to bother with good classes, don't bother with object-orientation.
Most of the time a bad class is worse than no class at all. |
| 346 |
If you haven't
got a good subject matter model giving you your metaphor, ensure that
you find a good metaphor anyway. |
| 347 |
To be object-oriented
means having objects do the work. And that means avoiding functions
in favor of methods (member functions). It also means avoiding class
methods (static methods or member functions). |
| 348 |
Avoid class variables
as well. Class methods and class variables should pass the test of
being necessary in each and every reuse of a class in any other applications,
anywhere, anytime. |
| 348 |
Be a little bit
afraid each time your code uses a constructor directly for all but
the most stable of value objects. |
| 348 |
Self messaging
is elegant and powerful. If you aren't self messaging then you have
missed a step in your ascension to true object-orientated greatness. |
| 350 |
Delegate and
empower. Understand the Law of Demeter. |
| 351 |
If your documentation
system can't produce a printout of the interface of any class or interface
at a moment's notice, then it's a feeble and sickly kind of documentation. |
| 351 |
There should
also be a note as to the stability of the interface: is it work-in-progress,
or is it stable and under change control? |
| 352 |
Name concrete
classes such that if ever a superclass is factored out, the original
name remains the good and correct name of the resultant concrete subclass. |
| 358 |
If your language
supports class visibility that is less than public, make non-public
your initial default. Don't just slap public in front of every class
declaration. |
| 358 |
Don't expect
anyone to understand your diagrams if you insist on putting in every
single method and instance variable of every single class. |
| 358 |
Diagrams take
time to create, and maintain. Every diagram should have a purpose
and can often benefit from a comment saying what that purpose is. |
| 359 |
A good question
concerning an object is, "Yes but what does it do for me?"
If your first reaction to an object is "What message signatures
does it publish?", then full marks; if it's "What data does it
have?", think again. |
| 362 |
Multiple inheritance
to give an object multiple types is OK. Multiple inheritance to give
a class several sources of implementation is not OK. All, or all bar
one, of a class' superclasses should be purely abstract (pABC). |
| 363 |
Unless it's for
stable value objects, concrete classes are usually poor types for
variables, parameters and returns. Interfaces and pABCs are better. |
| 369 |
Don't leave readers
of designs guessing as to relationship direction. A design is only
complete when each relationship has its direction. Associations particularly
must be checked to ensure they have an arrow at one end or the other,
or occasionally both. |
| 382 |
Don't be tempted
to omit a good, de-coupling interface just because you can only see
one implementing class in version 1. |
| 384 |
There should
be a compelling and unusual reason to use private inheritance. Normally,
composition is the best way to avail yourself of the capabilities
of something without acquiring its type. |
| 384 |
You will have
the evidence as to the types and concrete classes before you have
the evidence as to inheritance; so don't do the inheritance too early. |
| 385 |
Freshly-written
code takes time to stabilize. There will be surprising opportunities
to share implementation; and early assumptions as to common implementation
will be often be wrong. Get through a round of test, debug and fix
before doing inheritance. |
| 385 |
7 ± 2 applies
to loosely-coupled chunks. Inheritance doesn't produce loosely-coupled
chunks, so 7 ± 2 doesn't apply. A class is allowed 1 ± 0 implementation-holding
superclasses. Inheritance structures are allowed to be around 3 ±
1 levels deep. |
| 389 |
The more that
a superclass' subclasses override (and don't call back for) the superclass'
concrete methods, the more one must question the raison d'ętre of
the superclass. |
| 389 |
If you arrive
at a point where a subclass method wants to access an inherited instance
variable, you haven't discovered that you need non-private instance
variables; you've discovered that the variable or the method is in
the wrong place. |
| 393 |
super increases
coupling. The right keyword for self-messaging is this, whether or
not you have a superclass. super is only for when an overriding method
must use the method it's overriding. |
| 393 |
When the time
comes to factor out common implementation, into superclasses, don't
sully the type system with common implementation dependencies. Isolate
fragile superclasses between pure types and concrete classes. (Never
turn pABCs into ABCs.) |
| 395 |
Don't use up
good type names on superclasses. (And make sure you follow the advice
about isolating the superclass layers, in case you do.) Have a little
bit of artificiality in superclass names. |
| 396 |
Superclasses
shouldn't be instantiated even if potentially they could be. If your
language allows you to enforce the abstractness of superclasses, then
do so. |
| 396 |
Superclasses
must be designed to be superclasses. Try never to allow concrete classes
to slip into the role of superclass. If your language allows you to
prevent classes becoming superclasses (final, sealed), then do so. |
| 400 |
Only use inheritance
when primarily sharing type relationships and secondarily sharing
implementation. If you want implementation alone, composition is a
much better contender. |
| 403 |
If you must provide
libraries, prefer libraries of component instances over libraries
of superclasses. If you must provide superclasses, provide them in
a framework (and be prepared for quite an investment in the framework's
design). |
| 404 |
A C++ style guide
can't ban multiple inheritance. An object simply has to be able to
carry more than one type. One must ban more than one superclass having
inheritable implementation. |
| 405 |
During detailed
design, avoid terms like "association", "aggregation"
and "generalization". Prefer terms like "reference",
"pointer", "extends", "implements",
etc. |
| 413 |
You should probably
be considering object factories in preference to direct instantiation
(new expressions for example) more often than you think. |
| 413 |
Keep superclass
names exclusively in subclass declarations (i.e. don't use them as
types; and don't instantiate them). That way, when these fragile,
volatile creatures change, it will have the minimum impact. |
| 415 |
Methods should
be cohesive; they should do one job, all of that job and nothing but
that job. They should have a good, focused mission statement. |
| 416 |
Multiply a method's
argument count by two and that's the number of object experts that
must agree that that number of arguments is unavoidable. (The designer
counts as an expert here.) (Constructors aren't methods.) |
| 416 |
An argument should
bring information. It shouldn't bring instructions as to how to do
something. |
| 416 |
Modifying pass-by-reference
arguments as a way of communicating with a message sender increases
the coupling in non-obvious ways. Doing so requires very strong justification. |
| 417 |
Don't access
an instance variable if self-messaging would tell you what you want
to know about yourself. |
| 418 |
Don't get into
the habit of making all methods public. Package or internal is a better
default. Methods can always be opened up to public later. If they
start as public, there's no going back. |
| 418 |
Don't name a
method for how it works, name it for the service it provides. This
is particularly important for methods with public and package access. |
| 419 |
Support polymorphism.
Don't design a signature to be the same as that of a method providing
a different service. |
| 419 |
Support polymorphism.
Don't invent a new signature for a method when objects of other classes
are already providing the same service under a different signature. |
| 420 |
Don't expend
effort trying to handle exceptional conditions unless you are 100%
sure that you will handle them correctly. If you can't terminate the
program gracefully, draft in expert help - possibly exceptions expertise,
but possibly not. |
| 420 |
Avoid the coded
return. If you're supposed to be returning an answer then don't try
to return the fact that you couldn't return the answer. Think of something
else. |
| 421 |
The "what, why,
when, how, where and who" of exception throwing and catching
are strategically important. Ensure that the project standards are
clear on exceptions. (And locate a guru who really knows exceptions
and who can answer questions.) |
| 425 |
Just about all
opportunities to make something const (final, sealed, readonly, query,
immutable) should be taken. Final (sealed) methods - ones that can't
be overridden - would be the exception to the rule, only being used
when really needed. |
| 426 |
Don't spend time
on separate, procedural method specifications unless you have already
assembled an excellent set of test cases and have pressing reasons
for not writing short expressive first versions of the code in a modern
language. |
| 426 |
Your reading
this book makes it unlikely that you're implementing in a restrictive,
creaky old language. Specifying methods with pseudocode would require
a strong justification. |
| 426 |
If methods are
to be specified in advance of being written, organizations above CMM
level 2 would do well to consider declarative specifications in preference
to procedural specifications. |
| 429 |
Non-private instance
variables make any class fragile. It's bad enough having fragile superclasses;
we don't want any other fragile classes. 99.99% of instance variables
should be private. |
| 429 |
Outside of copy
construction or copy assignment, pretend your language has instance-level
encapsulation, even if it doesn't. Don't allow ordinary methods of
instances to access the data of other instances. |
| 437 |
Unless you are
level 3 or above, with copious time on your hands, focus your effort
on state machines that are essential. Subject all state machines to
stringent inspection. |
| 437 |
In typical OO
languages, especially outside of real time systems equate state machine
events with messages and let the messages imply the methods, i.e.
avoid separated activities, i.e. stick to protocol state machines. |
| 446 |
Don't include
class names as part of method names. |