SlideShare a Scribd company logo
1 of 73
How to Start Test-Driven
Development in Legacy Code
   The New York XP & Agile Meetup
            May 17, 2012

          Daniel Wellman
         Director of Technology
                                      Tweet
                                    #legacytdd
                                      #xpnyc
A Quick Survey
“red, green, refactor” by Török Gábor
Yay, TDD!
Boo, my project!
Get to Safety
Be Persistent
Photo by the Dorothy Peyton Gray Transportation Library and Archive at the Los Angeles County Metropolitan
                                        Transportation Authority
“Another flaw in the human
character is that everybody
wants to build and nobody
wants to do
                      Kurt Vonnegut
maintenance.”          Hocus Pocus
Photo by Fraser Speirs
Get to Safety
TDD Cycle

   Red
  Green
 Refactor
What makes code
hard to test?
Highly Coupled Code
Smaller Code
How do I test this?
Seams




Photo by Art Crimes a.k.a. Susan M. Coles
Legacy TDD Cycle

  Introduce Seams
        Red
       Green
      Refactor
??
Break dependencies
  just enough
to get tests in place
Use Safe Refactoring
       Tools
  (if you have them)
Or move very slowly
   and carefully
A Few
Techniques
The Challenge of ‘new’
public class TestCase {

    public void run() {
        TestResult result = new TestResult();

        try {
            setUp();
            runTest(result);
        } catch (Exception e) {
            result.addFailure(e, this);
        }
        tearDown();
    }
}
public class TestCase {

    public void run() {
        TestResult result = new TestResult();

        try {
            setUp();
            runTest(result);
        } catch (Exception e) {
            result.addFailure(e, this);
        }
        tearDown();
    }
}
public class TestCase {

    public void run() {
        TestResult result = new TestResult();

        try {
            setUp();
            runTest(result);
        } catch (Exception e) {
            result.addFailure(e, this);
        }
        tearDown();
  @Test
    }
} public void exceptionsReportAsFailures() {
      TestCase testCase = new TestCase();
      testCase.run();
      // ...??
  }
After Extract Parameter
public class TestCase {

    public void run(TestResult testResult) {
        TestResult result = testResult;

         try {
             setUp();
             runTest(result);
         } catch (Exception e) {
             result.addFailure(e, this);
         }
         tearDown();
    }
}
After Extract Parameter
public class TestCase {

    public void run(TestResult testResult) {
        TestResult result = testResult;

        try {
            setUp();
            runTest(result);
  @Test } catch (Exception e) {
            result.addFailure(e, this);
  public void exceptionsReportAsFailures() {
        }
      TestCase testCase = new TestCase();
        tearDown();
      TestResult result = new TestResult();
    } testCase.run(result);
}     // Make assertions on result
  }
The Dangerous
 “Live Wire”
public class MailingListDispatcher {
    private MailService mailService;

    public MailingListDispatcher(Status status) {
        this.mailService =
           new SMTPMailService("smtp.gmail.com");
        // ...
    }

    public Result send(Message message) {
        // ...
        mailService.send(message);
        // ...
    }
}
public class MailingListDispatcher {
    private MailService mailService;

    public MailingListDispatcher(Status status) {
        this.mailService =
           new SMTPMailService("smtp.gmail.com");
        // ...
    }

    public Result send(Message message) {
        // ...
        mailService.send(message);
    @Test
        // ...
    public void testSendSuccessful() {
    }   MailingListDispatcher dispatch =
}          new MailingListDispatcher(OK);
        dispatch.send(new Message());
        // ... ???
    }
After Parameterize Constructor
public class MailingListDispatcher {
    private MailService mailService;

    public MailingListDispatcher(
            MailService service, Status status) {
        this.mailService = service;
        // ...
    }

    public Result send(Message message) {
        // ...
        mailService.send(message);
        // ...
    }

}
After Parameterize Constructor
public class MailingListDispatcher {
    private MailService mailService;

     public MailingListDispatcher(
             MailService service, Status status) {
         this.mailService = service;
         // ...
     }

