SlideShare une entreprise Scribd logo
1  sur  68
Working Effectively with Legacy Code Michael Feathers [email_address]
Background ,[object Object],[object Object],if (m_nCriticalError)‏ return; m_nCriticalError=nErrorCode; switch (nEvent)‏ { case FD_READ: case FD_FORCEREAD: if (GetLayerState()==connecting && !nErrorCode)‏
First Reaction ,[object Object],[object Object],[object Object],[object Object]
Let’s Try It
PageGenerator::generate()‏ std::string PageGenerator::generate()‏ { std::vector<Result> results  = database.queryResults(beginDate, endDate); std::string pageText; pageText += &quot;<html>&quot;; pageText += &quot;<head>&quot;; pageText += &quot;<title>&quot;; pageText += &quot;Quarterly Report&quot;; pageText += &quot;</title>&quot;; pageText += &quot;</head>&quot;; pageText += &quot;<body>&quot;; pageText += &quot;<h1>&quot;; pageText += &quot;Quarterly Report&quot;; pageText += &quot;</h1><table>&quot;; …
Continued.. … if (results.size() != 0) { pageText += &quot;<table border=amp;quot;1amp;quot;>&quot;; for (std::vector<Result>::iterator it = results.begin();  it != results.end(); ++it) { pageText += &quot;<tr border=amp;quot;1amp;quot;>&quot;; pageText += &quot;<td>&quot; + it->department + &quot;</td>&quot;; pageText += &quot;<td>&quot; + it->manager + &quot;</td>&quot;; char buffer [128]; sprintf(buffer, &quot;<td>$%d</td>&quot;, it->netProfit / 100); pageText += std::string(buffer); sprintf(buffer, &quot;<td>$%d</td>&quot;, it->operatingExpense / 100); pageText += std::string(buffer); pageText += &quot;</tr>&quot;; } pageText += &quot;</table>&quot;; } else { …
Continued.. … pageText += &quot;<p>No results for this period</p>&quot;; } pageText += &quot;</body>&quot;; pageText += &quot;</html>&quot;; return pageText; } // Argh!!
Changes ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Chia Pet Pattern ,[object Object]
Why are we so Conservative? ,[object Object],[object Object]
The Refactoring Dilemma ,[object Object]
Most applications are glued together ,[object Object]
Kinds of Glue ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Breaking Dependencies ,[object Object],[object Object],[object Object]
‘ The Undetectable Side-Effect’ ,[object Object]
(told you)‏ public class AccountDetailFrame extends Frame implements ActionListener, WindowListener { private TextField display = new TextField(10); … private AccountDetailFrame(…) { … } public void performAction(ActionEvent event) { String source = (String)event.getActionCommand(); if (source.equals(“project activity”)) { DetailFrame detailDisplay = new DetailFrame(); detailDisplay.setDescription( getDetailText() + “ “ + getProjectText()); detailDisplay.show(); String accountDescription =  detailDisplay.getAccountSymbol(); accountDescription += “: “; … display.setText(accountDescription); … } }
Separate a dependency public class AccountDetailFrame extends Frame implements ActionListener, WindowListener { private TextField display = new TextField(10); … private AccountDetailFrame(…) { … } public void performAction(ActionEvent event) { String source = (String)event.getActionCommand(); if (source.equals(“project activity”)) { DetailFrame detailDisplay = new DetailFrame(); detailDisplay.setDescription( getDetailText() + “ “ + getProjectText()); detailDisplay.show(); String accountDescription =  detailDisplay.getAccountSymbol(); accountDescription += “: “; … display.setText(accountDescription); … } }
After a method extraction.. public class AccountDetailFrame extends Frame implements ActionListener, WindowListener { … public void performAction(ActionEvent event) { performCommand((String)event.getActionCommand()); } void performCommand(String source); if (source.equals(“project activity”)) { DetailFrame detailDisplay = new DetailFrame(); detailDisplay.setDescription( getDetailText() + “ “ + getProjectText()); detailDisplay.show(); String accountDescription =  detailDisplay.getAccountSymbol(); accountDescription += “: “; … display.setText(accountDescription); … } }
More offensive dependencies.. public class AccountDetailFrame extends Frame implements ActionListener, WindowListener { … void performCommand(String source); if (source.equals(“project activity”)) { DetailFrame detailDisplay = new DetailFrame(); detailDisplay.setDescription( getDetailText() + “ “ + getProjectText()); detailDisplay.show(); String accountDescription =  detailDisplay.getAccountSymbol(); accountDescription += “: “; … display.setText(accountDescription); … } }
More refactoring.. public class AccountDetailFrame extends Frame implements ActionListener, WindowListener { private TextField display = new TextField(10); private DetailFrame detailDisplay; … void performCommand(String source); if (source.equals(“project activity”)) { setDescription(getDetailText() + “” +  getProjectText()); … String accountDescripton =  getAccountSymbol(); accountDescription += “: “; … setDisplayText(accountDescription); … } } …
The aftermath.. We can subclass and override  getAccountSymbol ,  setDisplayText ,  and  setDescription  to sense our work
A Test.. public void testPerformCommand() { TestingAccountDetailFrame frame =  new TestingAccountDetailFrame(); frame.accountSymbol = “SYM”; frame.performCommand(“project activity”); assertEquals(“06 080 012”, frame.getDisplayText()); }
Classes are like cells.. ,[object Object]
Making it Better ,[object Object]
Better vs. Best ,[object Object]
Automated Tool Moves ,[object Object],[object Object]
Manual Moves ,[object Object],[object Object],[object Object]
Leaning on the Compiler ,[object Object],[object Object],[object Object],[object Object]
Signature Preservation ,[object Object],[object Object]
Single Goal Editing ,[object Object]
The Legacy Code Change Algorithm ,[object Object],[object Object],[object Object],[object Object],[object Object]
Development Speed ,[object Object],[object Object]
Breaking Dependencies 0 Extract Interface Extract Implementor
Extract Interface ,[object Object],[object Object],[object Object],[object Object]
Extract Interface ,[object Object],[object Object],[object Object]
Extract Interface Steps ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
The Non-Virtual Override Problem ,[object Object],class EventProcessor { public: void handle(Event *event); }; class MultiplexProcessor : public EventProcessor { public: void handle(Event *event); };
The Non-Virtual Override Problem ,[object Object],[object Object],[object Object],[object Object]
The Non-Virtual Override Problem ,[object Object],[object Object],[object Object],[object Object]
Extract Implementor ,[object Object]
Breaking Dependencies 1 Parameterize Method Extract and Override Call
Parameterize Method ,[object Object],[object Object],void TestCase::run() { m_result =  new TestResult; runTest(m_result); } void TestCase::run() { run(new TestResult); } void TestCase::run( TestResult *result) { m_result = result; runTest(m_result); }
Steps – Parameterize Method ,[object Object],[object Object],[object Object]
Extract and Override Call ,[object Object]
Steps – Extract and Override Call ,[object Object],[object Object],[object Object]
Breaking Dependencies 2 Link-Time Polymorphism
Link-Time Polymorphism void account_deposit(int amount)‏ { struct Call *call = (struct Call *)‏ calloc(1, sizeof (struct Call)); call->type = ACC_DEPOSIT; call->arg0 = amount; append(g_calls, call); }
Steps – Link-Time Polymorphism ,[object Object],[object Object],[object Object]
Breaking Dependencies 3 Expose Static Method
Expose Static Method ,[object Object],[object Object],class RSCWorkflow { public void validate(Packet packet) { if (packet.getOriginator() == “MIA”  || !packet.hasValidCheckSum()) { throw new InvalidFlow(); } … } }
Expose Static Method ,[object Object],[object Object],[object Object]
Expose Static Method ,[object Object],[object Object],[object Object],[object Object],[object Object]
Steps – Expose Static Method ,[object Object],[object Object],[object Object],[object Object],[object Object]
Breaking Dependencies 4 Introduce Instance Delegator
Introduce Instance Delegator ,[object Object],[object Object],static void BankingServices::updateAccountBalance( int userID,  Money amount) { … }
Introduce Instance Delegator ,[object Object],public class BankingServices { public static void updateAccountBalance( int userID,  Money amount) { … } public void updateBalance( int userID,  Money amount) { updateAccountBalance(userID, amount); } }
Steps –Introduce Instance Delegator ,[object Object],[object Object],[object Object],[object Object],[object Object]
Dependency Breaking 5 Template Redefinition
Template Redefinition ,[object Object],class AsyncReceptionPort { private: CSocket m_socket;  // bad dependency Packet m_packet; int m_segmentSize; … public: AsyncReceptionPort(); void Run(); … };
Template Redefinition template<typename SOCKET> class AsyncReceptionPortImpl { private: SOCKET m_socket; Packet m_packet; int m_segmentSize; … public: AsyncReceptionPortImpl(); void Run(); }; typedef AsyncReceptionPortImpl<CSocket> AsyncReceptionPort;
Steps – Template Redefinition ,[object Object],[object Object],[object Object],[object Object],[object Object]
Writing Tests
Characterization Testing ,[object Object],[object Object],[object Object]
Characterization Testing ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Characterization Testing Example ,[object Object],class ResidentialAccount void charge(int gallons, date readingDate){   if (billingPlan.isMonthly()) { if (gallons < RESIDENTIAL_MIN)  balance += RESIDENTIAL_BASE; else  balance += 1.2 *  priceForGallons(gallons); billingPlan.postReading(readingDate,  gallons);   } }
Characterization Testing Example ,[object Object],[object Object],if (gallons < RESIDENTIAL_MIN)  balance += RESIDENTIAL_BASE; else  balance += 1.2 *  priceForGallons(gallons); billingPlan.postReading(readingDate,  gallons);
Questions & Concerns ,[object Object],[object Object],[object Object]
WELC Understanding, Isolating,  Testing, and Changing ..Untested Code www.objectmentor.com www.michaelfeathers.com

Contenu connexe

Tendances (20)

Exception handling
Exception handlingException handling
Exception handling
 
Templates in c++
Templates in c++Templates in c++
Templates in c++
 
Access specifiers (Public Private Protected) C++
Access specifiers (Public Private  Protected) C++Access specifiers (Public Private  Protected) C++
Access specifiers (Public Private Protected) C++
 
Introduction to Koltin for Android Part I
Introduction to Koltin for Android Part I Introduction to Koltin for Android Part I
Introduction to Koltin for Android Part I
 
C# Basics
C# BasicsC# Basics
C# Basics
 
C# operators
C# operatorsC# operators
C# operators
 
Working with Legacy Code
Working with Legacy CodeWorking with Legacy Code
Working with Legacy Code
 
Encapsulation C++
Encapsulation C++Encapsulation C++
Encapsulation C++
 
Four Pillers Of OOPS
Four Pillers Of OOPSFour Pillers Of OOPS
Four Pillers Of OOPS
 
Java interfaces
Java   interfacesJava   interfaces
Java interfaces
 
Clean code
Clean code Clean code
Clean code
 
C# basics
 C# basics C# basics
C# basics
 
Pure virtual function and abstract class
Pure virtual function and abstract classPure virtual function and abstract class
Pure virtual function and abstract class
 
Working With Legacy Code
Working With Legacy CodeWorking With Legacy Code
Working With Legacy Code
 
Data types in java
Data types in javaData types in java
Data types in java
 
Python-Encapsulation.pptx
Python-Encapsulation.pptxPython-Encapsulation.pptx
Python-Encapsulation.pptx
 
Oops concept on c#
Oops concept on c#Oops concept on c#
Oops concept on c#
 
Introduction To C#
Introduction To C#Introduction To C#
Introduction To C#
 
CSharp Presentation
CSharp PresentationCSharp Presentation
CSharp Presentation
 
Object-oriented Programming-with C#
Object-oriented Programming-with C#Object-oriented Programming-with C#
Object-oriented Programming-with C#
 

En vedette

XPDays Ukraine: Legacy
XPDays Ukraine: LegacyXPDays Ukraine: Legacy
XPDays Ukraine: LegacyVictor_Cr
 
Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"Victor_Cr
 
Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Victor_Cr
 
XP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy codeXP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy codeDmytro Mindra
 
Как пишутся и поддерживаются Enterprise системы
Как пишутся и поддерживаются Enterprise системыКак пишутся и поддерживаются Enterprise системы
Как пишутся и поддерживаются Enterprise системыSergey Nemchinsky
 
Towards a Principle-based Classification of Structural Design Smells
Towards a Principle-based Classification of Structural Design SmellsTowards a Principle-based Classification of Structural Design Smells
Towards a Principle-based Classification of Structural Design SmellsTushar Sharma
 
SOLID Principles and Design Patterns
SOLID Principles and Design PatternsSOLID Principles and Design Patterns
SOLID Principles and Design PatternsGanesh Samarthyam
 
Pragmatic Technical Debt Management
Pragmatic Technical Debt ManagementPragmatic Technical Debt Management
Pragmatic Technical Debt ManagementTushar Sharma
 
Infographic - Pragmatic Technical Debt Management
Infographic - Pragmatic Technical Debt ManagementInfographic - Pragmatic Technical Debt Management
Infographic - Pragmatic Technical Debt ManagementTushar Sharma
 
PHAME: Principles of Hierarchy Abstraction Modularization and Encapsulation
PHAME: Principles of Hierarchy Abstraction Modularization and EncapsulationPHAME: Principles of Hierarchy Abstraction Modularization and Encapsulation
PHAME: Principles of Hierarchy Abstraction Modularization and EncapsulationTushar Sharma
 
Why care about technical debt?
Why care about technical debt?Why care about technical debt?
Why care about technical debt?Tushar Sharma
 
A Checklist for Design Reviews
A Checklist for Design ReviewsA Checklist for Design Reviews
A Checklist for Design ReviewsTushar Sharma
 
Tools for Identifying and Addressing Technical Debt
Tools for Identifying and Addressing Technical DebtTools for Identifying and Addressing Technical Debt
Tools for Identifying and Addressing Technical DebtTushar Sharma
 
Refactoring for Software Design Smells: Managing Technical Debt
Refactoring for Software Design Smells: Managing Technical DebtRefactoring for Software Design Smells: Managing Technical Debt
Refactoring for Software Design Smells: Managing Technical DebtTushar Sharma
 
Tools for refactoring
Tools for refactoringTools for refactoring
Tools for refactoringTushar Sharma
 
Applying Design Principles in Practice
Applying Design Principles in PracticeApplying Design Principles in Practice
Applying Design Principles in PracticeTushar Sharma
 

En vedette (16)

XPDays Ukraine: Legacy
XPDays Ukraine: LegacyXPDays Ukraine: Legacy
XPDays Ukraine: Legacy
 
Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"
 
Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)
 
XP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy codeXP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy code
 
Как пишутся и поддерживаются Enterprise системы
Как пишутся и поддерживаются Enterprise системыКак пишутся и поддерживаются Enterprise системы
Как пишутся и поддерживаются Enterprise системы
 
Towards a Principle-based Classification of Structural Design Smells
Towards a Principle-based Classification of Structural Design SmellsTowards a Principle-based Classification of Structural Design Smells
Towards a Principle-based Classification of Structural Design Smells
 
SOLID Principles and Design Patterns
SOLID Principles and Design PatternsSOLID Principles and Design Patterns
SOLID Principles and Design Patterns
 
Pragmatic Technical Debt Management
Pragmatic Technical Debt ManagementPragmatic Technical Debt Management
Pragmatic Technical Debt Management
 
Infographic - Pragmatic Technical Debt Management
Infographic - Pragmatic Technical Debt ManagementInfographic - Pragmatic Technical Debt Management
Infographic - Pragmatic Technical Debt Management
 
PHAME: Principles of Hierarchy Abstraction Modularization and Encapsulation
PHAME: Principles of Hierarchy Abstraction Modularization and EncapsulationPHAME: Principles of Hierarchy Abstraction Modularization and Encapsulation
PHAME: Principles of Hierarchy Abstraction Modularization and Encapsulation
 
Why care about technical debt?
Why care about technical debt?Why care about technical debt?
Why care about technical debt?
 
A Checklist for Design Reviews
A Checklist for Design ReviewsA Checklist for Design Reviews
A Checklist for Design Reviews
 
Tools for Identifying and Addressing Technical Debt
Tools for Identifying and Addressing Technical DebtTools for Identifying and Addressing Technical Debt
Tools for Identifying and Addressing Technical Debt
 
Refactoring for Software Design Smells: Managing Technical Debt
Refactoring for Software Design Smells: Managing Technical DebtRefactoring for Software Design Smells: Managing Technical Debt
Refactoring for Software Design Smells: Managing Technical Debt
 
Tools for refactoring
Tools for refactoringTools for refactoring
Tools for refactoring
 
Applying Design Principles in Practice
Applying Design Principles in PracticeApplying Design Principles in Practice
Applying Design Principles in Practice
 

Similaire à Working Effectively With Legacy Code

Stopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under TestStopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under TestSeb Rose
 
CLR Exception Handing And Memory Management
CLR Exception Handing And Memory ManagementCLR Exception Handing And Memory Management
CLR Exception Handing And Memory ManagementShiny Zhu
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testingpleeps
 
Pragmatic Parallels: Java and JavaScript
Pragmatic Parallels: Java and JavaScriptPragmatic Parallels: Java and JavaScript
Pragmatic Parallels: Java and JavaScriptdavejohnson
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to javaciklum_ods
 
Framework Design Guidelines For Brussels Users Group
Framework Design Guidelines For Brussels Users GroupFramework Design Guidelines For Brussels Users Group
Framework Design Guidelines For Brussels Users Groupbrada
 
2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability
2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability
2008 - TechDays PT: WCF, JSON and AJAX for performance and manageabilityDaniel Fisher
 
Framework engineering JCO 2011
Framework engineering JCO 2011Framework engineering JCO 2011
Framework engineering JCO 2011YoungSu Son
 
Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsJeff Durta
 
Dot Net Accenture
Dot Net AccentureDot Net Accenture
Dot Net AccentureSri K
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)Jose Manuel Pereira Garcia
 
C# interview-questions
C# interview-questionsC# interview-questions
C# interview-questionsnicolbiden
 
Testing And Drupal
Testing And DrupalTesting And Drupal
Testing And DrupalPeter Arato
 
Can't Dance The Lambda
Can't Dance The LambdaCan't Dance The Lambda
Can't Dance The LambdaTogakangaroo
 
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...PVS-Studio
 
Professional JavaScript: AntiPatterns
Professional JavaScript: AntiPatternsProfessional JavaScript: AntiPatterns
Professional JavaScript: AntiPatternsMike Wilcox
 
SMI - Introduction to Java
SMI - Introduction to JavaSMI - Introduction to Java
SMI - Introduction to JavaSMIJava
 

Similaire à Working Effectively With Legacy Code (20)

Stopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under TestStopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under Test
 
Clean code
Clean codeClean code
Clean code
 
CLR Exception Handing And Memory Management
CLR Exception Handing And Memory ManagementCLR Exception Handing And Memory Management
CLR Exception Handing And Memory Management
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testing
 
Pragmatic Parallels: Java and JavaScript
Pragmatic Parallels: Java and JavaScriptPragmatic Parallels: Java and JavaScript
Pragmatic Parallels: Java and JavaScript
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
Framework Design Guidelines For Brussels Users Group
Framework Design Guidelines For Brussels Users GroupFramework Design Guidelines For Brussels Users Group
Framework Design Guidelines For Brussels Users Group
 
2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability
2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability
2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability
 
Framework engineering JCO 2011
Framework engineering JCO 2011Framework engineering JCO 2011
Framework engineering JCO 2011
 
Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applications
 
Dot Net Accenture
Dot Net AccentureDot Net Accenture
Dot Net Accenture
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
 
C# interview-questions
C# interview-questionsC# interview-questions
C# interview-questions
 
Testing And Drupal
Testing And DrupalTesting And Drupal
Testing And Drupal
 
Coding Naked 2023
Coding Naked 2023Coding Naked 2023
Coding Naked 2023
 
Can't Dance The Lambda
Can't Dance The LambdaCan't Dance The Lambda
Can't Dance The Lambda
 
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
 
Professional JavaScript: AntiPatterns
Professional JavaScript: AntiPatternsProfessional JavaScript: AntiPatterns
Professional JavaScript: AntiPatterns
 
SMI - Introduction to Java
SMI - Introduction to JavaSMI - Introduction to Java
SMI - Introduction to Java
 
Need 4 Speed FI
Need 4 Speed FINeed 4 Speed FI
Need 4 Speed FI
 

Plus de Naresh Jain

Problem Solving Techniques For Evolutionary Design
Problem Solving Techniques For Evolutionary DesignProblem Solving Techniques For Evolutionary Design
Problem Solving Techniques For Evolutionary DesignNaresh Jain
 
Agile India 2019 Conference Welcome Note
Agile India 2019 Conference Welcome NoteAgile India 2019 Conference Welcome Note
Agile India 2019 Conference Welcome NoteNaresh Jain
 
Organizational Resilience
Organizational ResilienceOrganizational Resilience
Organizational ResilienceNaresh Jain
 
Improving the Quality of Incoming Code
Improving the Quality of Incoming CodeImproving the Quality of Incoming Code
Improving the Quality of Incoming CodeNaresh Jain
 
Agile India 2018 Conference Summary
Agile India 2018 Conference SummaryAgile India 2018 Conference Summary
Agile India 2018 Conference SummaryNaresh Jain
 
Agile India 2018 Conference
Agile India 2018 ConferenceAgile India 2018 Conference
Agile India 2018 ConferenceNaresh Jain
 
Agile India 2018 Conference
Agile India 2018 ConferenceAgile India 2018 Conference
Agile India 2018 ConferenceNaresh Jain
 
Agile India 2018 Conference
Agile India 2018 ConferenceAgile India 2018 Conference
Agile India 2018 ConferenceNaresh Jain
 
Pilgrim's Progress to the Promised Land by Robert Virding
Pilgrim's Progress to the Promised Land by Robert VirdingPilgrim's Progress to the Promised Land by Robert Virding
Pilgrim's Progress to the Promised Land by Robert VirdingNaresh Jain
 
Concurrent languages are Functional by Francesco Cesarini
Concurrent languages are Functional by Francesco CesariniConcurrent languages are Functional by Francesco Cesarini
Concurrent languages are Functional by Francesco CesariniNaresh Jain
 
Erlang from behing the trenches by Francesco Cesarini
Erlang from behing the trenches by Francesco CesariniErlang from behing the trenches by Francesco Cesarini
Erlang from behing the trenches by Francesco CesariniNaresh Jain
 
Anatomy of an eCommerce Search Engine by Mayur Datar
Anatomy of an eCommerce Search Engine by Mayur DatarAnatomy of an eCommerce Search Engine by Mayur Datar
Anatomy of an eCommerce Search Engine by Mayur DatarNaresh Jain
 
Setting up Continuous Delivery Culture for a Large Scale Mobile App
Setting up Continuous Delivery Culture for a Large Scale Mobile AppSetting up Continuous Delivery Culture for a Large Scale Mobile App
Setting up Continuous Delivery Culture for a Large Scale Mobile AppNaresh Jain
 
Towards FutureOps: Stable, Repeatable environments from Dev to Prod
Towards FutureOps: Stable, Repeatable environments from Dev to ProdTowards FutureOps: Stable, Repeatable environments from Dev to Prod
Towards FutureOps: Stable, Repeatable environments from Dev to ProdNaresh Jain
 
Value Driven Development by Dave Thomas
Value Driven Development by Dave Thomas Value Driven Development by Dave Thomas
Value Driven Development by Dave Thomas Naresh Jain
 
No Silver Bullets in Functional Programming by Brian McKenna
No Silver Bullets in Functional Programming by Brian McKennaNo Silver Bullets in Functional Programming by Brian McKenna
No Silver Bullets in Functional Programming by Brian McKennaNaresh Jain
 
Functional Programming Conference 2016
Functional Programming Conference 2016Functional Programming Conference 2016
Functional Programming Conference 2016Naresh Jain
 
Agile India 2017 Conference
Agile India 2017 ConferenceAgile India 2017 Conference
Agile India 2017 ConferenceNaresh Jain
 
Unleashing the Power of Automated Refactoring with JDT
Unleashing the Power of Automated Refactoring with JDTUnleashing the Power of Automated Refactoring with JDT
Unleashing the Power of Automated Refactoring with JDTNaresh Jain
 

Plus de Naresh Jain (20)

Problem Solving Techniques For Evolutionary Design
Problem Solving Techniques For Evolutionary DesignProblem Solving Techniques For Evolutionary Design
Problem Solving Techniques For Evolutionary Design
 
Agile India 2019 Conference Welcome Note
Agile India 2019 Conference Welcome NoteAgile India 2019 Conference Welcome Note
Agile India 2019 Conference Welcome Note
 
Organizational Resilience
Organizational ResilienceOrganizational Resilience
Organizational Resilience
 
Improving the Quality of Incoming Code
Improving the Quality of Incoming CodeImproving the Quality of Incoming Code
Improving the Quality of Incoming Code
 
Agile India 2018 Conference Summary
Agile India 2018 Conference SummaryAgile India 2018 Conference Summary
Agile India 2018 Conference Summary
 
Agile India 2018 Conference
Agile India 2018 ConferenceAgile India 2018 Conference
Agile India 2018 Conference
 
Agile India 2018 Conference
Agile India 2018 ConferenceAgile India 2018 Conference
Agile India 2018 Conference
 
Agile India 2018 Conference
Agile India 2018 ConferenceAgile India 2018 Conference
Agile India 2018 Conference
 
Pilgrim's Progress to the Promised Land by Robert Virding
Pilgrim's Progress to the Promised Land by Robert VirdingPilgrim's Progress to the Promised Land by Robert Virding
Pilgrim's Progress to the Promised Land by Robert Virding
 
Concurrent languages are Functional by Francesco Cesarini
Concurrent languages are Functional by Francesco CesariniConcurrent languages are Functional by Francesco Cesarini
Concurrent languages are Functional by Francesco Cesarini
 
Erlang from behing the trenches by Francesco Cesarini
Erlang from behing the trenches by Francesco CesariniErlang from behing the trenches by Francesco Cesarini
Erlang from behing the trenches by Francesco Cesarini
 
Anatomy of an eCommerce Search Engine by Mayur Datar
Anatomy of an eCommerce Search Engine by Mayur DatarAnatomy of an eCommerce Search Engine by Mayur Datar
Anatomy of an eCommerce Search Engine by Mayur Datar
 
Setting up Continuous Delivery Culture for a Large Scale Mobile App
Setting up Continuous Delivery Culture for a Large Scale Mobile AppSetting up Continuous Delivery Culture for a Large Scale Mobile App
Setting up Continuous Delivery Culture for a Large Scale Mobile App
 
Towards FutureOps: Stable, Repeatable environments from Dev to Prod
Towards FutureOps: Stable, Repeatable environments from Dev to ProdTowards FutureOps: Stable, Repeatable environments from Dev to Prod
Towards FutureOps: Stable, Repeatable environments from Dev to Prod
 
Value Driven Development by Dave Thomas
Value Driven Development by Dave Thomas Value Driven Development by Dave Thomas
Value Driven Development by Dave Thomas
 
No Silver Bullets in Functional Programming by Brian McKenna
No Silver Bullets in Functional Programming by Brian McKennaNo Silver Bullets in Functional Programming by Brian McKenna
No Silver Bullets in Functional Programming by Brian McKenna
 
Functional Programming Conference 2016
Functional Programming Conference 2016Functional Programming Conference 2016
Functional Programming Conference 2016
 
Agile India 2017 Conference
Agile India 2017 ConferenceAgile India 2017 Conference
Agile India 2017 Conference
 
The Eclipse Way
The Eclipse WayThe Eclipse Way
The Eclipse Way
 
Unleashing the Power of Automated Refactoring with JDT
Unleashing the Power of Automated Refactoring with JDTUnleashing the Power of Automated Refactoring with JDT
Unleashing the Power of Automated Refactoring with JDT
 

Dernier

Dr. Admir Softic_ presentation_Green Club_ENG.pdf
Dr. Admir Softic_ presentation_Green Club_ENG.pdfDr. Admir Softic_ presentation_Green Club_ENG.pdf
Dr. Admir Softic_ presentation_Green Club_ENG.pdfAdmir Softic
 
Berhampur Call Girl Just Call 8084732287 Top Class Call Girl Service Available
Berhampur Call Girl Just Call 8084732287 Top Class Call Girl Service AvailableBerhampur Call Girl Just Call 8084732287 Top Class Call Girl Service Available
Berhampur Call Girl Just Call 8084732287 Top Class Call Girl Service Availablepr788182
 
CROSS CULTURAL NEGOTIATION BY PANMISEM NS
CROSS CULTURAL NEGOTIATION BY PANMISEM NSCROSS CULTURAL NEGOTIATION BY PANMISEM NS
CROSS CULTURAL NEGOTIATION BY PANMISEM NSpanmisemningshen123
 
joint cost.pptx COST ACCOUNTING Sixteenth Edition ...
joint cost.pptx  COST ACCOUNTING  Sixteenth Edition                          ...joint cost.pptx  COST ACCOUNTING  Sixteenth Edition                          ...
joint cost.pptx COST ACCOUNTING Sixteenth Edition ...NadhimTaha
 
PHX May 2024 Corporate Presentation Final
PHX May 2024 Corporate Presentation FinalPHX May 2024 Corporate Presentation Final
PHX May 2024 Corporate Presentation FinalPanhandleOilandGas
 
How to Get Started in Social Media for Art League City
How to Get Started in Social Media for Art League CityHow to Get Started in Social Media for Art League City
How to Get Started in Social Media for Art League CityEric T. Tung
 
SEO Case Study: How I Increased SEO Traffic & Ranking by 50-60% in 6 Months
SEO Case Study: How I Increased SEO Traffic & Ranking by 50-60%  in 6 MonthsSEO Case Study: How I Increased SEO Traffic & Ranking by 50-60%  in 6 Months
SEO Case Study: How I Increased SEO Traffic & Ranking by 50-60% in 6 MonthsIndeedSEO
 
Lundin Gold - Q1 2024 Conference Call Presentation (Revised)
Lundin Gold - Q1 2024 Conference Call Presentation (Revised)Lundin Gold - Q1 2024 Conference Call Presentation (Revised)
Lundin Gold - Q1 2024 Conference Call Presentation (Revised)Adnet Communications
 
Durg CALL GIRL ❤ 82729*64427❤ CALL GIRLS IN durg ESCORTS
Durg CALL GIRL ❤ 82729*64427❤ CALL GIRLS IN durg ESCORTSDurg CALL GIRL ❤ 82729*64427❤ CALL GIRLS IN durg ESCORTS
Durg CALL GIRL ❤ 82729*64427❤ CALL GIRLS IN durg ESCORTSkajalroy875762
 
Uneak White's Personal Brand Exploration Presentation
Uneak White's Personal Brand Exploration PresentationUneak White's Personal Brand Exploration Presentation
Uneak White's Personal Brand Exploration Presentationuneakwhite
 
Cannabis Legalization World Map: 2024 Updated
Cannabis Legalization World Map: 2024 UpdatedCannabis Legalization World Map: 2024 Updated
Cannabis Legalization World Map: 2024 UpdatedCannaBusinessPlans
 
Kalyan Call Girl 98350*37198 Call Girls in Escort service book now
Kalyan Call Girl 98350*37198 Call Girls in Escort service book nowKalyan Call Girl 98350*37198 Call Girls in Escort service book now
Kalyan Call Girl 98350*37198 Call Girls in Escort service book nowranineha57744
 
Phases of Negotiation .pptx
 Phases of Negotiation .pptx Phases of Negotiation .pptx
Phases of Negotiation .pptxnandhinijagan9867
 
Unveiling Falcon Invoice Discounting: Leading the Way as India's Premier Bill...
Unveiling Falcon Invoice Discounting: Leading the Way as India's Premier Bill...Unveiling Falcon Invoice Discounting: Leading the Way as India's Premier Bill...
Unveiling Falcon Invoice Discounting: Leading the Way as India's Premier Bill...Falcon Invoice Discounting
 
Arti Languages Pre Seed Teaser Deck 2024.pdf
Arti Languages Pre Seed Teaser Deck 2024.pdfArti Languages Pre Seed Teaser Deck 2024.pdf
Arti Languages Pre Seed Teaser Deck 2024.pdfwill854175
 
New 2024 Cannabis Edibles Investor Pitch Deck Template
New 2024 Cannabis Edibles Investor Pitch Deck TemplateNew 2024 Cannabis Edibles Investor Pitch Deck Template
New 2024 Cannabis Edibles Investor Pitch Deck TemplateCannaBusinessPlans
 
The Abortion pills for sale in Qatar@Doha [+27737758557] []Deira Dubai Kuwait
The Abortion pills for sale in Qatar@Doha [+27737758557] []Deira Dubai KuwaitThe Abortion pills for sale in Qatar@Doha [+27737758557] []Deira Dubai Kuwait
The Abortion pills for sale in Qatar@Doha [+27737758557] []Deira Dubai Kuwaitdaisycvs
 
Berhampur CALL GIRL❤7091819311❤CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDING
Berhampur CALL GIRL❤7091819311❤CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDINGBerhampur CALL GIRL❤7091819311❤CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDING
Berhampur CALL GIRL❤7091819311❤CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDINGpr788182
 
Katrina Personal Brand Project and portfolio 1
Katrina Personal Brand Project and portfolio 1Katrina Personal Brand Project and portfolio 1
Katrina Personal Brand Project and portfolio 1kcpayne
 

Dernier (20)

Dr. Admir Softic_ presentation_Green Club_ENG.pdf
Dr. Admir Softic_ presentation_Green Club_ENG.pdfDr. Admir Softic_ presentation_Green Club_ENG.pdf
Dr. Admir Softic_ presentation_Green Club_ENG.pdf
 
Berhampur Call Girl Just Call 8084732287 Top Class Call Girl Service Available
Berhampur Call Girl Just Call 8084732287 Top Class Call Girl Service AvailableBerhampur Call Girl Just Call 8084732287 Top Class Call Girl Service Available
Berhampur Call Girl Just Call 8084732287 Top Class Call Girl Service Available
 
CROSS CULTURAL NEGOTIATION BY PANMISEM NS
CROSS CULTURAL NEGOTIATION BY PANMISEM NSCROSS CULTURAL NEGOTIATION BY PANMISEM NS
CROSS CULTURAL NEGOTIATION BY PANMISEM NS
 
joint cost.pptx COST ACCOUNTING Sixteenth Edition ...
joint cost.pptx  COST ACCOUNTING  Sixteenth Edition                          ...joint cost.pptx  COST ACCOUNTING  Sixteenth Edition                          ...
joint cost.pptx COST ACCOUNTING Sixteenth Edition ...
 
PHX May 2024 Corporate Presentation Final
PHX May 2024 Corporate Presentation FinalPHX May 2024 Corporate Presentation Final
PHX May 2024 Corporate Presentation Final
 
How to Get Started in Social Media for Art League City
How to Get Started in Social Media for Art League CityHow to Get Started in Social Media for Art League City
How to Get Started in Social Media for Art League City
 
SEO Case Study: How I Increased SEO Traffic & Ranking by 50-60% in 6 Months
SEO Case Study: How I Increased SEO Traffic & Ranking by 50-60%  in 6 MonthsSEO Case Study: How I Increased SEO Traffic & Ranking by 50-60%  in 6 Months
SEO Case Study: How I Increased SEO Traffic & Ranking by 50-60% in 6 Months
 
Lundin Gold - Q1 2024 Conference Call Presentation (Revised)
Lundin Gold - Q1 2024 Conference Call Presentation (Revised)Lundin Gold - Q1 2024 Conference Call Presentation (Revised)
Lundin Gold - Q1 2024 Conference Call Presentation (Revised)
 
Durg CALL GIRL ❤ 82729*64427❤ CALL GIRLS IN durg ESCORTS
Durg CALL GIRL ❤ 82729*64427❤ CALL GIRLS IN durg ESCORTSDurg CALL GIRL ❤ 82729*64427❤ CALL GIRLS IN durg ESCORTS
Durg CALL GIRL ❤ 82729*64427❤ CALL GIRLS IN durg ESCORTS
 
Uneak White's Personal Brand Exploration Presentation
Uneak White's Personal Brand Exploration PresentationUneak White's Personal Brand Exploration Presentation
Uneak White's Personal Brand Exploration Presentation
 
Cannabis Legalization World Map: 2024 Updated
Cannabis Legalization World Map: 2024 UpdatedCannabis Legalization World Map: 2024 Updated
Cannabis Legalization World Map: 2024 Updated
 
Kalyan Call Girl 98350*37198 Call Girls in Escort service book now
Kalyan Call Girl 98350*37198 Call Girls in Escort service book nowKalyan Call Girl 98350*37198 Call Girls in Escort service book now
Kalyan Call Girl 98350*37198 Call Girls in Escort service book now
 
Phases of Negotiation .pptx
 Phases of Negotiation .pptx Phases of Negotiation .pptx
Phases of Negotiation .pptx
 
Unveiling Falcon Invoice Discounting: Leading the Way as India's Premier Bill...
Unveiling Falcon Invoice Discounting: Leading the Way as India's Premier Bill...Unveiling Falcon Invoice Discounting: Leading the Way as India's Premier Bill...
Unveiling Falcon Invoice Discounting: Leading the Way as India's Premier Bill...
 
Arti Languages Pre Seed Teaser Deck 2024.pdf
Arti Languages Pre Seed Teaser Deck 2024.pdfArti Languages Pre Seed Teaser Deck 2024.pdf
Arti Languages Pre Seed Teaser Deck 2024.pdf
 
WheelTug Short Pitch Deck 2024 | Byond Insights
WheelTug Short Pitch Deck 2024 | Byond InsightsWheelTug Short Pitch Deck 2024 | Byond Insights
WheelTug Short Pitch Deck 2024 | Byond Insights
 
New 2024 Cannabis Edibles Investor Pitch Deck Template
New 2024 Cannabis Edibles Investor Pitch Deck TemplateNew 2024 Cannabis Edibles Investor Pitch Deck Template
New 2024 Cannabis Edibles Investor Pitch Deck Template
 
The Abortion pills for sale in Qatar@Doha [+27737758557] []Deira Dubai Kuwait
The Abortion pills for sale in Qatar@Doha [+27737758557] []Deira Dubai KuwaitThe Abortion pills for sale in Qatar@Doha [+27737758557] []Deira Dubai Kuwait
The Abortion pills for sale in Qatar@Doha [+27737758557] []Deira Dubai Kuwait
 
Berhampur CALL GIRL❤7091819311❤CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDING
Berhampur CALL GIRL❤7091819311❤CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDINGBerhampur CALL GIRL❤7091819311❤CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDING
Berhampur CALL GIRL❤7091819311❤CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDING
 
Katrina Personal Brand Project and portfolio 1
Katrina Personal Brand Project and portfolio 1Katrina Personal Brand Project and portfolio 1
Katrina Personal Brand Project and portfolio 1
 

Working Effectively With Legacy Code

  • 1. Working Effectively with Legacy Code Michael Feathers [email_address]
  • 2.
  • 3.
  • 5. PageGenerator::generate()‏ std::string PageGenerator::generate()‏ { std::vector<Result> results = database.queryResults(beginDate, endDate); std::string pageText; pageText += &quot;<html>&quot;; pageText += &quot;<head>&quot;; pageText += &quot;<title>&quot;; pageText += &quot;Quarterly Report&quot;; pageText += &quot;</title>&quot;; pageText += &quot;</head>&quot;; pageText += &quot;<body>&quot;; pageText += &quot;<h1>&quot;; pageText += &quot;Quarterly Report&quot;; pageText += &quot;</h1><table>&quot;; …
  • 6. Continued.. … if (results.size() != 0) { pageText += &quot;<table border=amp;quot;1amp;quot;>&quot;; for (std::vector<Result>::iterator it = results.begin(); it != results.end(); ++it) { pageText += &quot;<tr border=amp;quot;1amp;quot;>&quot;; pageText += &quot;<td>&quot; + it->department + &quot;</td>&quot;; pageText += &quot;<td>&quot; + it->manager + &quot;</td>&quot;; char buffer [128]; sprintf(buffer, &quot;<td>$%d</td>&quot;, it->netProfit / 100); pageText += std::string(buffer); sprintf(buffer, &quot;<td>$%d</td>&quot;, it->operatingExpense / 100); pageText += std::string(buffer); pageText += &quot;</tr>&quot;; } pageText += &quot;</table>&quot;; } else { …
  • 7. Continued.. … pageText += &quot;<p>No results for this period</p>&quot;; } pageText += &quot;</body>&quot;; pageText += &quot;</html>&quot;; return pageText; } // Argh!!
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16. (told you)‏ public class AccountDetailFrame extends Frame implements ActionListener, WindowListener { private TextField display = new TextField(10); … private AccountDetailFrame(…) { … } public void performAction(ActionEvent event) { String source = (String)event.getActionCommand(); if (source.equals(“project activity”)) { DetailFrame detailDisplay = new DetailFrame(); detailDisplay.setDescription( getDetailText() + “ “ + getProjectText()); detailDisplay.show(); String accountDescription = detailDisplay.getAccountSymbol(); accountDescription += “: “; … display.setText(accountDescription); … } }
  • 17. Separate a dependency public class AccountDetailFrame extends Frame implements ActionListener, WindowListener { private TextField display = new TextField(10); … private AccountDetailFrame(…) { … } public void performAction(ActionEvent event) { String source = (String)event.getActionCommand(); if (source.equals(“project activity”)) { DetailFrame detailDisplay = new DetailFrame(); detailDisplay.setDescription( getDetailText() + “ “ + getProjectText()); detailDisplay.show(); String accountDescription = detailDisplay.getAccountSymbol(); accountDescription += “: “; … display.setText(accountDescription); … } }
  • 18. After a method extraction.. public class AccountDetailFrame extends Frame implements ActionListener, WindowListener { … public void performAction(ActionEvent event) { performCommand((String)event.getActionCommand()); } void performCommand(String source); if (source.equals(“project activity”)) { DetailFrame detailDisplay = new DetailFrame(); detailDisplay.setDescription( getDetailText() + “ “ + getProjectText()); detailDisplay.show(); String accountDescription = detailDisplay.getAccountSymbol(); accountDescription += “: “; … display.setText(accountDescription); … } }
  • 19. More offensive dependencies.. public class AccountDetailFrame extends Frame implements ActionListener, WindowListener { … void performCommand(String source); if (source.equals(“project activity”)) { DetailFrame detailDisplay = new DetailFrame(); detailDisplay.setDescription( getDetailText() + “ “ + getProjectText()); detailDisplay.show(); String accountDescription = detailDisplay.getAccountSymbol(); accountDescription += “: “; … display.setText(accountDescription); … } }
  • 20. More refactoring.. public class AccountDetailFrame extends Frame implements ActionListener, WindowListener { private TextField display = new TextField(10); private DetailFrame detailDisplay; … void performCommand(String source); if (source.equals(“project activity”)) { setDescription(getDetailText() + “” + getProjectText()); … String accountDescripton = getAccountSymbol(); accountDescription += “: “; … setDisplayText(accountDescription); … } } …
  • 21. The aftermath.. We can subclass and override getAccountSymbol , setDisplayText , and setDescription to sense our work
  • 22. A Test.. public void testPerformCommand() { TestingAccountDetailFrame frame = new TestingAccountDetailFrame(); frame.accountSymbol = “SYM”; frame.performCommand(“project activity”); assertEquals(“06 080 012”, frame.getDisplayText()); }
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33. Breaking Dependencies 0 Extract Interface Extract Implementor
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41. Breaking Dependencies 1 Parameterize Method Extract and Override Call
  • 42.
  • 43.
  • 44.
  • 45.
  • 46. Breaking Dependencies 2 Link-Time Polymorphism
  • 47. Link-Time Polymorphism void account_deposit(int amount)‏ { struct Call *call = (struct Call *)‏ calloc(1, sizeof (struct Call)); call->type = ACC_DEPOSIT; call->arg0 = amount; append(g_calls, call); }
  • 48.
  • 49. Breaking Dependencies 3 Expose Static Method
  • 50.
  • 51.
  • 52.
  • 53.
  • 54. Breaking Dependencies 4 Introduce Instance Delegator
  • 55.
  • 56.
  • 57.
  • 58. Dependency Breaking 5 Template Redefinition
  • 59.
  • 60. Template Redefinition template<typename SOCKET> class AsyncReceptionPortImpl { private: SOCKET m_socket; Packet m_packet; int m_segmentSize; … public: AsyncReceptionPortImpl(); void Run(); }; typedef AsyncReceptionPortImpl<CSocket> AsyncReceptionPort;
  • 61.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68. WELC Understanding, Isolating, Testing, and Changing ..Untested Code www.objectmentor.com www.michaelfeathers.com

Notes de l'éditeur

  1. Notes 2/5/2004 Michael Feathers