Skip to content

Unit 2 — Layers & interfaces

Weeks 6–7. Applying design principles to modules and systems instead of classes.

Unit 1 worked inside a codebase you own completely. Every interface you built — every seam, every pattern — had a caller you could still reach: if the shape turned out wrong, you refactored it and fixed every call site in the same pull request.

This unit takes that away, in two steps. First at module scale: define boundaries by examining the seams of abstraction we according to our analysis techniques from Unit 1. Then at the system boundary: publish an API, and the callers become teams you'll never meet, running code you can't see, on a schedule you don't control.

Lectures

LectureWhat it answersReadings
Patterns: Adapter & CompositeWhat does polymorphism buy at a boundary you don't own?Design Patterns
Patterns: Factory & DecoratorWhat does delegation buy once it goes through an interface?Design Patterns
API change severity & versioningHow do you change a promise without breaking it?Safe Versioning
API designWhat is an API, and what do you lose the moment it's published?APIs · REST Architecture
The testing pyramidGiven real layers, which one should a test actually run through?Testing Pyramid
Layered architectureWhat do you get when the same moves are applied everywhere?Design Principles

Slides are posted on the schedule as we go.

By the end of this unit you can

Compose the moves

  • Explain a design pattern as a named combination of principles you already know, rather than as a recipe
  • Given unfamiliar code, identify the Unit 1 problems and update the code to address them.

Choose where to test

  • Characterise a test as unit, integration, or end-to-end, and justify the label by what's real and what's doubled
  • Compose a test suite that balances automatability with completeness by choosing the correct relative amount of each test type.

Design an API

  • Identify the differences between an API and an internal interface
  • Apply cohesion, coupling, and testability principles at the API boundary to design a usable and maintainable API.

Change it without breaking anyone

  • Given a code change to an API, identify how severe it is
  • Encode change severity in terms of semantic versioning
  • Implement techniques to reduce change severity

Design in layers

  • Apply the dependency inversion principle to define an appropriate layer in software.

Course reader licensed under CC BY-SA 3.0.