loading...
Cover image for The Life-Changing Magic of Refactoring

The Life-Changing Magic of Refactoring

martingaston profile image Martin Gaston ・4 min read

There's a drawer underneath my desk I use to store all the little bits and bobs I randomly accrue, rarely use but don't really feel like getting rid of. But the contents of this drawer also have a naughty habit of escaping this space, then promptly spreading around my desk, office and eventually the rest of the flat.

In a perfect universe I'd find a way to efficiently store all this junk. Still, there's no need to be too dogmatic about it. This is the real world. Sometimes you've just got to cram half the contents of your living room into a cupboard because you've got guests coming over.

In our coding lives, this is called refactoring: applying small changes to our code in order to spruce up our design without changing the core functionality. Still, refactoring? I find the word a little cold, almost mathematical - it gives me feelings of a scholarly, scientific process. I think it sounds precise and clinical and, well, like it's absolutely no fun whatsoever. It feels like work.

There are fantastic reasons why many smart people have helped create a common language around code smells and refactoring patterns, of course, and it's not just so that you can try to look smart when you write blog posts. Having shared conventions means you can discuss them in teams, and a common rubric for communicating these ebbs and flows of moving code around creates the comforting dependability of a context. I am incredibly glad the discourse around software design exists, that the software engineers of today can stand on the shoulders of giants and I dream of being able to make even a fraction of the positive impact of these luminaries.

Sometimes, though, all these raw smarts can be a bit of a drag. With so many formal and complicated-sounding names, even approaching a discussion about a refactoring pattern can be intimidating for new programmers. Then they're often explained with some too-good-to-be-true examples that are hard to contextualise within your current work, which has always left me reeling - how do I apply that beautiful pattern to my actual code? I also think it's really hard to see why you should use a refactoring pattern until you've been stung by it. I'm intimated into sheer indecision.

But, really, refactoring is just doing a bit of tidying up. It's deciding to do the dishes before you're down to your last big plate, or making sure you've loaded the dishwasher before bed so you don't have to deal with it in the morning.

I'm terrible at examples, so let me pluck out quite literally what I'm working on as I write this. I was rushing to implement a feature to pass a test (if Java can find an "app.port' System Property then a server will bind to that port number) and threw in the below:

public static void main(String[] args) throws IOException {
    Connection connection;  
    if(System.getProperty("app.port") == null) {
        connection = new Connection();
    } else {
        int port = Integer.parseInt(System.getProperty("app.port")); 
        connection = new Connection(port)
    }  
    Server app = new Server(connection);  
    app.start();  
}

The tests pass. Awesome. I won't pretend that 75% of me wasn't super ready to just git commit and go for lunch. But no! There was time for a spot of cleaning.

So, first - I don't like doing anything in main other than setting up classes, so I felt like extracting most of the if statement would make the code easier to read for Future Me.

public static void main(String[] args) throws IOException {
    var connection = makeConnection();
    var app = new Server(connection);
    app.start();
}

Sure, that's just moving code around. But chunking our code down into smaller functions usually has the side-effect of making our work easier to test, maintain and extend. Now, my next step was to make all that boolean logic a little more expressive and more communicative of our intent.

private makeConnection() throws IOException { 
    if (hasSpecifiedPort()) {  
        int port = getPort();  
        return new Connection(port);  
    }   

    return new Connection();
}

private static int getPort() {  
    return Integer.parseInt(System.getProperty("app.port"));  
}  

private static boolean portIsSpecified() {  
    return !Objects.isNull(System.getProperty("app.port"));  
}

We've just extracted something in our extraction! Wow. Achingly meta. But now makeConnection doesn't really have to worry about what Java System Property we're fishing for, or the specifics on obtaining it. It simply... gets on with it.

Our if statement has also been tweaked to just bail early if it matches. That's a little refactoring I really enjoy because it gets us out of our braces, which - as someone mid-way through Invisalign right now - is a good thing indeed.

That's only a couple of simple steps, and if I'm being honest IntelliJ did most of the work there. But after doing just a couple of little steps, I was ready to git commit. Then I had a sandwich. It was delicious, thank you.

"Wait", you might be thinking. "Don't you have any more extravagant examples of, say, refactoring an Elixir module using Structs and Protocols to achieve polymorphism?" you plead, teary-eyed, coincidentally thinking about the immediate last project I was working on. "Please," you beg, "aren't there some more complicated patterns you could apply?"

And, well, sure. There's plenty of example of those, most of which are birthed from the tome of Refactoring. Yet I argue that, sometimes, that's not the point. Especially when deadlines, project managers and the need for lunch breaks come into play. We should celebrate each of our little wins, not worry too much about how a few dozen of those wins makes for a fascinating example of before and after.

I'd say it's always worth doing the little nips and tucks we can achieve today rather than trying to train ourselves to do the bigger, meatier, more interesting refactorings we promise we'll do tomorrow - a tomorrow that, if we're being honest, might never happen.

Refactoring is a broad church, but I think it's worth remembering how it always comes down to just taking that one item off that chair in your house you use for piling stuff onto; the one that you tell yourself is just being used to hold that pile of books temporarily.

The little changes? That's how we spark joy.

Posted on by:

martingaston profile

Martin Gaston

@martingaston

Polyglot developer taking the midnight train going anywhere

Discussion

pic
Editor guide