7.4
Design Principles
1 All the Design Guidelines
By the end of the course, you will be expected to have a strong grasp of all of the design principles listed below, and be able to discuss and apply them in your own work. A few notes: First, many of them overlap with each other. For example, several are simply more specific reinforcements or examples of a broader principle. Second, some of them may contradict each other. With design, there is often no one right answer, no silver bullet, but a matter of balancing tradeoffs and meeting the needs of the specific situation you are designing for. Third, many of them are prescriptive: things you should always or never do; others are guidelines: things to aspire to but that cannot always be adhered to.
- Javadoc all public classes and methods. Class comment should be at least two sentences, and provide information not already clear from its definition.
- Use interface types over concrete classes wherever possible. Exception: immutable "value" objects. Classes with no interface.
- Fields must always be private. Exception: constants. Methods, classes should be as private as possible.
- Class should never have public methods not in the interface (aside from constructor).
- Composition over inheritance.
- Catch and handle/report errors as early as possible. Use Java compiler checks, enums, final first, runtime checks second.
- Use class types over strings.
- Check inputs.
- Use exceptions only for exceptional situations -- not for flow control.
- Checked vs unchecked: checked: reasonable expectation that the program can recover. Unchecked: programmer error (may still be recoverable).
- Don't leave things in an inconsistent state for any substantive length of time.
- Beware of references, copies, and mutation. Make defensive copies.
- Separate responsibilities: one class, one responsibility.
- Use class hierarchies and dynamic dispatch over tagged classes, complex if/switch statements.
- Don't duplicate code.
- Open for extension, closed for modification: make changes without modifying existing code; write code to support later changes without modification.
- Extensibility: design to make likely later changes easier.
- Write tests first, cover the range of situations, edge cases. Write code to be testable (avoid System.out); do not expose fields or add public methods just to allow for testing.
- Loose coupling over tight coupling (avoid System.out). Write reusable components when possible.
- You can't change an interface once it's published.
- If you override equals(), override hashCode(), and vice-versa.
- Reuse existing exceptions, classes, libraries, and designs.