Chapter 8: Stratified design: Part 1
The chapter introduces stratified design as writing functions in terms of functions defined in lower layers.
After this chapter you will be able to
- Lower-layer function relationships. Explain that in stratified design, functions are written in terms of functions defined in lower layers.
- Software design as aesthetic judgment. Explain how the book defines software design and why a programmer’s frustration can signal a design problem.
- Layered function definitions. Explain that stratified design builds software in layers, with each layer defining new functions in terms of functions in layers below it, and describe the benefits a good arrangement can bring.
- Clues and design decisions. Describe how a developer reads clues in function bodies, layer structure, and function signatures, then uses them to guide decisions about code organization, implementation, and changes.
- Straightforward function implementations. Explain that a function’s body should solve the problem stated by its signature at the right level of detail, and that too much detail is a code smell.
- Implementation hiding through layers. Explain that an abstraction barrier is a layer whose interface hides an important implementation detail, allowing code to work at a higher level.
- Small powerful concept interfaces. Describe how an important business concept’s interface should evolve toward a small, powerful set of operations, with other operations defined in terms of that set.
- Pragmatic investment in layers. Justify adding layers when they help deliver software faster or with higher quality, rather than adding them merely to have more layers.
- Straightforward shopping cart implementations. Explain why replacing the loop in freeTieClip() with shopping-cart operations makes the function more straightforward.
- Call graph layer signals. Describe how a call graph reveals whether a function calls operations at similar or widely different levels of abstraction.
- Call graph zoom levels. Distinguish the global, layer, and function zoom levels by what each shows and the kind of design problem each helps locate.
- Arrow lengths and implementation detail. Explain what unequal arrow lengths reveal at the layer and function zoom levels, and describe the proposed change to remove_item_by_name().
- Extracted item search. Describe how extracting the for loop from remove_item_by_name() produces indexOfItem(), and explain what the new function returns.
- Search and membership layers. Explain why isInCart() is written in terms of indexOfItem() rather than the other way around.
- Shorter arrows in refactoring. Describe how reusing indexOfItem() and arraySet() changes setPriceByName(), and explain why the section treats these changes as progress even when the graph still points to multiple layers.
- Single Level of Detail. Explain why mixing levels of detail makes a function hard to read and how a straightforward implementation addresses that problem.
- General Extraction Without Concealment. Explain how extracting a general function can clarify an implementation, and distinguish that from merely hiding unclear code in helpers.
- Straightforward layered implementations. Explain that the first pattern of stratified design is to find straightforward implementations, using the layer structure to build simple functions out of other simple functions.
What it builds on
- A first glimpse of stratified design (chapter 2) · The earlier first glimpse of stratified design.
- The three steps of the copy-on-write discipline (chapter 6) · The copy-on-write discipline used by arraySet().
Section by section
Introduction
The chapter introduces stratified design as writing functions in terms of functions defined in lower layers.
- Lower-layer function relationships: Explain that in stratified design, functions are written in terms of functions defined in lower layers.
Why it matters: This gives you the basic relationship to look for when the chapter explains layers in more detail.
Key terms: stratified design, lower layers
8.1 What is software design?
Defines software design as using aesthetic judgment to make software easier to develop and maintain.
- Software design as aesthetic judgment: Explain how the book defines software design and why a programmer’s frustration can signal a design problem.
Why it matters: This gives you a way to notice when a design is making development harder.
Key terms: software design, aesthetic sense
8.2 What is stratified design?
This section defines stratified design as building software in layers and explains why arranging those layers calls for design judgment.
- Layered function definitions: Explain that stratified design builds software in layers, with each layer defining new functions in terms of functions in layers below it, and describe the benefits a good arrangement can bring.
Why it matters: The layer relationships give you a way to reason about whether a design will be easy to work with and change. - Judgment in arranging layers: Explain why identifying useful layers is not a matter of applying an absolute formula.
Why it matters: It frames stratified design as a judgment to develop, not a recipe that always yields one best answer.
Key terms: stratified design, layers, sense of good design, best design
8.3 Developing our design sense
The section presents stratified design sense as recognizing clues in code and using them to make design decisions, while explaining why that judgment is hard to teach explicitly.
- Clues and design decisions: Describe how a developer reads clues in function bodies, layer structure, and function signatures, then uses them to guide decisions about code organization, implementation, and changes.
Why it matters: It gives you a way to notice the evidence behind a design choice without expecting a fixed recipe yet. - Limits of expert explanation: Explain why an expert can make good design decisions yet struggle to describe exactly how they make them.
Why it matters: It explains why developing design sense takes practice noticing patterns, not just memorizing instructions.
Key terms: stratified design sense, clues, function bodies, layer structure, function signatures, curse of expertise, black box
8.4 Patterns of stratified design
Introduces four patterns for judging whether the layers of a stratified design help programmers work at an appropriate level of detail.
- Straightforward function implementations: Explain that a function’s body should solve the problem stated by its signature at the right level of detail, and that too much detail is a code smell.
Why it matters: This gives you a way to notice when a function exposes more detail than its purpose calls for. - Implementation hiding through layers: Explain that an abstraction barrier is a layer whose interface hides an important implementation detail, allowing code to work at a higher level.
Why it matters: Hiding details leaves more attention for the problem the higher-level code is solving. - Small powerful concept interfaces: Describe how an important business concept’s interface should evolve toward a small, powerful set of operations, with other operations defined in terms of that set.
Why it matters: A small set of fundamental operations gives the rest of the interface a clear foundation. - Pragmatic investment in layers: Justify adding layers when they help deliver software faster or with higher quality, rather than adding them merely to have more layers.
Why it matters: The point of layering is to make useful software easier to deliver, not to maximize the number of abstractions.
Key terms: straightforward implementation, function signature, code smell, abstraction barrier, interface, implementation detail, minimal interface, business concepts, operations, comfortable layers
8.5 Pattern 1: Straightforward implementations
The section shows how to make shopping-cart code easier to read by replacing low-level details with operations at a consistent level of abstraction and using call graphs to examine the resulting layers.
- Straightforward shopping cart implementations: Explain why replacing the loop in freeTieClip() with shopping-cart operations makes the function more straightforward.
Why it matters: It lets business rules express what they do without repeatedly handling array details. - Call graph layer signals: Describe how a call graph reveals whether a function calls operations at similar or widely different levels of abstraction.
Why it matters: The graph makes differences in abstraction visible that can be hard to spot across a larger system. - Purposeful function layer placement: Explain how the section places remove_item_by_name() in a layer using function purpose and call relationships.
Why it matters: Purpose and dependencies give you a way to discuss a layer choice rather than placing functions arbitrarily.
Key terms: straightforward implementations, low-level code, shopping cart operations, call graph, layers of abstraction, for loop, array index, remove_item_by_name(), isInCart(), layer
8.6 Three different zoom levels
The section uses three call-graph zoom levels to locate stratified-design problems and shows how long arrows reveal uneven implementation detail.
- Call graph zoom levels: Distinguish the global, layer, and function zoom levels by what each shows and the kind of design problem each helps locate.
Why it matters: Choosing a useful view makes a crowded call graph easier to diagnose. - Arrow lengths and implementation detail: Explain what unequal arrow lengths reveal at the layer and function zoom levels, and describe the proposed change to remove_item_by_name().
Why it matters: Arrow lengths make inconsistent levels of detail visible and suggest where to extract a function.
Key terms: global zoom level, layer zoom level, function zoom level, call graph, straightforward implementation, arrows, intermediary functions, remove_item_by_name()
8.7 Extracting the for loop
The section refactors shopping-cart functions into clearer layers and uses their call graphs to evaluate reuse and design tradeoffs.
- Extracted item search: Describe how extracting the for loop from remove_item_by_name() produces indexOfItem(), and explain what the new function returns.
Why it matters: Giving the search its own name makes the caller’s purpose clearer. - Search and membership layers: Explain why isInCart() is written in terms of indexOfItem() rather than the other way around.
Why it matters: The return values show which function exposes a data-structure detail and which can hide it. - Shorter arrows in refactoring: Describe how reusing indexOfItem() and arraySet() changes setPriceByName(), and explain why the section treats these changes as progress even when the graph still points to multiple layers.
Why it matters: A call graph can show an improvement that a simple count of referenced layers misses. - Contextual design judgment: Explain why the section does not give a fixed rule for wrapping the remaining array-index use in setPriceByName().
Why it matters: It helps you discuss a design choice in terms of the people and code involved, rather than treating a diagram as a verdict.
Key terms: linear search, indexOfItem(), remove_item_by_name(), isInCart(), array index, boolean, setPriceByName(), arraySet(), longer arrows, layers
8.8 Pattern 1 Review: Straightforward implementation
Reviews how straightforward implementations keep code at a consistent level of detail, using function extraction without merely hiding complexity.
- Single Level of Detail: Explain why mixing levels of detail makes a function hard to read and how a straightforward implementation addresses that problem.
Why it matters: Keeping code at one level of detail makes it easier to read and modify. - Clues for Function Layers: Describe how the call graph, function signature, and body provide clues for placing functions at levels of detail.
Why it matters: These clues help you see the design beyond one function’s code. - General Extraction Without Concealment: Explain how extracting a general function can clarify an implementation, and distinguish that from merely hiding unclear code in helpers.
Why it matters: A clearer caller is not enough if the extracted function remains difficult to understand.
Key terms: straightforward implementations, levels of detail, call graph, function signature, body, layers, extract out, more general function, helper functions, serendipitous reuse
8.9 Conclusion
The conclusion recaps how call graphs reveal abstraction layers and how stratified design uses those layers to build straightforward functions.
- Call graphs and abstraction layers: Explain that visualizing code as a call graph helps reveal distinct layers of abstraction.
Why it matters: Seeing the layers gives you a way to think about how the code is organized. - Straightforward layered implementations: Explain that the first pattern of stratified design is to find straightforward implementations, using the layer structure to build simple functions out of other simple functions.
Why it matters: This is the main design pattern the chapter wants you to carry forward.
Key terms: call graph, layers of abstraction, stratified design, straightforward implementations, layer structure
8.10 Summary
8.11 Up next…
This section previews the next chapter’s additional patterns based on code layers.
Where this is used later
- Pattern 2: Abstraction barrier (chapter 9) · Develops the abstraction barrier pattern.
- Pattern 3: Minimal interface (chapter 9) · Develops the minimal interface pattern.
- Pattern 4: Comfortable layers (chapter 9) · Develops the comfortable layers pattern.
- Patterns of stratified design (chapter 9) · The earlier treatment of straightforward implementations
- What does the graph show us about our code? (chapter 9) · Interpreting what a call graph shows about the code.
- Abstraction barriers hide implementations (chapter 9) · The distinction between an exposed array index and a data-structure-independent boolean supports the discussion of hiding implementations.
- Our code is more straightforward (chapter 9) · The later section revisits whether the code has become more straightforward.
Concepts explained in this chapter
- straightforward implementationA software implementation pattern that expresses behavior with operations at similar levels of abstraction while omitting irrelevant lower-level details.
- call graphA graph representation in which program entities are connected according to which functions or procedures call which others.
- stratified designAn architectural pattern that organizes software into layers ordered from relatively stable foundations to more frequently changing elements.
- indexingA numeric position identifying an element within an indexed array.
- linear searchA search algorithm that examines elements sequentially until a matching element is found or the collection is exhausted.
- comfortable layerA stratified-design pattern in which abstraction layers are added and shaped to support programmer productivity and software quality rather than abstraction for its own sake.
- minimal interfaceA stratified-design pattern in which important business concepts are represented by a small, powerful set of operations from which other operations can be constructed.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