      public Result send(Message message) {
    @Test
    public// ...
            void testSendSuccessful() throws Exception {
         MailService mailService = new FakeMailService();
           mailService.send(message);
         MailingListDispatcher dispatch =
           // ...
      }      new MailingListDispatcher(mailService, OK);
         dispatch.send(new Message());
         // Inspect the FakeMailService
}   }
Can’t Make a Fake?
public class SMTPMailServer {
    public void helo(String hostname) {}
    public void from(String address) {}
    public void size(long byteCount) {}
    public void data() {}
    public void send(Message message) {}
    public void quit() {}
    ...

    private int sendBytes(byte[] toSend) {}
    ...
}
Override Methods
public class FakeOverrideSMTPMailServer
                  extends SMTPMailServer {
    public byte[] sent; // public!

    @Override
    protected int sendBytes(byte[] toSend) {
        // Save the bytes for later inspection
        // ...
        return 0; // Whatever...
    }
}
Override Methods
public class FakeOverrideSMTPMailServer
                  extends SMTPMailServer {
    public byte[] sent; // public!

    @Override
    protected int sendBytes(byte[] toSend) {
        // Save the bytes for later inspection
        // ...
        return 0; // Whatever...
public class SMTPMailServer {
    }
} // ...
    protected int sendBytes(byte[] toSend) { }   ...


}
Extract Interface
public interface MailServer {
    public void helo(String hostname);
    public void send(Message message);
    public void quit();
}
Extract Interface




                           sh
                          -i
public interface MailServer {
    public void helo(String hostname);
    public void send(Message message);
    public void quit();
}
Extract Interface




                                  sh
                                 -i
   public interface MailServer {
       public void helo(String hostname);
       public void send(Message message);
       public void quit();
   }


public class SMTPMailServer implements MailServer {
    // Retro-fitted production...
}
Extract Interface




                                  sh
                                 -i
   public interface MailServer {
       public void helo(String hostname);
       public void send(Message message);
       public void quit();
   }


public class SMTPMailServer implements MailServer {
    // Retro-fitted production...
}
public class FakeMailServer implements MailServer {
    // Testing ...
}
Long Method?
public Duration vacationRemaining(Date today) {
    Duration remaining;
    // ...
    // ...
    // Calculate hours worked
    // ...
    // ...
    // How much vacation do they get?
    // ...
    // ...
    // Is it a leap year?
    // ...
    // ...
    return remaining;
}
Extract Methods
public Time hoursWorked(Time start, Time end) {
    // ...
}

public int vacationDaysAllowed(EmployeeType type) {
    // ...
}

public boolean isLeapMonth(Date date) {
    // ...
}
Not much time to
     change?
Sprout Method and
   Sprout Class




                “sprouting bean” photo by Zoë Jackson
public class EmployeeTable {
    private List<Employee> employees;

    public String table() {
        StringBuilder html = new StringBuilder();
        html.append("<table>");
        for (Employee employee : employees) {
            html.append("<tr>");
            // Print employee data ...
            html.append("</tr>");
        }
        html.append("</table>");
        return html.toString();
    }

}
public class EmployeeTable {
    private List<Employee> employees;

    public String table() {
        StringBuilder html = new StringBuilder();
        html.append("<table>");
        for (Employee employee : employees) {
            html.append("<tr>");
            // Print employee data ...
            html.append("</tr>");        TODO:
        }                              Show count
        html.append("</table>");
                                       of full-time
        return html.toString();
    }                                   employees

}
Sprout Class
public class FullTimeEmployeeCount {
    private List<Employee> employees;

    public FullTimeEmployeeCount(
                   List<Employee> employees) {
        this.employees = employees;
    }

