Sunday, May 31, 2015

Notes on Working Effectively with Legacy Code

What is legacy code?

Code without unit tests. May or may not be poorly structured.

Legacy Code Changing Algorithm


  1. Figure out where you need to make a change in the code
  2. Figure out how you're going to test the change
  3. Break dependencies
  4. Write unit tests
  5. Make the change

Unit Tests

Unit tests are important because they shorten the "feedback loop" - the time it takes to verify a change in the code. 

Why is shortening the feedback loop important? It's pretty simple: you can confidently make changes, and make them faster. You maintain intense mental focus on coding, because you aren't constantly waiting for a build to finish, or a very long test to finish.

A good unit test has these characteristics: 
  1. Tests one thing
  2. Is fast - they shouldn't do any IO (network, file system, database)
  3. Localizes errors - if a unit test fails i want to know right away that the problem was caused in my method, not some method or object that it's dependent on.
The main obstacle with writing unit tests is dependencies. The rest of the notes contain ways to break dependencies.

First, some terminology

Fake Object
1. Extract out the dependency code
2. Turn it into an interface
3. Create a class on that interface just for testing. 

Sensing = seeing the effects of calls on the fake object. 
Separation = extracting out the dependent code.

Seams
In OO if I have a class that calls something that is hard to test, for example, I could write a function with the same name, make it virtual, subclass it using TestingClass, then override the function and make it do nothing. This keeps production code the same, and simply bypasses the dependency

In procedural code I could write wrapper functions, check if it's test mode, and make it do the actual call if it's not test, and other behavior in another. 

Sprout methods/classes
These are used when i want to make a change to code without bringing the current code under test. 

Sprouts= put the change in its own method/class, use the method/class from the current code, and unit test the new code without testing the current code.

Test-driven development? It means writing a skeleton method, writing a unit test with the expected result, and then implementing the method until it passes the test. 

Hidden Dependency 
A constructor initializes class without us passing anything into the constructor.

Characterization tests
Tests written against existing code, using their current output as the assertion for after the change. Then you make the change and run the tests again, assuring the behavior didn't change by asserting the original output.

Adding unit tests in different scenarios

Testing a private method

1. Test through callers 
2. Make it public
    -this might expose poor design. In that case we can refactor by pulling the function out to its own class. This results in better design that is testable
    -if we can't refactor totally like that then make it protected and subclass it. 

Testing a method that uses sealed classes

-is it implementing an interface or superclass? Subclass or implement the interface, pass that in for testing
-neither of those - figure out what fields are needed, then extract an interface and wrap the API. Then a fake object can be used. The problem with this is before calling, the sealed class needs to be put into the wrapper.


Testing when there's hidden dependencies

  1. parameterize the constructor by adding the dependent class
  2. pass in a fake object for sensing in testing 
  3. extract original constructor to init() which accepts the new parameter.
  4. if the language supports it, have the old constructor call the parameterized constructor, passing in a new object of the type we need. 

Testing when using third party libraries

-write thin wrappers over top of them
-good libraries make use of virtual methods and use interfaces
-good code runs in test and production
-don't become overly reliant on one library

Adding tests when there are Big Classes
-problems: confusing, hard to test, long time to understand 
-solutions
Refactor the class based on the Single Responsibility Principle
Use sprout class/method to keep from adding to the mess
-seeing responsibilities
--describe in one sentence
--group methods: 1) match methods by what they do. 2) use a graph to figure out relationships between methods and variables. 3) if I want to test a private method it should probably be extracted into a new class
-don't get overly ambitious with refactoring big class. It will destabilize the program. It works right now. Figure out what refactoring should be done, then do it as needed, not all at once.

Adding tests when there are big methods

1. Types: bulleted (no indents), snarled (huge indents)
2. Method Extraction is the primary tool here
--separate logic
--break dependencies
--introduce seams and sensing variables. This allows the code to be put under test.
--start small: extract methods with low parameter counts first.
--Extract conditional logic
--use guard clauses to normalize indentation 

Dependency Breaking Techniques

