In the middle of a major change to the Leaf type system I encountered the refactoring demon. It reared it’s ugly little head chanting, “you’re doing it wrong, all wrong!” It was probably right, but there was no way to know until I was done. Seeing my determination did not sway the demon. Instead it started pointing out all the other changes I should be making instead.
Avoiding the big refactor
First off, problems like these are why I avoid refactoring that requires a lot to change at once. I much prefer coming up with small steps, where the test suite can be run after each change.
Alas, sometimes a big change is required. My change in Leaf was about how parametric types are handled. Trying to implement a feature I hit a block. There was just no way to reasonably introduce the feature that wasn’t either very messy, or involved a large change in the the type system. I deliberated until I convinced myself the change was the right thing to do.
Just a few hours into these changes I noticed other problems with the code. A lot of things started to crop up, things that could be done better. Things that would make everything easier. I even started doubting whether my approach was correct at all. Already demotivated, I came to another dissatisfying realization: my type identifier code was too hard to read and highly redundant as well.
I had a few basic options. I could carry on and come back to the issues later. Or I could rollback my current refactoring and do the other reductions first.
Carrying on with the parametric refactoring had these considerations:
- I already invested a lot of time in this refactoring. It’s something that has to be done anyway.
- It was a clear goal to work towards and would implement a concrete feature.
- A lot of the work would however be discarded by the next refactoring.
- I was putting in lots of strange hacks to work around issues the other refactoring would fix.
- Some of the tests had to be commented out since a proper solution could not be found.
- There’s technically nothing wrong with this refactoring.
Stopping this effort and doing the reductions first had these considerations:
- It would significantly reduce the work I needed to implement the parametric feature.
- The type identifier code would be a lot easier to understand, and could produce cleaner rules for the type system.
- The code would be significantly reduced.
- Though smaller it was also a rather large change.
- It didn’t include a semantic change to the system, thus would involve less tricky decisions.
At this point it wasn’t a matter of whether either refactoring should be done, I was convinced that both of them were needed. It was just very problematic that the work involved in one would significantly alter the other. Indeed, the parametric refactoring would be a whole lot easier if the reduction was done first.
Neither solution was great. These frustrating realizations can be depressing and lead to a code paralysis where nothing gets done. I took a step away from the machine for a while. I built a small shelving unit for my desk; wood presents a much simpler set of challenges than compiler code.
After more reflection I decided to continue with the parametric refactoring. It offered a real new feature in the system, as opposed to a pure refactoring. This was my primary consideration. I did not wish to abandon the work done so far to go traipsing about in refactor land.
To avoid losing too much time on code that would become redundant, I decided to simplify my effort. I’d take the questionable approach of hacking it to completion. I just turned a blind eye to any other issues I saw in the code. I used a few too many if statements. I commented out a few unit tests. I left the type identification code in a worse state than when I started.
I managed to complete the change. The new feature even functioned as desired without further work. That made me quite happy. Sure, I left a bunch of holes in the code, but the high-level language tests all worked.
Now I just need to do the reduction refactoring. I presume the little demon is waiting for me.
In my programming journeys I’ve seen oddities and curiosities of all sorts. Getting things done is always the primary goal, but it can be daunting at times. If your project needs some assistance getting through a tough spot, then contact me to see how I can help.