    public int count() {
        int count = 0;
        for (Employee employee : employees) {
            if (employee.isFullTime()) count++;
        }
        return count;
    }
}
public String table() {
    StringBuilder html = new StringBuilder();
    html.append("<table>");
    for (Employee employee : employees) {
        html.append("<tr>");
        // Print employee data ...
        html.append("</tr>");
    }

    html.append("<tr>");
    html.append("<td colspan='3'>");
    html.append(
       new FullTimeEmployeeCount(employees).count());
    html.append("</td>");
    html.append("</tr>");

    html.append("</table>");
    return html.toString();
}
Crazy
Third-Party API?
You are
not alone
Google
End-to-End
   Tests?
Be Persistent
It’s
going
to be
hard
12


  9


  6


  3


   0
Iteration 20   Iteration 21   Iteration 22   Iteration 23   Iteration 24




                          Velocity
What if
management
doesn’t think TDD is
     valuable?
Any amount
is an improvement over
    nothing
Many small steps
add up over time
Do it every day
Don’t be afraid to
delete and reshape
Be Creative
Pair Programming
Spread experts around
Get to Safety

Be Persistent
Yay, TDD
on my project!
Upcoming Event
 “How to Hire and Retain Developers”
           by Debbie Madden, EVP
              Monday @ 6 PM
              General Assembly
     http://generalassemb.ly/education/
More upcoming NYC and Boston Cyrus events at
 http://www.cyrusinnovation.com/about/events
Questions?
     Discussion!
          Twitter: @wellman
E-mail: dwellman@cyrusinnovation.com


                        www.cyrusinnovation.com
                        Twitter: @cyrusinnovation

More Related Content

What's hot

Code generation for alternative languages
Code generation for alternative languagesCode generation for alternative languages
Code generation for alternative languagesRafael Winterhalter
 
Apache Commons - Don\'t re-invent the wheel
Apache Commons - Don\'t re-invent the wheelApache Commons - Don\'t re-invent the wheel
Apache Commons - Don\'t re-invent the wheeltcurdt
 
Java_practical_handbook
Java_practical_handbookJava_practical_handbook
Java_practical_handbookManusha Dilan
 
Ensure code quality with vs2012
Ensure code quality with vs2012Ensure code quality with vs2012
Ensure code quality with vs2012Sandeep Joshi
 
5. Ввод-вывод, доступ к файловой системе
5. Ввод-вывод, доступ к файловой системе5. Ввод-вывод, доступ к файловой системе
5. Ввод-вывод, доступ к файловой системеDEVTYPE
 
201913046 wahyu septiansyah network programing
201913046 wahyu septiansyah network programing201913046 wahyu septiansyah network programing
201913046 wahyu septiansyah network programingwahyuseptiansyah
 
Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113SOAT
 
Java 7 at SoftShake 2011
Java 7 at SoftShake 2011Java 7 at SoftShake 2011
Java 7 at SoftShake 2011julien.ponge
 
Java 7 JUG Summer Camp
Java 7 JUG Summer CampJava 7 JUG Summer Camp
Java 7 JUG Summer Campjulien.ponge
 
Laporan multiclient chatting client server
Laporan multiclient chatting client serverLaporan multiclient chatting client server
Laporan multiclient chatting client servertrilestari08
 
ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)David Rodenas
 
Making Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMMaking Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMRafael Winterhalter
 

What's hot (20)

Code generation for alternative languages
Code generation for alternative languagesCode generation for alternative languages
Code generation for alternative languages
 
Test Time Bombs
Test Time BombsTest Time Bombs
Test Time Bombs
 
Apache Commons - Don\'t re-invent the wheel
Apache Commons - Don\'t re-invent the wheelApache Commons - Don\'t re-invent the wheel
Apache Commons - Don\'t re-invent the wheel
 
Ad java prac sol set
Ad java prac sol setAd java prac sol set
Ad java prac sol set
 
Java_practical_handbook
Java_practical_handbookJava_practical_handbook
Java_practical_handbook
 
Ensure code quality with vs2012
Ensure code quality with vs2012Ensure code quality with vs2012
Ensure code quality with vs2012
 
JDK Power Tools
JDK Power ToolsJDK Power Tools
JDK Power Tools
 
