Lecture Slides

Chapter 2: Object-Oriented Development Beyond Syntax

SE506: Object Oriented Development and Agile Practices

Dr. Polla Abdulhamid Fattah
Department of Computer Science & Artificial Intelligence
University of Kurdistan Hewlêr (UKH)

Chapter Roadmap (1 of 3)

  • 2.1 Objects: their knowledge, behaviour and identity
    • Four small classes, three kinds of identity, mutable and immutable objects.
  • 2.2 Who is responsible for keeping things true?
    • The half-open period convention and who protects which condition.
  • 2.3 Keeping state safe: encapsulation and information hiding
    • Why private is not enough, and what List.copyOf does.
  • 2.4 Is a long method the problem? Cohesion and coupling
    • Diagnosing a method by its reasons to change, then one modest refactoring.

Chapter Roadmap (2 of 3)

  • 2.5 Has-a or is-a? Composition and inheritance
    • Use versus subtype, and why a hierarchy is not the default.
  • 2.6 Drawing the design: UML class diagrams to read, write and check
    • The notation the midterm assesses, so it gets the most time.
  • 2.7 Making a change someone else can review
    • A small, reviewable change and the commands that inspect it.
  • 2.8 Checking an AI’s explanation of the coordinator
    • Classifying the claims of a plausible but flawed explanation.

Chapter Roadmap (3 of 3)

  • 2.9 Mistakes that look like good design
    • Eight misconceptions, each with a better question.
  • 2.10 Try it yourself: improve the design, with evidence
    • Parts A to D: trace, diagnose, change, organise the team.
  • 2.11 Questions to think with
    • Room-booking coordinator in a different domain.
  • What to take away, and what comes next
    • What carries into Chapter 3 (Agile development and the nature of change).

Learning Outcomes (1 of 2)

By the end of the chapter, you should be able to:

  1. Assign responsibilities to objects and explain the state they protect.
  2. Distinguish encapsulation and information hiding from mechanically adding getters and setters.
  3. Diagnose cohesion and coupling problems using concrete change scenarios.

Learning Outcomes (2 of 2)

  1. Compare composition with inheritance and justify a modest design choice.
  2. Draw and interpret a small UML class diagram that matches the code, using associations, multiplicity, aggregation, composition, inheritance and interface realisation appropriately.
  3. Make a behaviour-preserving improvement and present it as a reviewed Git change.

How to Use This Chapter

  • Core reading: Sections 2.1 to 2.9.
    • Section 2.6 (UML class diagrams) is the notation the midterm assesses, so give it the most time.
  • What you must do: the Section 2.8 AI activity and Parts A to D of Section 2.10.
    • Parts A to C run on the book’s project; Part D concerns your team’s project.
  • If you want more: the optional investigation at the end of 2.10, then the questions and the transfer challenge.

Build on Chapter 1, Use the Companion

  • This chapter builds on Chapter 1’s reservation-rule example.
  • You should be able to trace conditions, call methods and explain a returned value.
  • Java’s official class tutorial gives targeted syntax revision. Appendix A has a short refresher.
  • The companion holds every complete source file, a starting version, a completed refactoring, checks and suggested answers.
  • Use its starting listings first. Consult solutions after attempting the activity.

Toolchain Baseline

  • Java 17 language and API baseline. No preview features, no external dependencies.
  • A JDK is required to compile the examples.
  • JUnit, Maven and CI configuration are not prerequisites for this first design exercise.
  • They are introduced with the relevant later work. Appendix B records the toolchain and commands for the whole book.

Weekly Reading and the Project Version

  • Reading: Martin, Agile Software Development: Principles, Patterns, and Practices. The Part I introduction and the object-oriented design fundamentals. Sections 2.1 to 2.5 are the practical counterpart.
  • Starting version: the Chapter 2 starter in the companion.
  • Resulting version: the same code after the confirmation extraction. It becomes the running baseline for later chapters.
  • The fault demonstrations and the notation examples in 2.6 are separate teaching material. They do not join the project.

Opening Scenario: A Demonstration That Works

  • The equipment officer can now try a small reservation application.
  • It checks a borrower’s limit, looks for a conflicting reservation, records a successful request and returns a confirmation message.
  • The demonstration works.
  • But the developer who wrote it is absent when another team member is asked to change the message.

The New Developer Opens ReservationCoordinator

  • One method does all of this:
    • counts reservations,
    • applies a borrowing rule,
    • searches for date conflicts,
    • creates a record,
    • assembles the confirmation text.
  • Which lines may be changed safely?

Three Questions to Carry Through the Chapter

  1. Why is the conflict check concerned with an equipment item while the count is concerned with a borrower?
  2. Could the list of stored reservations be changed from outside the class?
  3. Which responsibilities belong together, and how should other code be allowed to use them?
  • Knowing how to declare a class is necessary. It does not answer these.

2.1 Objects

Their knowledge, behaviour and identity

Class and Object

  • A class defines a type and its implementation.
  • An object is an instance created at run time.
  • Two objects from the same class can represent different things and hold different state.
  • Java gives us fields, constructors and methods to express these distinctions.

The Reservation Record

  • A Reservation records an arrangement involving a borrower, an equipment item and a period.
  • Its state:
    • an identifier such as R1,
    • a borrower identifier such as B1,
    • an item identifier such as CAM1,
    • a LoanPeriod.

Identifiers Are Different Kinds of Identity

  • Two physical cameras may share a model name but need different item identifiers.
  • Two reservations for the same camera on different dates are still separate reservations.
  • A borrower’s name is a poor identifier: names can change or be shared by different people.
  • The identifiers stand in for borrower and equipment records. A non-blank identifier does not prove a real person or item exists.

Java Object Identity

  • Two references can point to the same instance, or to distinct instances that represent the same domain identifier.
  • == on references checks whether they refer to the same object.
  • Domain equality needs a deliberate definition. It is not automatically established by matching fields.
  • Our Reservation does not override equals. Do not assume identifier-based equality.

State and Behaviour

  • State is information an object holds.
  • Behaviour is what it can do through its operations.
  • A reservation can expose its identifier and period without letting callers replace them.
  • A coordinator can add a new record after checking the request.
  • A period can answer whether it overlaps another period.

Not Everything Needs to Be Mutable

  • In the starter, Reservation and LoanPeriod are immutable after construction:
    • their fields cannot be reassigned,
    • their referenced values are immutable,
    • their operations do not modify state.
  • The coordinator is different. It accumulates reservations in a private list.

Why the Same Request Can Give a Different Answer

  • Chapter 1’s mayRequest only examined supplied numbers.
  • A call to the coordinator may change the state that the next call examines.
  • After one successful reservation, the same request can be rejected as unavailable.

From the Numeric Rule to a Small System

  • ReservationRules stays unchanged: at most three active reservations, one to seven days.
  • The staff variation remains a future design exercise.
  • This version applies the student policy to every borrower identifier.
  • The starter has four domain and application classes.

