9.2.2 and 9.2.3 - Refactoring - Inline Method and Move Method - podcast episode cover

9.2.2 and 9.2.3 - Refactoring - Inline Method and Move Method

Nov 13, 202512 min
--:--
--:--
Download Metacast podcast app
Listen to this episode in Metacast mobile app
Don't just listen to podcasts. Learn from them with transcripts, summaries, and chapters for every episode. Skim, search, and bookmark insights. Learn more

Episode description

Software Engineering: A Modern Approach - Chapter 9 - Sections 9.2.2 and 9.2.3 - Refactoring - Inline Method and Move Method (AI-generated summary). Online book available at softengbook.org

Transcript

Welcome back to the Deep dive. Today we're not just talking about code cleanup in general. We're doing a really focused exploration, a surgical strike you might say, into two core refactoring techniques in line method and move methyl. That's right. And we're using Marco Tulio Valente's Software Engineering a Modern approach as our guide. It's all about understanding how these, well, seemingly small adjustments are actually fundamental to building robust, healthy software. Absolutely.

So refactoring just a level set quickly. It's about improving the inside without changing the outside. Precisely improving the design, making it cleaner, more maintainable, easier to work with down the line, all without altering what the software actually does for the user. And our mission today specifically is to unpack inline method and move method. Why do they matter so much? OK, let's stop straight in then with inline method.

Now many developers I think are familiar with extract method pulling code out into a new function. Inline method is well, the opposite journey isn't it? Putting code back. Exactly. It's about taking that separate methods code and folding it directly into wherever it was called from. So. Why would you do that? It feels a bit counterintuitive, like you're undoing organization when is less actually more here. That's the key question, and Valente points to very specific situations.

Primarily it's beneficial when a methods body is incredibly small, like maybe just one or two lines, sometimes even just a single expression. OK, really tiny. Yes, tiny. And crucially, it's also when that method isn't called from many different places, maybe just once or perhaps a couple of times in very close proximity. So it's not providing much reuse benefit anyway. Exactly. In those cases, the typical advantages of a separate method, you know, abstraction, modularity. They're minimal.

Sometimes such a tiny, rarely used method can even add unnecessary complexity, a little bit of indirection that just makes you jump around the code for no real game. Like cognitive overhead, having to keep track of too many tiny pieces. Precisely. It can fragment the logic. You're trying to follow a process and suddenly you have to navigate a way to understand this one tiny step before coming back. Inline method helps consolidate that makes the main flow

clearer. So the practical step is you find these tiny, maybe single use methods, you remove the method definition itself and you just paste it's, well, one or two lines of code directly into the spot or spots where it was being called the call sites. That's the essence of it, cleaning up that sort of micro clutter or maybe premature abstraction. Makes the code feel more direct.

Yes, but it's worth noting, as Valente highlights, inline method is generally less common, maybe less impactful overall than its counterpart extract method. Which makes sense. Usually the drive is to breakdown complexity, not consolidate simplicity, right? But it's still a valuable tool for tidying up when abstraction maybe went a bit too far or wasn't really needed in the 1st place. The. Source had a good clear example, didn't it? Something about writing to a file?

It did a method called write content to file sounds important, but its entire body was just a single line of code. Just one line. Just one, and critically, it was only ever called from one other place, a method called write. So 0 reuse minimal abstraction value. Pretty much. So the developers decided OK, this extra method isn't pulling its weight. They removed right content to file and just put that single line of code directly into the right method.

And the outcome? Simpler code, less indirection, easier to read the right methods, logic straight through, and crucially, no change at all to the external behavior. OK, so that's inline method neatening things up by removing very small underused functions. But sometimes the issue isn't that a function is too small, but that it's, well, in the wrong house entirely. And that brings us to move method. This one feels like it has bigger architectural implication.

Oh definitely. Move method is often a much more significant refactoring. It's about getting functionality to reside in the most logical place. So what's the core problem at solving? Why would a method end up in the wrong class to begin with? It happens often during development or evolution.

You might find a method sitting in, let's call it Class A, but when you look closely, that method uses features, data, other methods from Class B much more heavily than it uses anything from its own Class A. So it's real center of gravity is somewhere else. Exactly. It's more interested in Class B's business than Class A's. It feels misplaced, like keeping your gardening tools in the bedroom closet. They work, but it's not where they belong. Right. And moving them has real benefits.

Huge benefits. According to the source, moving the method to Class B where it belongs does 2 critical things. First, it significantly improves the cohesion of Class A Class A becomes more focused on its core responsibility because unrelated logic has been moved out. Makes sense? Tighter focus. Second, it reduces the coupling between Class A and Class B. Because Class A no longer needs to host this method that heavily depends on B, their

interdependence decreases. Less tangled up, which means changes in B are less likely to break A and vice versa. Precisely. It makes both classes easier to understand, easier to modify independently, and easier to test. That's vital for long term maintainability. So this sounds like it really impacts the overall system modularity. Getting methods into the right classes strengthens those boundaries. It absolutely does.

