refactoring legacy code driven by tests - eng
DESCRIPTION
re you working on code poorly designed or on legacy code that’s hard to test? And you cannot refactor it because there are no tests? During this Coding Dojo you’ll be assigned a coding challenge in Java, C#, Ruby, JavaScript or Python. You will face the challenge of improving the design and refactoring existing code in order to make it testable and to write unit tests. We will discuss SOLID principles, the relation between design and TDD, and how this applies to your solution. Reading list: Growing Object-Oriented Software, Guided by Tests; Steve Freeman, Nat Pryce Test Driven Development: By Example; Kent Beck Working Effectively with Legacy; Michael Feathers Agile Software Development, Principles, Patterns, and Practices; Robert C. Martin (C++, Java) Agile Principles, Patterns, and Practices in C#; Robert C. Martin (C#)TRANSCRIPT
![Page 1: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/1.jpg)
Refactoring legacy code driven by tests
Luca Minudel + Saleem Siddiqui
I’m the
Refactoring
Chicken
I’m the
TDD egg
![Page 2: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/2.jpg)
Let’s clarify the scope of this Workshop
![Page 3: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/3.jpg)
Languages supported in this Workshop
C#
Java
JavaScript
Ruby
Python
![Page 4: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/4.jpg)
Automatic Testing Continuum
Specification
(documentation)
DesignVerification
![Page 5: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/5.jpg)
Scope of this workshop
Specification
(documentation)
DesignVerification
![Page 6: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/6.jpg)
Types of Automatic Tests
End-to-end, out-of-process, business facing
Unit, in-process, technology facing
![Page 7: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/7.jpg)
Scope of this workshop
End-to-end, out-of-process, business facing
Unit, in-process, technology facing
![Page 8: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/8.jpg)
Exercise 1: Tire Pressure Monitoring System
Alarm class:
monitors tire pressure and sets an alarm if the pressure falls
outside of the expected range.
![Page 9: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/9.jpg)
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.
![Page 10: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/10.jpg)
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.
![Page 11: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/11.jpg)
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.
![Page 12: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/12.jpg)
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.
![Page 13: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/13.jpg)
The SOLID acronym
S single responsibility principle
O open closed principle
L Liskov substitution principle
I interface segregation principle
D dependency inversion principle
![Page 14: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/14.jpg)
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.
![Page 15: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/15.jpg)
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.
![Page 16: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/16.jpg)
DIP Violation In Example Code
High Level Class
Low Level Class
Dependency
![Page 17: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/17.jpg)
Open Closed Principle (OCP)
Bertrand Meyer's definition:
Software entities (classes, modules, functions,
etc.) should be open for extension, but closed for
modification.
![Page 18: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/18.jpg)
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.
![Page 19: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/19.jpg)
OCP Violation In Example Code
Want to use a new type of sensor?
Must modify code; cannot extend it
![Page 20: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/20.jpg)
Reference: WELC
Parametrize Constructor
Extract Interface
![Page 21: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/21.jpg)
Exercise 2: Unicode File To Htm Text Converter
UnicodeFileToHtmTextConverter class:
formats a plain text file for display in a browser.
![Page 22: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/22.jpg)
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.
![Page 23: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/23.jpg)
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.
![Page 24: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/24.jpg)
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.
![Page 25: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/25.jpg)
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.
![Page 26: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/26.jpg)
Mike Cohn's Test Pyramid. Explained !
UItests
Integration tests
Unit tests
![Page 27: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/27.jpg)
Reference: WELC
Parametrize Constructor
Extract Interface
Skin and Wrap the API
![Page 28: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/28.jpg)
Refactoring and TDD
Should we inject this dependency?
![Page 29: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/29.jpg)
Behavior of TextReader
TextReader documentation from MSDN
Non-idempotent behavior
![Page 30: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/30.jpg)
Dependency injection and
idempotent behavior
![Page 31: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/31.jpg)
Refactoring and TDD
![Page 32: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/32.jpg)
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.
![Page 33: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/33.jpg)
Exercise 3: Ticket Dispenser
TurnTicket class:
represent the ticket with the turn number.
TurnNumberSequence class:
returns the sequence of turn numbers.
![Page 34: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/34.jpg)
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
![Page 35: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/35.jpg)
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
![Page 36: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/36.jpg)
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
![Page 37: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/37.jpg)
Reference: WELC
Parametrize Constructor
Extract Interface
Skin and Wrap the API
Introduce Instance Delegator
…
![Page 38: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/38.jpg)
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
![Page 39: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/39.jpg)
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
![Page 40: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/40.jpg)
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
![Page 41: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/41.jpg)
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
![Page 42: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/42.jpg)
Single Responsibility Principle (SRP)
A class should have only one reason to change.
![Page 43: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/43.jpg)
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.
![Page 44: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/44.jpg)
Interface Segregation Principle (IRP)
Clients should not be forced to depend upon
interfaces that they do not use.
![Page 45: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/45.jpg)
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.
![Page 46: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/46.jpg)
Reference: SRP
http://www.objectmentor.com/resources/articles/srp.pdf
Pag. 151/152
![Page 47: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/47.jpg)
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 forthe deep synergy
between testability and good design.
![Page 48: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/48.jpg)
More references
![Page 49: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/49.jpg)
More references
![Page 50: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/50.jpg)
More references
![Page 51: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/51.jpg)
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
![Page 52: Refactoring legacy code driven by tests - ENG](https://reader034.vdocuments.mx/reader034/viewer/2022050922/5594443f1a28ab0c308b475d/html5/thumbnails/52.jpg)
References / Links / Slides
On TwitterOn Twitter :
@S2IL
@LUKADOTNET