Refactoring: Improving The Design Of Existing Code By .

Transcription

Refactoring: Improving the Design of Existing Codeby Martin Fowler, Kent Beck (Contributor), John Brant (Contributor), WilliamOpdyke, don RobertsAnother stupid release 2002JFor all the people which doesn’t have money to buy a good book

Your class library works, but could it be better? Refactoring: Improving the Design ofExisting Code shows how refactoring can make object-oriented code simpler and easierto maintain. Today refactoring requires considerable design know-how, but once toolsbecome available, all programmers should be able to improve their code using refactoringtechniques.Besides an introduction to refactoring, this handbook provides a catalog of dozens of tipsfor improving code. The best thing about Refactoring is its remarkably clear presentation,along with excellent nuts-and-bolts advice, from object expert Martin Fowler. The authoris also an authority on software patterns and UML, and this experience helps make this abetter book, one that should be immediately accessible to any intermediate or advancedobject-oriented developer. (Just like patterns, each refactoring tip is presented with asimple name, a "motivation," and examples using Java and UML.)Early chapters stress the importance of testing in successful refactoring. (When youimprove code, you have to test to verify that it still works.) After the discussion on howto detect the "smell" of bad code, readers get to the heart of the book, its catalog of over70 "refactorings"--tips for better and simpler class design. Each tip is illustrated with"before" and "after" code, along with an explanation. Later chapters provide a quick lookat refactoring research.Like software patterns, refactoring may be an idea whose time has come. Thisgroundbreaking title will surely help bring refactoring to the programming mainstream.With its clear advice on a hot new topic, Refactoring is sure to be essential reading foranyone who writes or maintains object-oriented software. --Richard DraganTopics Covered: Refactoring, improving software code, redesign, design tips, patterns,unit testing, refactoring research, and tools.Book News, Inc.A guide to refactoring, the process of changing a software system so that it does not alterthe external behavior of the code yet improves its internal structure, for professionalprogrammers. Early chapters cover general principles, rationales, examples, and testing.The heart of the book is a catalog of refactorings, organized in chapters on composingmethods, moving features between objects, organizing data, simplifying conditionalexpressions, and dealing with generalizations2

Foreword. 6Preface. 8What Is Refactoring? . 9What's in This Book? . 9Who Should Read This Book? . 10Building on the Foundations Laid by Others . 10Acknowledgments . 11Chapter 1. Refactoring, a First Example . 13The Starting Point. 13The First Step in Refactoring . 17Decomposing and Redistributing the Statement Method . 18Replacing the Conditional Logic on Price Code with Polymorphism . 35Final Thoughts . 44Chapter 2. Principles in Refactoring . 46Defining Refactoring . 46Why Should You Refactor? . 47Refactoring Helps You Find Bugs . 48When Should You Refactor? . 49What Do I Tell My Manager?. 52Problems with Refactoring . 54Refactoring and Design. 57Refactoring and Performance . 59Where Did Refactoring Come From?. 60Chapter 3. Bad Smells in Code. 63Duplicated Code . 63Long Method . 64Large Class . 65Long Parameter List. 65Divergent Change . 66Shotgun Surgery. 66Feature Envy. 66Data Clumps . 67Primitive Obsession . 67Switch Statements . 68Parallel Inheritance Hierarchies . 68Lazy Class . 68Speculative Generality. 68Temporary Field . 69Message Chains . 69Middle Man. 69Inappropriate Intimacy . 70Alternative Classes with Different Interfaces . 70Incomplete Library Class. 70Data Class . 70Refused Bequest. 713

Comments . 71Chapter 4. Building Tests. 73The Value of Self-testing Code . 73The JUnit Testing Framework . 74Adding More Tests . 80Chapter 5. Toward a Catalog of Refactorings . 85Format of the Refactorings . 85Finding References . 86How Mature Are These Refactorings?. 87Chapter 6. Composing Methods . 89Extract Method. 89Inline Method. 95Inline Temp. 96Replace Temp with Query . 97Introduce Explaining Variable. 101Split Temporary Variable . 104Remove Assignments to Parameters . 107Replace Method with Method Object . 110Substitute Algorithm . 113Chapter 7. Moving Features Between Objects. 115Move Method . 115Move Field . 119Extract Class . 122Inline Class . 125Hide Delegate . 127Remove Middle Man. 130Introduce Foreign Method. 131Introduce Local Extension. 133Chapter 8. Organizing Data . 138Self Encapsulate Field . 138Replace Data Value with Object . 141Change Value to Reference . 144Change Reference to Value . 148Replace Array with Object . 150Duplicate Observed Data . 153Change Unidirectional Association to Bidirectional . 159Change Bidirectional Association to Unidirectional . 162Replace Magic Number with Symbolic Constant . 166Encapsulate Field . 167Encapsulate Collection. 168Replace Record with Data Class . 175Replace Type Code with Class . 176Replace Type Code with Subclasses . 181Replace Type Code with State/Strategy. 184Replace Subclass with Fields. 188Chapter 9. Simplifying Conditional Expressions . 1924

