You know, it's funny. I can well remember the day I saw my first
syntax-highlighted code in an IDE. It looked a little weird compared
to the flat Notepad look of yester-editors, but, from that point on, non-
syntax-highlighted code just became harder to read. It was as if we
had been shown the z-axis from having lived in Flatland for so long.
And then came code completion lists. You'd be typing along and if you
suddenly became stuck trying to remember a member name, you could wait
half a second or so and a list would pop up showing the identifiers
you could type in at that particular spot. And again, you were shown
another dimension to your code, and there was a split from the past.
And now I see comments like this: "I have to laugh when I see what
these tools do. Any coder worth his salt will be instinctively writing
code as good as if not better than this tool produces." In case you
hadn't guessed, the writer was talking about refactoring tools. In
particular, the fake Yorkshireman macho-ness ("When I were a lad, we
were lucky to 'ave _fastcall") that infuses the prose might have
indicated to you that he was a C++ programmer, and you'd have been
right.
This just seems nutty to me and it's not because I work for a company
that puts out a refactoring tool. Yes, we all know what refactorings
are, the great geek god Martin Fowler wrote a best-selling eponymous
book on them. And we all know the names of the most popular ones:
Extract Method, Inline Temp, Extract Interface, Move Method, Rename
Identifier, and so on. Their names have become a mantra almost, a
paean to the new agilism. But, surely -- he says in a baffled voice --
having an automated tool is better than doing them by hand? Aren't
refactoring tools just another small step on the way to better
visualization of our code and of writing it better and faster? What am I missing that this comment writer implicitly understands, or, rather, vice versa.
The writer of this comment also seems to imply that Code, Once
Written, Is Never Changed. It must have been the eleventh commandment,
but God ran out of ink when printing it on the stone tablet. But we
all know from our own experience, without recourse to statistics, that most code is
changed. No matter how good we are, how much we're worth our salt, no matter what language we use, we
introduce bugs when we write code. It may be we change it immediately
("Duh, that should be a less than, not a greater than") or it may be
later, after testing. And, sure, when we modify our code, or we modify
someone else's (because we are lucky indeed if the only code we ever
work on is our own), we make use of refactorings as we make fixes.
Think of it like this. Since code will get changed (there's a bug; the
requirements change; you prefer to code in an organic fashion as if
you were playing with Play-Doh), why not take advantage of a tool that
helps you do it? Certainly you can do it all by hand and have members
of the opposite sex swoon as they watch you manipulate the code with the keyboard,
but to be honest who gives a damn.
I think of the way I write code. I'm an experimentalist developer:
someone who develops with TDD (Test-Driven Development). Despite years
of programming, I always approach a programming task as a blank sheet
of paper. Since I do TDD my blank sheet of paper always starts off
with something I'd like to be true (my first test). And then I write
the code that satisfies the test, and then I write something else I'd
like to be true (another test), and I write more code that makes it
so. And so on so forth.
During this continual piecemeal advance towards software of value, my
code is completely malleable. Just because I wrote it one way for one
test, doesn't mean that it's going to stay that way for ever. I
refactor ad nauseam and utterly rely on my refactoring tool to do
that.
The refactorings I use most of all are these:
1. Rename Identifier. This one is the most important
refactorings in my ever so humble opinion (it's my blog so what I say
goes!). When I'm coding, I never seem to get the names of things right
the first time. Indeed, I've given up trying to, since it just
interrupts the flow of getting an algorithm down. And the names of
things are perhaps the most important thing about our code. We can't
do anything about the syntax of our language, but, by gum, we can
about our identifiers. Name them badly and we obfuscate our code
quickly. We've all heard the (apocryphal?) stories about programmers
coming across some code where the previous programmer in an effort to
be funny used names of flowers or mountains to name local variables.
Compilers don't give a fig about what you name your identifiers. It's
your human audience that does, and you can guarantee you'll have one:
the hapless maintenance programmer that follows in your footsteps,
which, sometimes, is you. You are writing for your human reader first,
and your compiler second. Beware if you think it's the other way
round, because you'll appear on The Daily WTF. I've learned that the
real name for an identifier only becomes obvious once you use it.
Sometimes if you find it hard to name an identifier it indicates that
your code is not expressing the problem domain properly. So, being
able to rename an identifier, without worrying about search-and-
replace destruction, is a boon beyond compare.
2. Extract Method. I'm an advocate of small, low-
cyclomatic-complexity methods, and ones that have a single
responsibility. Ditto for classes, by the way. But constructing a set
of interacting methods as a complete thought exercise and getting them
all down in source code is a talent that has always eluded me. Call me
a stream-of-consciousness programmer by all means, but that generally
means slamming it all down and then sorting out the mess afterwards.
This is where Extract Method come into its own. Hey, that code over
there is essentially the same as this over here, let's extract it into
a common method that can be called (reused!) from both locations.
And an automated Extract Method is great: it works out the parameters,
constructs the right method signature, inserts calling code at the
location where the code was extracted, and in less time it takes to
think about the possibility. Toss in a few Rename Identifier
refactorings and your code becomes more readable and simpler to
understand.
Mind you, me, I can't wait for a tool that will find duplicate code
for me. Oooh, at that point the combination may topple Rename
Identifier from the top of the list.
3. Create Method Stub. This isn't really a
refactoring per se (it makes temporarily non-compilable code into
compilable code), but it's so handy for TDD enthusiasts. You're
writing a test that defines how you'd like something to read and to
work and you find you've used a method name that doesn't exist yet.
Hit the refactoring key, and boom, the tool adds a stub method to the
right class. Invaluable.
4. Decompose Parameter. This one is rapidly moving up
the list ever since I started playing with an early beta version of it
from Refactor! Pro. The set up for understanding why this is so good
is a little long-winded, but the payoff has all the more impact for
it.
When we use a framework like the .NET Framework we find ourselves
writing a lot of event handler code so that we can get called back
from the framework when something happens. Oftentimes, we'll get a
nice handy object passed in as part of the call containing property
values we can use in our handler code. The unfortunate thing is these
event handlers tend not to be reusable, because the caller has to
construct a new handy object to pass in some values. All in all a
pain. Especially so when, in general, we are given a particularly rich
or heavy object and we only use a couple of its properties. Far better
to extract out the specific code into another method, pass in the
property values (and not the rich, heavy object), and reuse this new
method, including calling it from our event handler.
Enter Decompose Parameter: it works out what's actually being used
inside the method's implementation and constructs a method that has
those properties as parameters. It then patches up the calling code
and you're done. So, instead of a non-reusable event handler that
needs an EventArgs but just uses the EventArgs' Graphics property, and
hence that requires an EventArgs object to be set up before calling,
you get a method that expects a Graphics object instead, and can be
used from other painting methods, for example.
5. Move Type to File. One of Refactor! Pro's
invaluable refactorings and every time we demo it, people in the
audience "get it" immediately. The way we write code these days is to
have one class per source file, the latter named after the former.
Makes it easy to find the code for classes, and great for when you
have multiple programmers working on the same team. But writing code
in that way is a pain in the neck. You want a new class, but have to
stop what you're doing in order to add a new file to the project, name
it accordingly, switch to it, add the new class, switch back to where
you were, etc. It's a complete drag to productivity. For the past
couple of years, I just continue writing code to build a class model
in the same one source file. When I'm ready to extract the classes, I
just invoke this refactoring on one class after the other. Boom, boom,
boom. Much easier.
6. Extract Interface. Another great refactoring.
You've written a class believing it to be the only one you'll need,
and, wham, you discover another exemplar that's slightly different. I
much prefer interface inheritance to implementation inheritance, and
so I'd be doing an Extract Interface so quick it would make your head
spin. Mock me, baby.
7. Inline Temp. A quick simple refactoring,
nevertheless very useful. It changes code that declares a temporary
variable, sets it, and then uses the variable in an expression. This
refactoring just gets rid of the temporary variable and moves the
initialization into the expression. Sometimes this can make the code a
little clearer. Sometimes it won't and you'll need the opposite
refactoring; Introduce Temporary Variable. I do tend to use both as I
polish code.
8. Use String.Format. Another refactoring that
audiences at demos instinctively "get" and that I use all the time.
Face it, writing a String.Format call is great for localization
efforts, but it's just a real pain to write. It's much easier to write
an expression that consists of a bunch of string concatenations, but
unfortunately that's hopeless from a localization viewpoint. So, do
the easy thing and let the refactoring tool do the tedious work. I
love just writing a string concatenation expression, getting it
exactly the way I want it, and then convert it to a String.Format call
as if I'd done it that way all along.
I'll stop there. My intent here is not to list out all the
refactorings I use, only those I use most of all. In doing so, I wanted to indicate why
I think a refactoring tool is deserving of being in your coding
environment.
Sure, the refactorings I've listed can all be done by hand. Indeed
if I were stern and hard-core I'd say do them by hand a couple of
times so that you get a real feeling for what each refactoring means
and how it works. And I'd laugh my evil taking-over-the-world laugh
while you did so. Afterwards you'd just use the automated tool and be
thankful that you can save time.
Because in the end, we're not all great programmers who write code
correctly in the first pass. We're all programmers writing code to
enhance/fix/extend existing code (and even green field projects turn into
a marathon of altering code). We're all maintenance programmers to a
smaller or larger extent. We're all programmers who have to
live with other people's code, and recognize that our code after a few months could be someone else's. And because we're all that and more we
deserve the best coding tools we can get. And that includes automated refactoring tools.
Free DevExpress Products – Get Your Copy Today
The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the
DevExpress Support Center at your convenience. We’ll be happy to follow-up.