Refactoring legacy code driven by tests Luca Minudel + Saleem Siddiqui I’m the Refactoring Chicken I’m the TDD egg
Let’s clarify the scope of this Workshop
Languages supported in this Workshop C# Java JavaScript Ruby Python
Automatic Testing Continuum Specification (documentation) DesignVerification
Scope of this workshop Specification (documentation) DesignVerification
Types of Automatic Tests End-to-end, out-of-process, business facing Unit, in-process, technology facing
Scope of this workshop End-to-end, out-of-process, business facing Unit, in-process, technology facing
Exercise 1: Tire Pressure Monitoring System Alarm class: monitors tire pressure and sets an alarm if the pressure falls outside of the expected range.
Exercise 1: Tire Pressure Monitoring System Alarm class: monitors tire pressure and sets an alarm if the pressure falls outside of the expected range. Sensor class: simulates the behavior of a real tire sensor, providing random but realistic values.
Exercise 1: Tire Pressure Monitoring System Write the unit tests for the Alarm class. Refactor the code as much as you need to make the Alarm class testable.
Exercise 1: Tire Pressure Monitoring System Write the unit tests for the Alarm class. Refactor the code as much as you need to make the Alarm class testable. Minimize changes to the public API as much as you can.
Exercise 1: Tire Pressure Monitoring System Write the unit tests for the Alarm class. Refactor the code as much as you need to make the Alarm class testable. Minimize changes to the public API as much as you can. Extra credits: Alarm class fails to follow one or more of the SOLID principles. Write down the line number, the principle & the violation.
The SOLID acronym S single responsibility principle O open closed principle L Liskov substitution principle I interface segregation principle D dependency inversion principle
Dependency Inversion Principle (DIP) Martin Fowler's definition: a) High level modules should not depend upon low level modules, both should depend upon abstractions. b) Abstractions should not depend upon details, details should depend upon abstractions.
Dependency Inversion Principle (DIP) Both low level classes and high level classes should depend on abstractions. High level classes should not depend on low level classes.
DIP Violation In Example Code High Level Class Low Level Class Dependency
Open Closed Principle (OCP) Bertrand Meyer's definition: Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
Open Closed Principle (OCP) Classes and methods should be open for extensions & strategically closed for modification. So that the behavior can be changed and extended adding new code instead of changing the class.
OCP Violation In Example Code Want to use a new type of sensor? Must modify code; cannot extend it
Reference: WELC Parametrize Constructor Extract Interface
Exercise 2: Unicode File To Htm Text Converter UnicodeFileToHtmTextConverter class: formats a plain text file for display in a browser.
Exercise 2: Unicode File To Htm Text Converter Write the unit tests for the UnicodeFileToHtmTextConverter class. Refactor the code as much as you need to make the class testable.
Exercise 2: Unicode File To Htm Text Converter Write the unit tests for the UnicodeFileToHtmTextConverter class. Refactor the code as much as you need to make the class testable. Minimize changes to the public API as much as you can.
Exercise 2: Unicode File To Htm Text Converter Write the unit tests for the UnicodeFileToHtmTextConverter class. Refactor the code as much as you need to make the class testable. Minimize changes to the public API as much as you can. Extra credits: UnicodeFileToHtmTextConverter class fails to follow one or more of the SOLID principles. Write down the line number, the principle & the violation.
Feathers’ rules of thumb. Extended ! A test is not a unit test when:  It talks to the database  It communicates across the network  It touches the file system or reads config info  It uses DateTime.now() or Random  It depends on non-deterministic behavior  It can't run at the same time as any of your other unit tests  You have to do special things to your environment (such as editing config files) to run it.
Mike Cohn's Test Pyramid. Explained ! UI tests Integration tests Unit tests
Reference: WELC Parametrize Constructor Extract Interface Skin and Wrap the API
Refactoring and TDD Should we inject this dependency?
Behavior of TextReader TextReader documentation from MSDN Non-idempotent behavior
Dependency injection and idempotent behavior
Refactoring and TDD
Exercise 3: Ticket Dispenser TicketDispenser class: manages a queuing system in a shop. There may be more than one ticket dispenser but the same ticket should not be issued to two different customers.
Exercise 3: Ticket Dispenser TurnTicket class: represent the ticket with the turn number. TurnNumberSequence class: returns the sequence of turn numbers.
Write the unit tests for the TicketDispenser class. Refactor the code as much as you need to make the TicketDispenser class testable. Exercise 3: Ticket Dispenser
Write the unit tests for the TicketDispenser class. Refactor the code as much as you need to make the TicketDispenser class testable. Minimize changes to the public API as much as you can. Exercise 3: Ticket Dispenser
Write the unit tests for the TicketDispenser class. Refactor the code as much as you need to make the TicketDispenser class testable. Minimize changes to the public API as much as you can. Extra credits: TicketDispenser class fails to follow one or more of the OO and SOLID principles. Write down the line number, the principle & the violation. Exercise 3: Ticket Dispenser
Reference: WELC Parametrize Constructor Extract Interface Skin and Wrap the API Introduce Instance Delegator …
Exercise 4: Telemetry System TelemetryDiagnosticControl class: establishes a connection to the telemetry server through the TelemetryClient, sends a diagnostic request and receives the response with diagnostic info. TelemetryClient class: simulates the communication with the Telemetry Server, sends requests and then receives and returns the responses
Write the unit tests for the TelemetryDiagnosticControl class. Refactor the code as much as you need to make the class testable. Exercise 4: Telemetry System
Write the unit tests for the TelemetryDiagnosticControl class. Refactor the code as much as you need to make the class testable. Minimize changes to the public API as much as you can. Exercise 4: Telemetry System
Write the unit tests for the TelemetryDiagnosticControl class. Refactor the code as much as you need to make the class testable. Minimize changes to the public API as much as you can. Extra credits: TelemetryClient class fails to follow one or more of the OO and SOLID principles. Write down the line number, the principle & the violation. Exercise 4: Telemetry System
Single Responsibility Principle (SRP) A class should have only one reason to change.
Single Responsibility Principle (SRP) There should never be more than one reason for a class to change. A class should have one and only one responsibility.
Interface Segregation Principle (IRP) Clients should not be forced to depend upon interfaces that they do not use.
Interface Segregation Principle (IRP) Clients should not be forced to depend upon interface members that they don't use. Interfaces that serve only one scope should be preferred over fat interfaces.
Reference: SRP http://www.objectmentor.com/resources/articles/srp.pdf Pag. 151/152
Synergy between testing and design Michael Feathers: writing tests is another way to look the code and locally understand it and reuse it, and that is the same goal of good OO design. This is the reason for the deep synergy between testability and good design.
More references
More references
More references
References  http://scratch.mit.edu/projects/13134082/  http://vimeo.com/15007792  http://martinfowler.com/bliki/TestPyramid.html  http://martinfowler.com/bliki/StranglerApplication.html  http://www.markhneedham.com/blog/2009/07/07/domain- driven-design-anti-corruption-layer/  http://www.objectmentor.com/resources/articles/srp.pdf  http://www.objectmentor.com/resources/articles/ocp.pdf  http://www.objectmentor.com/resources/articles/lsp.pdf  http://www.objectmentor.com/resources/articles/isp.pdf  http://www.objectmentor.com/resources/articles/dip.pdf
References / Links / Slides On Twitter On Twitter : @S2IL @LUKADOTNET

