• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
It Was Like That When I Got Here: Steps Toward Modernizing a Legacy Codebase
 

It Was Like That When I Got Here: Steps Toward Modernizing a Legacy Codebase

on

  • 1,802 views

 

Statistics

Views

Total Views
1,802
Views on SlideShare
1,573
Embed Views
229

Actions

Likes
4
Downloads
7
Comments
0

29 Embeds 229

http://zootlinux.blogspot.com 137
http://zootlinux.blogspot.in 9
http://zootlinux.blogspot.com.br 9
http://zootlinux.blogspot.ca 8
http://zootlinux.blogspot.co.uk 7
http://zootlinux.blogspot.fr 6
http://zootlinux.blogspot.com.es 6
http://zootlinux.blogspot.nl 5
http://zootlinux.blogspot.de 4
http://zootlinux.blogspot.ru 4
http://zootlinux.blogspot.cz 4
http://zootlinux.blogspot.it 3
http://zootlinux.blogspot.fi 3
http://zootlinux.blogspot.com.au 3
http://zootlinux.blogspot.ie 3
http://zootlinux.blogspot.mx 2
http://zootlinux.blogspot.hk 2
http://librosweb.es 2
https://twitter.com 2
http://zootlinux.blogspot.co.at 1
http://zootlinux.blogspot.com.ar 1
http://zootlinux.blogspot.co.il 1
http://prlog.ru 1
http://zootlinux.blogspot.ro 1
http://zootlinux.blogspot.sk 1
http://zootlinux.blogspot.se 1
http://zootlinux.blogspot.gr 1
http://www.blogger.com 1
http://zootlinux.blogspot.ae 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    It Was Like That When I Got Here: Steps Toward Modernizing a Legacy Codebase It Was Like That When I Got Here: Steps Toward Modernizing a Legacy Codebase Presentation Transcript

    • It Was Like That When I Got Here: Steps Toward Modernizing A Legacy Codebase Sunshine PHP 08 Feb 2013 paul-m-jones.com @pmjones joind.in/8001Friday, February 8, 13
    • Read TheseFriday, February 8, 13
    • About Me • 8 years USAF Intelligence • PHP since 1999 • Developer, Senior Developer, Team Lead, Architect,VP Engineering • Aura project, benchmarking series, Zend_DB, Zend_View • PHP-FIG voting member, ZCE educational advisorFriday, February 8, 13
    • Overview • The (codebase) hole you’re in • How to start climbing out • Life is easier (but not perfect)Friday, February 8, 13
    • It Was Like That When I Got HereFriday, February 8, 13
    • Messy Codebase • Spaghetti include logic • Few or no classes • Global variables • No unit tests -- QA working overtimeFriday, February 8, 13
    • No Time To Remedy • Bugs to fix, right now • Features to implement, right now • Making your own life easier? Not a priority. • Dig in and try to make do • How did it get this bad? “It was like that when I got here.”Friday, February 8, 13
    • The Great Thing About PHP ... • ... is that anyone can use it. • Have an idea? Implement it! • It works! Great success! • ... it “works.”Friday, February 8, 13
    • The Awful Thing About PHP ... • ... is that anyone can use it. • The codebase is like a “dancing bear” • Architecture? Maintenance? Testing? • Move on to the next idea ... • ... but you are stuck with it now.Friday, February 8, 13
    • Project Evolution Tracks One-Off Heap Standalone App Library ? Modular Collection App Framework CMSFriday, February 8, 13
    • One-Off Heap • No discernible architecture • Browse directly to scripts • Add to it piece by piece • Little to no separation of concerns • Global variablesFriday, February 8, 13
    • Standalone Application • One-off heap ++ • Page scripts and common includes • Installed in web root • Responsible for global execution environment • Script variables still globalFriday, February 8, 13
    • Typical Page Script see editor for exampleFriday, February 8, 13
    • Why Is It Like This? • Original developer probably didn’t know better • Subsequent developers worked with what was there • “We can fix it later ...” • ... until later becomes now.Friday, February 8, 13
    • Technical Debt • A metaphor referring to the eventual consequences of poor or evolving software architecture and software development within a codebase. • As a change is started on a codebase, there is often the need to make other coordinated changes at the same time in other parts of the codebase. • http://en.wikipedia.org/wiki/Technical_debtFriday, February 8, 13
    • Paying Off Technical DebtFriday, February 8, 13
    • Paying Off Technical Debt • A lot like paying off financial debt • Got the stuff first, but have to pay for it eventually • No easy way out. Suffer as things are, or suffer through change.Friday, February 8, 13
    • Big-Bang Approach • Rewrite from scratch! (mmm, sexy) • “It’s the only way to be sure.” • Expend effort while not earning revenue • End up with different bad architectureFriday, February 8, 13
    • Incremental Approach • Small changes across entire codebase • Build on previous small changes • Keeps running the whole timeFriday, February 8, 13
    • Incremental Goals • Keep the application running • Consolidate classes for autoloading (PSR-0) • Convert globals to injected dependenciesFriday, February 8, 13
    • Consolidate Classes For AutoloadingFriday, February 8, 13
    • What Is Autoloading? // without autoloading, must include file first include_once "/path/to/classes/Example/Name.php"; $obj = new Example_Name(); // with autoloading, gets included automatically $obj = new Example_Name();Friday, February 8, 13
    • PSR-0 • Class name maps directly to file name • Namespace separators map to directory separators • Class underscores map to directory separators • VendorPackage_NameExample_Name => Vendor/Package_Name/Example/Name.phpFriday, February 8, 13
    • function autoload($class) { $class = ltrim($class, ); $file = ; $ns = ; $pos = strripos($class, ) if ($pos) { $ns = substr($class, 0, $pos); $class = substr($class, $pos + 1); $file = str_replace(, DIRECTORY_SEPARATOR, $ns) . DIRECTORY_SEPARATOR; } $file .= str_replace(_, DIRECTORY_SEPARATOR, $class); $base = "/path/to/classes"; require "{$base}/{$file}.php"; } spl_autoload_register(autoload);Friday, February 8, 13
    • Move Class Files • If you have class files in several paths, move to same base path • If you have more than one class per file, split into separate files • If you define classes as part of a script, extract to own file • Remove include/require as you go (grep) • If needed, change names as you go (grep)Friday, February 8, 13
    • Convert Function Files to Class Files • Many projects have files of function definitions • Wrap in a class as static or instance methods • Move to classes directory • Change calls to static or instance calls (grep) • Remove include/require as you go (grep)Friday, February 8, 13
    • Original Function function fetch_results() { global $db; $results = $db->fetch(whatever); return $results; } $results = fetch_results();Friday, February 8, 13
    • Static Method class Example { public static function fetchResults() { global $db; $results = $db->fetch(whatever); return $results; } } $results = Example::fetchResults();Friday, February 8, 13
    • Instance Method class Example { public function fetchResults() { global $db; $results = $db->fetch(whatever); return $results; } } $example = new Example; $results = $example->fetchResults();Friday, February 8, 13
    • Convert Globals to Injected DependenciesFriday, February 8, 13
    • Instantiating Dependencies In Methods class Example { public function fetchResults() { $db = new Database(username, password); return $db->fetch(whatever); } }Friday, February 8, 13
    • Drawbacks Of Method Instantiation • New connection on each call • Cannot reuse connection • Parameter modificationFriday, February 8, 13
    • Global Dependencies // setup file $db = new Database(username, password); // example class file class Example { public function fetchResults() { global $db; return $db->fetch(whatever); } }Friday, February 8, 13
    • Global Drawbacks class Evil { public function actionAtADistance() { global $db; unset($db); } }Friday, February 8, 13
    • Dependency Injection • Instead of reaching out from inside the class to bring in dependencies ... • ... inject the dependency into the class from the outside.Friday, February 8, 13
    • Starting Point: Global In Method class Example { public function fetchResults() { global $db; return $db->fetch(results); } }Friday, February 8, 13
    • Interim: Global In Constructor class Example { public function __construct() { global $db; $this->db = $db; } public function fetchResults() { return $this->db->fetch(results); } }Friday, February 8, 13
    • Final: Dependency Injection class Example { public function __construct($db) { $this->db = $db; } public function fetchResults() { return $this->db->fetch(results); } }Friday, February 8, 13
    • Change Instantiation Calls • Must change all new instantiations to pass dependencies (grep) • Class instantiation inside methods? Pass intermediary dependencies.Friday, February 8, 13
    • Intermediary Dependency class Example { public function fetchResults() { global $db; return $db->fetch(whatever); } } class Service { public function action() { $example = new Example; return $example->fetchResults(); } }Friday, February 8, 13
    • class Example { public function __construct($db) { $this->db = $db; } public function fetchResults() { return $this->db->fetch(whatever); } } class Service { public function __construct($db) { $this->db = $db; } public function action() { $example = new Example($this->db); return $example->fetchResults(); } }Friday, February 8, 13
    • Eliminate Intermediary Dependency class Service { public function __construct($example) { $this->example = $example; } public function action() { return $this->example->fetchResults(); } }Friday, February 8, 13
    • Progression of Instantiation // all globals $service = new Service; // intermediary: Example uses DI, // but Service creates Example internally $db = new Database(username, password); $service = new Service($db); // all DI all the time $db = new Database(username, password); $example = new Example($db); $service = new Service($example);Friday, February 8, 13
    • Life After ReorganizingFriday, February 8, 13
    • Initial Goals Completed ... • Consolidated into classes with PSR-0 and autoloading • Removed globals in favor of dependency injection • Kept it running the whole timeFriday, February 8, 13
    • ... But Much Remains • Things are still not perfect • Individual page scripts still in place • No tests yet? Jeff Carouth, “Introducing Tests in Legacy PHP Applications” • But do write tests, or else ...Friday, February 8, 13
    • WE ALL TEST DOWN (with apologies to Stephen King’s “It”)Friday, February 8, 13
    • It’s Better Than Before • ... easier to test the classes you have • Organizational structure for future work • Paid off a lot of technical debtFriday, February 8, 13
    • Thanks! paul-m-jones.com @pmjones joind.in/8001 auraphp.github.comFriday, February 8, 13