From "Refactoring"
🎧 Listen to Summary
Free 10-min PreviewMove Function
Key Insight
The primary goal of moving a function is to improve modularity, enabling modifications to a program with minimal understanding of its entire scope. This involves grouping related software elements and ensuring clear, understandable links between them. As understanding of the software evolves, functions may need to be relocated to better reflect this improved design. Functions exist within a context, such as a global scope, module, or class, and their placement impacts encapsulation and dependency management.
A common reason to move a function is when it references elements more frequently in a different context than its current one; relocating it with those elements enhances encapsulation and reduces module dependencies. Similarly, a function's new location might be dictated by its callers or future enhancement needs. A helper function nested within another might be moved to a more accessible top-level context if it holds independent value, or a class method might be shifted for easier use. Deciding where to move a function involves examining its current and candidate contexts, assessing its callers, called functions, and data usage. If a new context is needed for a group of functions, refactorings like 'Combine Functions into Class' (144) or 'Extract Class' (182) can create it.
The mechanics of moving a function involve several steps, starting with examining all elements used by the function in its current context to determine if they should also move. If a called function needs to move, it is typically moved first to handle dependencies. For polymorphic methods, super- and subclass declarations must be accounted for. The function is copied to the target, adjusted to its new environment (e.g., passing elements as parameters or a reference to the source context), and potentially renamed for clarity in the new context. Static analysis is performed, and the original function is turned into a delegating function before testing. After successful testing, the delegating function can be inlined or removed if its callers can directly access the target. An example illustrates moving 'calculateDistance' and its helpers 'distance' and 'radians' from a nested scope to the top level, passing 'points' as a parameter to the new 'top_calculateDistance' function. Another example shows moving 'overdraftCharge' from 'Account' to 'AccountType', passing 'daysOverdrawn' or the 'Account' object as parameters to the new method.
📚 Continue Your Learning Journey — No Payment Required
Access the complete Refactoring summary with audio narration, key takeaways, and actionable insights from Martin Fowler, Kent Beck.