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.
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.
Do not 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.