Objects Working Together · practice
Read and Draw Object Collaborations
You have now written five classes that work together. Someone else joining this program would have to read all five to find out how. There is a faster way, and it is the last skill this chapter teaches: describing a design without writing it.
A design on five lines
The notation from Lesson 3 is enough for most conversations:
a Quiz has many Questions
a QuizAttempt has a Quiz
a QuizAttempt has many Responses
a Response has a Question
a ScoreReport has a QuizAttempt
Read it as a map of who can ask whom. A ScoreReport can reach a QuizAttempt, and through it a Quiz, but a Question can reach nothing at all. Questions sit at the bottom: they answer, and never ask.
That last observation is worth more than it looks. The
The same design as a picture
For anything with more than a handful of classes, a sketch reads faster:

Arrows point from the holder to the thing it holds. This is not a formal notation, and it does not need to be. Its whole job is to fit on one screen and let you notice things, such as: Question has two arrows pointing at it and none pointing away, and there is no path back up from a Question to the Quiz that holds it.
What to look for in a drawing
Once a design is drawn, some problems become visible without reading any code.
Arrows both ways. If Quiz points to QuizAttempt and QuizAttempt points back to Quiz, ask whether both directions are needed. The relationship can couple changes to the two classes. Object references do not require both classes to import each other, but unnecessary dependencies make later
One object with arrows to everything. That is the god object from Lesson 5, visible as a shape.
A long chain. ScoreReport -> QuizAttempt -> Quiz -> Question is fine while each step asks only its neighbor. It becomes a problem when the report starts reaching all the way down, which shows up in code as report.attempt.quiz.questions()[0].points.
An object nothing points to. Check who creates and uses it. It may be an entry point, an omitted caller may use it, or it may be unnecessary.
A design shows Quiz with an arrow to QuizAttempt, and QuizAttempt with an arrow back to Quiz. What does that suggest?
Drawing before writing
The most useful moment for this is before any class exists.
Take the requirement “a learner can retake a quiz, and we keep every attempt.” Write the nouns down, then the relationships:
a Learner has many QuizAttempts
a QuizAttempt has a Quiz
a QuizAttempt has a started_on day
Three lines, and a decision has already been made: attempts belong to a learner rather than to a quiz. That has consequences, because “show me everything Mina did” is now easy and “show me everyone who took the final” is now a search. Noticing this on paper costs a minute. Noticing it after writing four classes costs an afternoon.
The rule of thumb: sketch when you have more than about three classes, or whenever you catch yourself unsure which object should hold something.
The exercise
You are given a written design and a set of half-built classes. Make the code match the design, then use the design to answer a question about a change nobody has made yet.
Task
Finish Learner so the code matches this design:
a Learner has many QuizAttempts
a QuizAttempt has a Quiz
a QuizAttempt has many Responses
a Response has a Question
a Quiz has many Questions
Question, Quiz, Response, and QuizAttempt are supplied collaborators. Learner(name) keeps its public name. start(quiz) creates, remembers, and returns a new QuizAttempt for that quiz. attempt_count reports how many attempts were started. best_score reports the highest current attempt score, or 0 when there are no attempts. history() returns a new
Read the supplied classes against the arrows before you implement Learner. That keeps the exercise about interpreting a collaboration drawing rather than rebuilding four earlier lessons at once.
Follow the arrows. Nothing points from a Quiz back to a QuizAttempt, so a quiz must never mention attempts or learners. Nothing points from a Question anywhere, so a question keeps answering and never asks.
The program prints a short history for one learner across two attempts at the same quiz.