It's a key technique for improving the architectural health of a system, ensuring responsibilities are clearly delineated. Valente gives an example. I think it was average among medians. Yes, that was it. Right, so this method average among medians was initially found in a class called platform

test util a utility class. Sounds generic, but the method itself calculated the average of medians in an array, A mathematical array focused operation, and crucially, it had basically no connection to anything else in platform test util didn't use its data, didn't relate to its other utility functions, it was just there. Kind of an island within the class. Exactly. It felt like it belonged more with general array operations, so the developers moved it. Where did it go?

They moved it to a different class, potentially a new one called Array util, whose entire purpose was handling array manipulations. Makes perfect sense putting it with its peers, functionally speaking. Precisely. It's now in a class where its purpose aligns with the classes overall responsibility. Yeah, better cohesion, better findability. OK, but moving a method, especially in a big system,

raises A practical issue. What about all the code that was calling the method in its old location? You move the method, say from Class A to Class B. Don't you then have to find and update every single call site? That sounds risky. It can be, yes. The ripple effect is a real concern, but there are standard ways to manage this. If the method was static, it's often simpler. Usually just need to change the class name prefix at each call site so A method becomes B

method. Compilers help find these. OK, static is manageable. What about non static methods or cases where the calling code doesn't already have a reference to an object of Class B? That's where it gets more complex, but there's a very clever common technique mentioned in the source, the forwarding method. Forwarding method, yeah. Instead of immediately deleting the method from the original class, you leave behind a simple version. This version in Class A doesn't

do the work anymore. Its only job is to immediately call the method in its new location Class B. Like a redirect? Exactly like a redirect. So if a client was calling AF and you move F to Class B, you can leave a method F and A that just does return BF, assuming A has a reference to B. So the client code doesn't even need to know the method moved, at least not initially.

Correct. It allows you to make the move internally and then update the client calls gradually, or perhaps only when those clients are modified for other reasons. It decouples the refactoring from the immediate need to update all callers. Much safer in large systems. That's a really pragmatic approach. Makes a big change much less disruptive. Now, you mentioned moving between classes. Are there special kinds of moves within a class hierarchy, like between parent and child classes?

Yes, absolutely. Filente covers these two. When move method happens within an inheritance structure, we often use more specific names. There's pull up method. This is when you move a method from a subclass up into its superclass. OK, why would you do that? Usually because the same method exists duplicated in several sibling subclasses. By pulling it up into the common parent class you eliminate that redundancy. You have 1 shared implementation instead of many copies.

Promotes reuse, simplifies maintenance. Consolidating shared behavior upwards makes sense. What's the opposite? That would be pushed down method, moving a method from a superclass down into one or more of its subclasses. And the reason for pushing down? This is typically done when a method in the superclass is actually only relevant or used by a specific subclass, or maybe just a few. Of them. So it doesn't really belong to all children, right?

Pushing it down to only the relevant subclasses makes a superclass cleaner and more general, and clarifies the behavior is specific to those children. It avoids burdening other subclasses with irrelevant methods. So pull up centralizes commonality, push down localizes specificity, both about getting behavior to the right level in the hierarchy. Exactly. They're crucial for maintaining clean, understandable inheritance relationships.

It's really interesting how these refactorings aren't always isolated actions. You mentioned they can be combined performed in sequence. Yes, very much so. Refactoring is often an iterative process combining techniques to achieve a larger goal. The source gives a nice little example of this. How does that work? OK, imagine you start with a method F in Class A, and inside F there are two chunks of work. Let's call them statement S1 followed by statement S2.

OK, F does S1 then S2. Now you might look at S2 and think that's a distinct piece of logic. So your first step could be an extract method. You pull S2 out into its own new method, say G still within Class A. So now F just does S1 and then calls this G. Exactly. But then you look at this new method G and you realize based on what it does, maybe it's actually more related to Class B uses BS data or services. So the extraction revealed a misplaced responsibility. Precisely.

So the next step is a move method. You move method G from Class A over to Class B OK, so the final state is Method F in Class A still does S1, but now instead of calling this dot G, it calls BG, invoking the method on an instance of Class B. Wow. So extract followed by move. Two smaller steps to achieve a significant structural change, Yes. It shows how you can use these refactorings like building blocks. You don't have to refactor the

whole world at once. Small, deliberate steps, often combining techniques, lead to much better, more maintainable designs overtime. That really highlights the craft involved. It's not just banging out code, it's thoughtfully shaping it, making it easier to understand, maintain and evolve later on. So wrapping up our deep dive today, we've seen inline method as a way to clean up tiny,

underused functions. And move method is a really powerful technique for getting functionality into the right class, boosting cohesion and cutting down problematic dependencies. And it's crucial to remember these aren't just cosmetic changes. Refactoring like this is fundamental to managing technical debt and ensuring software can adapt to future needs. It's about building systems that last. Thank you for joining us on this deep dive.

Transcript source: Provided by creator in RSS feed: download file
For the best experience, listen in Metacast app for iOS or Android