TDD And Refactoring

9,591 views
9,234 views

Published on

Ganesan Rajamani's presentation on Test Driven Development and Refactoring. Was presented at the Agile Goa 2008 conference.

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

No Downloads
Views
Total views
9,591
On SlideShare
0
From Embeds
0
Number of Embeds
62
Actions
Shares
0
Downloads
464
Comments
0
Likes
22
Embeds 0
No embeds

No notes for slide
  • In this presentation, we will try to cover three things: Explain what is TDD and its potential benefits (i.e. TDD in theory) Discuss real-life obstacles we most likely encounter while adopting TDD (i.e. TDD in practice) Role of AS APD (A)TDD champions
  • TDD And Refactoring

    1. 1. TDD and Refactoring Ganesan R Sr.Software Developer Sabre Holdings
    2. 2. Game Plan <ul><li>Introduction (A Little Bit of Theory) </li></ul><ul><li>TDD Basics </li></ul><ul><li>Guidelines for Testable Design </li></ul><ul><li>Refactoring and its Techniques </li></ul>
    3. 3. Introduction Confidential
    4. 4. What is TDD? <ul><li>A Simple Definition </li></ul><ul><ul><li>Write a Failing (Automated) Test Before Writing Production Code </li></ul></ul><ul><ul><li>Make a Minimal Change to Production Code to Fix the Failing Test </li></ul></ul><ul><ul><li>When There are Enough Tests, Re-factor the code </li></ul></ul><ul><ul><ul><li>Primary Goals: Simplicity, Readability & No Duplication </li></ul></ul></ul><ul><ul><ul><li>Reliance Upon Automated Test Safety Net </li></ul></ul></ul><ul><ul><ul><li>Both Production & Test Code </li></ul></ul></ul><ul><li>Two Primary Goals of Writing Tests </li></ul><ul><ul><li>Safety Net </li></ul></ul><ul><ul><li>Documentation </li></ul></ul>
    5. 5. Testing Terminology
    6. 6. TDD: The Micro-Cycle of Agile Development Process
    7. 7. TDD: The Micro-Cycle of Agile Development Process
    8. 8. TDD Basics Confidential
    9. 9. TDD Basics (Discussion & Demo) <ul><li>Good Test is Atomic & Isolated </li></ul><ul><li>Decomposing Requirements Into a Test List </li></ul><ul><li>Programming by Intention </li></ul><ul><ul><li>Making the Compiler Happy </li></ul></ul><ul><ul><li>Running the Failing Test </li></ul></ul><ul><ul><li>Making the Test Pass </li></ul></ul><ul><ul><li>Repeating it Again for Other Tests In the List </li></ul></ul><ul><li>Breadth-First vs. Depth-First </li></ul><ul><li>Let’s Not Forget to Re-factor </li></ul><ul><ul><li>Both Production & Test Code Re-factoring </li></ul></ul><ul><ul><li>Remove Duplication </li></ul></ul><ul><ul><li>Re-factoring toward smaller methods </li></ul></ul><ul><ul><li>Keeping things in balance </li></ul></ul>
    10. 10. TDD Concepts & Patterns <ul><li>What to Test & in What Order? </li></ul><ul><ul><li>Details vs. big picture </li></ul></ul><ul><ul><li>Uncertain vs. familiar </li></ul></ul><ul><ul><li>High value vs. low-hanging fruit </li></ul></ul><ul><ul><li>Happy path vs. error situations </li></ul></ul><ul><li>Implementation Strategies </li></ul><ul><ul><li>Faking it </li></ul></ul><ul><ul><li>Triangulation </li></ul></ul><ul><ul><li>Obvious Implementation </li></ul></ul><ul><li>Prime Guidelines for Test-Driving </li></ul><ul><ul><li>Do Not Skip Re-factoring </li></ul></ul><ul><ul><li>Get to Green Fast </li></ul></ul><ul><ul><li>Slow Down After a Mistake </li></ul></ul>
    11. 11. TDD Concepts & Patterns (Continued) <ul><li>Unit-Testing Concepts </li></ul><ul><ul><li>Using Test Fixtures </li></ul></ul><ul><ul><li>Using Test Doubles (More Details to Follow) </li></ul></ul>
    12. 12. Test Doubles (Alternative Implementations) <ul><li>An Example of a Test Double </li></ul><ul><li>Reasons for Having Test Doubles </li></ul><ul><ul><li>Avoiding a Landslide of Failing Tests </li></ul></ul><ul><ul><li>Avoiding Slow Running Tests </li></ul></ul><ul><ul><li>Avoiding Availability (Existence) Problems </li></ul></ul><ul><ul><li>Avoiding Difficult Instantiation And/Or Configuration </li></ul></ul><ul><li>Test Double Taxonomy </li></ul><ul><ul><li>Stubs </li></ul></ul><ul><ul><li>Fakes </li></ul></ul><ul><ul><li>Mocks </li></ul></ul><ul><li>Exercise </li></ul>
    13. 13. Point Of Sale System… <ul><li>As an example, we’ve chosen a point-of-sale system, like one might encounter in any retail store. A sales clerk passes items over a scanner that reads the barcode. A display monitor shows information on each item as it is scanned and also tracks the total for each sale of one or more items to a given shopper. </li></ul><ul><li>Sample User Story </li></ul><ul><ul><li>The total price of all items in the sale is available. </li></ul></ul>
    14. 14. Guidelines for Testable Design Confidential
    15. 15. Guidelines for Testable Design <ul><li>Choose composition over inheritance </li></ul><ul><li>Avoid static and the Singleton </li></ul><ul><li>Isolate dependencies </li></ul><ul><li>Inject dependencies </li></ul>
    16. 16. Choose Composition Over inheritance <ul><li>Inheriting lets subclass to inherit all the functionality of Superclass. </li></ul><ul><li>Downside – Introduce inconvenient constraints related to Instantiating the subclass in test harness. </li></ul><ul><li>Composition allows more flexible design solution for reusability. </li></ul><ul><li>Example – Allows to instantiate the composite object with alternative implementations </li></ul>
    17. 17. Dependency Injection <ul><li>Refers to supplying an external dependency to a software component. </li></ul><ul><li>Forms of Dependency Injection – </li></ul><ul><ul><li>interface injection , in which the exported module provides an interface that its users must implement in order to get the dependencies at runtime </li></ul></ul><ul><ul><li>setter injection , in which the dependent module exposes a setter method which the framework uses to inject the dependency . </li></ul></ul><ul><ul><li>constructor injection , in which the dependencies are provided through the class constructor. </li></ul></ul>
    18. 18. Constructor Injection.. <ul><li>public class ImportantClass { </li></ul><ul><li>IFoo foo; </li></ul><ul><li>public ImportantClass() </li></ul><ul><li>{ </li></ul><ul><ul><li> this.foo = new EnterpriseFoo(); </li></ul></ul><ul><li>} </li></ul><ul><li>void doReallyImportantStuff() { </li></ul><ul><li>this.foo.bar(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>public class ImportantClass { </li></ul><ul><li>IFoo foo; </li></ul><ul><li>public ImportantClass(IFoo foo) { this.foo = foo; </li></ul><ul><li>} </li></ul><ul><li>void doReallyImportantStuff() { </li></ul><ul><li>this.foo.bar(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    19. 19. Refactoring Confidential
    20. 20. What is Refactoring? <ul><li>Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior. </li></ul><ul><li>Its heart is a series of small behavior preserving transformations. </li></ul>
    21. 21. What is Refactoring? <ul><li>Each transformation (called a 'Refactoring') does little, but a sequence of transformations can produce a significant restructuring. </li></ul><ul><li>The system is also kept fully working after each small Refactoring, reducing the chances that a system can get seriously broken during the restructuring. </li></ul>
    22. 22. Why Do we refactor ? <ul><li>Improves the design of the software. </li></ul><ul><li>Easier to maintain and understand. </li></ul><ul><li>Easier to facilitate change. </li></ul><ul><li>More flexibility. </li></ul><ul><li>Increased reusability. </li></ul><ul><li>To help find bugs </li></ul>
    23. 23. When do we refactor ? <ul><li>Duplicated code. </li></ul><ul><li>Long method. </li></ul><ul><li>Long parameter list.. </li></ul><ul><li>Improper naming. </li></ul>
    24. 24. Refactoring Techniques <ul><li>Here are some of the Refactoring techniques discussed in the session </li></ul><ul><ul><ul><li>Sprout Method </li></ul></ul></ul><ul><ul><ul><li>Sprout Class </li></ul></ul></ul><ul><ul><ul><li>Wrap Method </li></ul></ul></ul><ul><ul><ul><li>Wrap Class </li></ul></ul></ul>
    25. 25. Sprout Method <ul><li>While adding new feature to the existing method it can formulated completely as a new method. How ? </li></ul><ul><ul><ul><li>Write the code in the new method. </li></ul></ul></ul><ul><ul><ul><li>Call it from the places where the new functionality needs to be </li></ul></ul></ul><ul><li>Example: </li></ul><ul><ul><ul><li>Public class TransactionGate </li></ul></ul></ul><ul><ul><ul><li>{ </li></ul></ul></ul><ul><ul><ul><li>Public void postEntries(List entries){ </li></ul></ul></ul><ul><ul><ul><li>for(Iterator it=entries.iterator();it.hasNext();){ </li></ul></ul></ul><ul><ul><ul><li>Entry entry=(Entry)it.next(); </li></ul></ul></ul><ul><ul><ul><li>entry.postDate(); </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>transactionBundle.getListManager.add(entries) ; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul>
    26. 26. Sprout method - Continue <ul><ul><ul><li>Public class TransactionGate </li></ul></ul></ul><ul><ul><ul><li>{ </li></ul></ul></ul><ul><ul><ul><li>Public void postEntries(List entries){ </li></ul></ul></ul><ul><ul><ul><li>List entriesToAdd=uniqueEntries(entries); </li></ul></ul></ul><ul><ul><ul><li>-------- </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>transactionBundle.getListManager.add(entries) ; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>List uniqueEntries(List entries) { </li></ul></ul></ul><ul><ul><ul><li>//Unique Entries impl comes here </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul>
    27. 27. Sprout method - steps <ul><li>Identify the place to make the code change </li></ul><ul><li>If the change can be formulated as a single sequence of statement write down a call for the new method that will do the work involved and comment it out. </li></ul><ul><li>Determine the local variables you need from the source method and make them arguments for the call. </li></ul>
    28. 28. Sprout method - steps <ul><li>Determine whether the sprouted method will need to return values to source method. If so change the call so that its return value is assigned to a variable. </li></ul><ul><li>Develop the sprout method using TDD. </li></ul><ul><li>Remove the comment in the source code to enable the call. </li></ul>
    29. 29. Sprout Class <ul><li>Sprout method is powerful but in some tangled dependency situation it is not powerful though </li></ul><ul><li>Example: </li></ul><ul><li>std::string QuaterlyReportGenerator::generate() </li></ul><ul><li>{ </li></ul><ul><li>std::veactor<Result> results=database.queryResults(beginDate,endDate) ; </li></ul><ul><li>std::string pageText ; </li></ul><ul><li>pageText+=“<html><head><title>Quaterly Report</title></head> </li></ul><ul><li><body><table>” </li></ul><ul><li>if(results.size()!=0){ </li></ul><ul><li>//html page generator code comes here </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    30. 30. Sprout class - Continues <ul><li>Suppose if we need to add a new functionality. </li></ul><ul><ul><ul><li>Add a Header row for the HTML table its producing. </li></ul></ul></ul><ul><ul><ul><li>“ QuaterlyReportGenerator” is a huge class to get into test harness. </li></ul></ul></ul><ul><li>Formulate the new change into a little class and bring it in test harness. </li></ul><ul><li>class QuaterlyReportTableHeaderGenerator{ </li></ul><ul><li>public: </li></ul><ul><li>string generate() ; </li></ul><ul><li>} </li></ul>
    31. 31. Sprout class - continues <ul><li>Move the generate method to a interface. </li></ul><ul><li>Class HTMLGenerator{ </li></ul><ul><li>public : </li></ul><ul><li>virtual ~HTMLGenerator() ; </li></ul><ul><li>virtual string generate() ; </li></ul><ul><li>} </li></ul><ul><li>Make QuaterlyReportGenerator and QuaterlyReportTableHeaderGenerator inherit from HTMLGenerator. </li></ul><ul><li>Now the new class is in testharness at somepoint in time we would be able to get the QuaterlyReportGenerator also in test harness. </li></ul>
    32. 32. Sprout class - steps <ul><li>Identify where you need to make the code change. </li></ul><ul><li>Think of a good name for the class, create an object of the class and call the method that will do the work ; then comment the lines. </li></ul><ul><li>Determine the local variables you need from the source method and make them as constructor arguments. </li></ul>
    33. 33. Sprout class - steps <ul><li>Determine whether the sprouted class will need to return value to the source method. </li></ul><ul><li>If so, provide a method in the class that will supply those values and add a call to the source method to receive the same. </li></ul><ul><li>Develop the sprout class test first. </li></ul>
    34. 34. Further.. <ul><li>Recommended reading </li></ul><ul><ul><ul><li>Working Effective with Legacy code By Michael Feathers </li></ul></ul></ul><ul><ul><ul><li>http://www.refactoring.com/sources.html </li></ul></ul></ul><ul><ul><ul><li>Refactoring: Improving the Design of Existing Code – Martin Fowler </li></ul></ul></ul><ul><ul><ul><li>http://tech.groups.yahoo.com/group/refactoring/ </li></ul></ul></ul><ul><ul><ul><li>http://www.refactoring.com/tools.html </li></ul></ul></ul>

    ×