Working effectively with legacy code

328 122 0
Working effectively with legacy code

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Table of Contents Robert C Martin Series Foreword Preface Acknowledgments Introduction How to Use This Book Part I: The Mechanics of Change Chapter Changing Software .6 Four Reasons to Change Software Improving Design Risky Change Chapter Working with Feedback .10 Software Vise .10 What Is Unit Testing? 11 Test Harnesses .12 .12 Higher-Level Testing 15 .19 Test Coverings .16 The Legacy Code Dilemma 19 .21 Figure 2.2 Invoice update classes with dependencies broken 21 The Legacy Code Change Algorithm 22 Chapter Sensing and Separation 23 Faking Collaborators .24 Fake Objects Support Real Tests 27 The Two Sides of a Fake Object 27 Chapter The Seam Model 27 A Huge Sheet of Text 28 Seams .30 Seam .31 Seam Types 34 Seam .35 Enabling Point 35 .37 Link Seams 35 Usage Tip .37 Object Seams 41 Chapter Tools .1 Automated Refactoring Tools Tests and Automated Refactoring Mock Objects Unit-Testing Harnesses 10 General Test Harnesses 12 Part II: Changing Software 14 Chapter I Don't Have Much Time and I Have to Change It 17 It Happens Someplace Every Day .17 Sprout Method .18 Sprout Class 18 Wrap Method 19 Wrap Class 23 The Decorator Pattern 23 Summary .24 Chapter It Takes Forever to Make a Change 24 i Table of Contents Part II: Changing Software Understanding .24 Lag Time .25 Breaking Dependencies 26 The Dependency Inversion Principle 26 .31 Figure 7.5 Package structure 30 Summary .37 Chapter How Do I Add a Feature? 37 .39 Test-Driven Development (TDD) 38 Remove Duplication 39 TDD and Legacy Code 40 .42 Programming by Difference 41 The Liskov Substitution Principle .44 Figure 8.7 Normalized hierarchy 45 Summary .45 Chapter I Can't Get This Class into a Test Harness 46 .51 The Case of the Irritating Parameter .49 Figure 9.1 RGHConnection 53 Test Code vs Production Code 57 Pass Null 60 Null Object Pattern 62 The Case of the Hidden Dependency 65 The Case of the Construction Blob .65 .68 The Case of the Irritating Global Dependency 67 The Case of the Horrible Include Dependencies 68 The Case of the Onion Parameter 71 The Case of the Aliased Parameter .73 Chapter 10 I Can't Run This Method in a Test Harness .75 .77 The Case of the Hidden Method 76 Subverting Access Protection 77 The Case of the "Helpful" Language Feature .78 The Case of the Undetectable Side Effect .78 Command/Query Separation 80 Figure 10.1 AccountDetailFrame 82 Chapter 11 I Need to Make a Change What Methods Should I Test? .85 Reasoning About Effects .86 IDE Support for Effect Analysis 87 .87 .88 Figure 11.1 declarations impacts geTDeclarationCount 88 .90 Reasoning Forward 90 Figure 11.9 Effects through the Element class .91 .93 Effect Propagation 93 .97 Tools for Effect Reasoning 94 Learning from Effect Analysis 97 Simplifying Effect Sketches 100 Effects and Encapsulation 101 Chapter 12 I Need to Make Many Changes in One Area Do I Have to Break Dependencies for .102 All the Classes Involved? 101 .103 Interception Points .103 Higher-Level Interception Points 105 Pinch Point 106 Judging Design with Pinch Points .106 Using Effect Sketches to Find Hidden Classes 106 ii Table of Contents Part II: Changing Software Pinch Point Traps 107 Chapter 13 I Need to Make a Change, but I Don't Know What Tests to Write 109 .110 Characterization Tests 110 The Method Use Rule 111 Characterizing Classes 111 When You Find Bugs 112 .112 Targeted Testing 112 Refactoring Tool Quirks 116 A Heuristic for Writing Characterization Tests 119 Chapter 14 Dependencies on Libraries Are Killing Me 120 .121 Chapter 15 My Application Is All API Calls 123 Figure 15.1 A better mailing list server 124 Chapter 16 I Don't Understand the Code Well Enough to Change It .127 Notes/Sketching 129 Listing Markup 130 Scratch Refactoring .130 Delete Unused Code 131 Chapter 17 My Application Has No Structure 132 Telling the Story of the System 133 Naked CRC 134 Conversation Scrutiny 137 Chapter 18 My Test Code Is in the Way 139 Class Naming Conventions 142 Test Location .144 Chapter 19 My Project Is Not Object Oriented How Do I Make Safe Changes? 145 An Easy Case .145 A Hard Case 147 Adding New Behavior 147 Taking Advantage of Object Orientation 148 It's All Object Oriented .148 Chapter 20 This Class Is Too Big and I Don't Want It to Get Any Bigger 148 Single-Responsibility Principle (SRP) .149 Figure 20.1 Rule parser 150 Seeing Responsibilities 151 Heuristic #1: Group Methods .152 Heuristic #2: Look at Hidden Methods 156 Figure 20.3 RuleParser and TermTokenizer 156 Heuristic #3: Look for Decisions That Can Change 158 Heuristic #4: Look for Internal Relationships 158 .159 Figure 20.4 Variables in the Reservation class 159 Figure 20.6 Feature sketch for Reservation 160 Heuristic #5: Look for the Primary Responsibility 160 Figure 20.11 The ScheduledJob class 162 Interface Segregation Principle (ISP) 162 Figure 20.14 Segregating the interface of ScheduledJob 164 Heuristic #6: When All Else Fails, Do Some Scratch Refactoring 165 Heuristic #7: Focus on the Current Work 166 Other Techniques 167 Moving Forward 168 After Extract Class 170 Chapter 21 I'm Changing the Same Code All Over the Place 176 iii Table of Contents Part II: Changing Software Figure 21.1 AddEmployeeCmd and LoginCommand 178 First Steps 178 Deciding Where to Start .179 .183 Figure 21.2 Command hierarchy 182 Figure 21.3 Pulling up writeField .184 Abbreviations .185 Open/Closed Principle .190 Chapter 22 I Need to Change a Monster Method and I Can't Write Tests for It 193 Varieties of Monsters 193 .194 Tackling Monsters with Automated Refactoring Support 194 Figure 22.4 Logic class extracted from CommoditySelectionPanel 195 The Manual Refactoring Challenge 198 Strategy 200 Chapter 23 How Do I Know That I'm Not Breaking Anything? Hyperaware Editing Single-Goal Editing Preserve Signatures Lean on the Compiler Chapter 24 We Feel Overwhelmed It Isn't Going to Get Any Better Part III: Dependency-Breaking Techniques Chapter 25 Dependency-Breaking Techniques Adapt Parameter Steps 13 .14 Break Out Method Object .13 Steps 15 Definition Completion 16 .17 Encapsulate Global References .16 Steps 21 .22 Expose Static Method 22 Steps 24 Extract and Override Call 25 .26 Extract and Override Factory Method 25 Steps 28 .32 Extract and Override Getter 30 Steps 34 .36 Extract Implementer 34 Steps 38 Extract Interface 38 Interface Naming 40 .42 Steps 42 Extract Interface and Non-Virtual Functions .43 Introduce Instance Delegator 46 Introduce Static Setter 46 The Singleton Design Pattern 47 .47 Steps 48 Link Substitution 48 .50 Parameterize Constructor 50 Steps 50 .54 Parameterize Method .53 Steps 56 iv Table of Contents Part III: Dependency-Breaking Techniques .59 Primitivize Parameter 58 Steps 59 .64 Pull Up Feature 61 Push Down Dependency .66 .67 Replace Function with Function Pointer .66 Steps 68 Replace Global Reference with Getter 69 Subclass and Override Method 70 .71 Supersede Instance Variable 70 Steps 71 .72 Template Redefinition 71 Steps 74 .title Text Redefinition 75 Steps title Appendix Refactoring .title .title Extract Method title Glossary .title v vi Part I: The Mechanics of Change Chapter Changing Software Chapter Working with Feedback Chapter Sensing and Separation Chapter The Seam Model Chapter Tools Chapter Changing Software Changing code is great It's what we for a living But there are ways of changing code that make life difficult, and there are ways that make it much easier In the industry, we haven't spoken about that much The closest we've gotten is the literature on refactoring I think we can broaden the discussion a bit and talk about how to deal with code in the thorniest of situations To that, we have to dig deeper into the mechanics of change Four Reasons to Change Software For simplicity's sake, let's look at four primary reasons to change software Adding a feature Fixing a bug Improving the design Optimizing resource usage Adding Features and Fixing Bugs Adding a feature seems like the most straightforward type of change to make The software behaves one way, and users say that the system needs to something else also Suppose that we are working on a web-based application, and a manager tells us that she wants the company logo moved from the left side of a page to the right side We talk to her about it and discover it isn't quite so simple She wants to move the logo, but she wants other changes, too She'd like to make it animated for the Part I: The Mechanics of Change Part I: The Mechanics of Change next release Is this fixing a bug or adding a new feature? It depends on your point of view From the point of view of the customer, she is definitely asking us to fix a problem Maybe she saw the site and attended a meeting with people in her department, and they decided to change the logo placement and ask for a bit more functionality From a developer's point of view, the change could be seen as a completely new feature "If they just stopped changing their minds, we'd be done by now." But in some organizations the logo move is seen as just a bug fix, regardless of the fact that the team is going to have to a lot of fresh work It is tempting to say that all of this is just subjective You see it as a bug fix, and I see it as a feature, and that's the end of it Sadly, though, in many organizations, bug fixes and features have to be tracked and accounted for separately because of contracts or quality initiatives At the people level, we can go back and forth endlessly about whether we are adding features or fixing bugs, but it is all just changing code and other artifacts Unfortunately, this talk about bug-fixing and feature addition masks something that is much more important to us technically: behavioral change There is a big difference between adding new behavior and changing old behavior Behavior is the most important thing about software It is what users depend on Users like it when we add behavior (provided it is what they really wanted), but if we change or remove behavior they depend on (introduce bugs), they stop trusting us In the company logo example, are we adding behavior? Yes After the change, the system will display a logo on the right side of the page Are we getting rid of any behavior? Yes, there won't be a logo on the left side Let's look at a harder case Suppose that a customer wants to add a logo to the right side of a page, but there wasn't one on the left side to start with Yes, we are adding behavior, but are we removing any? Was anything rendered in the place where the logo is about to be rendered? Are we changing behavior, adding it, or both? It turns out that, for us, we can draw a distinction that is more useful to us as programmers If we have to modify code (and HTML kind of counts as code), we could be changing behavior If we are only adding code and calling it, we are often adding behavior Let's look at another example Here is a method on a Java class: public class CDPlayer { public void addTrackListing(Track track) { } } The class has a method that enables us to add track listings Let's add another method that lets us replace track listings public class CDPlayer { public void addTrackListing(Track track) { } public void replaceTrackListing(String name, Track track) { } Part I: The Mechanics of Change ... Coverings .16 The Legacy Code Dilemma 19 .21 Figure 2.2 Invoice update classes with dependencies broken 21 The Legacy Code Change Algorithm ... choose a surgeon who operated with a butter knife just because he worked with care Effective software change, like effective surgery, really involves deeper skills Working with care doesn't much for... for the testing code that we write to exercise some piece of software and the code that is needed to run it We can use many different kinds of test harnesses to work with our code In Chapter

