Chapter twenty-one
In 1999, an English software engineer named Martin Fowler published a book called Refactoring, which gave a name to a practice that working programmers had been doing without a name for as long as there had been working programmers.
The practice was this. Take a piece of code that does what it is supposed to do. Without changing what it does, change how it does it. Move things around. Rename variables to better describe what they hold. Extract long passages into smaller, well-named functions. Eliminate duplication. Tidy up. At every step, run the tests, to make sure the external behavior of the code has not changed. At the end of the session, the code does exactly what it did before. The user, if they had been watching the output, would have noticed nothing. The internals are now legible. The next person to read the code, who in most cases is you in six months, will be able to read it without anguish.
Fowler's book formalized this practice into a discipline. It listed the small individual moves that, applied carefully, produce dramatic improvements in code quality over time. It distinguished refactoring from adding features. It distinguished refactoring from fixing bugs. It made clear that refactoring is its own kind of activity, with its own value, and that the value is, on inspection, the difference between code you can work with and code that, however correctly it happens to function, has become unmaintainable.
I want to write about this in the last chapter of this book, because the practice of refactoring is, in my honest estimation, the cleanest model I have for what it means to be an adult who is taking themselves seriously, over the long span of a life.
I want to start by saying what refactoring is not, because the confusions are predictable.
Refactoring is not adding features. The refactored self is not, in the relevant sense, a more impressive self. It is not a self with a longer list of accomplishments. It is not a self that has, since the previous refactoring, achieved more. The achievements are on a different axis entirely. Achievements are output. Refactoring is structure. The two are not in competition, but they are not the same. A person who has, over a year, achieved nothing visible and refactored extensively, is, on the inside, in much better shape than they were a year ago. The fact that this is not visible from the outside is the entire point. Refactoring is, by construction, invisible to the receiver of the function's outputs.
Refactoring is also not fixing bugs. The Part-two chapters of this book were about fixing bugs: identifying specific failure modes in the legacy code of the anxious brain and recalibrating them. The Part-three chapters have been, in part, about installing new procedures to handle the failures the legacy code keeps producing. These are real and useful kinds of work. They are not, however, refactoring. They are repair. Refactoring is what you do after the repairs are mostly done. Refactoring is the slow continuous improvement of the parts that are not, by any local measure, broken, but that could be, with care, cleaner, simpler, easier to live with.
This distinction matters because the anxious mind has, by long habit, treated itself only as a system in need of repair. The framing is exhausting because, on this framing, the work is never done. There is always another bug. There is always another failure. There is always another moment that should have gone differently. The repair model produces, over years, a particular kind of weary self-improver who never feels they have arrived, because the goal of the work has been silently defined as be without bugs, and bug-free systems do not exist.
Refactoring offers a different framing. The work is not toward a state. The work is itself the state. A person who is refactoring continuously is not on the way to becoming a finished person. They have, in some quiet way, already arrived. The arrival was not at any particular destination. The arrival was at a mode of operation in which the continuous small improvements are themselves the life, rather than work toward an imagined future life in which the improvements would no longer be needed.
Let me show you what this looks like in real code, because the contrast between a function before and after refactoring is, on inspection, the cleanest illustration I can offer.
# BEFORE refactoring: a function that does its job, but
# would make anyone reading it slightly uncomfortable.
def calc(d):
r = 0
for x in d:
if x[2] == 1 and x[3] > 0:
if x[1] in ['a', 'b', 'c']:
r += x[3] * 1.1
else:
r += x[3]
return r
# AFTER refactoring: the same function, doing exactly the same
# computation, but with the internals rearranged for legibility.
PREMIUM_CATEGORIES = {'a', 'b', 'c'}
PREMIUM_MULTIPLIER = 1.1
def is_active_purchase(transaction):
is_active = transaction['status'] == 1
is_positive = transaction['amount'] > 0
return is_active and is_positive
def value_of(transaction):
base = transaction['amount']
if transaction['category'] in PREMIUM_CATEGORIES:
return base * PREMIUM_MULTIPLIER
return base
def total_revenue(transactions):
return sum(value_of(t) for t in transactions if is_active_purchase(t))
The two functions, given the same input, return the same output. The tests, if I had written them in advance, would pass on both versions. The user of the function, if they had been watching the output, would notice nothing. The change is entirely internal. The function has not become more functional. It has become, in the technical sense, more legible. The next programmer who has to work with it, including the future version of me, will have a much easier time.
I have made roughly these kinds of changes, in roughly this spirit, to the internal structures of my own mind over the last several years. The external behavior of the man at this desk is, in most observable ways, the same as the external behavior of the man at this desk three years ago. The same friendships. The same work. The same modest domestic life. The same body, give or take. The same dogs, mathematically, in the form of the structures they left behind. To anyone who has known me for more than a decade, I am, on inspection, the same person.
The internals, however, are not the same. The function that handles the impulse to micromanage a colleague has been refactored. The procedure that runs at three in the morning has been refactored. The way I respond to a sharp word, the way I read a friend's silence, the way I sit through the slow lap of a difficult afternoon, are all internally rearranged in ways that, taken individually, would not register to an outside observer, and that, taken together, are the single largest difference between the man I now am and the man I once was. The output is the same. The code is, by an enormous margin, easier to live inside.
I want to draw the timeline of what this looks like, because the picture is more honest than prose.
Figure 21.1 The external behavior of a person who is steadily refactoring barely changes over time. The internal complexity drops, slowly, in small unflashy steps, until the system that produced the same outputs is, on the inside, much easier to maintain.
This is what a refactored life looks like, in graph form. The black line at the top is the external behavior of the person, which is essentially flat. They are, by every observable measure, the same person. The accent line below, descending in small unspectacular steps, is the internal complexity. Each step is one small piece of structural improvement that does not change anything anyone else can see. The aggregate of these steps, over years, is the difference between a system that is exhausting to be inside and a system that is, on the whole, livable.
I want you to notice something about this graph. There is no destination. The accent line does not terminate at any particular value. It keeps descending, slightly, indefinitely. There is no point on the timeline at which the refactoring is, in any meaningful sense, finished. There is, however, a clear long-term direction. The line, over the span shown, has dropped substantially. The system, at the right edge of the graph, is much less complex internally than the system at the left edge. The drop happened without any of the individual steps being heroic. The drop happened because the steps kept happening.
I want to make the claim, plainly, that this book has been about teaching you what it would feel like to live this way.
Part one diagnosed the legacy code. Part two gave you the toolkit to recalibrate the existing faculties. Part three offered the constructive practices: writing new algorithms, running them through test-driven cycles, letting the garbage collector clear what is no longer reachable. The whole apparatus, taken together, is not a self-improvement program. It is, on inspection, a manual for entering the refactoring mode of life, and staying there.
The refactoring mode is, importantly, not effortful in the way the alternatives are. The alternatives, which I have been all of in my life, are these. One: ignore the legacy code, let it run as it was installed, and accept the suffering that the unattended bugs produce. Two: declare war on the legacy code, attempt to rewrite the entire system from scratch, and burn out within months. Three: enter the refactoring mode, in which the work is continuous, small, unspectacular, and, importantly, never finished, and discover that the never-being-finished is not a flaw of the practice but the practice itself.
This is the move I have been trying to convince you to make for twenty chapters. The book is not a guide to fixing yourself. The book is a guide to entering the mode in which the question of being fixed is, on inspection, the wrong question. The right question is whether you are, right now, in this small unspectacular moment, doing the next small refactoring that the system is asking for. If yes, you are in the mode. If no, you have stepped out of the mode briefly, which is, on inspection, what most adults do most of the time, and which is fine, because the mode is always there to step back into.
The mode is, in some quiet way, what the chapter titles of this book have been describing as the eventual destination. The mode is what the negotiator in Chapter 3 was prevented from access to by its insistence that every internal claim be litigated. The mode is what the chaser in Chapter 6 could never reach because the chasing was the obstacle. The mode is, on inspection, the fixed point that the function this book has been describing eventually settles to, which is the topic of the very short Epilogue that follows this chapter.
I owe you one last piece of honesty, because the chapter would be incomplete without it.
This book has, itself, been a refactoring. I started writing it as one version of myself. I am finishing it, twenty-one chapters later, as a different version. The book is now public. The book will outlast me, in some small measure, regardless of what I do next. But the man writing this paragraph is not, in the relevant sense, the man who wrote the opening of Chapter 1. The act of writing the book was, for me, the largest single refactoring of my interior life I have ever undertaken. The function I run, when I encounter the world, does the same things it did. The internal procedures by which I do them have been, page by page, rearranged.
I want to say this without sentimentality, because the chapter has been arguing against sentimentality on principle. The book changed me. It changed me by requiring me to be precise, on the page, about things I had previously been imprecise about in my head. It changed me by requiring me to give names to procedures I had been running unnamed for decades. It changed me by requiring me to render my own life as code, which is, on inspection, a particular kind of refactoring that no other activity I have ever undertaken provides quite the same forcing function for.
If the book ever does any of this for you, it will not be because of anything in particular I have said. It will be because the act of reading carefully, of running the exercises, of converting your own wishes into procedures and your own procedures into tests, is itself a piece of refactoring, performed on your interior by the discipline of paying attention to it in mathematical terms. The reading is the writing. The writing was the refactoring. The refactoring, on inspection, is the only thing the book was ever pointing at.
A small exercise
Look at the long line.
Think back to where you were ten years ago. Not what you were doing. Not who you were with. The interior shape of you. The way you handled difficult moments. The procedures that ran in your head when something hard happened. The texture of your three in the morning.
Now compare it to today. Honestly. Without flattery. Without harshness.
Almost certainly, the external life is recognizable. The friends, the work, the broad shape of the days, are continuous with what they were. The internals, on inspection, are not the same. The procedures have, over ten years, been rearranged in dozens of small ways. Some of the rearrangements were deliberate. Some happened to you. Some you cannot remember happening at all.
Notice that there was no single moment of arrival. Notice that you are not, in any meaningful sense, a finished person. Notice that you are also, by any honest accounting, in much better shape than you were ten years ago, even on the days when you have forgotten that you are.
This is the refactoring. This is what it has been the whole time. The line has been descending, in small unspectacular steps, the whole time you were not watching it. The line will continue to descend. The work is not toward a state. The work is the state. The state is where you have, on inspection, already been living for some time.
The Epilogue is on the next page. It is shorter than any chapter in this book. It is about the mathematical concept of a fixed point, and about the small consolation that the function this book has been describing, run on itself long enough, does, in fact, settle.
For now, the page closes here. The refactoring is forever. The refactoring is also, in some quiet way, what living thoughtfully is. The work is not toward a destination. The work is the mode. You are, on most days, already in it, although nobody, including possibly you, has been calling it that. From this page forward, you may.
End of Part three. End of the book proper. The toolkit has been delivered. The constructive practices have been laid out. What follows is the Epilogue, in which the function this book has been describing finds, at last, its fixed point.