Decompose Conditional . 192Consolidate Conditional Expression . 194Consolidate Duplicate Conditional Fragments . 196Remove Control Flag . 197Replace Nested Conditional with Guard Clauses . 201Replace Conditional with Polymorphism . 205Introduce Null Object . 209Introduce Assertion . 216Chapter 10. Making Method Calls Simpler. 220Rename Method . 221Add Parameter. 222Remove Parameter . 223Separate Query from Modifier . 225Parameterize Method . 228Replace Parameter with Explicit Methods. 230Preserve Whole Object . 232Replace Parameter with Method . 235Introduce Parameter Object . 238Remove Setting Method. 242Hide Method . 245Replace Constructor with Factory Method . 246Encapsulate Downcast. 249Replace Error Code with Exception . 251Replace Exception with Test . 255Chapter 11. Dealing with Generalization. 259Pull Up Field . 259Pull Up Method . 260Pull Up Constructor Body. 263Push Down Method. 266Push Down Field . 266Extract Subclass . 267Extract Superclass . 272Extract Interface . 277Collapse Hierarchy. 279Form Template Method . 280Replace Inheritance with Delegation. 287Replace Delegation with Inheritance. 289Chapter 12. Big Refactorings . 293Tease Apart Inheritance . 294Convert Procedural Design to Objects . 300Separate Domain from Presentation. 302Extract Hierarchy. 306Chapter 13. Refactoring, Reuse, and Reality. 311A Reality Check . 311Why Are Developers Reluctant to Refactor Their Programs? . 312A Reality Check (Revisited) . 3235

Resources and References for Refactoring . 323Implications Regarding Software Reuse and Technology Transfer. 324A Final Note . 325Endnotes. 325Chapter 14. Refactoring Tools . 328Refactoring with a Tool. 328Technical Criteria for a Refactoring Tool. 329Practical Criteria for a Refactoring Tool. 331Wrap Up . 332Chapter 15. Putting It All Together . 333Bibliography. 336References . 336Foreword"Refactoring" was conceived in Smalltalk circles, but it wasn't long before it found its way intoother programming language camps. Because refactoring is integral to framework development,the term comes up quickly when "frameworkers" talk about their craft. It comes up when theyrefine their class hierarchies and when they rave about how many lines of code they were able todelete. Frameworkers know that a framework won't be right the first time around—it must evolveas they gain experience. They also know that the code will be read and modified more frequentlythan it will be written. The key to keeping code readable and modifiable is refactoring—forframeworks, in particular, but also for software in general.So, what's the problem? Simply this: Refactoring is risky. It requires changes to working code thatcan introduce subtle bugs. Refactoring, if not done properly, can set you back days, even weeks.And refactoring becomes riskier when practiced informally or ad hoc. You start digging in thecode. Soon you discover new opportunities for change, and you dig deeper. The more you dig,the more stuff you turn up and the more changes you make. Eventually you dig yourself into ahole you can't get out of. To avoid digging your own grave, refactoring must be donesystematically. When my coauthors and I wrote Design Patterns, we mentioned that designpatterns provide targets for refactorings. However, identifying the target is only one part of theproblem; transforming your code so that you get there is another challenge.Martin Fowler and the contributing authors make an invaluable contribution to object-orientedsoftware development by shedding light on the refactoring process. This book explains theprinciples and best practices of refactoring, and points out when and where you should startdigging in your code to improve it. At the book's core is a comprehensive catalog of refactorings.Each refactoring describes the motivation and mechanics of a proven code transformation. Someof the refactorings, such as Extract Method or Move Field, may seem obvious.But don't be fooled. Understanding the mechanics of such refactorings is the key to refactoring ina disciplined way. The refactorings in this book will help you change your code one small step ata time, thus reducing the risks of evolving your design. You will quickly add these refactoringsand their names to your development vocabulary.My first experience with disciplined, "one step at a time" refactoring was when I was pairprogramming at 30,000 feet with Kent Beck. He made sure that we applied refactorings from thisbook's catalog one step at a time. I was amazed at how well this practice worked. Not only did myconfidence in the resulting code increase, I also felt less stressed. I highly recommend you trythese refactorings: You and your code will feel much better for it.6

—Erich GammaObject Technology International, Inc.7

