Chapter 5: Improving the design of actions
The chapter introduces why improving actions means reducing, rather than eliminating, their implicit inputs and outputs.
After this chapter you will be able to
- Partial reduction of implicit dependencies. Explain why actions remain necessary even though reducing their implicit inputs and outputs can improve their design.
- Business-aligned function inputs. Explain why get_free_shipping() takes the wrong arguments for the question it is meant to answer. Describe why choosing a useful abstraction requires more than mechanically extracting a calculation.
- Cart-based free shipping decision. Explain that gets_free_shipping() now takes a cart and returns whether its total is at least 20, rather than taking a total and a price. Describe why callers of the old signature must change.
- Implicit and explicit function boundaries. Distinguish implicit inputs and outputs from arguments and return values. Explain that calculations have no implicit inputs or outputs, while actions can still benefit from eliminating as many as possible.
- Modularity reuse and testability. Explain how implicit inputs and outputs restrict when a function can run and make it harder to reuse and test. Describe why converting them to explicit ones makes the function more modular.
- Explicit arguments instead of globals. Explain how to replace a function’s implicit input with an argument and why its caller must then pass that value. State that this change alone does not necessarily turn an action into a calculation.
- Shopping-cart action cleanup. Explain why shopping_cart_total and calc_cart_total() can be removed, and describe where the function’s code goes.
- Calculation groups and meaning. Describe how to label calculations as cart operations, item operations, or business rules, and explain what the grouping reveals about the code.
- Separation through smaller functions. Explain how functions separate concerns by separating a value supplied as an argument from how that value is used, and why separated pieces can be composed again.
- Separate item and cart structure. Explain why pulling item creation out of add_item() improves its design: one function handles the item’s structure, while another handles the cart’s structure.
- Reusable copy-on-write array utility. Explain how giving the extracted function and its arguments generic names makes the operation useful beyond shopping carts, while keeping add_item() simple.
- Updated add_item() calls. Describe how callers use the new add_item() signature: construct an item separately, then pass the cart and item to add_item().
- Function knowledge categories. Distinguish cart operations, item operations, business rules, and array utilities by what each function knows or does. Explain why a cart operation may be generic to e-commerce stores while a business rule may be specific to MegaMart.
- Shipping icon responsibility groups. Describe how the work in update_shipping_icons() can be grouped into button, cart-and-item, and DOM operations, and what the proposed separation achieves.
- Action Classification Rule. Explain why a function containing an action is classified as an action, even if it contains other kinds of code.
- Actions and data structure boundaries. Explain the design improvement described in the conclusion: actions no longer need to know the structure of the data, and useful, reusable interface functions are emerging.
What it builds on
- Extracting a calculation from an action (chapter 4) · Extracting a calculation from an action by eliminating implicit inputs and outputs.
- Functions have inputs and outputs (chapter 4) · Introduces function inputs and outputs.
- Testing and reuse relate to inputs and outputs (chapter 4) · Relates testing and reuse to function inputs and outputs.
- Actions spread through code (chapter 3) · Actions can spread through code.
Section by section
Introduction
The chapter introduces why improving actions means reducing, rather than eliminating, their implicit inputs and outputs.
- Partial reduction of implicit dependencies: Explain why actions remain necessary even though reducing their implicit inputs and outputs can improve their design.
Why it matters: You can improve an action without trying to turn every action into a calculation.
Key terms: actions, calculations, implicit inputs and outputs
5.1 Aligning design with business requirements
The section shows why mechanically extracting a calculation may leave a function poorly aligned with the business question, and identifies duplicated logic as a design warning.
- Business-aligned function inputs: Explain why get_free_shipping() takes the wrong arguments for the question it is meant to answer. Describe why choosing a useful abstraction requires more than mechanically extracting a calculation.
Why it matters: A function is easier to use when its inputs match the question the business is asking. - Duplicated price addition: Describe the duplicated calculation the section points out and why reusing calc_total() is proposed. Explain what the section means by a code smell.
Why it matters: Spotting duplicated logic can reveal an opportunity to improve the design without assuming every duplication is a bug.
Key terms: level of abstraction, get_free_shipping(), current cart, new item, duplication, code smell, calc_total()
5.2 Aligning the function with business requirements
The section changes the free-shipping function to answer a question about a shopping cart, then discusses the design tradeoffs of small calculations and copying the cart.
- Cart-based free shipping decision: Explain that gets_free_shipping() now takes a cart and returns whether its total is at least 20, rather than taking a total and a price. Describe why callers of the old signature must change.
Why it matters: A function that speaks in terms of carts directly expresses the decision the business needs. - Modified cart copy tradeoff: Describe how the calculation uses a modified copy of the cart without changing the existing cart, and explain the section's response to the cost of copying.
Why it matters: The section explains why preserving the original cart can be worth a copying cost. - Small calculation design benefits: Explain why an increased line count does not, by itself, make this design harder to maintain.
Why it matters: It gives the reader a way to evaluate the design beyond counting lines.
Key terms: gets_free_shipping(), cart, signature, modified copy, add_item(), cart array, lines of code, small functions, calculations, cohesive
5.3 Principle: Minimize implicit inputs and outputs
Defines implicit inputs and outputs and explains why reducing them makes functions, including actions, easier to reuse and test.
- Implicit and explicit function boundaries: Distinguish implicit inputs and outputs from arguments and return values. Explain that calculations have no implicit inputs or outputs, while actions can still benefit from eliminating as many as possible.
Why it matters: This distinction lets you improve an action without requiring it to become a calculation. - Modularity reuse and testability: Explain how implicit inputs and outputs restrict when a function can run and make it harder to reuse and test. Describe why converting them to explicit ones makes the function more modular.
Why it matters: Fewer hidden connections give you more freedom to call, reuse, and test a function.
Key terms: implicit inputs, implicit outputs, arguments, return value, calculations, actions, modular, testability, reusability
5.4 Reducing implicit inputs and outputs
This section applies the principle of minimizing implicit inputs by replacing global-variable reads with function arguments and updating callers.
- Explicit arguments instead of globals: Explain how to replace a function’s implicit input with an argument and why its caller must then pass that value. State that this change alone does not necessarily turn an action into a calculation.
Why it matters: Making an input explicit shows what value the caller supplies without assuming the function has become a calculation.
Key terms: implicit input, explicit input, argument, global variable reads, action
5.5 Giving the code a once-over
The section gives the shopping-cart actions a final cleanup by removing an unused global variable and inlining an unnecessary function.
- Shopping-cart action cleanup: Explain why shopping_cart_total and calc_cart_total() can be removed, and describe where the function’s code goes.
Why it matters: These cleanups leave fewer unnecessary pieces in the actions before examining their design further.
Key terms: shopping_cart_total, calc_cart_total(), add_item_to_cart(), inline
5.6 Categorizing our calculations
The section groups shopping-cart calculations by what they know or do, showing how those groups can become layers of meaning in the code.
- Calculation groups and meaning: Describe how to label calculations as cart operations, item operations, or business rules, and explain what the grouping reveals about the code.
Why it matters: The labels help you notice different responsibilities in the calculations without needing to redesign them yet.
Key terms: cart operation, item operation, business rule, layers of meaning
5.7 Principle: Design is about pulling things apart
The section presents pulling functions apart as a design principle and explains why smaller functions are worth trying.
- Separation through smaller functions: Explain how functions separate concerns by separating a value supplied as an argument from how that value is used, and why separated pieces can be composed again.
Why it matters: Separating concerns gives you smaller pieces without losing the ability to use them together. - Benefits of extracting functions: Describe why smaller functions can be easier to reuse, maintain, and test, and why an extraction may be worth trying even when no problem is apparent.
Why it matters: An extraction can improve the design even before a function causes an obvious problem.
Key terms: separate concerns, argument, composed back together, reuse, maintain, test, extract
5.8 Improving the design by pulling add_item() apart
The section separates item creation from cart updating in add_item() while keeping the copy-and-modify steps together as copy-on-write.
- Separate item and cart structure: Explain why pulling item creation out of add_item() improves its design: one function handles the item’s structure, while another handles the cart’s structure.
Why it matters: A change to the cart’s representation can then require fewer changes elsewhere. - Copy and modify together: Describe why the copying and modifying steps remain together after item creation is pulled out.
Why it matters: Pulling a function apart does not mean separating steps that work together to preserve immutability.
Key terms: add_item(), structure of items, structure of carts, copy-on-write, immutability
5.9 Extracting a copy-on-write pattern
This section turns a shopping-cart-specific array operation into a reusable copy-on-write utility.
- Reusable copy-on-write array utility: Explain how giving the extracted function and its arguments generic names makes the operation useful beyond shopping carts, while keeping add_item() simple.
Why it matters: Recognizing a generic operation lets you reuse it instead of repeating cart-specific code.
Key terms: copy-on-write discipline, add_item(), utility function
5.10 Using add_item()
Shows how callers change after add_item() is refactored to accept an item instead of separate name and price arguments.
- Updated add_item() calls: Describe how callers use the new add_item() signature: construct an item separately, then pass the cart and item to add_item().
Why it matters: The refactoring works only if callers pass arguments in the form the new function expects.
Key terms: add_item(), cart, item
5.11 Categorizing our calculations
The section categorizes calculations by what they know and uses the shipping-icon function to practice separating different responsibilities.
- Function knowledge categories: Distinguish cart operations, item operations, business rules, and array utilities by what each function knows or does. Explain why a cart operation may be generic to e-commerce stores while a business rule may be specific to MegaMart.
Why it matters: These categories make it easier to see which concerns a function combines. - Mixed business and cart concerns: Explain why a function can currently be both a business rule and a cart operation, and why that combination may be a code smell.
Why it matters: Spotting a mixed concern helps explain why a function may be worth revisiting as business rules change. - Shipping icon responsibility groups: Describe how the work in update_shipping_icons() can be grouped into button, cart-and-item, and DOM operations, and what the proposed separation achieves.
Why it matters: Grouping work by responsibility makes a large function’s different jobs visible.
Key terms: cart operation, item operation, business rule, array utility, code smell, update_shipping_icons(), buy button operations, cart and item operations, DOM operation
5.12 Smaller functions and more calculations
The section applies action, calculation, and data labels to the new code and reiterates that one action makes an entire function an action.
- Action Classification Rule: Explain why a function containing an action is classified as an action, even if it contains other kinds of code.
Why it matters: This rule keeps the A, C, and D labels consistent when a function contains mixed code.
Key terms: action, calculation, data, A, C, or D
5.13 Conclusion
The conclusion highlights how the design changes have organized the shopping-cart code, while deferring further bugs and immutability to later sections.
- Actions and data structure boundaries: Explain the design improvement described in the conclusion: actions no longer need to know the structure of the data, and useful, reusable interface functions are emerging.
Why it matters: It captures the design benefit the chapter has achieved before moving on.
Key terms: actions, structure of our data, interface functions
5.14 Summary
5.15 Up next…
This section previews the next two chapters on immutability and a later return to design.
Where this is used later
- The three steps of the copy-on-write discipline (chapter 6) · Introduces the copy-on-write discipline behind making changes without modifying the original.
- Converting a global variable to an argument (chapter 15) · The principle of minimizing implicit inputs and outputs.
- Making our code more reusable (chapter 15) · The distinction between implicit and explicit outputs.
- Production: Eliminate a bug today (chapter 19) · Recognizing implicit inputs and outputs when examining functions
- What is stratified design? (chapter 8) · Develops the idea of layers in software design.
- What to do if an operation is a read and a write (chapter 6) · The design principle of pulling things apart.
- Swapping the shopping cart’s data structure (chapter 9) · Changing the shopping cart’s data structure builds on separating cart-specific knowledge from item-specific knowledge.
- Can immutability be applied everywhere? (chapter 6) · Previously introduced a copy-on-write pattern.
Concepts explained in this chapter
- mathematical calculationA calculation is a category of code that deterministically computes a result from its inputs without directly interacting with the outside world.
- code smellA code smell is a characteristic of source code that may indicate deeper design or maintenance problems.
- cart operationA computation that operates on a shopping cart while depending on the cart's structural representation.
- item operationA computation that operates on an item while depending on the item's structural representation.
- validation ruleA rule that specifies behavior or constraints within the problem domain modeled by software.
- implicit inputAn input obtained by a computation from surrounding state or context rather than supplied explicitly as a function argument.
- implicit outputAn effect of a function that changes external state or performs an observable operation rather than returning the result directly.
- shopping cartA collection associated with an online purchase that holds selected items and their quantities before checkout.
- immutable collectionData or state whose represented values cannot be modified after creation.
- copy-on-writeA data-management technique that creates a copy before modifying data so the original remains unchanged.
- reuseThe practice of using existing code in multiple places or contexts instead of duplicating its implementation.
- explicit inputAn input to a function that is supplied directly at the call site through an argument or parameter.
- return valueThe value produced as the result of a function invocation.
- actionAn action is a computation whose observable result depends on when or how it is performed and may involve effects beyond producing a value.
- dataAn inert representation of information that requires interpretation to acquire meaning and can be stored or transmitted.
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.
