Chapter 7

Compose Flat, Never Deep

Every super() call is a question you're asking a class you can't see.
Demo: Render a user profile page: inheritance chain vs flat pipeline
☠ 4-level inheritance: super() bouncing
BaseComponent.render()
AuthComponent.render()
DataLoader.render()
UserProfilePage.render()
Direction changes: 0
super() calls: 0
✦ Flat pipeline: linear data flow
authenticate(req)
validate(req.params)
load_user(user_id)
render_profile(user)
Direction changes: 0
super() calls: 0
0
Stack direction changes
0
Stack direction changes
0
super() calls
0
super() calls

What you just saw

The left panel is a four-level class hierarchy. UserProfilePage extends DataLoader extends AuthComponent extends BaseComponent. When render() is called on UserProfilePage, it calls super().render() which bounces up to DataLoader, which calls super().render() which bounces up to AuthComponent, which calls super().render() which bounces up to BaseComponent. BaseComponent finally does its work and returns. Control flows back down through each level. The call stack goes down, up, down, up, down, up, down. Seven direction changes. Four super() calls. To understand what UserProfilePage.render() actually does, you must read four files and trace the execution through all of them.

The right panel is a flat pipeline. The request passes through authenticate, then validate, then load_user, then render_profile. Each function receives data and returns data. Control flows in one direction: forward. Zero direction changes. Zero super() calls. To understand what happens, you read the pipeline top to bottom.

How this works: This demo visualizes control flow complexity, not timing. The inheritance chain bounces up and down through super() calls (7 direction changes). The flat pipeline flows in one direction (0 direction changes). Counts are architectural facts. Source: github.com/adamzwasserman/honest-code-traces
← Ch.6: Declare, Don't Instruct Ch.8: Let It Crash →