Site Map  Search

OOA Home OOD content UML Corrections book Code object Exercise Solutions oriented Resources tutorial Miscellany textbook

150 Dos and Don'ts

These "dos and don'ts" are from an appendix to my Object-Oriented Analysis and Design book. (And they began as an appendix to the notes from the course I give that gave rise to the book.) (The page numbers refer to the explanations of the dos and don'ts in the book -- the 1st printing of the 1st edition).

[ return to top "25"  return to top "10" ]

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.

[ return to top "25"  return to top "10" ]