The Four Starter Classes

ClassMain roleState held
ReservationRulesEvaluate the numeric borrowing policyNo instance fields
LoanPeriodRepresent a valid period; answer overlap questionsStart date and exclusive end date
ReservationRecord a confirmed reservationThree identifiers; a period
ReservationCoordinatorProcess requests using policy and existing recordsIn-memory reservations; a rules object

The Starter Files

FileRole
ReservationRules.javaThe unchanged numeric policy from Chapter 1
LoanPeriod.javaValid dates and exclusive-end overlap semantics
Reservation.javaImmutable reservation details
ReservationCoordinator.javaThe starting request workflow
Chapter02Demo.javaThree requests: success, overlap, adjacency
Chapter02Checks.javaSupplied behavioural checks (34)

2.2 Who Is Responsible for Keeping Things True?

Who protects which condition?

Responsibility vs. Data

  • A responsibility is an obligation assigned to part of the system.
  • “Hold two dates” describes data.
  • “Represent a period whose end follows its start” describes an obligation that gives the data meaning.

Invariants Belong at Different Boundaries

  • An invariant is a condition that must hold for valid objects or valid system states.
  • One LoanPeriod can ensure its end is after its start.
  • It cannot, by itself, ensure that another reservation has not already claimed the same equipment.
  • Local invariants and system-level conditions need different enforcement points.

A Period Convention We Can Test

  • Dates are calendar dates with no time of day.
  • A period is start inclusive, end exclusive: [start, end).
  • 20 October to 22 October covers the 20th and 21st. Another period may begin on the 22nd.
  • This is an explicit teaching policy. A real service might require a cleaning or inspection interval, which would need another rule.

LocalDate and the Convention

  • Java’s LocalDate is immutable and represents a date without a time or time zone.
  • We use isBefore and plusDays to express the convention.
  • We do not interpret these dates as UTC instants or fixed numbers of elapsed hours.
  • The exclusive-end convention is a project decision, not a rule LocalDate imposes.

The LoanPeriod Constructor

public LoanPeriod(LocalDate start, LocalDate endExclusive) {
    this.start = Objects.requireNonNull(start, "start");
    this.endExclusive =
        Objects.requireNonNull(endExclusive, "endExclusive");
    if (!start.isBefore(endExclusive)) {
        throw new IllegalArgumentException("End must be after start.");
    }
}
  • Missing date: NullPointerException. Zero-length or reversed interval: IllegalArgumentException.

The overlaps Operation

public boolean overlaps(LoanPeriod other) {
    Objects.requireNonNull(other, "other");
    return start.isBefore(other.endExclusive)
            && other.start.isBefore(endExclusive);
}
  • Two periods overlap when each begins before the other ends.
  • Both comparisons are strict, so adjacent periods do not overlap.
  • requireNonNull throws for a null argument. It does not fabricate a replacement period.

Four Overlap Examples on a Timeline

19 Oct20 Oct21 Oct22 Oct23 Oct24 Oct[20, 22) and [21, 23)Overlap: Yes. Both include 21 Oct[20, 22) and [22, 23)Overlap: No. Second starts at the first's end[20, 22) and [20, 22)Overlap: Yes. Identical periods overlap[20, 22) and [19, 24)Overlap: Yes. The second contains the firstfirst period, always [20, 22)second period

The Same Examples as a Table

FirstSecondOverlap?Why
[20 Oct, 22 Oct)[21 Oct, 23 Oct)YesBoth include 21 October
[20 Oct, 22 Oct)[22 Oct, 23 Oct)NoSecond begins at the first’s exclusive end
[20 Oct, 22 Oct)[20 Oct, 22 Oct)YesIdentical periods overlap
[20 Oct, 22 Oct)[19 Oct, 24 Oct)YesThe second contains the first
  • Comparing start dates alone would miss some of these relationships.

Who Protects Which Condition?

  • The constructor protects the local validity of a period.
  • ReservationRules protects the numeric policy, only when given an accurate count.
  • The coordinator counts its records and checks item conflicts before storing.
  • No one class can enforce all of these without information from the others.

Operating Assumptions of the Starter (1 of 2)

  • All stored records are confirmed and remain active: no cancellation, completion or expiry.
  • Calls occur sequentially in one process.
  • Data disappear when the process ends.
  • Identifiers are matched exactly, with no normalisation or authentication.

Operating Assumptions of the Starter (2 of 2)

  • The coordinator checks availability only against its own stored records.
  • Maintenance schedules and other coordinators are outside this version.
  • Within one sequential coordinator, checking conflicts before adding prevents the demonstrated overlap.
  • It does not establish safe concurrent booking by multiple processes. Later integration work revisits that boundary.

2.3 Keeping State Safe

Encapsulation and information hiding

  • Encapsulation groups state with the operations that govern its use, and controls access to that state.
  • Information hiding concerns which implementation decisions callers should not need to know.
  • Abstraction presents what is relevant to a caller and leaves out unnecessary detail.
  • None is achieved simply by writing private before every field.

Abstraction Through an Ordinary Method

  • A caller can ask a period whether it overlaps another without repeating the date comparisons.
  • That abstraction exists through an ordinary public method.
  • It does not need Java’s abstract keyword or a separate interface.
  • A useful abstraction still needs a clear contract, including our decision that adjacent periods do not overlap.

Setters Can Defeat Private Fields

  • Suppose a class exposes separate setters for a period’s start and end.
  • A caller could move the start beyond the current end.
  • If each setter merely assigns a field, making the fields private has not protected the relationship between them.

How LoanPeriod Avoids This

  • The constructor requires both dates together and validates the relationship.
  • It provides readers but no setters.
  • To express another period, a caller creates another valid object.
  • No invalid intermediate state enters the public protocol.
  • In another domain a controlled mutation operation could be right. Immutability is a design choice, not a rule.

A Getter Can Expose a Mutation Path

// Unsafe alternative for diagnosis; not the starter implementation.
public List<Reservation> reservations() {
    return reservations;
}
  • The field is private. The caller still receives a reference to the mutable list.

The Attack: clear()

  • A caller can invoke coordinator.reservations().clear().
  • That erases records without passing through the coordinator’s request checks.
  • The next request finds no conflicts.
  • “My fields are private” does not mean the state is protected.

The Starter’s Protection

public List<Reservation> reservations() {
    return List.copyOf(reservations);
}
  • List.copyOf returns an unmodifiable list whose contents are not updated by later changes to the source.
  • It protects the list structure and provides a snapshot.

What List.copyOf Does Not Do

  • It does not deep-copy the elements.
  • It does not make mutable elements immutable.
  • Here, Reservation, LoanPeriod, String and LocalDate already provide the immutability needed for the values we expose.
  • Be able to explain the protection without claiming all copies are deep copies.

final Does Not Help

  • private final List<Reservation> alone would be insufficient.
  • final prevents reassignment of the field to another list.
  • It does not prohibit add or clear on that list.
  • Reference fixed, object immutable, or both? Always ask which.

