Interview Practice

Chapter 1 of 5

Objects, contracts and invariants

Model responsibilities and legal states before drawing classes.
Read aloud is unavailable in this browser. Reading preferences still work.

Objects protect rules

An object combines behavior with state whose invariants it can enforce. Encapsulation is more than private fields plus public setters: a setter that permits an impossible state still exposes the invariant. Start with a use case, the decisions it makes and the rules that must always hold. Identify entities with identity, value objects with value equality and services that coordinate behavior without becoming bags of unrelated state.

Interfaces describe behavioral promises

An interface should express capabilities callers actually need. Its contract includes preconditions, results, failures, ownership and timing expectations. Substitutable implementations must preserve those promises; a subtype that rejects valid parent inputs or unexpectedly changes state breaks that reasoning even if method signatures compile. Composition lets one object delegate to another without inheriting capabilities it should not expose.

Value boundaries reduce accidental coupling

Use immutable value objects for concepts such as money, identifiers and date intervals, with explicit validation. Money includes a currency and rounding policy; time needs an instant or a business time-zone interpretation rather than a server-default assumption. Records are convenient but their components can still refer to mutable objects. Model behavior around the domain vocabulary rather than passing a loose map of strings everywhere.

Worked Java example

Illustrative snippet: imports, surrounding types or collaborators may be omitted. Read the assumptions before adapting it.

record Money(BigDecimal amount, Currency currency) {
    Money {
        Objects.requireNonNull(amount);
        Objects.requireNonNull(currency);
    }
    Money add(Money other) {
        if (!currency.equals(other.currency())) {
            throw new IllegalArgumentException("Currency mismatch");
        }
        return new Money(amount.add(other.amount()), currency);
    }
}

Walkthrough

Adding two Money values returns a new value and keeps the inputs unchanged. Different currencies cannot be combined implicitly. This simplified value still needs a business policy for scale, rounding and equality: BigDecimal.equals distinguishes values with different scales. Currency conversion needs an explicit rate/time/source, not an accidental arithmetic shortcut.

Practice it yourself

Design a DateRange value object. Decide whether end is inclusive, whether empty ranges are valid and which time representation it contains.

Check your reasoning

One reasonable contract is a half-open [start, end) range of instants with start ≤ end. Validate construction, document whether equality uses normalized instants and define overlap as startA < endB and startB < endA for nonempty intervals. Business-local dates need a different explicit model.

Recall checklist

  • Explain the main invariant or contract without looking.
  • Trace the example and test an edge case.
  • State time, space, input variables and assumptions where relevant.
  • Explain one alternative and when you would choose it.

Read further