5. Ввод-вывод, доступ к файловой системе
5. Ввод-вывод, доступ к файловой системе5. Ввод-вывод, доступ к файловой системе
5. Ввод-вывод, доступ к файловой системе
 
Spock framework
Spock frameworkSpock framework
Spock framework
 
201913046 wahyu septiansyah network programing
201913046 wahyu septiansyah network programing201913046 wahyu septiansyah network programing
201913046 wahyu septiansyah network programing
 
Notepad
NotepadNotepad
Notepad
 
JavaExamples
JavaExamplesJavaExamples
JavaExamples
 
Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113
 
Java 7 at SoftShake 2011
Java 7 at SoftShake 2011Java 7 at SoftShake 2011
Java 7 at SoftShake 2011
 
Java 7 JUG Summer Camp
Java 7 JUG Summer CampJava 7 JUG Summer Camp
Java 7 JUG Summer Camp
 
Laporan multiclient chatting client server
Laporan multiclient chatting client serverLaporan multiclient chatting client server
Laporan multiclient chatting client server
 
ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)
 
Making Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMMaking Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVM
 
Jersey Guice AOP
Jersey Guice AOPJersey Guice AOP
Jersey Guice AOP
 
Vaadin 7
Vaadin 7Vaadin 7
Vaadin 7
 

Viewers also liked

Courtney white intro
Courtney white introCourtney white intro
Courtney white introAndrew Fynn
 
Preferred Parking Perplexity
Preferred Parking PerplexityPreferred Parking Perplexity
Preferred Parking PerplexityJi Li
 
Steven apfelbaum quivira final nov 2010 v2
Steven apfelbaum quivira final nov 2010 v2Steven apfelbaum quivira final nov 2010 v2
Steven apfelbaum quivira final nov 2010 v2Andrew Fynn
 
Sequestering Carbon for the Carbon Market ~ Doing it and Proving it ~ Dr. Bil...
Sequestering Carbon for the Carbon Market ~ Doing it and Proving it ~ Dr. Bil...Sequestering Carbon for the Carbon Market ~ Doing it and Proving it ~ Dr. Bil...
Sequestering Carbon for the Carbon Market ~ Doing it and Proving it ~ Dr. Bil...Andrew Fynn
 
Working with Carbon ~ The Interplay of Range Management, Grassfed Beef, Wind ...
Working with Carbon ~ The Interplay of Range Management, Grassfed Beef, Wind ...Working with Carbon ~ The Interplay of Range Management, Grassfed Beef, Wind ...
Working with Carbon ~ The Interplay of Range Management, Grassfed Beef, Wind ...Andrew Fynn
 
Underground Economics - Making Markets to Solve Cities' Problems through Soil...
Underground Economics - Making Markets to Solve Cities' Problems through Soil...Underground Economics - Making Markets to Solve Cities' Problems through Soil...
Underground Economics - Making Markets to Solve Cities' Problems through Soil...Andrew Fynn
 
Apavou Hotels-Resorts & Spa- Amazing Holiday Destination
Apavou Hotels-Resorts & Spa- Amazing Holiday DestinationApavou Hotels-Resorts & Spa- Amazing Holiday Destination
Apavou Hotels-Resorts & Spa- Amazing Holiday DestinationYatra.Com
 

Viewers also liked (8)

Courtney white intro
Courtney white introCourtney white intro
Courtney white intro
 
Raul PRESENTACION
Raul PRESENTACIONRaul PRESENTACION
Raul PRESENTACION
 
Preferred Parking Perplexity
Preferred Parking PerplexityPreferred Parking Perplexity
Preferred Parking Perplexity
 
Steven apfelbaum quivira final nov 2010 v2
Steven apfelbaum quivira final nov 2010 v2Steven apfelbaum quivira final nov 2010 v2
Steven apfelbaum quivira final nov 2010 v2
 
Sequestering Carbon for the Carbon Market ~ Doing it and Proving it ~ Dr. Bil...
Sequestering Carbon for the Carbon Market ~ Doing it and Proving it ~ Dr. Bil...Sequestering Carbon for the Carbon Market ~ Doing it and Proving it ~ Dr. Bil...
Sequestering Carbon for the Carbon Market ~ Doing it and Proving it ~ Dr. Bil...
 