What Remains Exposed

  • The coordinator still exposes more representation than a mature system might require: callers know stored reservations can be inspected as a list.
  • That is acceptable for a small teaching version.
  • If a caller later needs only a count or an availability answer, a narrower operation may reduce what the caller must understand.

2.4 Is a Long Method the Problem?

Cohesion and coupling

Cohesion

  • Cohesion concerns how closely the responsibilities within a component belong together.
  • LoanPeriod has a focused purpose: its validation and overlap calculation concern the same period concept.
  • A coordinator that also knows message wording, storage details and borrowing policy has more varied responsibilities.

Coupling

  • Coupling concerns the dependencies between components.
  • A component depends on another when it relies on its type, operations, data format or behaviour.
  • Some dependency is necessary: software works because components collaborate.
  • The question: does the dependency express a useful relationship, or let unrelated changes spread?

The reserve Method: Validate and Count

public String reserve(String borrowerId, String itemId,
                      LocalDate start, int requestedDays) {
    if (borrowerId == null || borrowerId.isBlank()
            || itemId == null || itemId.isBlank()) {
        throw new IllegalArgumentException(
            "Identifiers must not be blank.");
    }
    Objects.requireNonNull(start, "start");
    int activeCount = 0;
    for (Reservation existing : reservations) {
        if (existing.borrowerId().equals(borrowerId)) { activeCount++; }
    }

The reserve Method: Policy and Conflict

    if (!rules.mayRequest(activeCount, requestedDays)) {
        return "Rejected: borrower limit or duration.";
    }
    LoanPeriod requested =
            new LoanPeriod(start, start.plusDays(requestedDays));
    for (Reservation existing : reservations) {
        if (existing.itemId().equals(itemId)
                && existing.period().overlaps(requested)) {
            return "Rejected: item unavailable.";
        }
    }
  • Policy is rejected before availability; keep that order.

The reserve Method: Store and Confirm

    Reservation reservation = new Reservation(
            "R" + (reservations.size() + 1), borrowerId, itemId, requested);
    reservations.add(reservation);
    return "Confirmed: " + reservation.id()
            + " for " + reservation.borrowerId()
            + " on " + reservation.itemId()
            + " [" + reservation.period().start()
            + ", " + reservation.period().endExclusive() + ").";
}
  • It creates and stores a reservation, then assembles its confirmation. It does not send it.

The Request as a Flow

Validateidentifiersand startCount thisborrower'srecordsrules.mayRequest(count, days)?Overlaps a recordfor this item?Create, addand returnconfirmationRejected: borrowerlimit or durationRejected:item unavailableallowedfreenoyesNeither rejection adds a record or uses an identifier.

Not Wrong Merely Because It Has Several Steps

  • Coordination often involves several collaborators.
  • “The method is long” is not a diagnosis.
  • The useful question is: which decisions have independent reasons to change?

Diagnosis by Change Scenario (1 of 2)

Possible requestDecision it affectsCurrent location
Change a borrowing limitNumeric policyReservationRules
Add a maintenance gap between reservationsAvailability policy and period useCoordinator conflict check, possibly period rules

Diagnosis by Change Scenario (2 of 2)

Possible requestDecision it affectsCurrent location
Store records beyond process lifetimeStorage mechanismCoordinator’s list and storage operations
Translate a confirmation messagePresentation wordingCoordinator’s final return expression
  • This identifies which changes currently require editing the coordinator, and why.
  • A future database is a possible boundary. It is not a reason to build a repository framework now.

A Small Improvement with a Limited Claim

  • Extract the confirmation expression into a private method confirmationFor.
  • The request method still adds the record first, then returns the helper’s result.
  • The helper receives the existing reservation and returns exactly the same text.
  • This is a modest refactoring: it gives the formatting a name.

What the Extraction Does Not Do

  • It does not create a separate presentation component.
  • It does not remove storage coupling.
  • It does not make the coordinator thread-safe.
  • A private helper changes readability inside the class. A new component would change the collaboration between classes.
  • If translation later needs collaborators, a separate formatting responsibility may become justified.

Preserving Behaviour: Text and State

  • The supplied checks examine both returned messages and stored state.
  • After the extraction both must remain the same.
  • Preserving the success string while forgetting to store the reservation would not preserve behaviour.

2.5 Has-A or Is-A?

Composition and inheritance

Composition

  • Composition, in the broad programming sense: building behaviour by giving an object collaborators or component objects.
  • A Reservation has a LoanPeriod and delegates the overlap question through it.
  • A coordinator has a ReservationRules object. It does not inherit from it.

It Fits the Domain Meanings

  • A coordinator is not a kind of borrowing rule.
  • A reservation is not a kind of period.
  • Their relationships concern what they use or contain, not a subtype relationship.

Inheritance

  • Inheritance defines a derived class in relation to a superclass.
  • Java supports inherited members, method overriding and run-time selection of overridden instance methods.
  • These mechanisms can express a useful family of related behaviours.
  • They also establish expectations that callers may rely on.

A Hypothetical SpecialReservation

  • Suppose a subclass is introduced only because some borrowers have longer limits.
  • Is the difference really a new kind of reservation, or a policy governing whether one may be created?
  • If staff status can change while an existing reservation keeps its identity, forcing that distinction into a hierarchy may be awkward.

Not a Verdict Against Inheritance

  • This does not prove inheritance is always unsuitable.
  • Ask: what varies, what remains stable, and what a caller expects from the base type.
  • Chapter 5 develops behavioural substitutability more formally.
  • For this version, constructors, fields and collaborators already express the relationships without a custom hierarchy.

Composition vs. Inheritance: Questions

QuestionComposition can help whenInheritance deserves consideration when
What is the relationship?One object uses or contains anotherOne type has a meaningful subtype relationship
What varies?A collaborator or delegated responsibilityBehaviour shared through a stable base contract
What must be reviewed?How collaborators are selected and calledWhether derived behaviour preserves caller expectations

Composition Has Costs Too

  • Too many small collaborators make a request harder to follow.
  • Avoid replacing one readable expression with several classes unless that organisation solves an actual problem.
  • The design goal is understandable responsibility boundaries, not the maximum number of objects.

2.6 Drawing the Design

UML class diagrams to read, write and check

What a Class Diagram Is

  • A class diagram is a selective explanation of a design.
  • It answers one question for one audience: for example, “which objects take part in a reservation request, and how are they related?”
  • It is not a copy of the source code. A diagram showing every field and method answers no question well.
  • Class diagrams are the only UML notation used in this chapter.

Three Skills in This Section

  1. Read a diagram.
  2. Draw one from a written description.
  3. Check one against code.
  • Hand-drawn diagrams use the same symbols as the ones in this book.
  • The book’s diagrams are written as text (Mermaid) so they can be kept beside the code. Appendix A shows the syntax.

Figure 2.1: The Starter’s Collaborators

