www.sixfingeredman.net
..................................................
::. .  .   .     .       .          .

HOME
readme
brain
ideas
todo
writing
photos
graphics
projects
quotes
recipes
books
movies
links
old site

refactoring and adding features

Refactoring is any change which preserves semantics. This change can be of any size (although it's hard to prove a large change is semantics-preserving without breaking it into smaller ones first), and it can include changing ``how things work and possibly interfaces too.''

That's because ``semantics preserving'' means with respect to the behaviour of the black box within which we are refactoring. Take a simple example: within a function we change the name of a lexically-scoped local variable. This is not semantics-preserving within the function, because it is easy to invent a line that would work with the old function but not with the new (it would just use the old variable name). However, it is semantics-preserving outside the function because any calling code that worked with the old function will work with the new.

I explain that really obvious case to extend it to the activity you said is not part of refactoring: namely changing interfaces. The only thing that's different is that our ``black box'' of semantics-preservation now extends to all users of that interface. Indeed, ANY semantics-preserving change you make to code can be seen as changing an interface and visa versa: in the first example, the ``interface'' was the get-reference invoked implicitly by the object name, and the user of the interface was the function.

(An interface is the surface where two distinct bodies meet, and all of computer programming is about building interfaces; that is, splitting things into isolated sections with well-defined borders (interfaces) so that changes to those sections do not splash over. Like compartments in a submarine. If part of your code sinks, interfaces make sure the rest still floats. Or something like that.)

Hopefully that's all clear now, and we can see that there are two kinds of changes: those that don't affect the end-user and those that do, that all architectural changes fall into the first category, and furthermore that all architectural changes can be achieved by refactoring. I don't know of any formal definition for ``rewriting'', and can't think of a particularly good one. Perhaps you mean ``any change which ought to preserve semantics but because it's so large and untested it very well may not.'' Or maybe ``refactoring and adding new features at the same time.''

The latter seems to work; we often refactor in order to add new features. But the question is whether we gain anything by doing both at the same time, as you seem to be advocating. The idea behind refactoring is to reduce changes to the smallest possible units so that you always know exactly what change introduced the newest bug.

As an aside: we can place adding new features in the context of refactoring as well, except in this case the semantics-preserving box is the universe, and the interface to be changed is the contract between your program and the universe. So we alter the contract, alter the program to adhere to the new contract, and test the universe to be sure semantics were preserved. Semantics being preserved in this case means the logical rules of the universe still function normally under the assumption that the new contract accurately reflects the relationship between universe and program. If your program has a bug, that means that there is a logical inconsistency in the universe: either your program is true or the contract is true but not both. :)

Anyways, the point of that philosophical diversion is that adding new features can be done in the same spirit as refactoring, by making small changes and testing. So back to explaining why we shouldn't mix the two:

If you combine a refactoring-step and a feature-step together, you now have twice as big a change unit with the possibility of bugs created not just by external inconsistencies but internal ones as well: in other words, something like the number of bugs squared, and harder to find. :) Since, as I explained, adding new features is refactoring the universe, we can make the extension that this is no different than applying two refactorings simultaneously within your program, say, changing a variable name within a function and changing the interface to that function. Sure, you can do it. But it's dangerous.

Since you can achieve the same end-result by interleaving refactoring and feature-adding (aka doing refactorings in sequence rather than simultanously), I'm dubious that ``rewriting'' has any advantages other than it's less tedious and more fun.


[in response to statement by the Chinese government]

If the Internet is "online heroin", slashdot is "an online jet-powered
crackpipe burning a two ton ball of primo Detriot crack, laced with LSD, PCP,
Ecstasy, and some weird shit we've never seen before"