OO Design Heuristics

by

Last week, I went looking for informal guidelines, on what makes a good class design. These are called heuristics, and when you are done designing your classes it can help you decide if you've done a decent enough job or not.
Some of these are from "Object-Oriented Design Heuristics by Arthur J. Riel", while others are from Allen Holub.

  1. Unused properties in a class:
    If your object is being used with some property that has no value or has nulls very often, it could mean that this object is doing more than its share.
  2. Make a class diagram, change one property and ask yourself which other classes are going to be affected. Follow the ripples, and you follow the problems.
  3. Most of the methods defined on a class should be using most of the data members most of the time. (This is all about cohesion)
  4. On the God Class:
    • A single class drives the application, all other classes are dumb data holders. Do not create god classes/objects in your system. Be very suspicious of a class whose name contains “Driver”, “Manager”, “System”, or “Subsystem.
    • Beware of classes that have many accessor methods defined in their public interface. Having many implies that related data and behavior are not being kept in one place.
    • Beware of classes that have too much noncommunicating behavior, that is, methods that operate on a proper subset of the data members of a class. God classes often exhibit much non-communicating behavior.
    • The god class tends to have a lot of getter Calls.
    • Consider a typical procedural "god" class, which collects the information that it needs to do some piece of work from other objects. The god-class implementation is littered with "get" calls. What if the object that already has the data does the work, though? That is, what if you moved the code that does real work from the god class to the place where the data is stored? The accessor calls disappear, and the code is simplified."
  5. Classes should not contain more objects than a developer can fit in shortterm memory
  6. Most common mistake
    – Using multiple inheritance in place of containment.
  7. A class must know what it contains, but should never know who contains it.
  8. The maintainability of a program is inversely proportional to the amount of data that flows between objects.
  9. Classes that directly model the system at the domain level, sometimes called business objects, hardly ever need accessors or mutators.
  10. To pass information around, use the following two rules of thumb: Pass around objects (ideally in terms of the interfaces they implement) rather than raw data, and use a "push" model, not a "pull" model.
  11. Base classes are fragile:
    Change to the base class may affect the derived class. Some people call this the fragile base class problem. This may be one of the drawbacks of using inheritance. If you find yourself overriding everything, you should really be implementing an interface, not extending a base class." The Gangof-Four Design Patterns book is, in fact, largely about replacing implementation inheritance (extends) with interface inheritance (implements).
  12. Any use of operators like (instanceof in Java) would indicate programming to concrete types and you can think how the instanceof check can be get rid of.
  13. When a developer says "I need to make this piece of data public", they should ask themselves "What is it that I'm trying to so with the data and why doesn't the class perform that operation for me?"
  14. Procedural applications break an application down according to function which then share data structures. While it is easy to see which functions access which data structures, it is difficult to go the other way, to see which data structures are used by which functions. The problem: a change to a data structure may have unintended consequences because the developer was not aware of all the dependencies on the data structure.
  15. It should be illegal for a derived class to override a base class method with a NOP method, that is, a method that does nothing.
  16. Subclasses should not use directly data of superclasses.
  17. All data in a base class should be private, i.e. do not use protected data.
  18. The OO-design process is centered on use cases: stand-alone tasks performed by an end user that have some useful outcome. "Logging On" isn't a use case because there's no outcome that's useful in the problem domain. "Drawing a Paycheck" is a use case.
  19. The notion of emergence is critical to OO thinking. You design (and build) around use-case scenarios, and you don't design for every possible scenario. Nonetheless, scenarios that you hadn't thought of are handled by the program.