ReservationCoordinator+reserve(String borrowerId, String itemId,LocalDate start, int requestedDays) String+reservations() List<Reservation>ReservationRules+mayRequest(int activeReservations,int requestedDays) booleanReservation-String id-String borrowerId-String itemId+period() LoanPeriodLoanPeriod-LocalDate start-LocalDate endExclusive+overlaps(LoanPeriod other) boolean11uses10..*stores0..*1refers to

Reading the Boxes

  • Each box is a class with up to three compartments:
    • top: the class name,
    • middle: the attributes (data the class keeps),
    • bottom: the operations (methods other code can call).
  • A label in double angle brackets above the name, such as <<interface>>, says what kind of class it is.
  • + marks a public member and - a private one.

A Box and the Java It Describes

// Excerpt from LoanPeriod.java; method bodies omitted.
public final class LoanPeriod {
    private final LocalDate start;
    private final LocalDate endExclusive;

    public LoanPeriod(LocalDate start, LocalDate endExclusive) { ... }
    public LocalDate start() { ... }
    public LocalDate endExclusive() { ... }
    public boolean overlaps(LoanPeriod other) { ... }
}

Mapping Box Parts to Source

Part of the boxIn the Java sourceHow to read it
LoanPeriodclass LoanPeriodThe class name
-LocalDate startprivate final LocalDate start;A private attribute start of type LocalDate
+overlaps(LoanPeriod other) booleanpublic boolean overlaps(LoanPeriod other)A public operation taking a LoanPeriod, returning boolean
  • Type comes before the name, as in Java. The return type comes after the parameter list.

What a Box Leaves Out

  • The constructor and the accessors start() and endExclusive() exist in the code but not in the box.
  • The explanation does not need them.
  • You can trust a diagram for what it shows.
  • You cannot assume that what it omits does not exist.

Attribute or Line, Not Both

  • A field whose type is a plain value (String, int, LocalDate) is normally an attribute.
  • A field whose type is another class of your design is normally a line to that class’s box.
  • Do not show it both ways. A -LoanPeriod period attribute beside a line to LoanPeriod says one thing twice.

Reading Multiplicity

  • The number at each end of a line is a multiplicity: how many objects take part.
  • Stand at one class and read the number at the far end.
  • That is how many objects of the far class one object of your class is linked to.
WrittenMeans
1exactly one
0..1none or one
0..*zero or more
1..*one or more

Reading One Line in Both Directions

ReservationCoordinator "1" --> "0..*" Reservation : stores

  • From the coordinator: “each coordinator stores zero or more reservations.”
  • From a reservation: “each reservation is stored by exactly one coordinator.”
  • The arrowhead shows which object holds the reference.

Try It 1: The Other Two Lines

  • Write one sentence for each of the other two lines in Figure 2.1, reading from both ends.
  • For each number, find where the Java code enforces it and where the model merely assumes it.
  • A strong answer separates “enforced by the code” from “true of how the code happens to be used”.

Try It 1: Answers (1 of 2)

LineReadingEnforced by
Coordinator 1 to 1 RulesEach coordinator uses one rules object; each rules object is used by one coordinatorprivate final ReservationRules rules = new ReservationRules();
Coordinator 1 to 0..* ReservationEach coordinator stores zero or more; each reservation is stored by one coordinatorThe list starts empty and has no upper limit

Try It 1: Answers (2 of 2)

LineReadingEnforced by
Reservation 0..* to 1 LoanPeriodEach reservation refers to exactly one period; a period may be referred to by any number of reservationsrequireNonNull(period, "period") and the final field
  • Only assumed:
    • that a rules object is never shared,
    • that a reservation is held by only one coordinator (the constructor is public; snapshots hold the same objects),
    • the 0..* on periods (nothing prevents sharing, though each reservation currently gets its own).

The Relationships You Need to Read and Draw

AssociationABLasting link; arrowhead shows who holds itDependencyABUses another class without keeping itAggregationABWhole groups parts that exist on their ownCompositionABWhole owns parts that need it to existInheritanceABSubclass is a kind of the superclassRealisationABClass implements the interface's contract

Relationships: When to Use Each (1 of 2)

RelationshipRead it asUse it when
AssociationOne object is linked to anotherThe link is structural and lasting
DependencyOne class uses another without keeping itA parameter or brief call is the only link
AggregationA whole groups parts that can exist without itParts can be shared or removed and still exist

Relationships: When to Use Each (2 of 2)

RelationshipRead it asUse it when
CompositionA whole owns parts with no meaning without itA part’s lifetime is tied to its owner
InheritanceThe subclass is a kind of the superclassA real subtype relationship holds
Interface realisationThe class implements the interface’s contractSeveral classes satisfy one contract callers rely on

Figure 2.2: A Notation Sampler

Pack-String title+print(Printer printer) String«interface»Printer+render(List<String> lines) StringPdfPrinterPageArticleResearchArticleAuthor11..*contains0..*1..*collects1..*1..*written byextendsusesimplements

Reading the Sampler

  • A pack owns its pages: a page has no meaning without its pack (composition).
  • A pack only collects articles, which exist independently and can appear in many packs (aggregation).
  • Articles and authors: a plain association, no arrowheads, because the description does not say who holds the reference.
  • This is a notation sampler for a course-pack printing service. It is not part of the reservation project.

Reading the Sampler, Continued

  • A research article is a kind of article (inheritance).
  • A pack uses a printer only while printing (dependency).
  • PdfPrinter implements the Printer interface (realisation).

Choosing a Relationship by Meaning

Choose by what it means, not how it looks. For each pair of classes, ask in order:

  1. Does one class implement a contract that other classes rely on? Realisation.
  2. Is A a kind of B, so a client of B could be handed an A without noticing? Inheritance (Chapter 5 tests this with the Liskov Substitution Principle).
  3. Does A keep a lasting reference to B in a field? If not, and A only uses B as a parameter, local variable or short-lived object: dependency.

Choosing a Relationship, Continued

  1. If A keeps the reference, does B belong to A so completely that it has no meaning without A and is discarded with it? Composition.
  2. Does A group Bs that exist independently and could be shared or removed? Aggregation, but only if you can say what the grouping adds. Otherwise a plain association.

Aggregation and Composition Are Claims

  • Aggregation is often indistinguishable from association in code.
  • Composition describes a lifetime the Java types do not enforce.
  • Both are claims about meaning.
  • Figure 2.1 uses plain associations: periods can be shared by reference, and the code enforces no lifetime.
  • Do not confuse “composition” as a programming idea (building from collaborators) with the filled diamond, a stronger ownership claim.

From Code to Diagram (1 of 2)

In the Java sourceIn the diagram
private final LocalDate start;Attribute -LocalDate start
private final List<Reservation> reservationsAssociation to Reservation, 0..* at that end
private final ReservationRules rulesAssociation to ReservationRules, 1 at that end
A parameter, local variable or new X() used only inside a methodDependency on X

From Code to Diagram (2 of 2)

