27. Design rules summary#

27.1. General#

These principles are discussed in more detail in Part 6 - Design.

27.1.1. Access modifiers#

  • Keep the number of public methods as low as possible

  • Minimize the accessibility of class members(fields, methods, member classes).

  • Use getters and setters to intercept and control access to fields.

Changing public API methods is a nuisance since it may create backward incompatibility.

27.1.2. equals() and hashCode()#

  • Always implement equals() and hashCode() when objects are going to live in collections (which is quite often!)

  • Always implement both equals and hashCode; never only one!

  • And have your IDE generate them for you…

27.1.3. Code against interfaces, not implementations#

Use interfaces and abstract classes as the declared type of your variables. That way, implementation details may change without serious repercussions.

27.1.4. Exceptions#

27.2. Methods#

27.2.1. General rules#

  • Methods have very descriptive names (verb), in camelCase() with lowercase-first.

  • They do one thing only (SRP!)

  • They preferably define no more than 2 or 3 parameters. This keeps testing at an acceptable level of difficulty.

Warning

KEEP METHODS TESTABLE

27.2.2. Keep methods small#

  • Keep methods short and simple: not too deep nesting of flow control blocks (maximum four) and not too many method parameters. Prefer a small data class (record) as return value over complex data structures.

  • Keep a maximum of two indentation levels.

27.3. Classes#

  • When a class defines an instance variable that needs to be initialized in order to have an object that makes sense, and you can not give it a reasonable default value, you should make it a constructor parameter

  • Chain constructors using this(fieldValue, fieldValue)

  • Consider the use of factory methods instead of constructors

  • Make classes abstract that should not be instantiated

  • Preferably use records for data classes instead of normal classes; they have immutability in their nature already.

27.4. Single Responsibility Principle#

  • A module, class or method should have one, and only one, reason to change.

Alternative description: every module, class, or function should have responsibility over a single part of the functionality, and that responsibility should be entirely encapsulated by the class

27.5. Various#

  • Prefer enums to define a static set of possible values for a given property above public static final constants

  • Always put Java classes in well-defined packages with a correct name structure