14 July 2011<br />© Agile Institute 2011<br />1<br />Café<br />TDD?<br />Sure, but What About My Legacy Code?<br />Rob Mye...
What is “Legacy Code”?<br />14 July 2011<br />© Agile Institute 2011<br />2<br />
14 July 2011<br />© Agile Institute 2011<br />3<br />“Code we’re afraid to change.”<br />-- James Shore<br />“Code without...
14 July 2011<br />© Agile Institute 2011<br />4<br />
Adding Tests Is Difficult<br />14 July 2011<br />© Agile Institute 2011<br />5<br />Circumstantial coupling: "I can’t test...
A Conundrum<br />14 July 2011<br />© Agile Institute 2011<br />6<br />We add tests to refactor safely.<br />We have to ref...
14 July 2011<br />© Agile Institute 2011<br />7<br />What could possibly go wrong?!<br />
Choose Your Battles<br />Test the code you need to change now (unless it is very difficult)<br />Test the code that change...
Write “Pinning” Tests<br />We don’t add or change behavior.<br />We’re not bug-hunting.<br />We aim for coverage.<br />We ...
Technique: “The Three Questions”<br />What behavior needs test coverage?<br />What’s preventing us from writing a test?<br...
Technique:Separate Behavior from Initialization<br />It’s easier to test behavior when not coupled to initialization code....
Before<br />14 July 2011<br />© Agile Institute 2011<br />12<br />public void OpenOrderReport(<br />OutputGadget output, s...
After ‘Extract Method’<br />14 July 2011<br />© Agile Institute 2011<br />13<br />public void OpenOrderReport(<br />Output...
Technique:Expose A Private Variable or Method<br />Make a method public (at least accessible to tests)<br />Wrap a variabl...
Before<br />14 July 2011<br />© Agile Institute 2011<br />15<br />private void FormatOpenOrderReport(<br />OutputGadget ou...
After<br />14 July 2011<br />© Agile Institute 2011<br />16<br />public void FormatOpenOrderReport(<br />OutputGadget outp...
Technique:Wrap, Then Mock<br />Add a simple delegating Proxy to…<br />Code we cannot change.<br />Final (Java) or sealed (...
Delegating Proxy<br />14 July 2011<br />© Agile Institute 2011<br />18<br />ObjectUnderTest<br />+ MethodToTest()<br />Bra...
A New Production Class<br />14 July 2011<br />© Agile Institute 2011<br />19<br />public class BrainlessProxy {<br />    p...
Tough Problem (Simple Example)<br />14 July 2011<br />© Agile Institute 2011<br />20<br />public class TrafficLight {<br /...
Technique:Factory-Method Injection<br />Extract a Factory Method for the dependency.<br />Let the test create a “Testable”...
Before ‘Extract Method’<br />14 July 2011<br />© Agile Institute 2011<br />22<br />public void SwitchLights() {<br />     ...
After ‘Extract Method’ part I<br />14 July 2011<br />© Agile Institute 2011<br />23<br />public void SwitchLights() {<br /...
After ‘Extract Method’ Part II<br />14 July 2011<br />© Agile Institute 2011<br />24<br />private Color NextColor(Color cu...
A Small Change<br />14 July 2011<br />© Agile Institute 2011<br />25<br />protected virtual Color NextColor(Color currentC...
The Test, Part 1<br />14 July 2011<br />© Agile Institute 2011<br />26<br />public static MockColornewColor;<br />[TestMet...
The Test, Part 2Override Just  the Factory Method<br />14 July 2011<br />© Agile Institute 2011<br />27<br />public class ...
When to Use a Factory Method<br />“I don’t know, but…”<br />If creation of the dependency is buried deep within conditiona...
14 July 2011<br />© Agile Institute 2011<br />29<br />
14 July 2011<br />© Agile Institute 2011<br />30<br />
14 July 2011<br />© Agile Institute 2011<br />31<br /> Rob.Myers@agileInstitute.com<br />http://PowersOfTwo.agileInstitute...
Upcoming SlideShare
Loading in...5
×

TDD? Sure, but What About My Legacy Code?

1,646

Published on

Published in: Technology, Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,646
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • We want to convert the old tin can into &lt;click&gt;Why?
  • It’s a compromise for quality’s sake.Unless you buy TypeMock ($$$). There is a down-side to TypeMock: If you can test without improving your design, will you *ever*…???
  • Unplug the network!
  • This isn’t TDD. But you won’t be able to proceed with TDD without these techniques.If we find a bug, record it: In a bug tracker, or as a story.Not isolation. These are not “unit tests” - These tests can cover as much behavior as possible (though they must still be deterministic and pretty fast). And they don’t have to be pretty!Pinning tests should pass.The test is trying to “pin” behavior so we can refactor further.
  • What needs testing?
  • Very easyLean on the compiler
  • Production code!Can you test it?What good is it?
  • Varying dependency creation ORDuplicated dependency creation OR both.
  • Varying dependency creation ORDuplicated dependency creation OR both.
  • Creation has been separated from use. JUST A LITTLE, BUT ENOUGH.
  • What are we up to?
  • Alex Chaffee and WilliamPietre
  • Thank you!
  • Transcript of "TDD? Sure, but What About My Legacy Code?"

    1. 1. 14 July 2011<br />© Agile Institute 2011<br />1<br />Café<br />TDD?<br />Sure, but What About My Legacy Code?<br />Rob Myers<br />for<br />Test Driven Developers<br />Bay Area<br />14 Jul 2011<br />
    2. 2. What is “Legacy Code”?<br />14 July 2011<br />© Agile Institute 2011<br />2<br />
    3. 3. 14 July 2011<br />© Agile Institute 2011<br />3<br />“Code we’re afraid to change.”<br />-- James Shore<br />“Code without tests.”<br />-- Michael Feathers<br />
    4. 4. 14 July 2011<br />© Agile Institute 2011<br />4<br />
    5. 5. Adding Tests Is Difficult<br />14 July 2011<br />© Agile Institute 2011<br />5<br />Circumstantial coupling: "I can’t test this without instantiating half the system!"<br />Peculiar encapsulation: “I wish I could just test that private method!”<br />Duplication:"I'll have to test this on all the subclasses!"<br />Poor cohesion: "This MasterControlClass does everything, so the test will be enormous and complex!"<br />
    6. 6. A Conundrum<br />14 July 2011<br />© Agile Institute 2011<br />6<br />We add tests to refactor safely.<br />We have to refactor to add safe tests.<br />
    7. 7. 14 July 2011<br />© Agile Institute 2011<br />7<br />What could possibly go wrong?!<br />
    8. 8. Choose Your Battles<br />Test the code you need to change now (unless it is very difficult)<br />Test the code that changes most often (even if it is difficult)<br />Test the code that haunts your nightmares!<br />14 July 2011<br />© Agile Institute 2011<br />8<br />
    9. 9. Write “Pinning” Tests<br />We don’t add or change behavior.<br />We’re not bug-hunting.<br />We aim for coverage.<br />We must see GREEN.<br />14 July 2011<br />© Agile Institute 2011<br />9<br />
    10. 10. Technique: “The Three Questions”<br />What behavior needs test coverage?<br />What’s preventing us from writing a test?<br />What can we do about that?<br />14 July 2011<br />© Agile Institute 2011<br />10<br />
    11. 11. Technique:Separate Behavior from Initialization<br />It’s easier to test behavior when not coupled to initialization code.<br />Use ‘Extract Method’ to preserve existing interfaces.<br />14 July 2011<br />© Agile Institute 2011<br />11<br />
    12. 12. Before<br />14 July 2011<br />© Agile Institute 2011<br />12<br />public void OpenOrderReport(<br />OutputGadget output, string accountNumber) {<br /> Account account =<br />LunExData.QueryAccount(accountNumber);<br /> Order[] openOrders =<br />LunExData.QueryOrders(<br /> "open", accountNumber, DateTime.Now);<br />foreach (Order order in openOrders) {<br /> // ...<br />output.Write("Order #" + order.Number);<br /> // ...<br /> }<br />}<br />
    13. 13. After ‘Extract Method’<br />14 July 2011<br />© Agile Institute 2011<br />13<br />public void OpenOrderReport(<br />OutputGadget output, string accountNumber) {<br /> Account account =<br />LunExData.QueryAccount(accountNumber);<br /> Order[] openOrders =<br />LunExData.QueryOrders(<br /> "open", accountNumber, DateTime.Now);<br />FormatOpenOrderReport(output, account, openOrders);<br />}<br />private void FormatOpenOrderReport(<br />OutputGadget output,<br /> Account account, Order[] openOrders) {<br />foreach (Order order in openOrders) {<br /> // ...<br />output.Write("Order #" + order.Number);<br /> // ...<br />
    14. 14. Technique:Expose A Private Variable or Method<br />Make a method public (at least accessible to tests)<br />Wrap a variable in getter/setter methods.<br />It may smell really bad.<br />It will eventually be a useful addition to the interface, or will move to another object.<br />14 July 2011<br />© Agile Institute 2011<br />14<br />
    15. 15. Before<br />14 July 2011<br />© Agile Institute 2011<br />15<br />private void FormatOpenOrderReport(<br />OutputGadget output,<br /> Account account, Order[] openOrders) {<br />foreach (Order order in openOrders) {<br /> // ...<br />output.Write("Order #" + order.Number);<br /> // ...<br /> }<br />}<br />
    16. 16. After<br />14 July 2011<br />© Agile Institute 2011<br />16<br />public void FormatOpenOrderReport(<br />OutputGadget output,<br /> Account account, Order[] openOrders) {<br />foreach (Order order in openOrders) {<br /> // ...<br />output.Write("Order #" + order.Number);<br /> // ...<br /> }<br />}<br />
    17. 17. Technique:Wrap, Then Mock<br />Add a simple delegating Proxy to…<br />Code we cannot change.<br />Final (Java) or sealed (.NET) classes.<br />Classes with no accessible constructors.<br />Anything with a broad (mostly-unused) interface.<br />Feathers’s “Adapt Parameter” is an example of this.<br />14 July 2011<br />© Agile Institute 2011<br />17<br />
    18. 18. Delegating Proxy<br />14 July 2011<br />© Agile Institute 2011<br />18<br />ObjectUnderTest<br />+ MethodToTest()<br />BrainlessProxy<br />XYZZY<br />+ intFoo()<br />+ string Bar(int)<br />+ intFoo()<br />+ string Bar(int)<br />+ double Baz()<br />
    19. 19. A New Production Class<br />14 July 2011<br />© Agile Institute 2011<br />19<br />public class BrainlessProxy {<br /> private XYZZY realOne;<br /> public BrainlessProxy(XYZZY theRealXYZZY) {<br />this.realOne = theRealXYZZY;<br /> }<br /> public virtual intFoo() {<br /> return realOne.Foo();<br /> }<br /> public virtual string Bar(int parameter) {<br /> return realOne.Bar(parameter);<br /> }<br />}<br />
    20. 20. Tough Problem (Simple Example)<br />14 July 2011<br />© Agile Institute 2011<br />20<br />public class TrafficLight {<br /> public void SwitchLights() {<br /> Color newColor;<br /> if (currentColor.IsRed())<br />newColor = new Green();<br /> else if (currentColor.IsGreen())<br />newColor = new Yellow();<br /> else<br />newColor = new Red();<br />currentColor.Flash();<br /> Pause(3);<br />currentColor.StopFlashing();<br />newColor.LightUp();<br />currentColor.Off();<br />currentColor = newColor;<br /> }<br />
    21. 21. Technique:Factory-Method Injection<br />Extract a Factory Method for the dependency.<br />Let the test create a “Testable” subclass of the Object Under Test.<br />TestableFoo overrides the Factory Method and injects the mock.<br />14 July 2011<br />© Agile Institute 2011<br />21<br />
    22. 22. Before ‘Extract Method’<br />14 July 2011<br />© Agile Institute 2011<br />22<br />public void SwitchLights() {<br /> Color newColor;<br /> if (currentColor.IsRed())<br />newColor = new Green();<br /> else if (currentColor.IsGreen())<br />newColor = new Yellow();<br /> else<br />newColor = new Red();<br />currentColor.Flash();<br /> Pause(3);<br />currentColor.StopFlashing();<br />newColor.LightUp();<br />currentColor.Off();<br />currentColor = newColor;<br /> }<br />
    23. 23. After ‘Extract Method’ part I<br />14 July 2011<br />© Agile Institute 2011<br />23<br />public void SwitchLights() {<br /> Color newColor;<br />newColor = NextColor(currentColor);<br />currentColor.Flash();<br /> Pause(3);<br />currentColor.StopFlashing();<br />newColor.LightUp();<br />currentColor.Off();<br />currentColor = newColor;<br />}<br />
    24. 24. After ‘Extract Method’ Part II<br />14 July 2011<br />© Agile Institute 2011<br />24<br />private Color NextColor(Color currentColor) {<br /> Color newColor;<br /> if (currentColor.IsRed())<br />newColor = new Green();<br /> else if (currentColor.IsGreen())<br />newColor = new Yellow();<br /> else<br />newColor = new Red();<br /> return newColor;<br />}<br />
    25. 25. A Small Change<br />14 July 2011<br />© Agile Institute 2011<br />25<br />protected virtual Color NextColor(Color currentColor) {<br /> Color newColor;<br /> if (currentColor.IsRed())<br />newColor = new Green();<br /> else if (currentColor.IsGreen())<br />newColor = new Yellow();<br /> else<br />newColor = new Red();<br /> return newColor;<br />}<br />
    26. 26. The Test, Part 1<br />14 July 2011<br />© Agile Institute 2011<br />26<br />public static MockColornewColor;<br />[TestMethod]<br />public void TrafficLightSwitchTurnsNextColorOn() {<br />newColor = new MockColor();<br />TrafficLighttrafficLight = new TestableTrafficLight();<br />trafficLight.SwitchLights();<br />Assert.IsTrue(newColor.WasTurnedOn());<br />}<br />
    27. 27. The Test, Part 2Override Just the Factory Method<br />14 July 2011<br />© Agile Institute 2011<br />27<br />public class TestableTrafficLight : TrafficLight {<br /> protected override Color NextColor(Color currentColor) {<br /> return newColor;<br /> }<br />}<br />public class MockColor : Color {<br /> bool wasLit = false;<br /> public override void LightUp() {<br /> wasLit = true;<br /> }<br /> public bool WasTurnedOn() {<br /> return wasLit;<br /> }<br />}<br />
    28. 28. When to Use a Factory Method<br />“I don’t know, but…”<br />If creation of the dependency is buried deep within conditional code.<br />If the Factory Method is (or can be) used in multiple places.<br />If Dependency Injection seems worse (e.g. at a published API).<br />14 July 2011<br />© Agile Institute 2011<br />28<br />
    29. 29. 14 July 2011<br />© Agile Institute 2011<br />29<br />
    30. 30. 14 July 2011<br />© Agile Institute 2011<br />30<br />
    31. 31. 14 July 2011<br />© Agile Institute 2011<br />31<br /> Rob.Myers@agileInstitute.com<br />http://PowersOfTwo.agileInstitute.com/<br />

    ×