Working with Carbon ~ The Interplay of Range Management, Grassfed Beef, Wind ...
Working with Carbon ~ The Interplay of Range Management, Grassfed Beef, Wind ...Working with Carbon ~ The Interplay of Range Management, Grassfed Beef, Wind ...
Working with Carbon ~ The Interplay of Range Management, Grassfed Beef, Wind ...
 
Underground Economics - Making Markets to Solve Cities' Problems through Soil...
Underground Economics - Making Markets to Solve Cities' Problems through Soil...Underground Economics - Making Markets to Solve Cities' Problems through Soil...
Underground Economics - Making Markets to Solve Cities' Problems through Soil...
 
Apavou Hotels-Resorts & Spa- Amazing Holiday Destination
Apavou Hotels-Resorts & Spa- Amazing Holiday DestinationApavou Hotels-Resorts & Spa- Amazing Holiday Destination
Apavou Hotels-Resorts & Spa- Amazing Holiday Destination
 

Similar to How to Start Test-Driven Development in Legacy Code

2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good TestsTomek Kaczanowski
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good TestsTomek Kaczanowski
 
Confitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good TestsConfitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good TestsTomek Kaczanowski
 
GeeCON 2012 Bad Tests, Good Tests
GeeCON 2012 Bad Tests, Good TestsGeeCON 2012 Bad Tests, Good Tests
GeeCON 2012 Bad Tests, Good TestsTomek Kaczanowski
 
Introduction à Dart
Introduction à DartIntroduction à Dart
Introduction à DartSOAT
 
TDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETTDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETtdc-globalcode
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotationjavatwo2011
 
