Riel's heuristics

From CSSEMediaWiki
Jump to: navigation, search

In his book Arthur Riel 1996, Riel collects together 61 heuristics used in the OO community. In the preface of his book, he describes how they should be used:

"I refer to these 60 guidelines as "heuristics", or rules of thumb. They are not hard and fast rules that must be followed under penalty of heresy. Instead, they should be thought of as a series of warning bells that ring when violated. The warning should be examined, and if warranted, a change should be enacted to remove the violation of the heuristic. It is perfectly valid to state that the heuristic does not apply in a given example for one reason or another. In fact, in many cases, two heuristics will be at odds with one another in a particular area of an object-oriented design. The developer is required to decide which heuristic plays the more important role."

(Descriptions of heuristics copied from [1]. We need to make up short wiki names.)

Chapter 2 Classes and Objects: The Building Blocks of the Object-Oriented Paradigm
2.1 Hide data within its class All data should be hidden within its class.
2.2 A class should not depend on its users Users of a class must be dependent on its public interface, but a class should not be dependent on its users.
2.3 Minimize number of methods Minimize the number of messages in the protocol of a class.
2.4 Minimal public interface Implement a minimal public interface which all classes understand (e.g. operations such as copy (deep versus shallow), equality testing, pretty printing, parsing from a ASCII description, etc.).
2.5 Avoid interface bloat Do not put implementation details such as common-code private functions into the public interface of a class.
2.6 Avoid interface pollution Do not clutter the public interface of a class with things that users of that class are not able to use or are not interested in using.
2.7 Nil or export coupling only Classes should only exhibit nil or export coupling with other classes, i.e. a class should only use operations in the public interface of another class or have nothing to do with that class.
2.8 One key abstraction A class should capture one and only one key abstraction.
2.9 Keep related data and behavior in one place Keep related data and behavior in one place.
2.10 Separate non-communicating behaviour Spin off non-related information into another class (i.e. non-communicating behavior).
2.11 Model classes not roles Be sure the abstractions that you model are classes and not simply the roles objects play.
Chapter 3 Topologies of Action-Oriented Vs. Object-Oriented Applications
3.1 Distribute system intelligence Distribute system intelligence horizontally as uniformly as possible, i.e. the top level classes in a design should share the work uniformly.
3.2 Avoid god classes Do not create god classes/objects in your system. Be very suspicious of an abstraction whose name contains Driver, Manager, System, or Subsystem.
3.3 Beware of many accessors Beware of classes that have many accessor methods defined in their public interface, many of them imply that related data and behavior are not being kept in one place.
3.4 Beware of non-communicating methods Beware of classes which have too much non-communicating behavior, i.e. methods which operate on a proper subset of the data members of a class. God classes often exhibit lots of non-communicating behavior.
3.5 Interface should be dependent on model In applications which consist of an object-oriented model interacting with a user interface, the model should never be dependent on the interface. The interface should be dependent on the model.
3.6 Model the real world Model the real world whenever possible. (This heuristic is often violated for reasons of system intelligence distribution, avoidance of god classes, and the keeping of related data and behavior in one place).
3.7 Eliminate irrelevant classes Eliminate irrelevant classes from your design.
3.8 Eliminate unnecessary classes Eliminate classes that are outside the system.
3.9 Avoid verb classes Do not turn an operation into a class. Be suspicious of any class whose name is a verb or derived from a verb. Especially those which have only one piece of meaningful behavior (i.e. do not count sets, gets, and prints). Ask if that piece of meaningful behavior needs to be migrated to some existing or undiscovered class.
3.10 Agent classes irrelevant Agent classes are often placed in the analysis model of an application. During design time, many agents are found to be irrelevant and should be removed.
Chapter 4 The Relationships Between Classes and Objects
4.1 Minimise class collaborations Minimize the number of classes with which another class collaborates.
4.2 Minimise method collaborations Minimize the number of message sends between a class and its collaborator.
4.3 Minimise methods between collaborators Minimize the amount of collaboration between a class and its collaborator, i.e. the number of different messages sent.
4.4 Minimize fanout Minimize fanout in a class, i.e. the product of the number of messages defined by the class and the messages they send.
4.5 Containment implies uses If a class contains objects of another class then the containing class should be sending messages to the contained objects, i.e. the containment relationship should always imply a uses relationship.
4.6 Methods should use most fields of a class Most of the methods defined on a class should be using most of the data members most of the time.
4.7 Limit compositions in a class Classes should not contain more objects than a developer can fit in his or her short term memory. A favorite value for this number is six.
4.8 Distribute system intelligence vertically down narrow and deep containment hierarchies.
4.9 Put semantic constraints in class definition When implementing semantic constraints, it is best to implement them in terms of the class definition. Often this will lead to a proliferation of classes in which case the constraint must be implemented in the behavior of the class, usually, but not necessarily, in the constructor.
4.10 Put semantic constraints in constructors When implementing semantic constraints in the constructor of a class, place the constraint test in the constructor as far down a containment hierarchy as the domain allows.
4.11 The semantic information on which a constraint is based is best placed in a central third-party object when that information is volatile.
4.12 The semantic information on which a constraint is based is best decentralized among the classes involved in the constraint when that information is stable.
4.13 Contain contents not parents A class must know what it contains, but it should never know who contains it.
4.14 Contained objects should not use each other Objects which share lexical scope, i.e. those contained in the same containing class, should not have uses relationships between them.
Chapter 5 The Inheritance Relationship
5.1 Inheritance for specialization Inheritance should only be used to model a specialization hierarchy.
5.2 Dependency inversion principle Derived classes must have knowledge of their base class by definition, but base classes should not know anything about their derived classes.
5.3 Avoid protected data All data in a base class should be private, i.e. do not use protected data.
5.4 Favour deep hierarchies Theoretically, inheritance hierarchies should be deep, i.e. the deeper the better.
5.5 Limit hierarchy depth Pragmatically, inheritance hierarchies should be no deeper than an average person can keep in their short term memory. A popular value for this depth is six.
5.6 Abstract classes should be base classes All abstract classes must be base classes.
5.7 Avoid concrete base classes All base classes should be abstract classes.
5.8 Move common factors up the hierarchy Factor the commonality of data, behavior, and/or interface as high as possible in the inheritance hierarchy.
5.9 Introduce common data class If two or more classes only share common data (no common behavior) then that common data should be placed in a class which will be contained by each sharing class.
5.10 Introduce common base class If two or more classes have common data and behavior (i.e. methods) then those classes should each inherit from a common base class which captures those data and methods.
5.11 If two or more classes only share common interface (i.e. messages, not methods) then they should inherit from a common base class only if they will be used polymorphically.
5.12 Beware type switches Explicit case analysis on the type of an object is usually an error, the designer should use polymorphism in most of these cases.
5.13 Beware value switches Explicit case analysis on the value of an attribute is often an error. The class should be decomposed into an inheritance hierarchy where each value of the attribute is transformed into a derived class.
5.14 Avoid becomes Do not model the dynamic semantics of a class through the use of the inheritance relationship. An attempt to model dynamic semantics with a static semantic relationship will lead to a toggling of types at runtime.
5.15 Beware singletons Do not turn objects of a class into derived classes of the class. Be very suspicious of any derived class for which there is only one instance.
5.16 Generalize object into a class If you think you need to create new classes at runtime, take a step back and realize that what you are trying to create are objects. Now generalize these objects into a class.
5.17 Avoid no-op overrides It should be illegal for a derived class to override a base class method with a NOP method, i.e. a method which does nothing.
5.18 Avoid inheritance for optional containment Do not confuse optional containment with the need for inheritance, modelling optional containment with inheritance will lead to a proliferation of classes.
5.19 Reusable frameworks over reusable components When building an inheritance hierarchy try to construct reusable frameworks rather than reusable components.
Chapter 6 Multiple Inheritance
6.1 Avoid multiple inheritance If you have an example of multiple inheritance in your design, assume you have made a mistake and prove otherwise.
6.2 Beware inheritance over composition Whenever there is inheritance in an object-oriented design ask yourself two questions: 1) Am I a special type of the thing I'm inheriting from? and 2) Is the thing I'm inheriting from part of me?
6.3 Avoid accidental multiple inheritance Whenever you have found a multiple inheritance relationship in a object-oriented design be sure that no base class is actually a derived class of another base class, i.e. accidental multiple inheritance.
Chapter 7 The Association Relationship
7.1 Favour containment over association When given a choice in an object-oriented design between a containment relationship and an association relationship, choose the containment relationship.
Chapter 8 Class Specific Data and Behavior
8.1 No global variables or functions Do not use global data or functions to perform bookkeeping information on the objects of a class, class variables or methods should be used instead.
Chapter 9 Physical Object-Oriented Design
9.1 Object-oriented designers should never allow physical design criteria to corrupt their logical designs. However, very often physical design criteria is used in the decision making process at logical design time.
9.2 Do not change the state of an object without going through its public interface Do not change the state of an object without going through its public interface.
Personal tools