Programming foundations: Java

Sefism.

Chapter 07

Object-oriented design and clean code

How to organise programs so they stay readable as they grow: classes where they help, clear boundaries, good names and the principles reviewers ask about.

Classes and objects

Also called OOP, instance, constructor, methods, object-oriented

What
A class is a blueprint that groups data (fields) with the behaviour that works on it (methods). An object is one instance of a class, created by its constructor.
Why
Use a class when data and the rules that change it belong together, such as an account whose balance only changes through deposits.
Java
public class Account {
  private final String owner;
  private long balance;
  public Account(String owner) { this.owner = owner; }

  public void deposit(long amount) {
    if (amount <= 0) throw new IllegalArgumentException();
    balance += amount;
  }

  public long balance() { return balance; }
}

Watch out

Making everything a class because a tutorial did; a plain function is often simpler.

Encapsulation

Also called information hiding, private, access modifiers

What
Keeping an object's data private and exposing only the operations that keep it valid.
Why
If only deposit can change a balance, a negative deposit is rejected in one place instead of every caller having to remember the rule.

Watch out

Adding a public getter and setter for every field, which exposes the data as if it were public anyway.

Inheritance and composition

Also called extends, subclass, has-a vs is-a

What
Inheritance builds a class from a parent class and reuses its code ("is a"). Composition builds a class from other objects it holds and delegates to ("has a").
Why
Composition is usually more flexible: you can swap parts and avoid deep hierarchies. Inheritance fits true "is a" relationships with shared behaviour.
Example
A ReportExporter that holds a Formatter (CSV or PDF) can switch formats at runtime. A CsvReportExporter extends PdfReportExporter hierarchy cannot, and breaks when either parent changes.

Watch out

Inheriting just to reuse a few methods, which ties the child to every future change in the parent.

Interfaces and polymorphism

Also called abstraction, abstract class, abstract base class, duck typing, protocol

What
An interface is a contract listing methods a type must provide. Polymorphism means code written against the contract works with any type that fulfils it.
Why
It lets you add a new kind of notifier, payment method or storage without changing the code that uses it, and lets tests pass in fakes.
Java
interface Notifier {
  void send(String to, String text);
}
class EmailNotifier implements Notifier {
  @Override
  public void send(String to, String text) {
    System.out.println("email " + to + ": " + text);
  }
}
static void remind(Notifier notifier, String user) {
  notifier.send(user, "Your book is due");
}

Watch out

Creating an interface for every class up front, when there is only ever one implementation.

Separation of concerns

Also called layers, modularity, single responsibility

What
Splitting a program so each part handles one concern: reading input, business logic, storage and output live in separate functions or modules.
Why
You can change the output format without touching the calculations, and you can unit test the logic without a terminal, file or network.
Example
A budget tracker with parse_ledger (file to records), monthly_totals (records to numbers) and print_report (numbers to text). Only the middle one needs detailed tests.

Watch out

Mixing print or database calls into calculation functions, so they cannot be tested or reused.

DRY, KISS and YAGNI

Also called DRY, KISS, YAGNI, Don't Repeat Yourself, do not repeat yourself, keep it simple, You Aren't Gonna Need It, you are not going to need it

What
DRY: keep each piece of knowledge in one place. KISS: prefer the simplest design that works. YAGNI: do not build features or flexibility until they are needed.
Why
Together they keep code small and changeable. Use them as questions while refactoring, not rules for a first draft.

Watch out

Forcing DRY on code that only looks similar, creating a shared function full of flags that is harder to change than the duplicates were.

Naming and small functions

Also called clean code, readability

What
Names that say what a value is or what a function does (unpaid_invoices, send_reminder), and functions short enough to do one thing at one level of detail.
Why
Code is read far more often than written. Good names remove the need for most comments and make bugs easier to spot.
Example
Rename d to days_overdue and extract the 20 lines that build the email into build_reminder_email(invoice). The main function now reads like a short list of steps.

Watch out

Vague names like data, temp, manager or handle, which hide what the code actually does.

SOLID

Also called single responsibility, open closed, Liskov substitution, interface segregation, dependency inversion

What
Five design principles: a class has one reason to change; extend behaviour without editing working code; subtypes must work wherever the parent does; keep interfaces small; depend on abstractions rather than concrete details.
Why
They are useful review questions when a design is getting hard to change or test, especially in object-oriented languages.

Watch out

Applying all five to a 200-line program, which adds layers of interfaces that make simple code harder to follow.

Code smells and refactoring

Also called refactor, technical debt

What
A code smell is a sign of a deeper design problem: long functions, duplicated blocks, many parameters, deep nesting. Refactoring improves the structure in small steps without changing behaviour.
Why
Regular small refactors keep code easy to change. Tests are what make refactoring safe.

Watch out

Refactoring and changing behaviour in the same commit, so when something breaks you cannot tell which change caused it.

Comments, docstrings and READMEs

Also called docs, Javadoc, XML doc comments, JSDoc

What
Comments explain why code does something non-obvious. Docstrings and doc comments describe what a function expects and returns. A README explains what a project is and how to run it.
Why
Good documentation lets someone else (or you in six months) use and change the code without reading all of it.

Watch out

Comments that repeat the code, such as i += 1 # add one to i, which add noise and go stale.

07 · Object-oriented design and clean code7 / 10