Day 29 - Extract Method

Today’s task is all about improving readability.

Investigate your larger methods, especially ones longer than 10 lines. Do you see any groups of functionality that could be extracted out into smaller, more clearly named, methods?

For example:

# Sanitize Input

escaped_input = HTML::Escaper.new(input).escape

stripped_input = SpaceRemover.new(escaped_input).run

censored_input = ForbiddenWordCensor.new(stripped_input).run

Here we are doing things that sanitize input, so these could be pulled out into a new method called sanitize_input. Then we could also remove the associated comment, since the name clearly describes what is happening.

def sanitize_input(input)

  escaped_input = HTML::Escaper.new(input).escape

  stripped_input = SpaceRemover.new(escaped_input).run

  ForbiddenWordCensor.new(stripped_input).run

end

By pulling out small, clearly named methods, our code will not require readers to sift through implementation details or rely on comments in order to understand what is being done. It also can help us remove duplicated code, because we can now use this new smaller method again elsewhere.

Take 20 minutes to see if you can find some code that would benefit from this refactor, and if so update it.

I extracted importing a single user from import_users to Imports::UserImport service class following the convention of the codebase. It creates a new user or updates an existing one, so there is a bit of logic involved.

I already do this, and it’s a very nice cleanup

In the codebase I am working on, the challenge was not so much finding an extractable method as finding a small enough chunk that could safely be extractable during the allocated time. :wink: Lots of candidates for Extract Class as well but I didn’t venture there today.

I found a low-hanging fruit in some DB cleanup/backup script, extracted it, and deployed the change.

Found a few places where we were setting up some date predicates that could be extracted to an extension on the predicate type to make it easier to reuse.

Started by extracting some decision-making code into a method. Realised all the subroutines were only being called from this one location.
Refactored all that code into a separate class (trait in PHP).

And because the coverage was 100% for this class (that is fairly code to the application), I felt pretty confident that I did it right.

The project I joined recently did a good job paying attention to this so there were no big findings so far! Or at least where there are longer functions they’re in the right place where it’s okay to have them (think “main” where most things get created and injected).

Picked up work on GitHub - julianrubisch/bridgetown-media-transformation again, and extracted a class that was long overdue…

I realize given this self selected audience, and the name of the technique for today, this audience has likely already encountered “Refactoring” by Martin Fowler. But just in case, if you’re looking for more techniques like this one:

1 Like

My favourite! This always makes your code so much more readable.

The code we work currently on does not have so many large classes as it is based on FastAPI (python web app framework), which is heavily using inversion of control - needed objects are injected as declared in function signature.

It was nice to see, that extracting a method out of another method applies in a way to injected objects too. What would be extracted from a method into another method is here extracted into injected object with corresponding function delivering it.

Tough to find something in the project I was working on the cqc for, a newer project with pretty solid code review. I found something… because I had ignored a suggestion on a previous code review :smiley:

2 Likes

My project is not that complex, but I was brainstorming some ideas based on today’s challenge. :slight_smile:

together with inline, probably my most used automated refactoring in intellij :slight_smile:
Removed some duplication in tests today by extracting methods. 20min well spent.

I found this incredibly hard to do. Maybe it is just for this project, but in hundreds of lines of code across dozens of classes I couldn’t find a single longish method that I could sensibly make shorter by extracting something. I’ll keep trying to get better at this.

One of the other pleasing side-effects of this is that your tests become a lot more self contained. :+1: