Arthur Riel, 1996. 60 guidelines/heuristics for OO programming
Hide data within its class:
- Information hiding
- Private fields should only be accessible by internal methods; public interfaces should be used to provide services
A class should not depend on its users:
- Users of a class should depend on the public interface
Minimize the number of public methods:
- More methods mean it is more difficult to use and maintain
- Reuse is harder
- YAGNI
Have a minimal public interface:
- Single responsibility principle
- The more public methods, the more restrictive the contracts
Avoid interface bloat:
- Do not put implementation details (e.g. methods used within public methods) within the public interface of the class
- Do not put ‘extra’ items into the interface
Avoid interface pollution:
- Do not clutter the public interface with things that the class’s users cannot or will not use
- Don’t over-engineer
Nil or export-coupling only:
- Class should only use operations in the public interfaces of other classes, or not use it at all
- Program to the interface, not the implementation
One key abstraction:
- A class should capture one and only one key abstraction
- One ‘noun’ in requirements
- Too may key abstractions -> God classes
Keep related data and behavior in one place:
- Law of Demeter
Separate non-communicating behavior:
- Spin off non-related information into another class
- If a few methods rely on one set of data and other methods work on another: no/little communication between the two sets, separate them into two classes
- Reduce coupling
Model classes, not roles:
- Abstractions should model classes rather then the roles the objects play
- Look at behavior, not roles
- e.g. Lecturer, Tutor, Student are all roles of Person
Distribute system intelligence:
- Uniformly distribute system intelligence horizontally
- Top-level classes should share the work uniformly
- Avoid a system with a God class combined with several minor classes
Avoid God classes:
- Too many responsibilities
- Too many irrelevant functions or global variables
- Difficult to maintain
- Centralized data center
- Could be useful when performance is required
- Be very suspicious of classes with Driver, Manager, System, or Subsystem in its name
Beware of many accessors:
- Classes with too many accessors may mean:
- Related data and behavior are not being kept in one place
- Too many unrelated things are together: SRP
- If other methods can fiddle with internals, the class no longer has control over its own data
Beware of non-communicating methods:
- Classes which have too many non-communicating methods: methods which operate on a subset of the class
- Interfaces should be dependent on the model
Interfaces should be dependent on the model:
- The model should never be dependent on the user interface
- The model should not need to know about the user interface
- Changing the user interface should not change the model
Model the real world:
- Whenever possible: intelligence distribution, God class avoidance, keeping related methods/behavior together
- Easier to understand, decompose and maintain
- May go against tell, don’t ask
Eliminate irrelevant classes
- Usually sub-classes with no behavior
- Can go against ‘avoid concrete base classes’
Avoid verb classes:
- Do not turn an operation into a class: operations should usually be methods
Agent classes irrelevant:
- e.g. Bookshelf, librarian, book: sorting should be done the bookshelf, not the librarian
Minimize class collaborations:
- Reduce coupling
Minimize method collaborations:
- Reduce the number of messages sent between a class and its collaborators
Minimize methods between collaborators:
- Reduce dependencies
- If there are many, should the class and its collaborator be merged into a single class?
Minimize fan-out:
- Product of number of messages defined by the class and the messages they send
Containment implies uses:
- If a class contains objects of another class, the container should send methods to the contained objects: a use relationship
- Otherwise, the container class must have an accessor for the object in order for it to be of any use, which violates the information hiding principle
Methods should use most fields of a class:
- Otherwise, there may be more than one key abstraction
- Lack of cohesion of methods (LCOM)
- Violates SRP
- Non-communicating methods
Limit compositions in a class:
- Developers should be able fit all objects for a class within their short term memory
- Limit the number of objects in the class: 7±2
- Most methods should use data
- Helps with keeping methods maintainable
Contain contents, not parents:
- A class should not know who contains it
Contained objects should not be able to use each other:
- Objects with the same lexical scope: those with the same containing class, should not have uses relationships between them
- Leads to dependencies between classes that don’t need it