login as:
~/abapcraft.dev — code, crafted in SAP
florin@s4hana:~/abap/posts/book-goos $ cat README.md

Growing Object-Oriented Software, Guided by Tests — Freeman & Pryce

TDD taken to its full conclusion — outside-in development driven by acceptance tests, illustrated through a real-world application built from scratch.

What the book is about

Written by Steve Freeman and Nat Pryce, Growing Object-Oriented Software, Guided by Tests picks up where Kent Beck’s TDD by Example leaves off. Where Beck demonstrates TDD at the unit level, Freeman and Pryce show how TDD works at the full application level — from the first acceptance test to a working system, built incrementally, guided entirely by tests.

The title is deliberate. Software is not built — it is grown. Features are added one at a time, the design evolves in response to new requirements, and tests provide the safety net that makes that evolution possible without breaking what already works.

The garden metaphor

The book compares a codebase to a garden. A garden not being maintained grows wild. Weeds spread, plants entangle, and what was once organised becomes progressively harder to navigate and impossible to control. Getting it back under control requires far more effort than keeping it maintained in the first place would have.

Code works the same way. A system without tests and without deliberate design accumulates entanglements — classes that know too much about each other, logic scattered in the wrong places, changes that ripple unexpectedly across the codebase. The longer it goes unmaintained, the harder it becomes to recover. Tests, applied continuously, are what keep the garden in order.

Most important ideas

Tests always give feedback. Not just about correctness — about design. A test that is hard to write is a signal that the code it tests has a design problem. Hard-to-test code is usually code that does too much, knows too much about its dependencies, or has responsibilities that belong elsewhere. Freeman and Pryce call this “listening to the tests.” If the tests are painful, the pain is information.

Start each feature with an acceptance test. Before writing any production code, write a test that describes what the feature should do from the outside — from the user’s or caller’s perspective. This is Outside-In TDD: the acceptance test defines the goal, and the unit tests guide the implementation toward it. The acceptance test stays red until the feature is complete, acting as a constant reminder of what done looks like.

Design for maintainability. The book gives practical guidance on the design principles that make systems testable and changeable:

  • Separate the concerns — each class and method should do one thing. Mixed concerns make testing harder and change riskier.
  • Use abstractions — depend on interfaces, not concrete implementations. This keeps the code flexible and the tests fast and isolated.
  • Hide information — expose only what callers need. The less a class reveals about its internals, the more freely those internals can change.
  • Create good and understandable APIs — the interface a class presents to the world is its contract. A clear API makes the class easy to use correctly and hard to use incorrectly.

The Auction Sniper example

The second half of the book builds the Auction Sniper — a real application that participates in online auctions — from the first acceptance test to a working system. Every design decision is driven by tests. Every abstraction is introduced in response to pressure from the tests, not from upfront design.

This is the book’s most instructive section. It is also the most demanding. The example is complex, and some chapters require more than one reading to follow the full thread. But that complexity is the point — real applications are complex, and seeing TDD applied to a real problem is more useful than a simplified toy example.

Personal note

This book illustrates how complex testing can be — and how important. The chapters that walk through the earlier stages of the Auction Sniper are clear and easy to follow. The later chapters, where the design becomes more intricate, require more careful reading.

What stays with me is the acceptance test discipline: always start with a test that describes what the feature should do from the outside, before thinking about how it will be implemented. That outside-in approach changes the way you think about what you are building — you are always working toward a defined, verifiable outcome.

Together with TDD by Example by Kent Beck, this book completes the TDD picture: Beck shows you the micro-cycle of Red-Green-Refactor at the unit level, and Freeman and Pryce show you how that cycle scales to a full application, guided from the outside in by acceptance tests.