More years ago than I’d care to admit, I took a software engineering course as part of my graduate CS program. At the time, I worked a full-time job during the day and did remote classes in the evening. As a result, I disproportionately valued classes with applicability to my job. And this class offered plenty of that.
We scratched the surface on such diverse topics as agile methodologies, automated testing, cost of code ownership, and more. But I found myself perhaps most interested by the dive we did into refactoring. The idea of reworking the internal structure of code while preserving inputs and outputs is a surprisingly complex one.
Historical Complexity of Refactoring
At the risk of dating myself, I took this course in the fall of 2006. While automated refactorings in your IDE now seem commonplace, back then, they were hard. In fact, the professor of the course considered them to be sufficiently difficult as to steer a group of mine away from a project implementing some. In the world of 2006, I suspect he had the right of it. We steered clear.
In 2016, implemented automated refactorings still present a challenge. But modern tool and IDE vendors can stand on the shoulders of giants, so to speak. Back then? Not so much.
Refactorings present a unique challenge to tool vendors because of the inherent risk. They can really screw up users’ code. If a mistake happens, best case scenario is that the resultant code fails to compile because then, at least, it fails fast. Worse still is semantically and syntactically correct code that somehow behaves improperly. In this situation, a refactoring — a safe change to code — becomes a modification to the behavior of production code instead. Ouch.
On top of the risk, the implementation of refactoring anywhere beyond the trivial involves heady concepts such as abstract syntax trees. In other words, it’s not for lightweights. So to recap, refactoring is risky and difficult. And this is the landscape faced by tool authors.
I Don’t Fix — I Just Flag
If you live in the US, you may have seen a commercial that features a funny quip. If I’m not mistaken, it advertises for some sort of fraud prevention services. (Pardon any slight inaccuracies, as I recount this as best I can, from memory.)
In the ad, bank robbers hold a bank hostage in a rather cliché, dramatic scene. Off to the side, a woman stands near a security guard, asking him why he didn’t do anything to stop it. “I’m not a robbery prevention service — I’m a robbery monitoring service. Oh, by the way, there’s a robbery.” (here is a copy of the commercial)
It brings a chuckle, but it also brings an underlying point. In many situations, monitoring alone can prove woefully ineffective, prompting frustration. As a former manager and current consultant, I generally advise people that they should only point out problems when they have also prepared proposed solutions. It can mean the difference between complaining and solving.
So you can imagine and probably share my frustration at tools that just flag problems and leave it to you to investigate further and fix them. We feel like the woman standing next to the “robbery monitor,” wondering how useful the service is to us.
Levels of Solution
Going back to the subject of software development, we see this dynamic in a number of places. The compiler, the IDE, productivity add-ins, static analysis tools, and linting utilities all offer us warnings to heed.
Often, that’s all we get. The utility says, “hey, something is wrong here, but you’re going to have to figure out what.” I tend to think of that as the basic level of service, or level 0, if you will.
The next level, level 1, involves at least offering some form of next action. It might be as simple as offering a help file, inline reading, or a link to more information. Anything above “this is a problem.”
Level 2 ups the ante by offering a recommendation for what to do next. “You have a dependency cycle. You should fix this by looking at these three components and removing one mutual dependency.” It goes beyond giving you a next thing to do and gives you the next thing to do.
Level 3 rounds out the field by actually performing the action for you (following a prompt, of course). “You’ve accidentally hidden a method on the parent class. Click here to rename or click here to make parent virtual.” That’s just an example off the top, of course, but it illustrates the interaction paradigm. “We’ve noticed a problem, and you can click here to fix it.”
Fixes in Your Tooling
There are a number of such tools out there, including CodeIt.Right. Using tools like this is a pleasure because it removes the burden of research and implementation from you. Well, you can always do the research if you want, but at your own leisure. But it’s much better to do research at your leisure than when you’re trying to accomplish something else.
The other, important concern here is that you find trusted tooling to help you with this sort of thing. After all, you don’t want something messing with your source code if it might mess up your source code. But, assuming you can trust it, this provides an invaluable boost to your effectiveness by automatically resolving your problems and by helping you learn.
In the year 2016, we have far more tooling available, with a far better track record, than we did in 2006. Leverage it whenever possible so that you can focus on solving the pressing problems of your day to day work.
Tools at your disposal
SubMain offers CodeIt.Right that easily integrates into Visual Studio for flexible and intuitive “We’ve noticed a problem, and you can click here to fix it.” solution.