In the Java sourceIn the diagram
class A extends BInheritance, triangle at B
class A implements IRealisation, triangle at I
public and private+ and -
  • Caution 1: the Java type does not settle the meaning. A List<Reservation> might be an association or a composition. Only the design decides.
  • Caution 2: a field that can be null is 0..1, not 1.

A Worked Example: From Scenario to Diagram

The workshop keeps tools in numbered lockers.

  • A locker holds at most one tool, and a tool sits in at most one locker.
  • A technician looks after any number of lockers; each locker has exactly one technician at a time, and can be reassigned.
  • Every inspection of a locker is logged as an entry with a date and a note; an entry is meaningless without its locker.
  • Reports are printed as plain text now; other formats are expected later.

Steps 1 and 2: Nouns, Then Classes

  • Step 1: find the nouns. Workshop, tools, lockers, technician, inspection, entry, date, note, report, plain text, formats.
  • Step 2: decide which become classes. Keep a noun as a class when it has data or rules the description needs.
  • The table on the next slides records each decision and its reason.

Step 2: Candidates and Decisions (1 of 2)

CandidateDecisionReason
WorkshopLeave outThe whole system; no behaviour described for it
LockerClassHas a number, a log and a report
ToolClassA locker holds one
TechnicianClassLooks after lockers

Step 2: Candidates and Decisions (2 of 2)

CandidateDecisionReason
Inspection entryClassHas a date and a note; belongs to a locker
Date, note, number, nameAttributesPlain values describing a class
ReportOperation of LockerSomething a locker does, not a thing with its own data
Plain text, other formatsReportPrinter interface and PlainTextPrinter classThe format is expected to vary

Step 3: Attributes and Operations

  • Separate what the description states from what you assume.
  • Stated: a locker’s number and report; an entry’s date and note.
  • Assumptions, which you should label as assumptions:
    • a technician’s name and a tool’s name as identifying attributes,
    • a single print operation on the printer, one reasonable way to give the report a format-independent contract.
  • A different, justified choice is acceptable.

Step 4: Choose a Relationship for Each Pair

PairWhat decides itResult
Technician and lockerNeither owns the other; a locker can be reassignedPlain association
Locker and toolNeither is part of the otherPlain association
Locker and inspection entryAn entry is meaningless without its lockerComposition, diamond at Locker
Locker and ReportPrinterA locker uses a printer only while reportingDependency
PlainTextPrinter and ReportPrinterThe class implements the contractRealisation

Step 5: Write Each Multiplicity as a Sentence

  • Each locker is looked after by exactly one technician: 1 at the Technician end.
  • A technician looks after any number of lockers: 0..* at the Locker end.
  • A locker holds at most one tool and a tool sits in at most one locker: 0..1 at both ends.
  • A locker has any number of entries; an entry belongs to exactly one locker.

Step 6: Read It Aloud and Delete

  • Read every line in both directions against the description.
  • Remove anything the description does not say.
  • Then compare with the model on the next slide: ask why each line differs, not whether it matches.

Figure 2.3: The Resulting Model

Technician-String nameLocker-int number+report(ReportPrinterprinter) StringTool-String nameInspectionEntry-LocalDate date-String note«interface»ReportPrinter+print(List<String> lines) StringPlainTextPrinter10..*looks after0..10..1holds10..*logsusesimplements

Reading Figure 2.3

  • The two plain associations have no arrowheads: the description does not say which object holds the reference.
  • A model should record what the description says and no more.
  • Other answers are defensible: Tool only as an attribute, or a Workshop class if the task were scheduling.

Checking a Diagram Against the Code

A diagram that disagrees with its code is worse than no diagram, because readers trust it.

  • For every box, find the class. For every attribute, find the field with that name and type.
  • For every line, find the field, parameter or extends/implements clause that creates it. If you cannot, remove the line or fix the code.

Checking Multiplicities and Omissions

  • For every multiplicity, find where the code enforces it: a constructor check, a final field, a collection type. If nothing does, mark it as an assumption.
  • List what the diagram leaves out, and decide whether each omission is deliberate.

Try It 2: What Figure 2.1 Leaves Out

  • Find two details present in the Java but absent from Figure 2.1.
  • Say why leaving each out is acceptable.
  • Examples of acceptable answers: the constructors and their validation; the accessors id(), borrowerId(), itemId(); the period field (the association line already says it); the private reservations and rules fields; the order of the checks and the exceptions thrown.

What the Diagram Cannot Tell You

  • It omits standard library classes and some accessors.
  • It does not establish the order of operations, display every validation, or prove overlapping bookings are rejected.
  • Read the method body and the period convention for those questions.
  • After extracting a private formatting method, the relationships in Figure 2.1 are unchanged: useful evidence about the scale of the edit.

Spot the Errors: Figure 2.4

Technician-String name-Locker lockerLocker-int number+report(PlainTextPrinterprinter) StringToolInspectionEntryPlainTextPrinter«interface»ReportPrinter+print(List<String> lines) String0..*1looks after0..10..1holdslogsuses

Try It 3

  • Another student’s first attempt at the workshop model (Figure 2.4) contains at least five mistakes.
  • List every mistake you can find.
  • For each, say why it is wrong using the description.
  • Say what the correct notation is.
  • Then redraw the diagram.

Try It 3: Answers (1 of 2)

#MistakeWhy it is wrong
1-Locker locker attribute in TechnicianRepeats the line; implies one locker per technician
2Multiplicities reversed on Technician to LockerSays each locker has many technicians and each technician one locker
3Filled diamond at TechnicianClaims lockers die with their technician, but a locker can be reassigned

Try It 3: Answers (2 of 2)

#MistakeCorrect notation
4Locker <|-- InspectionEntryComposition: filled diamond at Locker, 1 and 0..*
5Locker ..> PlainTextPrinter and report(PlainTextPrinter printer)Depend on ReportPrinter; type the parameter as ReportPrinter
6ReportPrinter <|-- PlainTextPrinterDashed line, hollow triangle at ReportPrinter
  • Mistakes 2 and 3 sit on the same line. Count them as two ideas if both are explained.

Common Drawing Mistakes (1 of 3)

MistakeWhy it is wrongBetter habit
Multiplicity at the wrong endThe far number counts the far class; reversed numbers say the oppositeRead every line aloud in both directions
Arrowhead as ownershipAn arrowhead shows who holds the reference, not who owns whomUse diamonds, with a reason, for ownership
Inheritance for “uses” or “has”A locker is not a kind of technician; an entry is not a kind of lockerTest “A is a kind of B” and its promises

Common Drawing Mistakes (2 of 3)

MistakeWhy it is wrongBetter habit
Solid line for realisationRealisation is dashed; solid with a triangle is inheritanceCheck the line style of every triangle
Filled diamond because the field is finalComposition claims a lifetime; final only fixes a referenceAsk whether the part can exist without the owner
Showing a relationship twice-Locker locker plus a line to Locker repeats one factShow a field of a design class as a line only

Common Drawing Mistakes (3 of 3)

