Refactoring: Improving the Design of Existing Code 184
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.
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.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 |
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.
who doesn't know about Refactoring? (Score:4, Interesting)
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.
Java-Specific (Score:1, Interesting)
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.
Love refactoring but primary problem is legal (Score:5, Interesting)
"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.
A problem with 'refactoring' (Score:5, Interesting)
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.
Re:Old news. (Score:4, Interesting)
Re:Change, we love it! (Score:3, Interesting)
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.
Re:Love refactoring but primary problem is legal (Score:3, Interesting)
Re:Love refactoring but primary problem is legal (Score:3, Interesting)
From here:
http://www.pkftexas.com/pkf/NewsBot.asp?MODE=VIEW&ID=15&SnID=2 [pkftexas.com]
The entrepreneurial owner of a growing business would like to expand into other cities and states, but is hesitant. He does not believe his current accounting software will be able to handle the increased transaction load and produce the type of management reports he needs to make effective decisions, and the cost of the next tier software has always been a little out of reach. Under the 2003 Act, the business could expense the first $100,000 of the cost of the next tier accounting software and could immediately save $34,000 in taxes, using a 34% tax rate.
In other words, "new" software is 2/3 the price of the same code done as maintenance code.
So the ROI on your 100,000 maintenance change must be at least 34,000 to be equally justified to replacing the code with a new 100,000 project.
I know that there are huge benefits to refactoring code- but there are huge tax advantages (that translate to large real amounts of money) to writing it new.
Re:Love refactoring but primary problem is legal (Score:3, Interesting)
Agreed! And that's the best way to explain it to execs.
On a new project, you refactor to keep debt low. On a legacy project, you refactor to keep "interest" costs low. The interest on technical debt comes out as less reliable systems, buggier code, increased maintenance cost, and higher costs for new features. All of those cost cash money, which in my experience is a lot more money than you'd pay to do things right.
Re:Love refactoring but primary problem is legal (Score:3, Interesting)
I'm not sure where "reusable" code falls in this mix. Here you reuse existing code for a new project.
Refactoring (Score:2, Interesting)
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.