Skip to content
Back to writing

Zoom In, Zoom Out: Reasoning About Software Systems

A feature can look straightforward inside each component and still be difficult to deliver as a complete business workflow. Inventory returns a quantity. Locations returns an address. The interface displays both. Whether the customer can actually receive the item is a larger question.

I use the idea of Lego pieces when talking about software systems because it helps me think at both levels. I can focus on an individual capability and then step back to consider how it contributes to the whole system. When a feature request arrives, that movement also helps me reason about what is reusable and what work remains.

Neither view is sufficient alone. The details explain what a piece can do. The complete workflow explains whether that behavior serves the business request.

Give the whole system a concrete purpose

Consider an illustrative commerce workflow: a customer selects a location and requests pickup of an item. The example is deliberately hypothetical; it makes the reasoning visible without implying a particular implementation or project outcome.

At the macro level, describe the result the business needs. The customer must choose an eligible location, receive an accurate explanation of availability, and know whether the request has been accepted. Operations needs enough information to fulfill that request or resolve an exception.

That description provides a useful frame for the smaller pieces. It also exposes a decision that a component diagram might hide: when does a tentative customer choice become a commitment?

Until that is clear, inventory, checkout, and fulfillment can each implement a reasonable interpretation and still disagree about the same order.

Zoom into one responsibility

Take inventory availability. At this level, the goal is to understand the behavior other parts of the system may rely on.

What does the quantity mean? Which location does it refer to? How recent is it? Who owns the underlying stock record? Can the caller distinguish no stock from an unavailable source?

These questions define the useful surface of the capability. They do not require every caller to understand its database queries or vendor payloads. They require the interface to preserve distinctions that affect the business decision.

For example, returning zero after a timeout may simplify a function's return type, but it tells the customer something the system does not know. Returning an explicit unavailable result lets the larger workflow decide whether to retry, offer another path, or explain that availability cannot currently be confirmed.

Adapter boundaries can contain vendor details while retaining that meaning. A boundary becomes less useful when it hides the very uncertainty the caller needs to handle.

Zoom back out before calling the piece complete

An inventory capability can be internally correct while serving the wrong purpose. It might accurately report a warehouse count, yet omit reservations that matter to a pickup promise.

Follow the customer's path with the result in hand. The customer sees availability, selects a location, spends time completing checkout, and submits the request. What can change between those steps? Which operation checks the final condition? What happens if the chosen location becomes ineligible?

Now follow an exception. If the request was accepted but the response was lost, does the next attempt resume the existing request or create another one? A local success test cannot establish that the complete workflow handles uncertainty correctly.

The macro view identifies which questions matter. The micro view tells us whether the current pieces can answer them. Move between the two until the workflow's promises match the capabilities' actual behavior.

Use the change in scale to locate decisions

The following pairs help keep a design conversation specific:

Looking at one pieceLooking at the complete workflow
What does this result mean?What promise will someone make using it?
What state can this operation change?Which step owns the overall business commitment?
How does this operation fail?Can the customer or operator recover from that failure?
Which inputs does it require?Where do those inputs come from, and can their meaning change?
Can this call be repeated safely?What happens when the entire request is attempted again?

Answering these questions can reveal a missing policy rather than a missing integration. The platform may already know stock levels and locations. It may still lack a decision about which locations may accept a pickup request. That policy needs an owner and an implementation, even though all the relevant data is available.

Keep the pieces understandable inside one application

A Lego piece does not have to be a separately deployed service. Inventory lookup, location eligibility, and order acceptance can be modules within one application, connected through ordinary function calls.

The useful separation is a responsibility someone can name, inspect, and change with understandable consequences. Deployment boundaries need their own justification. Independent scaling or isolation may warrant them; the desire to draw separate boxes does not establish that need.

There is a cost to decomposition as well. Splitting every small operation into a separate abstraction makes the reader assemble too much context. Choose boundaries that let an engineer understand a meaningful decision without navigating the entire codebase.

That is consistent with building around business capabilities: the shape of the business work should help explain the shape of the software.

Leave a path the next engineer can follow

A useful design record should let another engineer trace one successful request and one consequential failure. Record the business promise, the participating capabilities, the ownership decisions, and the assumptions that cross their boundaries.

It does not need to reproduce every implementation detail. It needs to explain why the pieces fit and where their limits matter. If a future feature changes the promise, the engineer can identify which assumptions to revisit.

That same view supports feature estimation. A piece may be reusable in isolation while the larger workflow needs a new decision or recovery path. Seeing both levels gives the team a more defensible account of what remains to be built.

Discuss on Twitter