1. adapt parameter 
A parameter that is hard to get under test, such as SqlDataReader.
-extract an interface that only contains the functionally needed
-implement the production code, which is simply a wrapper for the SQLDataReader
-implement a test class, which passes back whatever you need

Another way to do this is to implement the interface that is used by the concrete class. For example, SqlDataReader implements the IDataRecord interface. I can change the parameter to IDataRecord, pass in SqlDataReader in production and a fake implemention in testing

2. Break out method object
Basically cut and paste a method to a new class. Preserve the method signature. Have the old method delegate to this new class. This breaks the dependency of having to instantiate the old methods class, and therefore can be put under test pretty easily


3. Encapsulate globals
   . Extract globals into a class, make the object global
   . Fix broken references to the globals
   . For testing - static setter, parameterize constructor

4. Expose static method
       .extract method to static method using the same signature
       .now you can write tests against the static method 
       .have old method delegate to static -or- get rid of it and fix compile errors

5. Extract and Override Method
       .subclass the pesky class
           .override the pesky method
    Use the subclass in tests
   Note this also opens the door for sensing in the method

6. Extract Factory Method and Override
A. Extract constructor logic to a method
B. Create a testing subclass
C. Override the method
You can now out the class under test, because pesky constructor code can be overridden 

7. Extract and override getter
A. Make a lazy getter for the pesky object
B. Subclass and override the getter method
Now it can be put under test, because you can pass in a fake. Factory method and override is better. 

8. Extract Interface
A. Make an empty interface
B. Make the class you're extracting from implement the interface
C. Change the code where you're using the class to accept the interface instead
D. Compile. This will show you all the methods that need to be added to the interface
E. Finally, add a test class implementer

9. Instance delegator
A. Find a static method to delegate to, copy its signature into an instance method
B. Simply call the static method
C. Find all callers of the static method and replace them with calls to the delegating method

10. Parameterize constructor - use this when a constructor creates an object that makes it hard to test
A. Copy the constructor
B. Add a parameter for the pesky object
C. Set the instance object to the parameter object
D. Remove the body of the original constructor and have it call this new constructor, passing on the created object. This preserves behavior so all the callers don't need to be updated.
E. Now you can pass fakes into the new constructor in unit tests
      
11. Parameterize method
A. Copy method you are going to parameterize
B. Add parameter for object that method is creating
C. Change the original method to delegate to the new method

12. Pull Up Feature
A. Create a superclass for a class that needs testing
B. Cut and paste the methods from the subclass 
C. Get it compiling
D. Create a testing subclass and implement the methods to be tested

13. Push Down Dependency
A. Create a subclass on a class you want to get under test
B. Cut and paste methods and instance variables to the subclass that cause dependency problems.
C. Turn the original class into an abstract class
D. Add a testing subclass 
Note: this seems very similar to pull up feature

14. Replace global with getter
1. Wrap global variable in a class
2. Add a getter Method
3. Fix all callers to use the getter
4. Testing Subclass and override the getter 

15. Subclass and Override Method - this is the main dependency breaker
A. Make method overridable, by setting it as a virtual 
B. Testing subclass and override the method

Tuesday, May 12, 2015

Error in equation '***ILLEGAL SYNTAX ***VIRTUAL'

Solution
There's a field in the Report Footer that has DisplayType=Last Occurence. I changed this to Data and it got rid of that error.

Tuesday, May 5, 2015

Dexterity repository is showing items that have been deleted (when using TFS)

Solution
TFS doesn't permanently delete items. You need to destroy the item. You can do that in the command line or use this extension to do it from the UI: https://visualstudiogallery.msdn.microsoft.com/af70cbb7-1e0d-4d16-bc57-cccc15370c51 

These steps are assuming you're using UI

Step 0 - Can you see deleted items?
If you can't see the deleted item in TFS Team Explorer, do this:
1. In VS > Options
2. Source Control > Visual Studio Team Foundation Server
3. Check "Show deleted items in the Source Control Explorer"

Step 1 - Destroy
1. Right-click on the item to delete
2. Advanced > Destroy
3. Choose the option saying you understand it deletes it

Step 2 - Verify in Dex repository that the item no longer shows up
There was an error in this gadget