Refactoring: Improving the Design of Existing Code
kabz writes "Refactoring (as I'll refer to the book from here on in) is a heavy and beautifully produced 418 page hardback book. The author is a UK-based independent consultant who has worked on many large systems and has written several other books including UML-Distilled. Refactoring is a self-help book in the tradition of Code Complete by Steve McConnell. It defines its audience clearly as working programmers and provides a set of problems, a practical and easily followed set of remedies and a rationale for applying those techniques." Read below for the rest of Johnathan's review.
Refactoring: Improving the Design of Existing Code
author
Martin Fowler with Kent Beck, John Brant, William Opdyke and Don Roberts.
pages
431
publisher
Addison-Wesley
rating
9/10
reviewer
Jonathan Watmough
ISBN
0201485672
summary
expands and formalizes the idea of applying explicit refactorings
Code refactoring is the process of restructuring code in a controlled way to improve the structure and clarity of code, whilst maintaining the meaning of the code being restructured. Many maintenance problems stem from poorly written code that has become overly complex, where objects are overly familiar with each other, and where solutions implemented expeditiously contribute to the software being hard to understand and hard to add features to.
Typically refactorings are applied over a testable or local scope, with existing behavior being preserved. Refactoring as defined in this book is not about fixing bad designs, but instead should be applied at lower levels.
Testing a la Extreme Programming is emphasized as a control for ensuring that program meaning is not changed by refactoring. It is not over emphasized, and this is not a book about testing, but it is often mentioned and stays in the background through the book.
The refactorings presented in the book are not intended as a comprehensive solution for all problems, but they do offer a means to regain control of software that has been implemented poorly, or where maintenance has been shown to simply replace old bugs with newer ones.
The book is divided into two main sections, introductory material that introduces and discusses refactorings, and a lengthy taxonomy of refactorings that includes both examples and further discussion. The introductory material consists of a long worked example through simple Java code that implements printing a statement for a video store. Despite the simplicity of the code, Fowler shows in clear detail where improvements can be made, and how those improvements make the code both impressively easy to understand, and easy to maintain and add features.
Several key refactorings are demonstrated in the opening chapter including Extract Method, Move Method and Replace Conditional with Polymorphism. This is a book about programming in the object oriented paradigm, so as you might expect, the first two refactorings refer to extracting and moving object methods either into new methods, or between objects. The third example provides a means to replace special cased behavior in a single object type by deriving a sub type of the object and moving type specific code to the sub types. This is a fundamental technique in object oriented programming, and is discussed here in practical terms.
Now that several actual refactorings have been introduced, Fowler provides a solid and well thought-out discussion of the why's, when's and when not's of refactoring. For example, code can decay as features are added, and programmers special-case, or bodge additional functionality into existing objects. Fowler argues that the bitrot and decay makes software more unreliable, leads to bugs and can accelerate as the problem gets worse. Faced with these problems, refactoring should be used to improve local design and clean up and improve code, leading to better software, that is easier to maintain, easier to debug, and easier to improve with new features as requirements change.
However, there is a caveat, in that since software functionality should remain unchanged during refactoring, the process of refactoring consumes resources, but provides no easily measurable value. Fowler confronts this issue in a section that discusses how to communicate with managers, that you are performing refactoring work. He denies being subversive, but his conclusion is that refactoring should essentially be folded in with normal work as it improves the overall result.
This is a bit like goofing off on the basis that you'll think better after 20 minutes of fooseball. I'd definitely subscribe to that theory, but many others may not.
Kent Beck guests in Chapter Three for a review of the issues in typical software that suggest a refactoring may be needed. This chapter is entitled Bad Smells in Code, and most of the smells presented will be familiar to any reasonably experienced programmer, and they will be a great learning experience for less experienced programmers. I got the same feeling reading this chapter as I did when I first read Code Complete. Here was someone writing down names and describing problems that I had a vague unease about, but was too inexperienced to really articulate or do something about. Typically the refactorings address the same kind of issues that a code review with a skilled experienced programmer would address. Long parameter lists, too long methods, objects delving about in each others private variables, case statements, related code spread across different objects etc. None of these problems are debilitating in themselves, but added up, they lead to software that can be prone to error and difficult to maintain.
Most of the remaining substance of the book, 209 pages, is given over to a taxonomy of refactorings. These 72 refactorings are covered in detail with comprehensive simple examples presented in Java. Each refactorings is given a clear name, a number and a line or two of descriptive text. The motivation for the refactoring is then discussed, often including caveats and cautions. The mechanics of implementing the refactoring are then listed, with 1 or more (and often more) examples of implementing the refactoring. Refactorings range from the very simple to more complex examples such as Convert Procedural Design to Objects.
Due to the difficulties of reproducing large and complex sections of code, Fowler sticks with relatively simple examples. These seem to grate on him more than the reader, and he can come across as somewhat embarrassed when we look at the employee, programmer, manager pay example for the tenth time. I certainly didn't have a problem with it though.
This is a very well written and fun to read book. I personally feel that much of the material is implied by from Code Complete, but Fowler does a fantastic job of expanding and formalizing the idea of applying explicit refactorings. Much like Code Complete gave a motivation for keeping code well commented and laid out, this book presents the case for care and feeding of how to structure software. To fight bitrot and technical debt, poorly structured and unclear code should be targeted and refactored to improve structure and clarity. This gives a very real payback in terms of less required maintenance, and ease in adding features later on down the line.
Despite the fact that all the examples are in Java, the ideas are easily transferable to C++ or any procedural object oriented language. I highly recommend this book.
You can purchase Refactoring: Improving the Design of Existing Code from amazon.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
Typically refactorings are applied over a testable or local scope, with existing behavior being preserved. Refactoring as defined in this book is not about fixing bad designs, but instead should be applied at lower levels.
Testing a la Extreme Programming is emphasized as a control for ensuring that program meaning is not changed by refactoring. It is not over emphasized, and this is not a book about testing, but it is often mentioned and stays in the background through the book.
The refactorings presented in the book are not intended as a comprehensive solution for all problems, but they do offer a means to regain control of software that has been implemented poorly, or where maintenance has been shown to simply replace old bugs with newer ones.
The book is divided into two main sections, introductory material that introduces and discusses refactorings, and a lengthy taxonomy of refactorings that includes both examples and further discussion. The introductory material consists of a long worked example through simple Java code that implements printing a statement for a video store. Despite the simplicity of the code, Fowler shows in clear detail where improvements can be made, and how those improvements make the code both impressively easy to understand, and easy to maintain and add features.
Several key refactorings are demonstrated in the opening chapter including Extract Method, Move Method and Replace Conditional with Polymorphism. This is a book about programming in the object oriented paradigm, so as you might expect, the first two refactorings refer to extracting and moving object methods either into new methods, or between objects. The third example provides a means to replace special cased behavior in a single object type by deriving a sub type of the object and moving type specific code to the sub types. This is a fundamental technique in object oriented programming, and is discussed here in practical terms.
Now that several actual refactorings have been introduced, Fowler provides a solid and well thought-out discussion of the why's, when's and when not's of refactoring. For example, code can decay as features are added, and programmers special-case, or bodge additional functionality into existing objects. Fowler argues that the bitrot and decay makes software more unreliable, leads to bugs and can accelerate as the problem gets worse. Faced with these problems, refactoring should be used to improve local design and clean up and improve code, leading to better software, that is easier to maintain, easier to debug, and easier to improve with new features as requirements change.
However, there is a caveat, in that since software functionality should remain unchanged during refactoring, the process of refactoring consumes resources, but provides no easily measurable value. Fowler confronts this issue in a section that discusses how to communicate with managers, that you are performing refactoring work. He denies being subversive, but his conclusion is that refactoring should essentially be folded in with normal work as it improves the overall result.
This is a bit like goofing off on the basis that you'll think better after 20 minutes of fooseball. I'd definitely subscribe to that theory, but many others may not.
Kent Beck guests in Chapter Three for a review of the issues in typical software that suggest a refactoring may be needed. This chapter is entitled Bad Smells in Code, and most of the smells presented will be familiar to any reasonably experienced programmer, and they will be a great learning experience for less experienced programmers. I got the same feeling reading this chapter as I did when I first read Code Complete. Here was someone writing down names and describing problems that I had a vague unease about, but was too inexperienced to really articulate or do something about. Typically the refactorings address the same kind of issues that a code review with a skilled experienced programmer would address. Long parameter lists, too long methods, objects delving about in each others private variables, case statements, related code spread across different objects etc. None of these problems are debilitating in themselves, but added up, they lead to software that can be prone to error and difficult to maintain.
Most of the remaining substance of the book, 209 pages, is given over to a taxonomy of refactorings. These 72 refactorings are covered in detail with comprehensive simple examples presented in Java. Each refactorings is given a clear name, a number and a line or two of descriptive text. The motivation for the refactoring is then discussed, often including caveats and cautions. The mechanics of implementing the refactoring are then listed, with 1 or more (and often more) examples of implementing the refactoring. Refactorings range from the very simple to more complex examples such as Convert Procedural Design to Objects.
Due to the difficulties of reproducing large and complex sections of code, Fowler sticks with relatively simple examples. These seem to grate on him more than the reader, and he can come across as somewhat embarrassed when we look at the employee, programmer, manager pay example for the tenth time. I certainly didn't have a problem with it though.
This is a very well written and fun to read book. I personally feel that much of the material is implied by from Code Complete, but Fowler does a fantastic job of expanding and formalizing the idea of applying explicit refactorings. Much like Code Complete gave a motivation for keeping code well commented and laid out, this book presents the case for care and feeding of how to structure software. To fight bitrot and technical debt, poorly structured and unclear code should be targeted and refactored to improve structure and clarity. This gives a very real payback in terms of less required maintenance, and ease in adding features later on down the line.
Despite the fact that all the examples are in Java, the ideas are easily transferable to C++ or any procedural object oriented language. I highly recommend this book.
You can purchase Refactoring: Improving the Design of Existing Code from amazon.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
This is a bit like goofing off on the basis that you'll think better after 20 minutes of fooseball. I'd definitely subscribe to that theory, but many others may not.
It's not at all like that. If you really need an analogy to understand this very simple concept, it's like seeing that your desk is overflowing with paperwork and spending some time filing everything properly. A little time invested can make it a lot quicker to find what you are looking for and help you deal with one thing at a time.
Reviewed back in 1999 on Slashdot.
http://books.slashdot.org/article.pl?sid=99/09/16/1333202
I don't mean to be a wet blanket, but the book has been out for quite some time -- checking Amazon, July of 1999. It is pretty great, and I would recommend it to those who somehow managed to miss it up to this point, but a review almost nine years later? Slow news day much?
On the other hand, maybe periodically prodding towards the direction of higher internal quality (to be distinguished from external quality, that which is perceived in a black-box fashion by your customers, the relationship between these two qualities is of course a matter of much friction and debate between the managing and laboring classes) isn't a bad call. Lord knows any extra ammo to convince people that this is worthwhile is appreciated. As much as we like to think of ourselves as poets, I sometimes think the traditional profession most software development resembles is "butcher" or "janitor", just one messy hack-job and sweep under the rug after another after four or five decades of which you can retire and grumble on the beach about putting cyanide in the guacamole, fondly reminiscing about your red swingline or asr-33 or what have you.
News for Geeks in Austin, TX
How this can be compared to McConnell's epic(s) I don't know.
Does your book cover that?
One point about the review: The note about the examples being transferrable to C++, etc. is a little off; some of the refactor techniques are basically workarounds for Java quirks. In fact, I've always felt that the book should have been called "Refactoring: Improving the Design of Existing Java Code".
Not a bad read overall, but it could have been made better by presenting examples in different languages, a la the GOF Design Patterns book.
And bury them deep.
"new" code is a capital investment and gets very high tax benefits.
"refactored" code is a pure cost.
I do a lot of refactoring but i always have to sneak it in under the cover of a "new" project instead of a "bug fix" project.
She was like chocolate when she drank... semi-sweet at first and then increasingly bitter.
At one time not so long ago the common wisdom was, jazz can't be taught, it is just something you have in you or not. Today, jazz is commonly taught by formal methods at schools like Julliard, producing many fine studio and live jazz musicians. So much for common wisdom.
Today, in computer science, it is commonly thought that there are star developers and there are normal developers, and that being a star developer is just something you have in you. Well. It smells like deja vu all over again.
Have you got your LWN subscription yet?
THe Pragmatics Programmer: From Journeyman to Master" was published as well in 1999 and is written by Andrew Hunt and David Thomas. I just got it for Christmas and have been enthralled with it. They spend some time dealing with the refactoring of code as well as wonderul insight into a wealth of other areas.
This is yet another book that I wish I had read years ago. Working a few years in industry really makes you realize how much you can learn from other people. But alas, the problem of youth is that you always think you're the exception.
Either give it away or get top dollar, but never sell yourself cheap.
At several places where I worked management was always happy to allow cycles to be spent on the process of 'refactoring' the code.
Unfortunately, in my experience, the process of 'refactoring' involved making code more complex by adding to it. In one case, I saw the product of the 'refactoring' process wrap two pieces of functionality into two separate EJBs (with a whole 'dto-pojo' conversion scheme for data "isolation"). In another, I saw some functionality wrapped into a collection of beans--which was later wrapped in another layer of beans, and so forth, until 20 lines of code which set up a call into the javax.xml.translate package (for performing an XSLT transformation) into something like 8 bean layers. The 20 lines of code was at the heart of an 8-layer onion, each layer added by someone else's "refactoring" operation.
In Java, because modern IDEs allow you to write code without thinking, the problem with code is not that there isn't enough code (to prevent incestuous classes from being overly familiar with each other), but that there is too much code as programmers unfamiliar with the problem decided to add beans and interprocess communication and multiple threads without properly sizing the problem. (Right now I'm looking at an internal system which may need to process 1 transaction a second, tops, built in an inter-cooperating network of 8 EJBs, which someone thought would help improve transactional performance. Eight? A second system essentially replicates an in-memory SQL system rolled in-house: the system has been buggy because the reverse index processing had a race condition. Um, why wasn't that built in a dozen classes on top of MySQL instead of built with a couple of hundred classes that reinvent the wheel poorly?)
While I'm glad someone wrote a book on refactoring methodology, in my experience what we need is a book which describes how to write "simple" code: code that is just as complicated as it needs to be, and no more. And a book which also describes how to simplify overly-complicated code, how to pick simpler techniques, and how to manage programmers who have an "itch" so they go scratch it somewhere else--I think that would be a much more useful book.
It's easy to add complexity. It's hard to simplify.
And if anyone whines about how old code needs to be rewritten, point them at this
http://www.joelonsoftware.com/articles/fog0000000027.html Old code doesn't rust, it gets better, as bugs are fixed. Lou Montulli again: "I laughed heartily as I got questions from one of my former employees about FTP code the he was rewriting. It had taken 3 years of tuning to get code that could read the 60 different types of FTP servers, those 5000 lines of code may have looked ugly, but at least they worked." That's just in a PC application. Try refactoring the 'ugliness' out of an embedded system and see how long your employer still has customers, and how long you still have a job. And it's interesting that evolution, an unconscious process that far outperforms human 'intelligent' designers doesn't have any concept of ugliness at all. Maybe that concept is just an artifact of your limited ability to deal with complexity.
echo -e 'global _start\n _start:\n mov eax, 2\n int 80h\n jmp _start' > a.asm; nasm a.asm -f elf; ld a.o -o a;
That's actually a dead-on seconded from me.
Only because of slashdot, can I feel slightly less ashamed
If the application is "done" and no major components are to be added, then by all means leave it alone.
However, most systems aren't like that. They need to be changed due to changes in requirements, new functionality, business rules, etc., and that's where refactoring helps you - it helps isolate functionality and help the system evolve. (The app should have been designed with that in mind from the beginning, but you and I both know that it never is.)
The main problem I have with refactoring (both the book and the concept) is that it's way too easy to go overboard with it because it presents a Right Way of writing code. Sometimes methods need to be 20 lines, sometimes classes need to do more than one thing, sometimes inheritance just gets in the way. Fowler respects these ideas, but I've known people who read this book and take refactoring to its logical extreme, which results in overly fragmented code.
I also despise the XP directive to not comment code, which Fowler promotes.
In all it's a good book but it's best to read it when after you've had a few years of real world experience and you can tell what should and shouldn't be taken seriously.
Actually, if you are in a situation like mine and take the 20 2k line block of code that are sprinkled all over the place and tweaked into one refactored lib that all these apps can use, your work load goes down considerably. Refactoring is a very good idea when you have maint problems.
Dan,
Yes, but that's more like encapsulation than refactoring.
I totally agree that complex functions should be contained in a 'black box' with well-defined interfaces (like your big 202k block of code).
The fallacy you're doing there is shifting the scales in that comparison. One side is learning Jazz at all, the other is being a _star_ in programming.
You'll find that being a star in _any_ discipline, Jazz included, isn't just a matter of being given a crash course in music notation. There are many who can learn Jazz, but there are few which are stars at it.
And there are a ton of people who just aren't any good at Jazz, no matter how much you teach them. There are those who are born tone deaf, or lack the coordination, or those who just aren't interested in a musical career, or those who find that learning uber-boring, or a dozen other cases which you just can't turn into _stars_ in any kind of music.
I'll further go and say that in Jazz (or any other kind of music) it's a relatively low pay career and with very few oportunity to become a super-star. So I'd wager that any music school gets an already filtered set of candidates. It's already those who love that genre, are sure that that's what they want to do, etc. It's already the people passionate and motivated.
In programming, we get a ton of drooling burger-flippers who think they can just get a quick training in Java and earn the big bucks. Not because they like it, not because it fits their personality type, not because they showed any kind of aptitude or inclination, just because they think they can fake their way to the big bucks. And it shows.
If you want a more apt comparison, compare them to the gang wanting to be a rock star in high school and college. The prospect of glamour and big bucks is there, and every other high-school boy wants to be in a rock band. The problem is that most suck, and will _never_ be even an acceptable player with any instrument. And aren't particularly motivated to train hard either. How many actually become a _star_? I'll say that's lost in the decimals.
So basically to sum up the comparison to Jazz:
1. Yes, you can teach Jazz. You can teach CS too. That's why we have that kind of colleges, you know.
2. You can't just take any guy off the street and turn him into a _star_ musician. If you went and took random people laid off by McDonald and tried to turn them into musicians, very few would even make an acceptable musician, and _extremely_ few will ever be considerable a _star_. Same as programming.
But, of course, that won't stop idiot PHBs from trying.
A polar bear is a cartesian bear after a coordinate transform.
Even when you plan for expansion and extension, you usually plan for extension in the wrong direction. Changing business requirements, new users, and brilliant but unexpected new features often require changes to your plans for change (or extensions to your extension mechanism). Let's face it, breakthrough ideas that simply must be worked into a program aren't anticipated fully. That's what makes them breakthrough ideas.
I have seen refactoring in action aswell.
It decreased the size of the program code, made the code more modular, faster, made possible to write good unit tests for it and decrease bug count per LOC, all in all rewarding the developer and user with a more stable, smaller, faster and more maintainable codebase.
It takes a man to suffer ignorance and smile
Be yourself no matter what they say
Where I work, we refactor only when fixing a bug, and since we have tests of everything that works in production code, you're guaranteed not to break anything.
There are frequently situations where an improved utility/helper class can handle a task that is currently re-implemented in the class you are editing. Removing duplicate code reduces bugs.
"Who is the Journal of Quantum Physics going to believe?" --Stephen Hawking
Two great reasons to refactor:
(1) Your requirements have changed.
(2) You are dealing with a piece of buggy code that is a nightmare to debug and test.
You were most fortunate, and no doubt you were the guy doing the refactoring in question.
Stick around a while and see what happens when some asshat 'refactors' your code and you are called in to clean up the mess.
It's nice to see comments about the pitfalls of refactoring. (I'm sure it would be different on reddit :) ) In my experience it is very rare that any refactoring will actually improve an application.
The worst part of refactoring, it breaks merges.
You took the words right out of my mouth. I have refactored a lot of the last coder's projects because the code just sucked balls. (It really did - only a little ego involved :) Now I have hardly anything to do at work and my (non-coder) colleagues wonder why there are so few errors reported now!
Most clients I have dealt with are unable to define their own requirements properly, about all they can do is express their intentions and answer questions, they need to be guided
This is why I think design and development need to happen concurrently starting out with an intention, and various anticipated outputs and functionality that is needed.
One also needs to be comfortable with chaos and unknowing, while the design unfolds perfectly if one goes with the flow. The other thing that affects the quality of code is budget constraints and the egoic mind.
Polishing and improvement come after one figures out what they needed which only comes from doing.
"an infinite player that has lost his finite mind" ~Infinite Play the Movie (it blends with reality)
Do you mean by that that your refactoring reduced reportable errors? I so, I salute you Sir!
Thing is, REFACTORING should exactly replicate the original, bugs and all.
A lot of folks here just don't understand what 'REFACTORING' means.
Wikki says:
"A code refactoring is any change to a computer program's code which improves its readability or simplifies its structure without changing its results."
It has nothing to do with the size source code or the functionality of the program.
A properly refactored program will have the exact same characteristics and bugs as the original.
Kids nowadays!
I see lots of comments about how old code is solid and reliable and should not be refactored. This group must be working in a very different environment than the ones I am accustomed too. All too often, I come into a project where the same bugs keep re-asserting their heads over and over again, and they keep getting fixed over and over again. Usually, it is because the original code contains some routines that were copied and pasted over and over again, and by refactoring you take the best block of code and re-use it. The result is smaller, more readable, and less error-prone.
First project: Tony's nifty custom MS Access financial-tracking application!
First step: Rename all 122 tables from table1, table2, table3, etc to REAL names!
What?
Beautifying code is a subjective business.
I used to work for IBM on the MVS (now z/os) operating system. At the time it was all written in s/370 assembler, but got rewritten in PL/S (a cousin of PL/I but with lower-level functions like direct register/memory access).
I spent 3 years of my life (mid to late 80's) refactoring the MVS operating system. It was a mammoth exercise, and exacting too. There were 28 of us on the team, all top IBM sysprogs, based in the US (Armonk NY) and UK (Portsmouth). We had 5 IBM 3090-4 mainframes in various states of disaster while we carefully recreated decades of s/370 OS code.
It was a bit like archeology. You analyzed and pealed away layer after layer of BXLE and MVCL instructions (mostly uncommented) and tried to grasp what the original programmer's intention was. There was self-modifying code in some modules (changing a BR branch destination!) and some of the code was actually lost, and only available on microfiche!
Now that's refactoring!
...and not with refactoring. Whenever I come across java code it always seems needlessly complex, with endless layers upon layers, unneeded abstractions, and patterns applied far beyond what would make for useful architecture.
Before you start flaming, I'd like to state that this is probably more a problem with java *programmers* than with the language itself, although its design has certainly caused too many people to follow down that path. So the language is probably ok, but the surrounding libraries and the attitude and inexperience of many of its users are the real problem.
Donning asbestos underwear... Now!
I once had to take over the support of a series of 10,000 line assembler programs that did not have a single comment. these programs would communicate through the printer port with a black box device that was use for testing monitoring equipment.
Each different monitor had its own program so to make an across the board change to the codebase one had to change each program that was similar but different from the other.
I took a couple days out and first added comments and dividing lines as to what test was being run. This also involved figuring out what the code was even suppose to be doing at times.
This simple documentation task literally found hundreds of errors when comparing each individual test among that same test in all of the codebase.
The original code was written by an old professor in his 70's who was really sharp but never bothered to learn "C" so the code was written in assembler instead. As new monitors were added to be tested then the snapshot of the present code was modified and named for that monitor thus an ever growing quantity of code in various states of being updated was created.
documentation, standardization, refactoring all permitted this mess to be fixed. It actually was a fun project.
And in the end, the love you take is equal to the love you make
Yeah, well, replicating the bugs is usually not a virtue unless you have to maintain compatibility with somebody else's code that you can't change. My refactoring work frequently reduces bugs in the code as well. The reason for that is that 99% of the refactoring that is worthwhile consists of consolidating nearly identical code into a single copy with special case code where needed.
It's often the case that software has special case behavior for... say a dozen very similar tasks. If you refactor those almost identical twenty versions of that function (the twelve versions you knew about plus the eight versions every previous coder missed because the word "process" had a capital 'P' in eight of the function names) into a single version of a function with special case logic, you A. reduce the number of places you have to change when you add a feature or fix a bug that affects all of those functions, B. significantly reduce the odds of forgetting to change one of them when adding features or fixing bugs, and C. almost invariably find places where the functions unintentionally differed in behavior slightly, generally as a result of missing one version of the function in prior feature additions or bug fixes.
I've found that this redundancy tends to happen far more in object-oriented programming than in procedural programming. I think that this is because programmers often override entire methods in the superclass without bothering to break out the minimum portions with variant behavior into their own methods. In procedural programming, by contrast, the tendency is to modify the existing function, though in some cases, I've still seen multiple copies of near-identical functions. *sigh*
In any case, whenever you increase code reuse through refactoring, you almost invariably reduce existing bugs and reduce the odds of new bugs creeping in. With the exception of cases where it reduces code volume, though, I wouldn't generally recommend refactoring a working app.
Check out my sci-fi/humor trilogy at PatriotsBooks.
Yes I know that replicating bugs is not a virtue, but strictly speaking, refactoring should neither introduce bugs nor eliminate them.
The other forms of documentation are meaningful names. If you want to document a sub-expression, which does not have a name, give it a name, by assigning it into a variable before using it. If a piece of code does not have a name, then give it a name by putting it in a separate function.
Variable and function names are much less likely to go out of sync with the meaning of the code than comments are, are more concise and less redundant (so they avoid violating the DRY principle).
Remember, bad/wrong documentation is worse than no documentation.
For the love of Christ, the book is more than eight years old! It's just getting slashdotted now?
What about "proactive refactoring." Before coding your new feature into a system, you can do some analysis and identify ways to refactor the existing code so that your change is easier to implement and will have the least amount of impact on the rest of the system.
I got nothin'
Encapsulation is a form of refactoring.
There's lots of posts about how Refactoring is a waste of time, broke something or leads to bad code. I would put it to you that taking a saw and a hammer, one can do a lot to damage a perfectly good house. On the other hand, they can be used to build a nice new deck. I imagine that since I have no experience with a hammer that I would do a lot of damage. Why does everyone with no experience at Refactoring, and who tries it with poor results, assume that Refactoring is bad?
What to about this? Some options:
Refactoring (properly) leads to improved productivity and contentment, but learning any tool requires more than reading a book.
Uh, do both.
Oh, please. At no time should you replicate errors. Refactoring is a method for finding and correcting errors as well as providing structure and legibility.
Consider the goal, not the means. The goal is documenting the code. Those who go against comments (me included) are not against documentation of the code. We are against documentation that may easily lose sync with the code, where better forms of documentation exist.
Yes, maintaining documentation in comments requires a certain amount of discipline. But if you don't have the discipline necessary to maintain comments, you're not going to have the discipline to write code that is as clear as XP thinks it should be.
Of course, most developers think they're perfect and infallible, so they will never admit that they don't have this discipline, and continue with their bad habits.
Furthermore, what is clear in code to one programmer isn't necessarily going to be clear to another. Human-language comments provide a lowest common denominator of clarity.
Remember, bad/wrong documentation is worse than no documentation.
Documentation is for intent. Documentation that is out of date can at least explain the intent of a piece of code, which will help a good developer deduce what is really going on.
Then, being a good developer, they will fix the documentation.
Comment removed based on user account deletion
"The Mythical Man Month" by Fred Brooks was first published in 1975, and republished in 2000 as a 25th anniversary edition.
;)
And it's still one of the most insightful books about commercial software development out there.
The Pragmatic chaps aren't bad either, but I'm not convinced they'll get republished in 2024
no taxation without representation!
Those who go against comments (me included) are not against documentation of the code. We are against documentation that may easily lose sync with the code, where better forms of documentation exist.
And what if commenting is the best form of documentation?
No offence, but if you often found your comments and code got out of sync, you were probably writing the wrong kind of comments. Good comments don't just repeat what the code does. They explain why and perhaps how it does it. They warn of subtleties not immediately obvious from the code (because sometimes, the appropriate algorithms or data structures just aren't obvious to someone unfamiliar with the code). They refer to other documentation with more detailed background information.
In short, they tell you the stuff the code can't, because sometimes code is too low level to represent the conceptual understanding of the programmer who wrote it. It's pretty hard for that sort of thing to get out of sync with the code without it being pretty darn obvious.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
Its not that _my_ code and comments go out of sync. Its that it is rare that I can't get the code to speak for itself, without comments being necessary.
It does happen, and I do sometimes have to write some comments because communicating something via the naming or other coding artifacts is impossible, but only very rarely.
Discipline is nice, and you should have it, but a system that requires less of it is better, because discipline is not boolean. Whenever discipline is required, some percentage of the time, it will not be adhered, and if there's an alternative that requires less discipline, its a better one.
This is refactoring, turning bad code that typically ends out being more expensive (server load) for the company into cheaper, better, faster, less buggy, code.
No, it isn't.
By definition, refactoring does not change behaviour, at all. Not for the worse. Not for the better.
Now, once you've finished refactoring the code into a more manageable shape, it should be easier to fix bugs or add new features. You might even discover new bugs in the course of the refactoring, and be able to address those when you do whatever you came to do in the first place. But these things are not themselves refactoring. It simply isn't what the word means.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
In theory, you are correct. In practice, though, such perfectly pure refactoring almost never happens and probably should never happen.
Refactoring frequently turns up glaringly obvious inconsistencies that nobody noticed before---usually because nobody was looking at those pieces of code before. If you don't fix the bugs (or at a minimum, log those inconsistencies for later review) while you do the refactoring, you are missing a great opportunity; odds are, those bugs will never get noticed again once you are no longer touching that piece of code and looking for inconsistencies....
Second, refactoring is often for the purpose of making it easy to add a feature. The easiest way to make sure that the change is practical is to make it while you are refactoring the code so that if you run into an "Oh, crap, I can't do this like that" moment, you can rethink the way you are refactoring the code and won't have to go back and do it all over again. As such, this sort of refactoring tends not to reproduce the original behavior, but rather some superset of the original behavior. A pure refactoring approach is more likely to waste a lot of time with a new architecture that almost works but fails to account for one edge case that requires rewriting the whole bloody module. :-)
Check out my sci-fi/humor trilogy at PatriotsBooks.
You have the key. Documentation is for intent. The code describes how "it" gets done, the documentation describes why. The code should be self-describing, but the documentation links the various functions together.
Not a sentence!
Write tests!
The only way you can make sure while refactoring an application that at the end of the process it will still behave the same way as it did before the refactoring is to write unit tests. Never (heavily) refactor untested code.
Refactoring makes most sense in XP/Agile/$buzzword development where the code has good unit test coverage and continous integration. When you commit the refactored code it's immediately unit tested. If it passes you know it's not broken. Caveat being you've got good tests. :)
I'm sorry if I haven't offended anyone
+1 Obscure
I think Martin Fowler (and everybody else with a lick of sense) actually agrees with you. As I understand it, the XP objection to writing comments has been overblown by a few XP proponents and a horde of XP detractors; what you find in the mainstream XP writings is a twofold argument that writing comments should not be the first response to unclear code:
Clarify your code before resorting to comments. If a section of code is complicated enough to need comments, it was probably written suboptimally the first time through, when the programmer's understanding is incomplete. If you write comments before cleaning up the code, the comments end up being an apology for a convoluted first-stab implementation. This (as I understand it) is Fowler's main complaint about lengthy code comments: they're a bad code smell in themselves and often indicate poorly organized code that should be scrapped, not documented. A quick rewrite with the benefit of hindsight will greatly improve the code clarity, perhaps eliminating the need for comments. Unfortunately, this bit of advice pisses programmers off because it assumes that they don't clean up code as they go along. Some programmers do so instinctively, and the rest are fed up with being told to.
Why write a comment when you can express it as a test and kill two birds with one stone? This tends to piss people off because it assumes, as many other part of XP do, that the programming group is following XP wholeheartedly. That means that every programmer who works on a piece of code is familiar with all the tests for that code and will refer to them when he needs information about the code. This is actually a very uncommon way of working, so the advice that depends on it is useless to most programmer. In the context of a full commitment to extreme programming, though, the advice makes perfect sense.
After applying these two principles (and ignoring the second if it doesn't apply,) I think XPers are happy to add whatever comments are useful. There are some XPers who take the "comments are bad" principle and make it EXTREME!!!!!!! (insert image of snowboarding Mountain Dew drinker, which dates XP pretty accurately,) and eXtreme Programming is an unfortunate name that positively *invites* confusions like these, where the most extreme statements made by any self-proclaimed XPer are taken to be the true XP way. The strict "no comments" rule is a minority viewpoint and not one advocated (AFAIK) by the originators of XP and the most common XP resources (the Extreme Programming Explained series, extremeprogramming.org, etc.)