Refactors are a necessary part of coding. Even the best code will need updates given enough time. It’s the nature of software.
Refactors also tend to become bottomless pits. What felt like a small refactor suddenly has you looking this way and that way with more things to refactor.
It can be like trying to untangle a rope. You might spend all this time working to undo a knot, think you’ve knocked it out, and then you find another one.
Or maybe you have been the author on a code review. Your work has a deadline, and you have pressure from your manager to complete it soon. Yet, your reviewer mentions she thinks you might be able to refactor something.
You are between getting your work, which you’ve worked hard to complete, merged on time, or doing a refactor “just cause.” You see your reviewer’s points, though, and the proposed changed will make the code a little bit better. Yet you are worried about how long those changes might take.
Perhaps you have been working on a crucial diagram to show your team’s service architecture. You’ve been struggling to get it “just right” and are having a hard time committing to a specific layout of the components.
In all these cases, we can apply some ideas from Agile to help out.
Timeboxing is pretty much exactly what it sounds like: you limit the amount of time you work on a task. Simple.
Instead of working until something is “done,” you work on something for fixed and agreed upon amount of time and evaluate the work completed. At that point, you can decide to continue the work, deliver what you have, or abandon what you have accomplished.
The definition given by the Agile Alliance is this:
Rather than allow work to continue until the goal is reached, and evaluating the time taken, the timebox approach consists of stopping work when the time limit is reached and evaluating what was accomplished
Of course, the hard part now isn’t finishing something. Instead, the new difficulty is the evaluation process. You now must decide if what to do with the completed work. A question might be, “Is this work good enough?”.
Is It Good Enough?
One common question in every form of craft is this: “Is it good enough?”.
And unfortunately, it is a HARD question to answer.
You could spend ALL of your time coming up with a better design if you had to. You could review and re-write your documentation every day and still find a better way to communicate an idea.
Musicians want to do if that melody is good enough to capture the emotion they want. The painter wonders the same about the colors they used. The novelist is always wondering if a character is “real” enough…
The gap between “do more” and “good enough” is infinite. You can still do more.
Is It Good Enough Now?
Software has a unique temporal component, though. We get to make changes all the time. Building a software solution is like painting a picture while viewing it as it hangs on the wall and knowing how it will be re-painted a few weeks.
With that in mind, a better question around the “good enough” issues can arise. Instead of asking, “Is this good enough” ask, “Is this good enough for right now?”.
This question is a go-to for me. Whenever I am reviewing a pull request, doing a refactor, or even designing an architecture, this question drives a lot of my decisions.
Where I find this question the most useful, and I expect you will too, is concerning actual code or documentation under review. Someone has written some code for a user story or bug and is asking for a code review. Or maybe someone is asking for a review of their diagram. Or someone has been writing up an RCA for a problem you experienced last week and wants input.
In these situations, asking “ is it good enough for right now” comes into play. Let’s assume the work under review looks pretty good. It meets requirements, but there are a few things that could be better but don’t necessarily need to be. There could be more clarity around one particular topic. There could be a crisper abstraction. There could be a way to apply a pattern that could be useful later.
At this point, you are evaluating the trade-offs. Is it worth the effort to redo or incorporate your feedback? You might be able to re-work — read: refactor — that function in a few minutes, but it might take your colleague longer. Maybe re-working that paragraph in the documentation would throw the rest of the surrounding sections off, and those would then need to be redone, etc.
Now, of course, there are many times work needs to be redone! It simply isn’t good enough. Not right now and not ever!
I have found this to be especially true in the realm of architecture. Many solutions simply won’t support the business needs. If you have to have high availability, you can’t only have one instance in your architecture. Even if its easier to have one running, it won’t cut it.
Back to those solutions that are good enough to ship, but you still have some recommendations. How do you ask the author who asked for your feedback to tackle it? How do you take into account deadlines?
Suggest a timebox.
Instead of merely saying “redo this” or saying “ship it,” you can agree with the author on an amount of time to try a suggestion or two. Maybe it’s a few hours. Perhaps it’s just one. Or maybe it’s just the end of the day.
Whatever timebox you decide, remember its a compromise. It’s between you and the author. They have work they want to deliver, and your recommendations are technically keeping them from doing so. This conversation can take into account how long they have been working on it, deadlines, and even skill level.
As an example, I was reviewing a pull request from a junior developer. We build a lot of Spring Boot applications, and I saw a way that we could modify some classes to use Spring properties more effectively. He had limited experience with it. When I suggested we re-work it, we had a good conversation. He mentioned that he had a deadline for the work to be done end of the day tomorrow and was nervous about attempting to do a refactor late in the game.
Instead of making a hard yes/no decision, we decided he would spend the rest of the day attempting to do the refactor on a separate branch after he addressed any blocking feedback. It was about 2:00 or so when he stared the refactor. At about 4:30, he decided to call it quits since he was having trouble figuring it out. We agreed to merge the work he had working, and we could walk through the refactor problem the next day.
The next day, we got together reviewed where he had reached the day before. I was able to walk with him through the suggestions I had made. Within an hour, we figured it out together. We opened a pull request that included only this new refactor and had it merged by lunch.
Timeboxing the initial work lead to us a few awesome outcomes:
- Getting the working solution in place. Getting the immediate need completed first allowed us to meet our deadline confidently before trying a ton of re-work.
- Alleviating stress. Timeboxing allowed this junior developer to focus on learning and experimenting rather than worrying about a deadline.
- We still got the re-work done before deployment time! We set ourselves up to quickly finish the re-work the next day since it was in a separate git branch. Getting both the initial work and re-work complete before deployment time doesn’t happen every time, but in this case, it did.
In closing, timeboxing tasks can help you stay productive. Timeboxing can be especially useful for tasks and work that are “good enough for right now” like refactors or general reworking through an idea. Its also true for many other tasks like brainstorming, starting something that seems daunting, or finishing sometime you’ve been neglecting.