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

1.1.4.1. Refactor

1.1.5. Repeat

1.1.6. Legacy Addition

1.1.6.1. Get the class under test

1.2. Inheritance

1.2.1. Can be useful but use carefully

1.2.1.1. long term could cause confusion & need refactoring

1.2.1.2. Liskov substitution principle

1.2.1.2.1. A Rectangle != Square

1.2.1.2.2. Objects of subclasses should be substitutable for their parent class

1.2.2. Avoid overwriting concrete classes

1.2.2.1. 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

2.1.1.1. Entire project compilation

2.1.2. Deploy Time

2.1.3. Manual Verification

2.1.3.1. 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

3.1.2.1. Worst case... exception

3.1.2.2. Maybe implement Null Object Pattern

3.1.2.2.1. 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

4.2.2.1. Worst Case Scenario

4.2.2.2. Public Setter

4.3. Global Dependencies

4.3.1. Singletons

4.3.1.1. Relax it

4.3.1.1.1. Introduce static setter

4.4. Subclass

4.4.1. when difficult to construct, dependencies can be overwritten by a subclass

4.4.1.1. 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

5.1.1.1. they will touch private methods, no need to test the private ones specifically

5.1.2. Make it public

5.1.2.1. if bad

5.1.2.1.1. fix class

5.1.3. Make it protected & subclass with a public method

5.1.3.1. java package level scope to circumvent the subclass

5.1.4. Reflection

5.1.4.1. Try to NEVER do this

5.1.4.1.1. sets bad presedence

5.1.4.1.2. 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

6.2.1.1. Characterization Tests

6.2.1.1.1. Tests what the code does, not supposed to do

6.2.1.1.2. Ensures you are not breaking current working functionality

6.2.1.1.3. 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

9.2.2.1. Scar left after

9.2.2.1.1. BUT

9.3. Legacy Code Change Algorithm

9.3.1. Identify Change Points

9.3.2. Find Test Points

9.3.3. Break Dependencies

9.3.3.1. interfaces

9.3.4. Write Tests

9.3.5. Make Changes & Refactor

10. Adding Tests

10.1. Seam

10.1.1. Definition

10.1.1.1. Alter behavior in program without editing in that place

10.1.1.1.1. Test & Prod code IS THE SAME CODE

10.1.1.2. enabling point

10.1.1.2.1. spot to enable seam

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

10.1.2.1. Then refactor

10.1.3. Types

10.1.3.1. Object Seam

10.1.3.1.1. Replace / Overwrite Object

10.1.3.2. Pre-Processing Seam

10.1.3.2.1. Compiler arguments to overwrite function definitions

10.1.3.3. Link Seam

10.1.3.3.1. Overwrite 'Linked'" / imported objects

10.1.3.3.2. 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

12.1.3.1. Static method w/ arguments of intended class

12.1.3.1.1. This is a scar

12.1.3.1.2. 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)

12.2.3.1. Caller Class = Source Class

12.3. Wrap Method

12.3.1. Wrap source method with simpler delegating method

12.3.1.1. 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