Refactoring legacy code driven by tests - ENG

  • 1.
    Refactoring legacy codedriven by tests Luca Minudel + Saleem Siddiqui I’m the Refactoring Chicken I’m the TDD egg
  • 2.
    Let’s clarify thescope of this Workshop
  • 3.
    Languages supported inthis Workshop C# Java JavaScript Ruby Python
  • 4.
  • 5.
    Scope of thisworkshop Specification (documentation) DesignVerification
  • 6.
    Types of AutomaticTests End-to-end, out-of-process, business facing Unit, in-process, technology facing
  • 7.
    Scope of thisworkshop End-to-end, out-of-process, business facing Unit, in-process, technology facing
  • 8.
    Exercise 1: TirePressure Monitoring System Alarm class: monitors tire pressure and sets an alarm if the pressure falls outside of the expected range.
  • 9.
    Exercise 1: TirePressure Monitoring System Alarm class: monitors tire pressure and sets an alarm if the pressure falls outside of the expected range. Sensor class: simulates the behavior of a real tire sensor, providing random but realistic values.
  • 10.
    Exercise 1: TirePressure Monitoring System Write the unit tests for the Alarm class. Refactor the code as much as you need to make the Alarm class testable.
  • 11.
    Exercise 1: TirePressure Monitoring System Write the unit tests for the Alarm class. Refactor the code as much as you need to make the Alarm class testable. Minimize changes to the public API as much as you can.
  • 12.
    Exercise 1: TirePressure Monitoring System Write the unit tests for the Alarm class. Refactor the code as much as you need to make the Alarm class testable. Minimize changes to the public API as much as you can. Extra credits: Alarm class fails to follow one or more of the SOLID principles. Write down the line number, the principle & the violation.
  • 13.
    The SOLID acronym Ssingle responsibility principle O open closed principle L Liskov substitution principle I interface segregation principle D dependency inversion principle
  • 14.
    Dependency Inversion Principle(DIP) Martin Fowler's definition: a) High level modules should not depend upon low level modules, both should depend upon abstractions. b) Abstractions should not depend upon details, details should depend upon abstractions.
  • 15.
    Dependency Inversion Principle(DIP) Both low level classes and high level classes should depend on abstractions. High level classes should not depend on low level classes.
  • 16.
    DIP Violation InExample Code High Level Class Low Level Class Dependency
  • 17.
    Open Closed Principle(OCP) Bertrand Meyer's definition: Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
  • 18.
    Open Closed Principle(OCP) Classes and methods should be open for extensions & strategically closed for modification. So that the behavior can be changed and extended adding new code instead of changing the class.
  • 19.
    OCP Violation InExample Code Want to use a new type of sensor? Must modify code; cannot extend it
  • 20.
  • 21.
    Exercise 2: UnicodeFile To Htm Text Converter UnicodeFileToHtmTextConverter class: formats a plain text file for display in a browser.
  • 22.
    Exercise 2: UnicodeFile To Htm Text Converter Write the unit tests for the UnicodeFileToHtmTextConverter class. Refactor the code as much as you need to make the class testable.
  • 23.
    Exercise 2: UnicodeFile To Htm Text Converter Write the unit tests for the UnicodeFileToHtmTextConverter class. Refactor the code as much as you need to make the class testable. Minimize changes to the public API as much as you can.
  • 24.
    Exercise 2: UnicodeFile To Htm Text Converter Write the unit tests for the UnicodeFileToHtmTextConverter class. Refactor the code as much as you need to make the class testable. Minimize changes to the public API as much as you can. Extra credits: UnicodeFileToHtmTextConverter class fails to follow one or more of the SOLID principles. Write down the line number, the principle & the violation.
  • 25.
    Feathers’ rules ofthumb. Extended ! A test is not a unit test when:  It talks to the database  It communicates across the network  It touches the file system or reads config info  It uses DateTime.now() or Random  It depends on non-deterministic behavior  It can't run at the same time as any of your other unit tests  You have to do special things to your environment (such as editing config files) to run it.
  • 26.
    Mike Cohn's TestPyramid. Explained ! UI tests Integration tests Unit tests
  • 27.
    Reference: WELC Parametrize Constructor ExtractInterface Skin and Wrap the API
  • 28.
    Refactoring and TDD Shouldwe inject this dependency?
  • 29.
    Behavior of TextReader TextReaderdocumentation from MSDN Non-idempotent behavior
  • 30.
  • 31.
  • 32.
    Exercise 3: TicketDispenser TicketDispenser class: manages a queuing system in a shop. There may be more than one ticket dispenser but the same ticket should not be issued to two different customers.
  • 33.
    Exercise 3: TicketDispenser TurnTicket class: represent the ticket with the turn number. TurnNumberSequence class: returns the sequence of turn numbers.
  • 34.
    Write the unittests for the TicketDispenser class. Refactor the code as much as you need to make the TicketDispenser class testable. Exercise 3: Ticket Dispenser
  • 35.
    Write the unittests for the TicketDispenser class. Refactor the code as much as you need to make the TicketDispenser class testable. Minimize changes to the public API as much as you can. Exercise 3: Ticket Dispenser
  • 36.
    Write the unittests for the TicketDispenser class. Refactor the code as much as you need to make the TicketDispenser class testable. Minimize changes to the public API as much as you can. Extra credits: TicketDispenser class fails to follow one or more of the OO and SOLID principles. Write down the line number, the principle & the violation. Exercise 3: Ticket Dispenser
  • 37.
    Reference: WELC Parametrize Constructor ExtractInterface Skin and Wrap the API Introduce Instance Delegator …
  • 38.
    Exercise 4: TelemetrySystem TelemetryDiagnosticControl class: establishes a connection to the telemetry server through the TelemetryClient, sends a diagnostic request and receives the response with diagnostic info. TelemetryClient class: simulates the communication with the Telemetry Server, sends requests and then receives and returns the responses
  • 39.
    Write the unittests for the TelemetryDiagnosticControl class. Refactor the code as much as you need to make the class testable. Exercise 4: Telemetry System
  • 40.
    Write the unittests for the TelemetryDiagnosticControl class. Refactor the code as much as you need to make the class testable. Minimize changes to the public API as much as you can. Exercise 4: Telemetry System
  • 41.
    Write the unittests for the TelemetryDiagnosticControl class. Refactor the code as much as you need to make the class testable. Minimize changes to the public API as much as you can. Extra credits: TelemetryClient class fails to follow one or more of the OO and SOLID principles. Write down the line number, the principle & the violation. Exercise 4: Telemetry System
  • 42.
    Single Responsibility Principle(SRP) A class should have only one reason to change.
  • 43.
    Single Responsibility Principle(SRP) There should never be more than one reason for a class to change. A class should have one and only one responsibility.
  • 44.
    Interface Segregation Principle(IRP) Clients should not be forced to depend upon interfaces that they do not use.
  • 45.
    Interface Segregation Principle(IRP) Clients should not be forced to depend upon interface members that they don't use. Interfaces that serve only one scope should be preferred over fat interfaces.
  • 46.
  • 47.
    Synergy between testingand design Michael Feathers: writing tests is another way to look the code and locally understand it and reuse it, and that is the same goal of good OO design. This is the reason for the deep synergy between testability and good design.
  • 48.
  • 49.
  • 50.
  • 51.
    References  http://scratch.mit.edu/projects/13134082/  http://vimeo.com/15007792 http://martinfowler.com/bliki/TestPyramid.html  http://martinfowler.com/bliki/StranglerApplication.html  http://www.markhneedham.com/blog/2009/07/07/domain- driven-design-anti-corruption-layer/  http://www.objectmentor.com/resources/articles/srp.pdf  http://www.objectmentor.com/resources/articles/ocp.pdf  http://www.objectmentor.com/resources/articles/lsp.pdf  http://www.objectmentor.com/resources/articles/isp.pdf  http://www.objectmentor.com/resources/articles/dip.pdf
  • 52.
    References / Links/ Slides On Twitter On Twitter : @S2IL @LUKADOTNET

Editor's Notes

  • #5 The triangle in action: http://scratch.mit.edu/projects/13134082/
  • #9 They could be code you inherited from a legacy code-base.
  • #22 They could be code you inherited from a legacy code-base.
  • #27 http://martinfowler.com/bliki/TestPyramid.html http://martinfowler.com/bliki/StranglerApplication.html http://www.markhneedham.com/blog/2009/07/07/domain-driven-design-anti-corruption-layer/
  • #33 They could be code you inherited from a legacy code-base.
  • #34 They could be code you inherited from a legacy code-base.
  • #39 They could be code you inherited from a legacy code-base.
  • #48 Michael Feathers, NDC 2010 The Deep Synergy Between Testability and Good Design http://vimeo.com/15007792 http://michaelfeathers.typepad.com/michael_feathers_blog/2007/09/the-deep-synerg.html
  • #49 http://martinfowler.com/bliki/TestPyramid.html http://martinfowler.com/bliki/StranglerApplication.html http://www.markhneedham.com/blog/2009/07/07/domain-driven-design-anti-corruption-layer/