MistakeWhy it is wrongBetter habit
Depending on a concrete class when an interface existsA client naming PlainTextPrinter cannot accept another formatPoint the dependency at the interface
Drawing every class and memberThe design question disappears among the detailOne diagram, one question, only the members it needs
A diagram that disagrees with the codeReaders trust the diagramRun the checking steps before sharing it

2.7 Making a Change Someone Else Can Review

A change a team can inspect

Version Control Is Not Evidence of Good Design

  • A codebase becomes a shared piece of work when the team can inspect its changes, reproduce its behaviour and explain its decisions.
  • Version control supports that work.
  • A commit alone is not evidence of a good design.

Working Files, Staging, Commits

Working files(what you edit)Staging area(the next commit)Recorded commits(history)git addgit commitgit diffgit diff --stagedEdit, stage the exact change, inspect it, then record it.

Why the Staging Area Matters

  • You edit working files, select content for the next commit, and record that selected state.
  • The staging area matters when unrelated edits are present.
  • The next commit should contain the change you intend to explain.

Branches and Pull Requests

  • A branch names a line of development. For the lab, use a short-lived branch containing the confirmation extraction.
  • A pull request (or merge request) is a hosting-platform review proposal. It is not the same as a local commit.
  • A local peer review can still serve the learning objective when no hosting account is available.

Trunk-Based or Feature Branches?

  • Trunk-based development: integrate small changes frequently into a main line, sometimes through very short-lived branches.
  • Feature-branch workflow: group a feature’s work on a branch before integration.
  • The approaches overlap: a short reviewed branch can be part of frequent integration.
  • For this course: keep changes small, reviewable and integrated regularly.

A Reviewable Change: The Sequence

  1. Begin with the supplied starting files and a recorded baseline.
  2. Confirm that the checks pass before editing.
  3. Create a branch.
  4. Perform only the extraction.
  5. Rerun the checks and inspect the diff.
  • The companion contains the complete setup commands.

The Inspection Commands

git status
git diff
git diff --staged
  • git status reports file state.
  • git diff normally shows tracked changes not yet staged.
  • git diff --staged shows staged changes against the current commit.

Reading the Output Correctly

  • An empty git diff after staging does not mean there is nothing to commit.
  • Untracked files also need attention in git status.
  • Keep compiled class files out of commits: the companion’s .gitignore handles generated files.
  • Appendix B collects the Git commands and the pull-request workflow (B.8).

Commit Messages

  • A useful message: Extract reservation confirmation formatting.
  • Many teams adopt a written convention. Conventional Commits puts a type before a short description: refactor: extract reservation confirmation formatting
  • Use whichever convention your team agrees, and apply it consistently.

A Useful Review Description

  • State the problem, the limited change, and the checks performed.
  • Example: “The request method interleaves storage and confirmation text. This change moves the text assembly into a private helper. The existing messages and stored records remain unchanged in the supplied checks.”
  • Add limits: persistence, concurrent booking, lifecycle operations and message delivery remain outside this version.

What the Reviewer Inspects

  • Inspect the diff.
  • Verify that the helper adds no state changes.
  • Check that the record is still added before confirmation is returned.
  • “Looks cleaner” is weaker than an explanation of what was inspected and why it matters.

A Diff With Only Additions Still Moves Behaviour

  • In Git, the extraction appears as four added lines and no removed lines.
  • The existing return "Confirmed: "... expression is kept and now sits inside the new method.
  • The reviewer must read where the retained lines ended up.

One Change at a Time

  • Do not combine this refactoring with changed limits, renamed identifiers or new message punctuation.
  • Each may be legitimate work.
  • Combining them makes it harder to determine why a result changed.

2.8 Checking an AI’s Explanation of the Coordinator

Classifying claims against the code

Ground Rules for the Activity (1 of 2)

For this activity
Your goalCompare an explanation of the coordinator with its actual control flow, state changes and side effects
You start withThe complete starting ReservationCoordinator and collaborators
What is in boundsJudge the explanation only; do not change the code

Ground Rules for the Activity (2 of 2)

For this activity
How to checkTracing the code, the three-request demonstration, the supplied checks
How to decideKeep supported claims, reject contradicted ones, mark claims the code does not establish
No AI account?The ready-made example is enough
  • Chapter 15 collects the recurring AI workflows. This activity is self-contained.

The Ready-Made Example (1 of 2)

An ready-made example written by the author imitating a plausible AI explanation. Not a captured response from a real model.

The coordinator validates identifiers, counts the borrower’s stored reservations and checks the numeric rule. It tests availability using existing reservations for the same item. On success, it adds a reservation before returning a confirmation.

The Ready-Made Example (2 of 2)

It sends that confirmation by email and persists the reservation to a database. Because the list field is final, callers receive a deeply immutable copy and booking is safe under concurrent requests.

  • Classify each claim as supported, contradicted or not established.
  • Cite the relevant operation, or the absence of one.

Claim Classification (1 of 2)

ClaimJudgementEvidence
Validates identifiersSupported within scopeRejects null or blank identifiers; no catalogue check
Counts the borrower’s stored reservationsSupportedLoops over records, compares borrower identifiers
Applies the numeric ruleSupportedCalls ReservationRules.mayRequest
Checks conflicts for the same itemSupportedMatching item and overlapping period

Claim Classification (2 of 2)

ClaimJudgementEvidence
Adds before returning a confirmationSupportedadd is called before the message is built
Sends emailContradictedNo sender or delivery call; the method returns a string
Persists to a databaseContradictedAn in-memory ArrayList; no database operation
Final list: callers get a deeply immutable copyIncorrectfinal stops reassignment; List.copyOf is shallow
Concurrent booking is safeNot establishedCheck and add are not one synchronised operation

A Corrected Four-Sentence Explanation

The coordinator rejects missing or blank identifiers and requires a start date, then counts the borrower’s stored records and applies the numeric rule. It checks overlapping periods for the same item before recording a successful reservation and returning confirmation text.

A Corrected Four-Sentence Explanation, Continued

Policy and availability rejections do not add a record, and the returned reservation list is an unmodifiable snapshot containing immutable elements. The implementation has in-memory storage only, sends no email, and is intended for sequential use rather than concurrent booking.

Optional Live Assistant

Trace this coordinator and its supplied collaborators. Identify inputs, returned values and state changes on success and rejection. State what is established about storage, notifications and concurrency. Separate facts visible in the code from assumptions. Do not change the code.

  • Record one accepted claim and one rejected or qualified claim with evidence.
  • A second model’s agreement is not a substitute for tracing the operations.

2.9 Mistakes That Look Like Good Design

Eight misconceptions, eight better questions

Mistakes 1 and 2

  • “Private fields mean the object is safely encapsulated.”
    • A returned mutable list can still expose a modification path.
    • Better question: what can callers change through the references they receive?
  • “A final field makes the referenced object immutable.”
    • The coordinator can still add to its final list.
    • Better question: is the reference fixed, the object immutable, or both?

