Let's continue our series of short posts about code refactoring! In it, we discuss technics and tools that can help you improve your code and projects.
Today we will discuss how to use Git to make refactoring easier and simplify future work with the code.
Use Small Atomic Commits
As we discussed previously, during refactoring, we want to avoid big change sets.
Small commits help us by splitting a large chunk of work into smaller and simpler ones. The smaller the change, the easier it is to evaluate it and find issues in it.
Commits become atomic if they represent an independent unit of work. Basically, we can say that if a commit evolves a code base from one valid and working state to another valid and working state, this commit is atomic.
Atomic commits help us with switching to other tasks at any point in time since the code always works and can be built.
When we make our commits both atomic and small, we make it easier for the reviewer to review the changes and at the same time make it possible for us to switch between different tasks even if the refactoring isn't yet finished. The project development becomes more flexible and safer.
Evaluate Changes with Diffs
Before making a commit, take a look at the changes in the diff. Check if the diff contains only the updates you want to stage.
Sometimes developers get distracted from their work and miss the moment when the commit starts containing something unrelated to the current task.
It's especially true when we use automated refactoring tools in the IDE or automated code formatters and linters.
For example, a formatter might update code in a different way than we expect from it:
// Before applying the formatter:
function setDiscount(discount) {
if (user.isVip) order.discount = discount, order.total -= discount
}
// After:
function setDiscount(discount) {
if (user.isVip) (order.discount = discount), (order.total -= discount);
}
// What we actually want:
function setDiscount(discount) {
if (user.isVip) {
order.discount = discount;
order.total -= discount;
}
}
In the diff, we can see what exactly changes and decide if we want this change to be staged:
Stash Changes to Switch Tasks
When refactoring in small steps and using atomic commits, it's easier to switch from refactoring to another task using git stash
.
Stashing helps us save the progress we've made and switch to another branch or roll the code back to the last working state.
It allows us to check out another branch to fix a sudden bug or test a hypothesis about the code without losing any work done during the refactoring session.
Prepare for Future Bisect
In “97 Things Every Programmer Should Know”, there's a chapter named “Know Your Next Commit”.
It describes the idea of building a narrative out of the commit messages. This narrative can help us in the future when debugging the code.
One of my favorite technics of debugging is using bisection. That is going through the commit history using binary search and checking what commit introduced the bug.
When refactoring, we can embrace this idea and think about our commits beforehand so that the future history is clean and convenient to use.
For example, we can:
- Use only one refactoring technic per commit;
- Avoid adding features or fixing bugs;
- Or use
stash
andrebase
to reorder changes in a way that makes more historical sense.
And, of course, always keep in mind the main idea of why we do it.
More About Refactoring in My Book
In this post, we discussed Git and how to use it for making refactoring easier but only scratched the surface of the topic of refactoring in general.
If you want to know more about refactoring and improving your code, I encourage you to check out my online book:
The book is free and available on GitHub. In it, I explain the topic in more detail and with more examples.
Hope you find it helpful! Enjoy the book 🙌
Top comments (0)