Agile Software Development Lab Spring 2008 R O O T S
1
Sina Golesorkhi([email protected])Thomas Schmickler([email protected])
XP: Extreme ProgrammingIntroduction into Refactoring, Refactoring to Patterns and Code Quality
Refactoring
Agile Software Development Lab Spring 2008 R O O T S
2
Overview
Definition An Example in Eclipse Short Description Precondition of Refactoring Checklist Advantages of Refactoring Indicators for Refactoring are called „Bad Smells“
Agile Software Development Lab Spring 2008 R O O T S
3
DefintionWhat is Refactoring ?
Refactor (verb): to restructure software by applying a series of refactorings.
Goals:
• Better readability, comprehensibility• Better design• Better maintainability and reusability
Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing ist observable behavior.
Agile Software Development Lab Spring 2008 R O O T S
4
Example in Eclipse
You can download the code from http://www.schmickler.de/code.zip
Agile Software Development Lab Spring 2008 R O O T S
5
Short Description Better readability, comprehensibility
Sourcecode is for humans ! Bytecode for the machines.
Agile Software Development Lab Spring 2008 R O O T S
6
Short Description Better readability, comprehensibility
Sourcecode is for humans ! Bytecode for the machines.
Some developers are proud of their cryptic code.
Agile Software Development Lab Spring 2008 R O O T S
7
Short Description Better readability, comprehensibility
Sourcecode is for humans ! Bytecode for the machines.
Some developers are proud of their cryptic code.Some developers think they write the code only for themself.
Agile Software Development Lab Spring 2008 R O O T S
8
Short Description Better readability, comprehensibility
Sourcecode is for humans ! Bytecode for the machines.
Some developers are proud of their cryptic code.Some developers think they write the code only for themself.
To maintain,reuse or extend a programm the code must be understood before from the programmer.
Agile Software Development Lab Spring 2008 R O O T S
9
-
Short Description Better readability, comprehensibility
Sourcecode is for humans ! Bytecode for the machines.
Some developers are proud of their cryptic code.Some developers think they write the code only for themself.
To maintain,reuse or extend a programm the code must be understood before from the programmer.
We want to make good software not good documentationpapers.To understand what the code does it must be good comprehensible.Comprehesible code doesn't need to be documented comprehensive.
Agile Software Development Lab Spring 2008 R O O T S
10
Short Description Better design
Beginning with minimal or comprehensive Design
Agile Software Development Lab Spring 2008 R O O T S
11
Short Description Better design
Beginning with minimal or comprehensive Design
Minimal (like in XP):Design grows with the Code. To get a good design we need to refactor.
Agile Software Development Lab Spring 2008 R O O T S
12
Short Description Better design
Beginning with minimal or comprehensive Design
Minimal (like in XP):Design grows with the Code. To get a good design we need to refactor.
Given Design (Traditional SE):Good Design is given before coding begins. Nice. But with evolution the design changes. Maybe then it is not more good.
Agile Software Development Lab Spring 2008 R O O T S
13
Short Description Better design
Beginning with minimal or comprehensive Design
Minimal (like in XP):Design grows with the Code. To get a good design we need to refactor.
Given Design (Traditional SE):Good Design is given before coding begins. Nice. But with evolution the design changes. Maybe then it is not more good.
What to do to keep the good design ?
Agile Software Development Lab Spring 2008 R O O T S
14
Short Description Better design
Beginning with minimal or comprehensive Design
Minimal (like in XP):Design grows with the Code. To get a good design we need to refactor.
Given Design (Traditional SE):Good Design is given before coding begins. Nice. But with evolution the design changes. Maybe then it is not more good.
What to do to keep the good design ?
Refactor after or before all changes.Yippiyeah
Agile Software Development Lab Spring 2008 R O O T S
15
Short Description Better maintainability and reusability
Maintainability and Reusability:Changing any behaviour or adding new functionalities become much easier tasks if you understood the codefast and when the design is good.
Agile Software Development Lab Spring 2008 R O O T S
16
Short Description Better maintainability and reusability
Maintainability and Reusability:Changing any behaviour or adding new functionalities become much easier tasks if you understood the codefast and when the design is good.
When a feature has to be added to a program, if the code is not structured in a convenient way to add the feature, first refactor the program to make it easy to add the feature, then add the feature.
When a feature has to be added to a program, if the code is not structured in a convenient way to add the feature, first refactor the program to make it easy to add the feature, then add the feature.
Important:
Agile Software Development Lab Spring 2008 R O O T S
17
Precondition
Is there anything we have to do before and after a refactoring step ?
Question:
Agile Software Development Lab Spring 2008 R O O T S
18
Precondition
YES !
Agile Software Development Lab Spring 2008 R O O T S
19
Precondition
Regressiontests:
To be sure that you don't change the behavior of the code make tests after every refactoring.
Before starting refactoring, it is important to have a solid test suite, with self-checking test cases. In fact, after refactoring the program, it is convenient to perform regression testing automatically, relying on its output to gain some confidence that bugs have not been introduced.
Regressiontests:
To be sure that you don't change the behavior of the code make tests after every refactoring.
Before starting refactoring, it is important to have a solid test suite, with self-checking test cases. In fact, after refactoring the program, it is convenient to perform regression testing automatically, relying on its output to gain some confidence that bugs have not been introduced.
Agile Software Development Lab Spring 2008 R O O T S
20
Precondition
Should we make big or many refactorings in a single step ?
Question:
Agile Software Development Lab Spring 2008 R O O T S
21
Precondition
NO !
Agile Software Development Lab Spring 2008 R O O T S
22
Precondition
We should make little iterations.
1. Test2. little refactoring step3. Test4. Add a feature5. Test6. little refactoring step7. Test
and so on...
Agile Software Development Lab Spring 2008 R O O T S
23
Precondition
We should make little iterations.
1. Test2. little refactoring step3. Test4. Add a feature5. Test6. little refactoring step7. Test
and so on...
Why is this important ?
Agile Software Development Lab Spring 2008 R O O T S
24
Precondition
We should make little iterations.
1. Test2. little refactoring step3. Test4. Add a feature5. Test6. little refactoring step7. Test
and so on...
Thats important because if the test fails you don't have to search a long timethe bug.
Why is this important ?
Agile Software Development Lab Spring 2008 R O O T S
25
Simple Design! In priority order, the code must:
• Run all the tests • Contain no duplicate
code • Express all the ideas
the author wants to express
• Minimize classes and methods
(Kent Beck)
• Run all the tests • Follow the once and
only once rule• Has high cohesion
(clarity) • Has loose coupling
(Alan Shalloway)
Checklist
Agile Software Development Lab Spring 2008 R O O T S
26
Steps for improvement
Eliminating temporary variables
Splitting the invoice()-method
Moving subroutines to appropriate classes
Replacing the pricecode dependentswitch-statements with message Moving the method Apply the Strategy pattern
MoviegetPriceCode()setPriceCode()getTitle()
1
1*
*Customerinvoice()
RentalgetDaysRented()getMovie()getCharge()getFrequentRenterPoints()
Agile Software Development Lab Spring 2008 R O O T S
27
Moving the charge()-method from Rental to Movie: Prior
class Rental ... public double getcharge() {
double result = 0;switch (getMovie().getPriceCode()) {
case Movie.REGULAR: result += 2;if (getDaysRented() > 2)
result += (getDaysRented()-2)*1.5;break;
case Movie.NEW_RELEASE:result +=getDaysRented()*3;break;
case Movie.CHILDRENS:result += 1.5;if (getDaysRented() > 3)
result += (getDaysRented()-3)*1.5;break;
}}
class Rental ... public double getcharge() {
double result = 0;switch (getMovie().getPriceCode()) {
case Movie.REGULAR: result += 2;if (getDaysRented() > 2)
result += (getDaysRented()-2)*1.5;break;
case Movie.NEW_RELEASE:result +=getDaysRented()*3;break;
case Movie.CHILDRENS:result += 1.5;if (getDaysRented() > 3)
result += (getDaysRented()-3)*1.5;break;
}}
Movie
getPriceCode()setPriceCode()getTitle()getcharge()
1
1*
*Customer
invoice()
Rental
getDaysRented()getMovie()getCharge()getFrequentRenterPoints(
Agile Software Development Lab Spring 2008 R O O T S
28
Moving the charge()-method from Rental to Movie: Afterwards
class Movie ... public double getCharge(int daysRented) {
double result = 0;switch ( getPriceCode()) {
case Movie.REGULAR: result += 2;if ( daysRented > 2)
result += ( daysRented -2)*1.5;break;
case Movie.NEW_RELEASE:result += daysRented *3;break;
case Movie.CHILDRENS:result += 1.5;if ( daysRented > 3)
result += ( daysRented -3)*1.5;break;
}
}
class Movie ... public double getCharge(int daysRented) {
double result = 0;switch ( getPriceCode()) {
case Movie.REGULAR: result += 2;if ( daysRented > 2)
result += ( daysRented -2)*1.5;break;
case Movie.NEW_RELEASE:result += daysRented *3;break;
case Movie.CHILDRENS:result += 1.5;if ( daysRented > 3)
result += ( daysRented -3)*1.5;break;
}
}
class Rental ...public double getCharge() {
return _movie.charge(_daysRented);}
class Rental ...public double getCharge() {
return _movie.charge(_daysRented);}
MoviegetPriceCode()setPriceCode()getTitle()getCharge()
1
1*
*Customerinvoice()
RentalgetDaysRented()getMovie()getCharge()getFrequentRenterPoints(
Agile Software Development Lab Spring 2008 R O O T S
29
Moving bonusPoints()-method from Rental to Movie
class Movie ...public int getFrequentRenterPoints(int daysRented) {
if ( (this.getPriceCode()==NEW_RELEASE) && daysRented>1)return 2;
elsereturn 1;
}
class Movie ...public int getFrequentRenterPoints(int daysRented) {
if ( (this.getPriceCode()==NEW_RELEASE) && daysRented>1)return 2;
elsereturn 1;
}
class Rental ...public int getFrequentRenterPoints() {
return _movie.getFrequentRenterPoints(_daysRented); }
class Rental ...public int getFrequentRenterPoints() {
return _movie.getFrequentRenterPoints(_daysRented); }
class Rental ...public int getFrequentRenterPoints() {
if ((getMovie().getPriceCode()==Movie.NEW_RELEASE) && getDaysRented()>1)
return 2;else
return 1;}
class Rental ...public int getFrequentRenterPoints() {
if ((getMovie().getPriceCode()==Movie.NEW_RELEASE) && getDaysRented()>1)
return 2;else
return 1;}
MoviegetPriceCode()setPriceCode()getTitle()getCharge()getFrequentRenterPoints()
1
1*
*Customerinvoice()
RentalgetDaysRented()getMovie()getCharge()getFrequentRenterPoints()
Agile Software Development Lab Spring 2008 R O O T S
30
Polymorphism
Polymorphism(from the Greek, meaning “many forms”) is a feature that allows one interface to be used for a general class of actions
Agile Software Development Lab Spring 2008 R O O T S
31
ChildrensPrice NewReleasePrice RegularPrice
Polymorphism via Inheritance
Movie
priceCode:int
getPriceCode()setPriceCode()getCharge(days:int)getFrequentRenterPoints(days:int)
1
1Customer
totalCharge()totalBonusPoints()invoice()invoiceAsHtml()
*
*
Rental
daysRented:int
charge()bonusPoints ()
getCharge(days:int) getCharge(days:int) getFrequentRenterPoints(days:int)
getCharge(days:int)
Not applicable here: A movie would always have a fixed pricecategory
Agile Software Development Lab Spring 2008 R O O T S
32
Polymorphism via State Pattern
Movie
– priceCode:int
getPriceCode()setPriceCode()charge(days:int)bonusPoints(days:int)
ChildrensPrice
getPriceCode()getcharge(days:int)
NewReleasePrice
getPriceCode() getcharge(days:int)getFrequentRenterPoints(days:int)
RegularPrice
getPriceCode()getcharge(days:int)
Price
– priceCode:int
getPriceCode()
charge(days:int)getFr...Points(days:int)
1
*
1
1Customer
invoice()– totalCharge()– totalBonusPoints()invoiceAsHtml()
*
*
Rental
– daysRented:int
getDaysRented():intgetMovie():Moviecharge()bonusPoints ()
charge(days:int) { return price.charge(days)}
Agile Software Development Lab Spring 2008 R O O T S
33
Polymorphismus via State Pattern
Movie
– priceCode:int
getPriceCode()setPriceCode()getCharge(days:int)getFr..Points(days:int)
NewReleasePrice
getPriceCode()getCharge(days:int)getFr...Points(days:int)
RegularPrice
getPriceCode()getCharge(days:int)
Price
– priceCode:int
getPriceCode()
getCharge(days:int)getFr..(days:int)
1
*
Steps
1. Create classes Price, …, RegularPrice
2. Implement getPriceCode()-methods therein
3. Replace the pricecode with a Price objekt (in Movie) setPriceCode(int) getPriceCode Construktor
4. Move charge() und bonusPoints() from Movie to Price
5. Replace switch-statements with polymorphism Move each occurance of the charge()
method from Price to the charge()-method of a subclass
Analogous for bonusPoints()
Agile Software Development Lab Spring 2008 R O O T S
34
Steps 1-3: Replacement of pricecode with Price object
class Movie { ... private int _priceCode;
public Movie(String name, int priceCode) {_name = name;_priceCode = priceCode;
}public int getPriceCode() {
return _priceCode;}public void setPriceCode(int arg) {
_priceCode = arg; }}
class Movie { ... private int _priceCode;
public Movie(String name, int priceCode) {_name = name;_priceCode = priceCode;
}public int getPriceCode() {
return _priceCode;}public void setPriceCode(int arg) {
_priceCode = arg; }}
3
abstract class Price {public abstract int getPriceCode();
}
abstract class Price {public abstract int getPriceCode();
}class RegularPrice extends Price {
public int getPriceCode() { return Movie.REGULAR;}
}
class RegularPrice extends Price {public int getPriceCode() { return Movie.REGULAR;}
}class ChildrensPrice extends Price {
public int getPriceCode() { return Movie.CHILDRENS;}
}
class ChildrensPrice extends Price {public int getPriceCode() { return Movie.CHILDRENS;}
}class NewReleasePrice extends Price {
public int getPriceCode() { return Movie.NEW_RELEASE;}
}
class NewReleasePrice extends Price {public int getPriceCode() { return Movie.NEW_RELEASE;}
}
1+2
class Movie ...private Price _price;
public void setPriceCode(int arg) {switch (arg) {
case REGULAR:_price = new RegularPrice();break;
case CHILDRENS:_price = new ChildrensPrice();break;
case NEW_RELEASE:_price = new NewReleasePrice();break;
default:throw new
IllegalArgumentException( “Incorrect price code“);
}}
}
public Movie(String name, int priceCode) {_name = name;setPriceCode(priceCode);
}public int getPriceCode() {
return _price.getPriceCode();}
Agile Software Development Lab Spring 2008 R O O T S
35
class Price { ... public double getCharge(int daysRented) {
double result = 0; switch (getPriceCode()) {
case Movie.REGULAR:result += 2;if (daysRented() > 2)
result += (daysRented()-2)*1.5;break;
case Movie.CHILDRENS:result += 1.5;if (daysRented() > 3)
result += ( daysRented()-3)*1.5;break;
case Movie.NEW_RELEASE:result +=daysRented()*3;break;
} }
class Price { ... public double getCharge(int daysRented) {
double result = 0; switch (getPriceCode()) {
case Movie.REGULAR:result += 2;if (daysRented() > 2)
result += (daysRented()-2)*1.5;break;
case Movie.CHILDRENS:result += 1.5;if (daysRented() > 3)
result += ( daysRented()-3)*1.5;break;
case Movie.NEW_RELEASE:result +=daysRented()*3;break;
} }
Steps 4-5: Replace Switch with Polymorphism
abstract class Price ...abstract public double getCharge(int days);
abstract class Price ...abstract public double getCharge(int days);
class RegularPrice extends Price { ...public double getCharge(int daysRented)
{ double result =2;if (daysRented > 2)
result += (daysRented -2)*1.5;return result;
}
class RegularPrice extends Price { ...public double getCharge(int daysRented)
{ double result =2;if (daysRented > 2)
result += (daysRented -2)*1.5;return result;
}
class ChildrensPrice extends Price { ...public double getCharge (int
daysRented){double result = 1.5;if (daysRented > 3)
result += (daysRented -3) * 1.5;return result;
}
class ChildrensPrice extends Price { ...public double getCharge (int
daysRented){double result = 1.5;if (daysRented > 3)
result += (daysRented -3) * 1.5;return result;
}
class NewReleasePrice extends Price { ...public double getCharge (int daysRented)
{return daysRented * 3;
}
class NewReleasePrice extends Price { ...public double getCharge (int daysRented)
{return daysRented * 3;
}
class Movie { ... public double charge(int daysRented) { return _price.charge(daysRented); }
class Movie { ... public double charge(int daysRented) { return _price.charge(daysRented); }
4
5
Agile Software Development Lab Spring 2008 R O O T S
36
The same for getFrequentRenterPoints
class Rental...int getFrequentRentedPoints(int daysRented) {
if ((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1)return 2;
elsereturn 1;
}
class Rental...int getFrequentRentedPoints(int daysRented) {
if ((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1)return 2;
elsereturn 1;
}
class NewReleasePrice...int getFrequentRenteroints (int daysRented) {
return (daysRented > 1) ? 2: 1; }
class NewReleasePrice...int getFrequentRenteroints (int daysRented) {
return (daysRented > 1) ? 2: 1; }
class Rental...int getFrequentRentedPoints (int daysRented) {
return _movie.bonusPoints(daysRented); }
class Rental...int getFrequentRentedPoints (int daysRented) {
return _movie.bonusPoints(daysRented); }
class Movie...int getFrequentRenteroints(int daysRented) {
return _price.getFrequentPoints(daysRented); }
class Movie...int getFrequentRenteroints(int daysRented) {
return _price.getFrequentPoints(daysRented); }
class Price...int getFrequentRenteroints (int daysRented) {
return 1; }
class Price...int getFrequentRenteroints (int daysRented) {
return 1; }
Agile Software Development Lab Spring 2008 R O O T S
37
Extreme Code Quality
Agile Software Development Lab Spring 2008 R O O T S
38
Benefits of refactoring
1. Improved Design
2. Better understanding of the code
3. Better bug detection
4. Faster development!
Agile Software Development Lab Spring 2008 R O O T S
39
Simplicity is Code Quality
Everything we write must
Run all the tests Express every idea that we need to express Say everything once and only once Have the minimum number of classes and
methods consistent with the above
(Ron Jeffries et al.: Extreme Programming Installed)
Agile Software Development Lab Spring 2008 R O O T S
40
Bad Smells
In the community of computer programming, code smell is any symptom that indicates something may be wrong. It generally indicates that the code should be refactored or the overall design should be reexamined. The term appears to have been coined by Kent Beck on WardsWiki.
Different Kinds of Bad Smells Duplicated code Long Method Large Class Switch Statements Temporary Field ….
Bad Smells in Code by Kent Beck and Martin Fowler
Agile Software Development Lab Spring 2008 R O O T S
41
Refactoring-Catalog
Composition of Methodes Extract Method Inline Method Replace Temp with Query Inline Temp Split Temporary Variable Remove Assignments to Parameters Replace Method with Method Object ...
Agile Software Development Lab Spring 2008 R O O T S
42
Extract Method
void printOwing(double amount) {printBanner();
// print detailsSystem.out.println(“name“+_name);System.out.println(“amount“+ amount);
}
void printOwing (double amount) {printBanner();printDetails(amount);
}
void printDetails (double amount) {System.out.println (“name“+_name);System.out.println (“amount“+ amount);
}
How to indicate? Code-Blocks that are logically related to each other
How to handle? Replace with a well-named methode .
Agile Software Development Lab Spring 2008 R O O T S
43
Steps Defining new and well-named methodes
always „private“
Copy the Code
Searching for the local variables in extracted code Variables that will be used just in new methodes
local variables of new methodes
Variables which are changed in new methodes and will be used in old methodes
If only one: give it back as the result of new method more than one: Parts that can not be extracted!
(„Replace Temp with Query“ or try to „Split Temp Variable“)
Variables that will be read in new methodes Parameters of new methodes
Agile Software Development Lab Spring 2008 R O O T S
44
Steps(2)
Compiling
in original methode Replacing the extracted code by calling the new methode Deleting of the delclaration of local variables which have use anymore
Compiling Testing
Agile Software Development Lab Spring 2008 R O O T S
45
Example: no local variables
void printOwing(double amount) {
Enumeration e = :orders.elements();double outstanding = 0.0;
// print bannerSystem.out.println("**********************");System.out.println("*** Customer owes ****");System.out.println("**********************");
// calculate outstandingwhile (e.hasMoreElements()) {
Order each = (Order) e.nextElement();outstanding += each.getAmount();
// print detailsSystem.out.println(“name“+ _name);System.out.println(“amount“+ outstanding);
}
Extraction of code for print banner
Agile Software Development Lab Spring 2008 R O O T S
46
Example: no local variables
void printOwing(double amount) {
Enumeration e = :orders.elements();double outstanding = 0.0;
printBanner();
// calculate outstandingwhile (e.hasMoreElements()) {
Order each = (Order) e.nextElement();outstanding += each.getAmount();
// print detailsSystem.out.println(“name“+ _name);System.out.println(“amount“+ outstanding);
}
Extraction of code for print banner Local variable which is not altered („outstanding“)
private void printBanner() {System.out.println("**********************");System.out.println("*** Customer owes ****");System.out.println("**********************");
}
Agile Software Development Lab Spring 2008 R O O T S
47
Local variable which is not altered
void printOwing(double amount) {
Enumeration e = :orders.elements();double outstanding = 0.0;
printBanner();
// calculate outstandingwhile (e.hasMoreElements()) {
Order each = (Order) e.nextElement();outstanding += each.getAmount();
printDetails(outstanding);
}
Extraction of codes for calculation Local variable , which will be altered and finally used(„outstanding“) Local variable , which will be altered and will not be used anymore „e“
private void printDetails(double outstanding) {System.out.println(“name“+ _name);System.out.println(“amount“+ outstanding);
}
Agile Software Development Lab Spring 2008 R O O T S
48
Example:Local variable wchich will be altered
void printOwing(double amount) {
Enumeration e = :orders.elements();double outstanding = 0.0;
printBanner();
outstanding = getOutstanding();
printDetails(outstanding);
}
Extracting code for calculation If local variable is assigned before in original method
private double getOutstanding() {Enumeration e = orders.elements();double outstanding = 0.0;while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();outstanding += each.getAmount();
}return outstanding;
}
Agile Software Development Lab Spring 2008 R O O T S
49
Exapmle : local variable that was altered even before
void printOwing(double amount) {
double outstanding = amount *1.2;
printBanner();
outstanding = getOutstanding(outstanding);
printDetails(outstanding);
}
private double getOutstanding(double startValue) {Enumeration e = orders.elements();double result = startValue;while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();result += each.getAmount();
}return result;
}
Now are more Rafactorings possible twice „inline temp“ for assigning to local variable „outstanding“ In this way we can eliminate „outstanding“ from „printOwing“-Methode
Agile Software Development Lab Spring 2008 R O O T S
50
Example: Elimination of „outstanding“
void printOwing(double amount) {
double outstanding = amount *1.2;
printBanner();
outstanding = getOutstanding(outstanding);
printDetails(outstanding);
}
Agile Software Development Lab Spring 2008 R O O T S
51
Example : End state of printOwing()
void printOwing(double amount) {
printBanner();
printDetails(getOutstanding(amount *1.2));
}
Agile Software Development Lab Spring 2008 R O O T S
52
Overview Refactoring Tools
Commercial Together since Version 5.5
Only a few refactorings www.togethersoft.com
jFactor Plug-in for JBuilder and VisualAge
for Java Extensive functionality www.instantiations.com/jfactor/
IDEA www.intellij.com/idea/ IDE with builtin refactorings
JBuilder since version 6 Not tested yet
Retool New www.chive.com
Free Smalltalk Refactoring Browser
First tool at all Very powerfull http://chip.cs.uiuc.edu/users/brant/Refactory/
Xrefactory Plug-in for Emacs http://www.xref-tech.com/speller
JavaRefactor Plug-in for jEdit http://plugins.jedit.org/plugins/JavaRefactor
Eclipse IDE Preview, Veto and Undo of changes Extract Method, Rename Method, ... www.eclipse.org
Agile Software Development Lab Spring 2008 R O O T S
53
Refrences
Slides of SWT Lecture (Günter Kniesel) Slides of Exterme Programming for Nanjing Univesity(Günter Kniesel) Osborne - Java 2--Complete Reference (5th Ed 2002) Exapmles of Kent Beck and Martin Fowler From Berkley University
http://www.berkeley.edu/ http://sis36.berkeley.edu/projects/streek/agile/bad-smells-in-code.html