Mistakes 3 and 4

  • “Every noun should immediately become a class.”
    • Several concepts have no behaviour or state we need yet.
    • Better question: what responsibility would that class own now?
  • “More interfaces automatically mean less harmful coupling.”
    • An interface can repeat an unstable contract without solving a caller’s problem.
    • Better question: which dependency would this interface improve?

Mistakes 5 and 6

  • “Calling another class means inheriting from it.”
    • The coordinator uses a policy; it is not a policy subtype.
    • Better question: is the relationship use, containment or substitution?
  • “A filled diamond just means ‘has a’.”
    • Composition claims the part cannot outlive its owner; LoanPeriod objects can be shared by reference.
    • Better question: does the code enforce this lifetime, and would the domain agree?

Mistakes 7 and 8

  • “A formatting refactoring fixes the whole design.”
    • The helper leaves storage and other responsibilities in the coordinator.
    • Better question: which improvement did this edit actually make?
  • “Green checks prove the application is production-ready.”
    • The starter omits lifecycle, persistence, catalogue validation and concurrency.
    • Better question: which claims have we tested, under which assumptions?

2.10 Try It Yourself

Improve the design, with evidence

Inputs and Starting Point

  • Parts A to C use the book’s project; Part D concerns your team’s project.
  • Use the companion’s common source files and the starting ReservationCoordinator.java.
  • Save all six Java files in one directory; compile and run them using the companion’s instructions.
  • The check runner should report 34 passing checks before you begin.
  • Read the checks as provided evidence. You need not master the runner yet.

Compile and Run

javac --release 17 -d out ReservationRules.java LoanPeriod.java \
    Reservation.java ReservationCoordinator.java \
    Chapter02Demo.java Chapter02Checks.java
java -cp out Chapter02Demo
java -cp out Chapter02Checks
  • Recompile after every source change. Otherwise the JVM may run old class files and give misleading evidence.

Expected Output

Confirmed: R1 for B1 on CAM1 [2026-10-20, 2026-10-22).
Rejected: item unavailable.
Confirmed: R2 for B2 on CAM1 [2026-10-22, 2026-10-23).
Stored: 2
All 34 chapter checks passed.

Part A: Understand the Request

Trace the three requests in Chapter02Demo.

  • Record the returned message and the number of stored records after each call.
  • Identify the first condition that rejects the overlapping request.
  • Explain why the adjacent request is accepted.
  • Explain why the rejected request does not consume a reservation identifier.

Part A: The Trace

CallOutcomeStoredImportant step
B1 requests CAM1 from 20 Oct for two daysConfirmed as R11Empty history has no conflict
B2 requests CAM1 from 21 Oct for one dayRejected: unavailable1Overlaps R1 for the same item
B2 requests CAM1 from 22 Oct for one dayConfirmed as R22Equality with R1’s exclusive end is permitted
  • Identifiers derive from the number of stored records, so a rejection consumes none. That may not suit deletion, persistence or several coordinators.

Part A: Diagram and Invariants

  • Draw a small class diagram of the starter without copying Figure 2.1.
    • Use the “From code to diagram” table, then run the four checking steps on your own drawing.
  • Annotate one local invariant and one condition that needs information from multiple objects.
  • A local invariant: a period’s end follows its start (the LoanPeriod constructor).
  • A multi-object condition: confirmed reservations for the same item do not overlap (the coordinator checks it).

Part A: A Separate Modelling Exercise

Equipment kits. It does not extend the project.

  • A kit has a name and holds one or more equipment items.
  • Removing a kit does not delete its items; an item belongs to at most one kit.
  • Each item keeps any number of maintenance records; a record belongs to exactly one item and has no meaning without it.
  • A kit summary is produced through an exporter: CSV now, other formats later.

Part A: What to Draw

  • A class diagram with the classes, their key attributes and multiplicities.
  • Include at least one aggregation, one composition, one interface realisation and one dependency.
  • State one assumption you had to make.
  • For each relationship, write the Section 2.6 question that decided it.
  • Then read every line aloud in both directions against the scenario.

One Suitable Model: Equipment Kits

EquipmentKit-String name+summary(Exporter exporter) StringEquipmentItem-String itemIdMaintenanceRecord-LocalDate performedOn-String note«interface»Exporter+format(List<String> lines) StringCsvExporter0..11..*groups10..*keepsusesimplements

What a Strong Kit Answer Shows

RequirementModel decision
A kit holds one or more items; removing it does not delete themAggregation, 1..* at the items end
An item belongs to at most one kit0..1 at the kit end
A record belongs to exactly one item and has no meaning without itComposition from item to record: 1 at the item, 0..* at the records
A summary is produced through an exporter; other formats expectedExporter interface realised by CsvExporter; the kit depends on the interface

Common Kit Errors

  • Interface realisation drawn as inheritance with a solid line.
  • The diamond reversed.
  • 1..* at the wrong end.
  • The kit depending directly on CsvExporter.
  • An assumption can be anything stated and consistent: for example, that an item with no kit is allowed.
  • Do not credit extra classes for their own sake.

Part B: Diagnose the Design

  • Write a short responsibility inventory for the coordinator.
  • Identify two distinct reasons it might change.
  • Explain one cohesive collaborator and one dependency that deserves attention.
  • Avoid judging quality by method length alone.

Part B: A Model Answer

  • The coordinator validates inputs, counts records, invokes policy, checks availability, allocates an identifier, stores a record and formats a message.
  • Two reasons to change: a new storage mechanism and changed confirmation wording.
  • LoanPeriod is cohesive: construction rules and overlap concern one concept.
  • The coordinator depends on both reservation representation and message wording.

Part C: Make the Change

  • On a short-lived branch, move only the confirmation-string expression into a private confirmationFor(Reservation reservation) method.
  • Keep unchanged: output, validation order, identifier allocation, storage effects.
  • Do not add a new interface or change public method signatures.
  • Run the checks again, inspect the diff, ask a peer to review.

Part C: The Completed Method

        reservations.add(reservation);
        return confirmationFor(reservation);
    }

    private String confirmationFor(Reservation reservation) {
        return "Confirmed: " + reservation.id()
                + " for " + reservation.borrowerId()
                + " on " + reservation.itemId()
                + " [" + reservation.period().start()
                + ", " + reservation.period().endExclusive() + ").";
    }

Part C: Git Baseline Commands

git init -b main
git add .gitignore ReservationRules.java LoanPeriod.java \
    Reservation.java ReservationCoordinator.java \
    Chapter02Demo.java Chapter02Checks.java
git diff --staged
git commit -m "Add chapter 2 reservation starter"
git switch -c refactor/confirmation-text
  • .gitignore contains out/ and *.class.

Part C: Commit the Extraction

git status
git diff
git add ReservationCoordinator.java
git diff --staged
git commit -m "Extract reservation confirmation formatting"
git log --oneline -2
git status
  • Produce one focused commit after addressing relevant feedback.
  • In independent study, perform a self-review and label it honestly as such.