PrefaceOnce upon a time, a consultant made a visit to a development project. The consultant looked atsome of the code that had been written; there was a class hierarchy at the center of the system.As he wandered through the hierarchy, the consultant saw that it was rather messy. The higherlevel classes made certain assumptions about how the classes would work, assumptions thatwere embodied in inherited code. That code didn't suit all the subclasses, however, and wasoverridden quite heavily. If the superclass had been modified a little, then much less overridingwould have been necessary. In other places some of the intention of the superclass had not beenproperly understood, and behavior present in the superclass was duplicated. In yet other placesseveral subclasses did the same thing with code that could clearly be moved up the hierarchy.The consultant recommended to the project management that the code be looked at and cleanedup, but the project management didn't seem enthusiastic. The code seemed to work and therewere considerable schedule pressures. The managers said they would get around to it at somelater point.The consultant had also shown the programmers who had worked on the hierarchy what wasgoing on. The programmers were keen and saw the problem. They knew that it wasn't really theirfault; sometimes a new pair of eyes are needed to spot the problem. So the programmers spent aday or two cleaning up the hierarchy. When they were finished, the programmers had removedhalf the code in the hierarchy without reducing its functionality. They were pleased with the resultand found that it became quicker and easier both to add new classes to the hierarchy and to usethe classes in the rest of the system.The project management was not pleased. Schedules were tight and there was a lot of work todo. These two programmers had spent two days doing work that had done nothing to add themany features the system had to deliver in a few months time. The old code had worked just fine.So the design was a bit more "pure" a bit more "clean." The project had to ship code that worked,not code that would please an academic. The consultant suggested that this cleaning up be doneon other central parts of the system. Such an activity might halt the project for a week or two. Allthis activity was devoted to making the code look better, not to making it do anything that it didn'talready do.How do you feel about this story? Do you think the consultant was right to suggest further cleanup? Or do you follow that old engineering adage, "if it works, don't fix it"?I must admit to some bias here. I was that consultant. Six months later the project failed, in largepart because the code was too complex to debug or to tune to acceptable performance.The consultant Kent Beck was brought in to restart the project, an exercise that involved rewritingalmost the whole system from scratch. He did several things differently, but one of the mostimportant was to insist on continuous cleaning up of the code using refactoring. The success ofthis project, and role refactoring played in this success, is what inspired me to write this book, sothat I could pass on the knowledge that Kent and others have learned in using refactoring toimprove the quality of software.8

What Is Refactoring?Refactoring is the process of changing a software system in such a way that it does not alter theexternal behavior of the code yet improves its internal structure. It is a disciplined way to clean upcode that minimizes the chances of introducing bugs. In essence when you refactor you areimproving the design of the code after it has been written."Improving the design after it has been written." That's an odd turn of phrase. In our currentunderstanding of software development we believe that we design and then we code. A gooddesign comes first, and the coding comes second. Over time the code will be modified, and theintegrity of the system, its structure according to that design, gradually fades. The code slowlysinks from engineering to hacking.Refactoring is the opposite of this practice. With refactoring you can take a bad design, chaoseven, and rework it into well-designed code. Each step is simple, even simplistic. You move afield from one class to another, pull some code out of a method to make into its own method, andpush some code up or down a hierarchy. Yet the cumulative effect of these small changes canradically improve the design. It is the exact reverse of the normal notion of software decay.With refactoring you find the balance of work changes. You find that design, rather than occurringall up front, occurs continuously during development. You learn from building the system how toimprove the design. The resulting interaction leads to a program with a design that stays good asdevelopment continues.What's in This Book?This book is a guide to refactoring; it is written for a professional programmer. My aim is to showyou how to do refactoring in a controlled and efficient manner. You will learn to refactor in such away that you don't introduce bugs into the code but instead methodically improve the structure.It's traditional to start books with an introduction. Although I agree with that principle, I don't find iteasy to introduce refactoring with a generalized discussion or definitions. So I start with anexample. Chapter 1 takes a small program with some common design flaws and refactors it intoa more acceptable object-oriented program. Along the way we see both the process of refactoringand the application of several useful refactorings. This is the key chapter to read if you want tounderstand what refactoring really is about.In Chapter 2 I cover more of the general principles of refactoring, some definitions, and thereasons for doing refactoring. I outline some of the problems with refactoring. In Chapter 3 KentBeck helps me describe how to find bad smells in code and how to clean them up withrefactorings. Testing plays a very important role in refactoring, so Chapter 4 describes how tobuild tests into code with a simple open-source Java testing framework.The heart of the book, the catalog of refactorings, stretches from Chapter 5 through Chapter 12.This is by no means a comprehensive catalog. It is the beginning of such a catalog. It includesthe refactorings that I have written down so far in my work in this field. When I want to dosomething, such as Replace Conditional with Polymorphism, the catalog reminds me how todo it in a safe, step-by-step manner. I hope this is the section of the book you'll come back tooften.In this book I describe the fruit of a lot of research done by others. The last chapters are guestchapters by some of these people. Chapter 13 is by Bill Opdyke, who describes the issues hehas come across in adopting refactoring in commercial development. Chapter 14 is by Don9

Roberts and John Brant, who describe the true future of refactoring, automated tools. I've left thefinal word, Chapter 15, to the master of the art, Kent Beck.Refactoring in JavaFor all of this book I use examples in Java. Refactoring can, of course, be done with otherlanguages, and I hope this book will be useful to those working with other languages. However, Ifelt it would be best to focus this book on Java because it is the language I know best. I haveadded occasional notes for refactoring in other languages, but I hope other people will build onthis foundation with books aimed at specific languages.To help communicate the ideas best, I have not used particularly complex areas of the Javalanguage. So I've shied away from using inner classes, reflection, threads, and many other ofJava's more powerful features. This is because I want to focus on the core refactorings as c

So the design was a bit more "pure" a bit more "clean." The project had to ship code that worked, not code that would please an academic. The consultant suggested that this cleaning up be done on other central parts of the system. Such