Working Effectively With Legacy Code

Book notes of Working Effectively With Legacy Code

Get Started. It's Free
or sign up with your email address
Rocket clouds
Working Effectively With Legacy Code by Mind Map: Working Effectively With Legacy Code

1. Adding a feature

1.1. Test Driven Development

1.1.1. Write a failing test

1.1.2. Get it to compile

1.1.3. Make it pass

1.1.4. Remove Duplication Refactor

1.1.5. Repeat

1.1.6. Legacy Addition Get the class under test

1.2. Inheritance

1.2.1. Can be useful but use carefully long term could cause confusion & need refactoring Liskov substitution principle A Rectangle != Square Objects of subclasses should be substitutable for their parent class

1.2.2. Avoid overwriting concrete classes if so, try to call super

2. Testing takes too long?

2.1. When we don't test it takes too long

2.1.1. Compile Time Entire project compilation

2.1.2. Deploy Time

2.1.3. Manual Verification Multiple Times

2.2. Testing

2.2.1. Instantaneous feedback

2.2.2. Helps keep you in context & focused

2.2.3. Future guarantee of the feature with no additional work afterward

2.3. Interfaces require less code to need compiling

2.3.1. so utilize them

3. Test Code

3.1. Not production code

3.1.1. Mock objects can break encapsulation if it makes testing easier

3.1.2. Try passing null Worst case... exception Maybe implement Null Object Pattern This can be production code

4. Getting Classes into Test Harness

4.1. Extract Interface

4.1.1. Mock out new interfaces

4.2. Hidden dependencies

4.2.1. Parameterized constructor

4.2.2. Supersede Instance Variable Worst Case Scenario Public Setter

4.3. Global Dependencies

4.3.1. Singletons Relax it Introduce static setter

4.4. Subclass

4.4.1. when difficult to construct, dependencies can be overwritten by a subclass used as an interface to test desirable testable code

5. Get Method into Test Harness

5.1. Private method

5.1.1. test appropriate public methods they will touch private methods, no need to test the private ones specifically

5.1.2. Make it public if bad fix class

5.1.3. Make it protected & subclass with a public method java package level scope to circumvent the subclass

5.1.4. Reflection Try to NEVER do this sets bad presedence can mask how bad a class is

6. Finding Bugs

6.1. Tests prevent future bugs

6.2. Once reducing the area a bug is in

6.2.1. write Characterization Tests Tests what the code does, not supposed to do Ensures you are not breaking current working functionality Steps

7. Legacy

7.1. Dilema

7.1.1. When we change code - have tests, to add tests, I need to change code

7.2. Definition

7.2.1. Code Without Tests

8. Unit Tests

8.1. FAST!

8.2. Localize problems

8.2.1. quickly

8.3. NOT

8.3.1. touch database

8.3.2. Communicate across network

8.3.3. touch file system

8.3.4. require special environment config

8.3.5. Integration tests

9. Refactoring

9.1. Definition

9.1.1. Changes made to structure w/out changing behavior to make it easier to understand

9.2. Initially

9.2.1. Start Ugly

9.2.2. Surgery analogy Scar left after BUT

9.3. Legacy Code Change Algorithm

9.3.1. Identify Change Points

9.3.2. Find Test Points

9.3.3. Break Dependencies interfaces

9.3.4. Write Tests

9.3.5. Make Changes & Refactor

10. Adding Tests

10.1. Seam

10.1.1. Definition Alter behavior in program without editing in that place Test & Prod code IS THE SAME CODE enabling point spot to enable seam

10.1.2. Use indirect / hard seams to change legacy code very little so you can get tests in place Then refactor

10.1.3. Types Object Seam Replace / Overwrite Object Pre-Processing Seam Compiler arguments to overwrite function definitions Link Seam Overwrite 'Linked'" / imported objects Java

11. Change Definition

11.1. Does it change behavior??

11.2. Functionality

11.3. New Functionality

11.4. Structure

11.5. Resource Usage

12. Adding Behavior

12.1. Sprout Method

12.1.1. Put behavior in a new, distinct, testable method

12.1.2. Test this method even if/though caller is untested

12.1.3. Worst Case Static method w/ arguments of intended class This is a scar Over time it will find a home

12.2. Sprout Class

12.2.1. When difficult to instantiate a class for testing

12.2.2. New class to do new behavior

12.2.3. Would NOT receive "Caller Class" (untested class where code was desired to be put in the first place) Caller Class = Source Class

12.3. Wrap Method

12.3.1. Wrap source method with simpler delegating method Or reuse method name & abstract original code

12.3.2. Decouple functionality from being shoved into the same method

12.3.3. Prevents temporal coupling

12.4. Wrap Class

12.4.1. Decorator Pattern