Part C: A Review Record

  • Problem: the request method contains message formatting alongside the request workflow.
  • Change: move only the confirmation-string construction into confirmationFor, keeping record creation and storage order.
  • Evidence: identical demonstration output; the same 34 checks pass; the diff changes only internal organisation.
  • Limits: persistence, concurrent booking, lifecycle operations and message delivery remain outside this version.

Part C: What the Review Record Needs

  • The change or commit identifier.
  • The reviewer.
  • The evidence inspected.
  • The findings and the response.
  • Creating a commit does not create a hosted pull request or establish that anyone reviewed it.
  • Record your own observed results. Do not copy a claim you did not verify.

Part D: Organise Collaboration

  • Form teams of three or four as directed by the module leader.
  • Confirm which provided starter domain your assessed project uses. If it is not equipment lending, use each chapter’s transfer note.
  • Set up an issue board with columns that match how your team will work.
  • Add three cards with concrete completion conditions.

Part D: Cards and Branch Policy

  • A good card: “extract confirmation formatting with unchanged output and checks”. Not: “improve OO”.
  • Agree a branch policy:
    • very short-lived branches integrated into a main line often, or
    • one feature branch per story.
  • Write down your reason. The reason matters more than the choice.
  • Agree who prepares the next demonstration and who reviews the next change. Rotate roles.

Evidence to Retain

  • The annotated diagram and the scenario model.
  • The responsibility diagnosis.
  • Before-and-after check results.
  • The commit identifier and the review note.
  • Your AI claim analysis.
  • Your team’s issue board and branch-policy note.
  • A short limitation statement: which risks remain after the extraction?

The Activity Is Complete When

  • The diagram matches the code.
  • The extraction preserves the checked behaviour.
  • Your review explains both the improvement and its limits.
  • You can explain the returned list’s protection without claiming all copies are deep copies.

Optional Investigation: Break It on Purpose

  • In a temporary copy, replace List.copyOf(reservations) with reservations.
  • Predict the effect of an external clear() call, then run the checks.
  • Result: snapshot::clear succeeds; the runner reports that snapshot unmodifiable expected an UnsupportedOperationException.
  • Restore the original before continuing. This is a fault demonstration, not an improvement.

A Second Fault: Omit the Storage

  • In another disposable copy, remove reservations.add(reservation);.
  • The first confirmation can still look correct.
  • The checks fail with one success stored.
  • A demonstration that inspects only printed text would miss the changed state.

2.11 Questions to Think with

Concept, diagnosis, transfer

Concept Questions

  1. Distinguish a Java object reference from a reservation’s domain identifier. Why are equal identifier strings not sufficient to make two Reservation instances equal through equals in this starter?
  2. Explain one local invariant and one system-level condition in the project. Why do they need different enforcement points?
  3. Explain cohesion and coupling using one likely change to the coordinator. Why is reducing the total number of dependencies not a sufficient design goal?
  4. Compare composition and inheritance for a reservation and its loan period. What would inheritance incorrectly suggest?

Diagnosis Questions

  1. A developer adds a getter returning the private mutable list and claims the coordinator is still encapsulated because the field is private. Give a concrete counterexample and explain the limits of the proposed correction using List.copyOf.
  2. A refactoring returns the same confirmation text but omits reservations.add(reservation). The developer demonstrates the printed text and declares success. Explain the behavioural change and identify evidence that would expose it.

Guidance: Questions 1 and 2

  1. A reference identifies a Java object instance; id represents domain identity in the teaching model. Two separately constructed reservations can hold the same identifier text yet remain distinct under the inherited equals. Identifier-based equality needs an explicit contract and implementation.
  2. LoanPeriod protects its own date relationship. Conflict prevention needs other reservations and the requested item, so it belongs at a boundary with that information.

Guidance: Questions 3 and 4

  1. Changed message wording affects presentation but currently requires editing the coordinator. A private helper makes the purpose easier to locate; it does not remove the class-level dependency. Zero dependencies would prevent collaboration; extra classes can add indirection without solving a problem.
  2. A reservation has a period. It is not a period subtype. Inheriting would conflate reservation identity and borrower/item details with an interval, and suggest inappropriate substitutability. LoanPeriod is also final.

Guidance: Questions 5 and 6

  1. Returning the mutable internal list allows clear or add outside the coordinator’s validation. List.copyOf blocks structural mutation and isolates later additions, but does not deep-copy mutable elements. This starter’s elements are separately immutable.
  2. A success string is returned for a reservation the coordinator does not retain. The next request can wrongly find no conflict. The one success stored check exposes the fault immediately.

Transfer Challenge: Room Booking

A university room-booking coordinator stores bookings, checks room conflicts and constructs confirmation text. Its users now request a wording change only.

  • Propose a responsibility diagram with at most four domain or application classes.
  • State a period convention.
  • Identify the state that callers must not modify directly.
  • Describe one small behaviour-preserving improvement and two before-and-after observations to accept it.
  • Include a brief review description and one remaining limitation.

Transfer Challenge: Guidance

  • One reasonable model: RoomBookingCoordinator, RoomBooking, BookingPeriod, BookingRules.
  • State an explicit convention, for example start-inclusive, end-exclusive periods in local building time.
  • Extract first, change the wording second: preserve the old output while extracting; then change the text as a separate behaviour change with updated expectations.
  • Two observations: identical confirmation text and identical stored records; a conflicting request still adds nothing.
  • A limitation: one process’s list cannot coordinate several application instances.

What to Take Away, and What Comes Next

What to carry forward

Summary: Objects as Design Units

  • Objects become useful design units when their responsibilities and permitted interactions are clear.
  • Constructors and controlled operations protect invariants.
  • Immutable values and careful collection access stop callers bypassing intended boundaries.

Summary: Cohesion, Coupling and the Limited Claim

  • Cohesion and coupling help us discuss the consequences of change.
  • The formatting extraction makes one operation easier to follow without resolving every responsibility the coordinator holds.
  • Explaining that limited improvement is part of sound design reasoning.

Summary: Evidence Should Agree

  • Diagrams, checks, diffs and review notes describe different aspects of the same codebase.
  • They should agree with the implementation.
  • An AI explanation is another candidate description to check against that evidence.

Next: Chapter 3

  • Chapter 3: Agile Development and the Nature of Change.
  • Turn project needs into an ordered backlog.
  • Write useful stories and acceptance criteria.
  • Examine how a team plans and learns through feedback.

Sources and Further Reading

  1. Dev.java: Classes and Objects; Inheritance.
  2. Oracle: Java SE 17 API for LocalDate, Objects and List.
  3. Chacon and Straub: Pro Git: Recording Changes; Branching Workflows.
  4. Git documentation: git diff and git switch.
  5. Conventional Commits 1.0.0.
  6. Martin, Robert C.: Agile Software Development: Principles, Patterns, and Practices, 2002.
  • Full references and links are in the chapter text.