Count responsibilities, not just lines
A function that validates an order, changes inventory, calculates a total and prints a receipt is difficult to reuse for a preview. The problem is its mixed responsibilities, not simply its line count.
function calculateSubtotal(priceCents, quantity) {
return priceCents * quantity;
}
function formatSubtotal(subtotalCents) {
return `Subtotal: ${subtotalCents} cents`;
}
const subtotalCents = calculateSubtotal(500, 3);
console.assert(subtotalCents === 1500);
console.assert(formatSubtotal(subtotalCents) === "Subtotal: 1500 cents");
Calculation and formatting return values. Printing is an effect performed by the caller. A side effect changes or interacts with something outside the function's returned value, such as shared state, files or console output. Effects are necessary at some boundaries, but should be intentional.
Guided comparison
Extracting multiplyTwoNumbers solely to wrap * may not communicate a business responsibility. CalculateSubtotal gives the same arithmetic a domain meaning. Conversely, a function that coordinates several clear steps can be longer while still having one responsibility: prepare a quote.
Independent exercise
A preview calls a function that reduces stock. Explain why this boundary is wrong and propose a separation. Which operation should be testable without changing inventory?
Correction
Preview calculation should return a quote without committing a sale. A separate confirmed-sale operation can update stock under its own rules. The calculation can be tested repeatedly without changing the next test's initial state.
Review
Ask whether a caller can understand and use a function without inheriting unrelated actions. Prefer local reasoning and explicit inputs over arbitrary rules such as "every function must be fewer than five lines."