Definition of Legacy Code: Code without tests. Code youve “inherited” Code noone understands. Technical debt Aim to understand the concepts and motivations. Get it into version control. Identify the inflection point. Create integration acceptance tests. Set up your continuous integration environment
Trang 1Legacy Code
Trang 2@rowan_m
Trang 3Ibuildings Plusnet
Trang 4What is
“Legacy Code”?
Trang 5What is
“Legacy Code”?
Trang 6Who has never created Legacy Code?
Trang 7My own
story
little
Trang 9Starting a project
Trang 10Aim to understand
the concepts and motivations
Trang 11Try using the application
Trang 12Find and then read
any / all documentation
Trang 14Talk to the original developers
Trang 15Talk to the users
… especially the
“different” ones
Trang 16the code
Trang 17Catalogue the live platform
& environment
Trang 18Recreate it!
Trang 19Deploy the code
Trang 21Time to enter
The Code
Trang 22Reading Static analysis
Dynamic analysis
Time to enter
The Code
Trang 23ph pd
oc
phpdoc -ti 'Sweet Application' \ -pp -o HTML:Smarty:PHP \ -d Libraries \
-t Docs
http://www.phpdoc.org/
Title
Style Code in here
Docs out here!
Trang 24Beware of type-hiding!
Type-hinting
Type-hiding
/**
* @param array $opts Current options
* @return array Options with flag set
*/
function setFlag( array $ opts ) {
$ opts ['flag'] = true ;
return $ opts ;
}
/**
* @param int $fullPence Full price in pence
* @return float Discounted price in pence
*/
function applyDiscount( $ fullPence ) {
return ( $ fullPence * 0.8 ) ;
}
Trang 25do xy
ge n
http://www.stack.nl/~dimitri/doxygen/
doxygen -s -g ~/doxy.conf vim ~/doxy.conf
# edit at least this OUPUT_DIRECTORY
# play with the rest
cd ~/dev/project doxygen ~/doxy.conf Docs out here Code in here
Trang 27bo um
l http://bouml.free.fr/
Trang 28bo um
l http://bouml.free.fr/
Trang 29bo um
l http://bouml.free.fr/
Trang 30bo um
l http://bouml.free.fr/
Trang 31bo um
l http://bouml.free.fr/
Trang 32bo um
l http://bouml.free.fr/
Trang 33bo um
l
Trang 3417 | WARNING | Line exceeds 80 characters; contains 87 characters
32 | WARNING | Line exceeds 80 characters; contains 87 characters
36 | ERROR | Opening class brace must be on a line by itself
36 | ERROR | Closing brace must be on a line by itself
-http://matrix.squiz.net/developer/tools/php_cs
Trang 35Cont inuo
us Inte grat
ion
http://www.phpundercontrol.org/
http://hudson-ci.org/
Trang 36n time!
Trang 37t, te st
Trang 38Ignore it, code anyway
Trang 39Ignore it, code anyway
Please don't.
Trang 40Ignore it, code anyway
Please don't.
however
Trang 41Deadlines, clients,
money, etc.
Trang 42Deadlines, clients,
money, etc.
Secure a follow-up project
Make everyone
aware of the risks
Trang 43Why do you need the code?
Trang 44Why do you need the code?
Library dependency Adding new behaviour Changing behaviour
simple
complex
Trang 45Isolate legacy dependencies
Trang 46Isolate legacy dependencies
Create an anti-corruption layer
Trang 47Complete isolation
Create a legacy service
Trang 48Partial isolation
Wrapper classes
or methods
Trang 49function extract_brain( & $ person ) {
$ brain = $ person [' brain '];
unset( $ person [' brain ']);
return $ brain ; }
/**
* @param array $person
* @return bool living or not
*/
function create_life( $ person ) {
require_once( LIB_DIR ' /nuts_n_bolts.inc ');
:(
Wrapper class
Trang 50public function extractBrain(Person $ p ) {
// format to legacy style
$ pLgcy = $this -> toArray( $ p ) ;
// run legacy code
$ bLgy = extract_brain( $ pLgcy ) ;
// format to new style
$ p = $this -> toPerson( $ pLgcy ) ;
$ b = $this ->t oBrain( $ bLgcy ) ;
return array ( $ p , $ b ) ; }
public function createLife(Person $ p )
{
// validate
if ( $ person-> isAlive()) throw new LivingException() ;
// format to legacy style
$ pLgcy = $this -> toArray( $ p ) ;
// run legacy code
$ pLgy = create_life( $ pLgcy ) ;
// format to new style
return $this -> toPerson( $ pLgcy ) ; }
}
Some code you can use
:) Wrapper class
Trang 51Changing the code
Trang 52Changing the code
Take an incremental approach
Commit to 1 day
at a time
Trang 53Difficult to estimate Hidden dependencies Unknown behaviour
Trang 541 Get it into
version control
Trang 552 Identify the inflection point
Trang 563 Create integration
& acceptance tests
Trang 574 Set up your continuous integration
environment
Trang 585 Rewrite and refactor!
Trang 59of changes
Trang 60Mixed Procedural →
Trang 61includes HTML PHP
PHP
HTML HTML PHP
HTML HTML
HTML PHP
PHP PHP
HTML
PHP PHP HTML
HTML
Trang 62includes HTML PHP
PHP
HTML HTML PHP
HTML HTML
HTML PHP
PHP PHP
HTML echo
if if
HTML
PHP PHP HTML
Trang 63Procedural OO →
Trang 65static method static method static method
static method
static method includes
Trang 66static method static method static method
static method
static method
includes
method method method
method
constructor includes
Trang 67Sprout method / class
Trang 68public function createInvoice(Account $ acc , array $ charges )
The existing code
“We just need to be able to give
each client their own personal
discount on certain charges.”
Trang 69public function createInvoice(Account $ acc , array $ charges )
$ accDisc = new AccountDiscounter( $ acc ) ;
$ discountedCharge = $ accDisc-> calculate( $ chg ) ;
return $ discountedCharge ;
}
The new code
Trang 70public function createInvoice(Account $ acc , array $ charges )
{
$ invoice = new Invoice() ;
foreach ( $ charges as $ chg ) {
// Sprout new behaviour!
$ chg = $ this-> calcDiscount( $ acc , $ chg ) ;
$ invoice-> addLine( $ chg-> getDesc() , $ chg-> getAmount()) ; }
return $ invoice ;
}
private function calcDiscount(Account $ acc , Charge $ chg )
{
$ accDisc = new AccountDiscounter( $ acc ) ;
$ discountedCharge = $ accDisc-> calculate( $ chg ) ;
return $ discountedCharge ;
}
Call it
Trang 71Untestable OO testable OO →
Trang 72Dependency Inversion / Extraction
Trang 73The Problem
public function calcDiscount(Account $ acc , Charge $ chg )
{
$ accDisc = new AccountDiscounter( $ acc ) ;
$ discountedCharge = $ accDisc-> calculate( $ chg ) ;
return $ discountedCharge ;
Trang 74The Problem
public function calcDiscount(Account $ acc , Charge $ chg )
{
$ accDisc = new AccountDiscounter( $ acc ) ;
$ discountedCharge = $ accDisc-> calculate( $ chg ) ;
// contact the database
// call a web service
}
}
Trang 75Quick Solution
public function calcDiscount(Account $ acc , Charge $ chg )
{
$ accDisc = $ this-> getAccountDiscounter( $ acc ) ;
$ discountedCharge = $ accDisc-> calculate( $ chg ) ;
Trang 76Dependency Injection Solution
public function calcDiscount(Account $ acc , Charge $ chg )
{
$ accDisc = $ this-> discounter ;
$ discountedCharge = $ accDisc-> calculate( $ chg ) ;
Trang 77(v2) Dependency Injection Solution →
public function calcDiscount(Account $ acc , Charge $ chg )
{
$ accDisc = $ this-> discounter ;
$ discountedCharge = $ accDisc-> calculate( $ chg ) ;
Trang 79Any questions?
Feedback to: http://joind.in/1242
@rowan_m