[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancjiJakub Marchwicki
 
Testing in android
Testing in androidTesting in android
Testing in androidjtrindade
 
Java осень 2012 лекция 2
Java осень 2012 лекция 2Java осень 2012 лекция 2
Java осень 2012 лекция 2Technopark
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy codeShriKant Vashishtha
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo....NET Conf UY
 

Similar to How to Start Test-Driven Development in Legacy Code (20)

2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
 
JUnit 5
JUnit 5JUnit 5
JUnit 5
 
Week 12 code
Week 12 codeWeek 12 code
Week 12 code
 
Confitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good TestsConfitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good Tests
 
GeeCON 2012 Bad Tests, Good Tests
GeeCON 2012 Bad Tests, Good TestsGeeCON 2012 Bad Tests, Good Tests
GeeCON 2012 Bad Tests, Good Tests
 
Introduction à Dart
Introduction à DartIntroduction à Dart
Introduction à Dart
 
Anti patterns
Anti patternsAnti patterns
Anti patterns
 
TDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETTDC2016SP - Trilha .NET
TDC2016SP - Trilha .NET
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
 
[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji
 
Testing in android
Testing in androidTesting in android
Testing in android
 
Java осень 2012 лекция 2
Java осень 2012 лекция 2Java осень 2012 лекция 2
Java осень 2012 лекция 2
 
My java file
My java fileMy java file
My java file
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Best practices unit testing
Best practices unit testing Best practices unit testing
Best practices unit testing
 
Codemotion appengine
Codemotion appengineCodemotion appengine
Codemotion appengine
 
VRaptor 4 - JavaOne
VRaptor 4 - JavaOneVRaptor 4 - JavaOne
VRaptor 4 - JavaOne
 

Recently uploaded

Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 

Recently uploaded (20)

Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 

How to Start Test-Driven Development in Legacy Code

  • 1. How to Start Test-Driven Development in Legacy Code The New York XP & Agile Meetup May 17, 2012 Daniel Wellman Director of Technology Tweet #legacytdd #xpnyc
  • 3. “red, green, refactor” by Török Gábor
  • 6.
  • 9. Photo by the Dorothy Peyton Gray Transportation Library and Archive at the Los Angeles County Metropolitan Transportation Authority
  • 10. “Another flaw in the human character is that everybody wants to build and nobody wants to do Kurt Vonnegut maintenance.” Hocus Pocus
  • 11. Photo by Fraser Speirs
  • 12.
  • 14. TDD Cycle Red Green Refactor
  • 18. How do I test this?
  • 19. Seams Photo by Art Crimes a.k.a. Susan M. Coles
  • 20. Legacy TDD Cycle Introduce Seams Red Green Refactor
  • 21. ??
  • 22. Break dependencies just enough to get tests in place
  • 23. Use Safe Refactoring Tools (if you have them)
  • 24. Or move very slowly and carefully
  • 25.
  • 27. The Challenge of ‘new’
  • 28. public class TestCase { public void run() { TestResult result = new TestResult(); try { setUp(); runTest(result); } catch (Exception e) { result.addFailure(e, this); } tearDown(); } }
  • 29. public class TestCase { public void run() { TestResult result = new TestResult(); try { setUp(); runTest(result); } catch (Exception e) { result.addFailure(e, this); } tearDown(); } }
  • 30. public class TestCase { public void run() { TestResult result = new TestResult(); try { setUp(); runTest(result); } catch (Exception e) { result.addFailure(e, this); } tearDown(); @Test } } public void exceptionsReportAsFailures() { TestCase testCase = new TestCase(); testCase.run(); // ...?? }
  • 31. After Extract Parameter public class TestCase { public void run(TestResult testResult) { TestResult result = testResult; try { setUp(); runTest(result); } catch (Exception e) { result.addFailure(e, this); } tearDown(); } }
  • 32. After Extract Parameter public class TestCase { public void run(TestResult testResult) { TestResult result = testResult; try { setUp(); runTest(result); @Test } catch (Exception e) { result.addFailure(e, this); public void exceptionsReportAsFailures() { } TestCase testCase = new TestCase(); tearDown(); TestResult result = new TestResult(); } testCase.run(result); } // Make assertions on result }
  • 34. public class MailingListDispatcher { private MailService mailService; public MailingListDispatcher(Status status) { this.mailService = new SMTPMailService("smtp.gmail.com"); // ... } public Result send(Message message) { // ... mailService.send(message); // ... } }
  • 35. public class MailingListDispatcher { private MailService mailService; public MailingListDispatcher(Status status) { this.mailService = new SMTPMailService("smtp.gmail.com"); // ... } public Result send(Message message) { // ... mailService.send(message); @Test // ... public void testSendSuccessful() { } MailingListDispatcher dispatch = } new MailingListDispatcher(OK); dispatch.send(new Message()); // ... ??? }
  • 36. After Parameterize Constructor public class MailingListDispatcher { private MailService mailService; public MailingListDispatcher( MailService service, Status status) { this.mailService = service; // ... } public Result send(Message message) { // ... mailService.send(message); // ... } }
  • 37. After Parameterize Constructor public class MailingListDispatcher { private MailService mailService; public MailingListDispatcher( MailService service, Status status) { this.mailService = service; // ... } public Result send(Message message) { @Test public// ... void testSendSuccessful() throws Exception { MailService mailService = new FakeMailService(); mailService.send(message); MailingListDispatcher dispatch = // ... } new MailingListDispatcher(mailService, OK); dispatch.send(new Message()); // Inspect the FakeMailService } }
  • 38. Can’t Make a Fake?
  • 39. public class SMTPMailServer { public void helo(String hostname) {} public void from(String address) {} public void size(long byteCount) {} public void data() {} public void send(Message message) {} public void quit() {} ... private int sendBytes(byte[] toSend) {} ... }
  • 40. Override Methods public class FakeOverrideSMTPMailServer extends SMTPMailServer { public byte[] sent; // public! @Override protected int sendBytes(byte[] toSend) { // Save the bytes for later inspection // ... return 0; // Whatever... } }
  • 41. Override Methods public class FakeOverrideSMTPMailServer extends SMTPMailServer { public byte[] sent; // public! @Override protected int sendBytes(byte[] toSend) { // Save the bytes for later inspection // ... return 0; // Whatever... public class SMTPMailServer { } } // ... protected int sendBytes(byte[] toSend) { } ... }
  • 42. Extract Interface public interface MailServer { public void helo(String hostname); public void send(Message message); public void quit(); }
  • 43. Extract Interface sh -i public interface MailServer { public void helo(String hostname); public void send(Message message); public void quit(); }
  • 44. Extract Interface sh -i public interface MailServer { public void helo(String hostname); public void send(Message message); public void quit(); } public class SMTPMailServer implements MailServer { // Retro-fitted production... }
  • 45. Extract Interface sh -i public interface MailServer { public void helo(String hostname); public void send(Message message); public void quit(); } public class SMTPMailServer implements MailServer { // Retro-fitted production... } public class FakeMailServer implements MailServer { // Testing ... }
  • 47. public Duration vacationRemaining(Date today) { Duration remaining; // ... // ... // Calculate hours worked // ... // ... // How much vacation do they get? // ... // ... // Is it a leap year? // ... // ... return remaining; }
  • 48. Extract Methods public Time hoursWorked(Time start, Time end) { // ... } public int vacationDaysAllowed(EmployeeType type) { // ... } public boolean isLeapMonth(Date date) { // ... }
  • 49. Not much time to change?
  • 50. Sprout Method and Sprout Class “sprouting bean” photo by Zoë Jackson
  • 51. public class EmployeeTable { private List<Employee> employees; public String table() { StringBuilder html = new StringBuilder(); html.append("<table>"); for (Employee employee : employees) { html.append("<tr>"); // Print employee data ... html.append("</tr>"); } html.append("</table>"); return html.toString(); } }
  • 52. public class EmployeeTable { private List<Employee> employees; public String table() { StringBuilder html = new StringBuilder(); html.append("<table>"); for (Employee employee : employees) { html.append("<tr>"); // Print employee data ... html.append("</tr>"); TODO: } Show count html.append("</table>"); of full-time return html.toString(); } employees }
  • 53. Sprout Class public class FullTimeEmployeeCount { private List<Employee> employees; public FullTimeEmployeeCount( List<Employee> employees) { this.employees = employees; } public int count() { int count = 0; for (Employee employee : employees) { if (employee.isFullTime()) count++; } return count; } }
  • 54. public String table() { StringBuilder html = new StringBuilder(); html.append("<table>"); for (Employee employee : employees) { html.append("<tr>"); // Print employee data ... html.append("</tr>"); } html.append("<tr>"); html.append("<td colspan='3'>"); html.append( new FullTimeEmployeeCount(employees).count()); html.append("</td>"); html.append("</tr>"); html.append("</table>"); return html.toString(); }
  • 58. End-to-End Tests?
  • 61. 12 9 6 3 0 Iteration 20 Iteration 21 Iteration 22 Iteration 23 Iteration 24 Velocity
  • 63. Any amount is an improvement over nothing
  • 64. Many small steps add up over time
  • 65. Do it every day
  • 66. Don’t be afraid to delete and reshape
  • 70. Get to Safety Be Persistent
  • 71. Yay, TDD on my project!
  • 72. Upcoming Event “How to Hire and Retain Developers” by Debbie Madden, EVP Monday @ 6 PM General Assembly http://generalassemb.ly/education/ More upcoming NYC and Boston Cyrus events at http://www.cyrusinnovation.com/about/events
  • 73. Questions? Discussion! Twitter: @wellman E-mail: dwellman@cyrusinnovation.com www.cyrusinnovation.com Twitter: @cyrusinnovation

Editor's Notes

  1. \n
  2. \n
  3. Learned about XP, TDD appealed to me.\n
  4. ... there is a sense of &amp;#x201C;Yay, pair programming!&amp;#x201D;\n
  5. &amp;#x201C;TDD sounds great, but it won&amp;#x2019;t work on my project.&amp;#x201D;\n
  6. Story: I&amp;#x2019;m a Survivor\n
  7. \n
  8. I&amp;#x2019;m not saying it will be easy. Many legacy projects are in maintenance mode. And maintenance is generally something that doesn&amp;#x2019;t feel particularly exciting or associated with new technology.\n
  9. But I think this may be a general part of the human condition. \nOr at least Kurt Vonnegut did. \n\n\n
  10. In maintenance it can feel as if the all the fun stuff has ended and the rest of the work is trivial. To get in a mindset where working with and testing legacy code can be fun,\n
  11. ... I offer you this quote from Michael Feathers \n&amp;#x201C;Design is a continuous process, even when a project is in maintenance mode.&amp;#x201D;\n\n
  12. CALL TO ACTION - If you are a programmer and you haven&amp;#x2019;t read this book, read it!\nDescribes:\n1. How to figure out what legacy code is doing\n2. How to add tests to legacy code bases\n3. Includes a catalog of patterns to make code easier to test\n
  13. \n
  14. This is the TDD Cycle. But on legacy code, even the first step of &amp;#x201C;Getting to Red&amp;#x201D; can be unpredictably hard.\nAnd so to get in to this loop, we need to figure out how to test our code -- and why it&amp;#x2019;s hard to test it.\n
  15. \n
  16. Highly coupled code is difficult to test because it can be hard to get small units to operate in isolation, and it can be hard to observe the effect you&amp;#x2019;re trying to test for.\n\nTesting Legacy Code is all about improving and refactoring the design.\n\nThat usually means decoupling highly-coupled code, and making big structures smaller.\n
  17. = Easier to reason about and test\n
  18. So how do you add tests to code that wasn&amp;#x2019;t designed for testing?\n
  19. &amp;#x201C;A seam is a place where you can alter behavior in your program without editing in that place.&amp;#x201D; - Feathers\n\nWhy Seams? They are places where it becomes possible to replace undesirable production behavior or observe changes.\n
  20. Sometimes the seams are there already, so you can just use them.\nBut if there isn&amp;#x2019;t a seam, you may need to change your code to create one.\n\n
  21. But how do you change the code if you&amp;#x2019;re supposed to have a test for it in the first place?\n
  22. The initial result may look weird, and maybe even ugly, but over time these tend to get smoothed over.\n\nAnd how do you break these dependencies safely?\n
  23. \n
  24. Concentrate on making the minimal amount of changes to get you into a place where you can test.\nAnd personally, I find that.... (finding seams can be fun!)\n
  25. Finding seams can be fun!\n\n\n
  26. ! Language Disclaimer !\n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. If you want, you can leave the single argument constructor from before and have it delegate to the new one, so that production code is left unchanged.\n
  34. Do whatever it takes!\n
  35. \n
  36. The &amp;#x2018;sent&amp;#x2019; byte array is public, which we&amp;#x2019;d probably never do in production code, but it till get us going for our tests.\nAnd we may not know what &amp;#x2018;sendBytes&amp;#x2019; needs to return, so we just send\n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n\n
  43. ... and you don&amp;#x2019;t want to break the habit of writing a test first and then production code.\n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. Tend to prevent more regressions in the project at first\nEasier to sell to new developers\nBut massive amounts can be expensive\n... Generally a few catch many deployment-related issues.\nStory: It&amp;#x2019;s all Selenium\n
  52. \n
  53. 1. New People (to TDD. and maybe the code)\n2. Legacy Code\n3. Political\n
  54. \n
  55. \n
  56. \n
  57. Being persistent\n
  58. - bugs \n- new features\n
  59. \n
  60. \n
  61. Pairing can help\n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. I&amp;#x2019;m not saying it will be easy. Many legacy projects are in maintenance mode. And maintenance is generally something that doesn&amp;#x2019;t feel particularly exciting or associated with new technology.\n
  73. \n
  74. Many techniques are available for this\nDebugging\nRefactoring for learning, then reverting\nCharacterization Tests\n