Ngày đăng: 18/04/2019, 15:35

Mục lục

  • Part I: The Mechanics of Change

    • Chapter 1. Changing Software

      • Four Reasons to Change Software

      • Software Vise

        • What Is Unit Testing?

          • The Legacy Code Change Algorithm

          • Chapter 3. Sensing and Separation

            • Faking Collaborators

            • Fake Objects Support Real Tests

              • The Two Sides of a Fake Object

              • Chapter 4. The Seam Model

                • A Huge Sheet of Text

                • Tests and Automated Refactoring

                  • Mock Objects

                  • Part II: Changing Software

                    • Chapter 6. I Don't Have Much Time and I Have to Change It

                    • It Happens Someplace Every Day

                      • Sprout Method

                      • Chapter 7. It Takes Forever to Make a Change

                        • Understanding

                        • Chapter 8. How Do I Add a Feature?

                          • Test-Driven Development (TDD)

                          • TDD and Legacy Code

                            • Programming by Difference

                            • Chapter 9. I Can't Get This Class into a Test Harness

                              • The Case of the Irritating Parameter

                              • Null Object Pattern

                                • The Case of the Hidden Dependency

                                • The Case of the Construction Blob

                                • The Case of the Irritating Global Dependency

                                  • The Case of the Horrible Include Dependencies

                                  • The Case of the Onion Parameter

                                  • The Case of the Aliased Parameter

                                  • Chapter 10. I Can't Run This Method in a Test Harness

                                    • The Case of the Hidden Method

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan