SlideShare ist ein Scribd-Unternehmen logo
1 von 35
It Was Like That When I Got Here:
Steps Toward Modernizing A Legacy Codebase
PHP Experience 2015
@pmjones
mlaphp.com
slideshare.net/pmjones88
Messy Codebase
• No router or front controller
• Page scripts in document root

(page-based)
• Spaghetti include logic

(include-oriented)
• Global variables
• No unit tests (never sure if a bug
is really fixed)
No Time To Make Things Better
• Bugs to fix, right now
• Features to implement, right now
• Making your own life easier?

Not a priority.
• How did it get this bad?

“It was like that when I got here.”
Typical Page Script
see editor for example
The Great Thing About PHP ...
• ... is that anyone can use it.
• Have an idea? Implement it!
• It works! Great success!
• ... it “works.”
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.
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_debt
Paying Off Technical Debt
• A lot like paying off financial debt
• Get the stuff first, but have to pay for it eventually
• Must pay off technical debt not of our own choosing
• Suffer as things are, or suffer through change
Declare Bankruptcy
• Rewrite from scratch — sexy!
• Not making money.
• Estimates are too optimistic.
• End up with 2 bad architectures.
Incremental Approach
• Pay off smallest debt first
• See immediate improvement —
happiness!
• Sequential small changes

across codebase
• Improve quality over time
• “Refactoring” — sounds like
work, but it actually works.
Refactoring Process
• Keep the application running
• Consolidate classes for autoloading (PSR-0)
• Convert globals to injected dependencies
• Each change: test, commit, push, QA
Consolidate Classes For 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();

What Is Autoloading?
PSR-0
• Also known as the “PEAR class-to-file standard”
• 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.php
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');

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
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)
Original Function
function fetch_results()

{

global $db;

$results = $db->fetch('whatever');

return $results;

}



$results = fetch_results();

Static Method
class Example

{

public static function fetch_results()

{

global $db;

$results = $db->fetch('whatever');

return $results;

}

}



$results = Example::fetch_results();

Instance Method
class Example

{

public function fetchResults()

{

global $db;

$results = $db->fetch('whatever');

return $results;

}

}



$example = new Example;

$results = $example->fetchResults();

Convert Globals to Injected Dependencies
Instantiating Dependencies In Methods
class Example

{

public function fetchResults()

{

$db = new Database('username', 'password');

return $db->fetch('whatever');

}

}

Drawbacks Of Method Instantiation
• New connection on each call
• Cannot reuse connection
• Parameter modification
Global Dependencies
// setup file

$db = new Database('username', 'password');



// example class file

class Example

{

public function fetchResults()

{

global $db;

return $db->fetch('whatever');

}

}

Global Drawbacks
class Evil

{

public function actionAtADistance()

{

global $db;

unset($db);

}

}

Dependency Injection
• Instead of reaching out from inside the
class to bring in dependencies ...
• ... inject the dependency into the class
from the outside.
• Not “containers” just “technique”
Starting Point: Global In Method
class Example

{

public function fetchResults()

{

global $db;

return $db->fetch('results');

}

}

Step 1: Global In Constructor
class Example

{

public function __construct()

{

global $db;

$this->db = $db;

}



public function fetchResults()

{

return $this->db->fetch('results');

}

}

Step 2: Dependency Injection
class Example

{

public function __construct($db)

{

$this->db = $db;

}



public function fetchResults()

{

return $this->db->fetch('results');

}

}

• Change new instantiations to pass parameters
• Reveals hidden dependencies
Step 3: Change Instantiation Calls
// globals

$example = new Example();



// dependency injection ($db can be from setup)

$db = new Database('username', 'password');

$example = new Example($db);
Life After Refactoring
Initial Goals Completed ...
• Consolidated into classes with PSR-0 and autoloading
• Removed globals in favor of dependency injection
• Kept it running the whole time
• Paid off some technical debt, feeling good about work
• Organizational structure for future work
• Start writing unit tests
... But Much Remains
• Using new keyword
• Embedded SQL statements
• Embedded domain logic
• Embedded presentation logic
• Embedded action logic
• Embedded include calls
• Router + front controller
• DI container
mlaphp.com
Autoloaded,
Dependency Injected,
UnitTested,
Layer Separated,
Front Controlled
Coupon for 25% Off:
leanpub.com/mlaphp/c/
phpexperience2015
Thanks!

Weitere ähnliche Inhalte

Was ist angesagt?

Php unit for drupal 8
Php unit for drupal 8Php unit for drupal 8
Php unit for drupal 8valuebound
 
SenchaCon 2016: The Modern Toolchain - Ross Gerbasi
SenchaCon 2016: The Modern Toolchain - Ross Gerbasi   SenchaCon 2016: The Modern Toolchain - Ross Gerbasi
SenchaCon 2016: The Modern Toolchain - Ross Gerbasi Sencha
 
Ruby onrails cucumber-rspec-capybara
Ruby onrails cucumber-rspec-capybaraRuby onrails cucumber-rspec-capybara
Ruby onrails cucumber-rspec-capybaraBindesh Vijayan
 
OpenERP and Perl
OpenERP and PerlOpenERP and Perl
OpenERP and PerlOpusVL
 
Ran Mizrahi - Symfony2 meets Drupal8
Ran Mizrahi - Symfony2 meets Drupal8Ran Mizrahi - Symfony2 meets Drupal8
Ran Mizrahi - Symfony2 meets Drupal8Ran Mizrahi
 
Parsing and Rewriting Ruby Templates
Parsing and Rewriting Ruby TemplatesParsing and Rewriting Ruby Templates
Parsing and Rewriting Ruby TemplatesJohn Hawthorn
 
"Real-time Collaborative Text Editing on Grammarly’s Front-End Team" Oleksii...
 "Real-time Collaborative Text Editing on Grammarly’s Front-End Team" Oleksii... "Real-time Collaborative Text Editing on Grammarly’s Front-End Team" Oleksii...
"Real-time Collaborative Text Editing on Grammarly’s Front-End Team" Oleksii...Fwdays
 
Saving Time with WP-CLI
Saving Time with WP-CLISaving Time with WP-CLI
Saving Time with WP-CLITaylor Lovett
 
Das Frontend richtig Testen – mit Jest @Developer Week 2018
Das Frontend richtig Testen – mit Jest @Developer Week 2018Das Frontend richtig Testen – mit Jest @Developer Week 2018
Das Frontend richtig Testen – mit Jest @Developer Week 2018Holger Grosse-Plankermann
 
Java EE 7 Batch processing in the Real World
Java EE 7 Batch processing in the Real WorldJava EE 7 Batch processing in the Real World
Java EE 7 Batch processing in the Real WorldRoberto Cortez
 
2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD WorkshopWolfram Arnold
 
Concurrency in Scala - the Akka way
Concurrency in Scala - the Akka wayConcurrency in Scala - the Akka way
Concurrency in Scala - the Akka wayYardena Meymann
 
Lessons Learnt in 2009
Lessons Learnt in 2009Lessons Learnt in 2009
Lessons Learnt in 2009pratiknaik
 
Integrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationIntegrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationAndrew Rota
 
Life Beyond Rails: Creating Cross Platform Ruby Apps
Life Beyond Rails: Creating Cross Platform Ruby AppsLife Beyond Rails: Creating Cross Platform Ruby Apps
Life Beyond Rails: Creating Cross Platform Ruby AppsTristan Gomez
 
Writing Software not Code with Cucumber
Writing Software not Code with CucumberWriting Software not Code with Cucumber
Writing Software not Code with CucumberBen Mabey
 
Refactoring @ Mindvalley: Smells, Techniques and Patterns
Refactoring @ Mindvalley: Smells, Techniques and PatternsRefactoring @ Mindvalley: Smells, Techniques and Patterns
Refactoring @ Mindvalley: Smells, Techniques and PatternsTristan Gomez
 
Javascript Test Automation Workshop (21.08.2014)
Javascript Test Automation Workshop (21.08.2014)Javascript Test Automation Workshop (21.08.2014)
Javascript Test Automation Workshop (21.08.2014)Deutsche Post
 
DSLs Internas e Ruby
DSLs Internas e RubyDSLs Internas e Ruby
DSLs Internas e RubyFabio Kung
 
Getting Started with Apache Camel at DevNation 2014
Getting Started with Apache Camel at DevNation 2014Getting Started with Apache Camel at DevNation 2014
Getting Started with Apache Camel at DevNation 2014Claus Ibsen
 

Was ist angesagt? (20)

Php unit for drupal 8
Php unit for drupal 8Php unit for drupal 8
Php unit for drupal 8
 
SenchaCon 2016: The Modern Toolchain - Ross Gerbasi
SenchaCon 2016: The Modern Toolchain - Ross Gerbasi   SenchaCon 2016: The Modern Toolchain - Ross Gerbasi
SenchaCon 2016: The Modern Toolchain - Ross Gerbasi
 
Ruby onrails cucumber-rspec-capybara
Ruby onrails cucumber-rspec-capybaraRuby onrails cucumber-rspec-capybara
Ruby onrails cucumber-rspec-capybara
 
OpenERP and Perl
OpenERP and PerlOpenERP and Perl
OpenERP and Perl
 
Ran Mizrahi - Symfony2 meets Drupal8
Ran Mizrahi - Symfony2 meets Drupal8Ran Mizrahi - Symfony2 meets Drupal8
Ran Mizrahi - Symfony2 meets Drupal8
 
Parsing and Rewriting Ruby Templates
Parsing and Rewriting Ruby TemplatesParsing and Rewriting Ruby Templates
Parsing and Rewriting Ruby Templates
 
"Real-time Collaborative Text Editing on Grammarly’s Front-End Team" Oleksii...
 "Real-time Collaborative Text Editing on Grammarly’s Front-End Team" Oleksii... "Real-time Collaborative Text Editing on Grammarly’s Front-End Team" Oleksii...
"Real-time Collaborative Text Editing on Grammarly’s Front-End Team" Oleksii...
 
Saving Time with WP-CLI
Saving Time with WP-CLISaving Time with WP-CLI
Saving Time with WP-CLI
 
Das Frontend richtig Testen – mit Jest @Developer Week 2018
Das Frontend richtig Testen – mit Jest @Developer Week 2018Das Frontend richtig Testen – mit Jest @Developer Week 2018
Das Frontend richtig Testen – mit Jest @Developer Week 2018
 
Java EE 7 Batch processing in the Real World
Java EE 7 Batch processing in the Real WorldJava EE 7 Batch processing in the Real World
Java EE 7 Batch processing in the Real World
 
2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop
 
Concurrency in Scala - the Akka way
Concurrency in Scala - the Akka wayConcurrency in Scala - the Akka way
Concurrency in Scala - the Akka way
 
Lessons Learnt in 2009
Lessons Learnt in 2009Lessons Learnt in 2009
Lessons Learnt in 2009
 
Integrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationIntegrating React.js Into a PHP Application
Integrating React.js Into a PHP Application
 
Life Beyond Rails: Creating Cross Platform Ruby Apps
Life Beyond Rails: Creating Cross Platform Ruby AppsLife Beyond Rails: Creating Cross Platform Ruby Apps
Life Beyond Rails: Creating Cross Platform Ruby Apps
 
Writing Software not Code with Cucumber
Writing Software not Code with CucumberWriting Software not Code with Cucumber
Writing Software not Code with Cucumber
 
Refactoring @ Mindvalley: Smells, Techniques and Patterns
Refactoring @ Mindvalley: Smells, Techniques and PatternsRefactoring @ Mindvalley: Smells, Techniques and Patterns
Refactoring @ Mindvalley: Smells, Techniques and Patterns
 
Javascript Test Automation Workshop (21.08.2014)
Javascript Test Automation Workshop (21.08.2014)Javascript Test Automation Workshop (21.08.2014)
Javascript Test Automation Workshop (21.08.2014)
 
DSLs Internas e Ruby
DSLs Internas e RubyDSLs Internas e Ruby
DSLs Internas e Ruby
 
Getting Started with Apache Camel at DevNation 2014
Getting Started with Apache Camel at DevNation 2014Getting Started with Apache Camel at DevNation 2014
Getting Started with Apache Camel at DevNation 2014
 

Ähnlich wie Modernizing Legacy Applications in PHP, por Paul Jones

Refactoring Workshop (Rails Pacific 2014)
Refactoring Workshop (Rails Pacific 2014)Refactoring Workshop (Rails Pacific 2014)
Refactoring Workshop (Rails Pacific 2014)Bruce Li
 
Leveling Up With Unit Testing - LonghornPHP 2022
Leveling Up With Unit Testing - LonghornPHP 2022Leveling Up With Unit Testing - LonghornPHP 2022
Leveling Up With Unit Testing - LonghornPHP 2022Mark Niebergall
 
Staging Drupal 8 31 09 1 3
Staging Drupal 8 31 09 1 3Staging Drupal 8 31 09 1 3
Staging Drupal 8 31 09 1 3Drupalcon Paris
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3Nate Abele
 
Yapc10 Cdt World Domination
Yapc10   Cdt World DominationYapc10   Cdt World Domination
Yapc10 Cdt World DominationcPanel
 
PHP from soup to nuts Course Deck
PHP from soup to nuts Course DeckPHP from soup to nuts Course Deck
PHP from soup to nuts Course DeckrICh morrow
 
Supercharging WordPress Development - Wordcamp Brighton 2019
Supercharging WordPress Development - Wordcamp Brighton 2019Supercharging WordPress Development - Wordcamp Brighton 2019
Supercharging WordPress Development - Wordcamp Brighton 2019Adam Tomat
 
Automated php unit testing in drupal 8
Automated php unit testing in drupal 8Automated php unit testing in drupal 8
Automated php unit testing in drupal 8Jay Friendly
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO DevsWO Community
 
The Solar Framework for PHP 5 (2010 Confoo)
The Solar Framework for PHP 5 (2010 Confoo)The Solar Framework for PHP 5 (2010 Confoo)
The Solar Framework for PHP 5 (2010 Confoo)Paul Jones
 
Working Effectively With Legacy Perl Code
Working Effectively With Legacy Perl CodeWorking Effectively With Legacy Perl Code
Working Effectively With Legacy Perl Codeerikmsp
 
Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021Scott Keck-Warren
 
Developer testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing FanaticDeveloper testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing FanaticLB Denker
 
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Campmodern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet CampPuppet
 
My first powershell script
My first powershell scriptMy first powershell script
My first powershell scriptDavid Cobb
 

Ähnlich wie Modernizing Legacy Applications in PHP, por Paul Jones (20)

JS Essence
JS EssenceJS Essence
JS Essence
 
Modern php
Modern phpModern php
Modern php
 
CakePHP
CakePHPCakePHP
CakePHP
 
Refactoring Workshop (Rails Pacific 2014)
Refactoring Workshop (Rails Pacific 2014)Refactoring Workshop (Rails Pacific 2014)
Refactoring Workshop (Rails Pacific 2014)
 
Leveling Up With Unit Testing - LonghornPHP 2022
Leveling Up With Unit Testing - LonghornPHP 2022Leveling Up With Unit Testing - LonghornPHP 2022
Leveling Up With Unit Testing - LonghornPHP 2022
 
Staging Drupal 8 31 09 1 3
Staging Drupal 8 31 09 1 3Staging Drupal 8 31 09 1 3
Staging Drupal 8 31 09 1 3
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Yapc10 Cdt World Domination
Yapc10   Cdt World DominationYapc10   Cdt World Domination
Yapc10 Cdt World Domination
 
PHP from soup to nuts Course Deck
PHP from soup to nuts Course DeckPHP from soup to nuts Course Deck
PHP from soup to nuts Course Deck
 
Supercharging WordPress Development - Wordcamp Brighton 2019
Supercharging WordPress Development - Wordcamp Brighton 2019Supercharging WordPress Development - Wordcamp Brighton 2019
Supercharging WordPress Development - Wordcamp Brighton 2019
 
Automated php unit testing in drupal 8
Automated php unit testing in drupal 8Automated php unit testing in drupal 8
Automated php unit testing in drupal 8
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO Devs
 
The Solar Framework for PHP 5 (2010 Confoo)
The Solar Framework for PHP 5 (2010 Confoo)The Solar Framework for PHP 5 (2010 Confoo)
The Solar Framework for PHP 5 (2010 Confoo)
 
Configuration management with Chef
Configuration management with ChefConfiguration management with Chef
Configuration management with Chef
 
Working Effectively With Legacy Perl Code
Working Effectively With Legacy Perl CodeWorking Effectively With Legacy Perl Code
Working Effectively With Legacy Perl Code
 
Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021
 
Developer testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing FanaticDeveloper testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing Fanatic
 
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Campmodern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
 
My first powershell script
My first powershell scriptMy first powershell script
My first powershell script
 

Mehr von iMasters

O que você precisa saber para modelar bancos de dados NoSQL - Dani Monteiro
O que você precisa saber para modelar bancos de dados NoSQL - Dani MonteiroO que você precisa saber para modelar bancos de dados NoSQL - Dani Monteiro
O que você precisa saber para modelar bancos de dados NoSQL - Dani MonteiroiMasters
 
Postgres: wanted, beloved or dreaded? - Fabio Telles
Postgres: wanted, beloved or dreaded? - Fabio TellesPostgres: wanted, beloved or dreaded? - Fabio Telles
Postgres: wanted, beloved or dreaded? - Fabio TellesiMasters
 
Por que minha query esta lenta? - Suellen Moraes
Por que minha query esta lenta? - Suellen MoraesPor que minha query esta lenta? - Suellen Moraes
Por que minha query esta lenta? - Suellen MoraesiMasters
 
Relato das trincheiras: o dia a dia de uma consultoria de banco de dados - Ig...
Relato das trincheiras: o dia a dia de uma consultoria de banco de dados - Ig...Relato das trincheiras: o dia a dia de uma consultoria de banco de dados - Ig...
Relato das trincheiras: o dia a dia de uma consultoria de banco de dados - Ig...iMasters
 
ORMs heróis ou vilões dentro da arquitetura de dados? - Otávio gonçalves
ORMs heróis ou vilões dentro da arquitetura de dados? - Otávio gonçalvesORMs heróis ou vilões dentro da arquitetura de dados? - Otávio gonçalves
ORMs heróis ou vilões dentro da arquitetura de dados? - Otávio gonçalvesiMasters
 
SQL e NoSQL trabalhando juntos: uma comparação para obter o melhor de ambos -...
SQL e NoSQL trabalhando juntos: uma comparação para obter o melhor de ambos -...SQL e NoSQL trabalhando juntos: uma comparação para obter o melhor de ambos -...
SQL e NoSQL trabalhando juntos: uma comparação para obter o melhor de ambos -...iMasters
 
Arquitetando seus dados na prática para a LGPD - Alessandra Martins
Arquitetando seus dados na prática para a LGPD - Alessandra MartinsArquitetando seus dados na prática para a LGPD - Alessandra Martins
Arquitetando seus dados na prática para a LGPD - Alessandra MartinsiMasters
 
O papel do DBA no mundo de ciência de dados e machine learning - Mauro Pichil...
O papel do DBA no mundo de ciência de dados e machine learning - Mauro Pichil...O papel do DBA no mundo de ciência de dados e machine learning - Mauro Pichil...
O papel do DBA no mundo de ciência de dados e machine learning - Mauro Pichil...iMasters
 
Desenvolvimento Mobile Híbrido, Nativo ou Web: Quando usá-los - Juliana Chahoud
Desenvolvimento Mobile Híbrido, Nativo ou Web: Quando usá-los - Juliana ChahoudDesenvolvimento Mobile Híbrido, Nativo ou Web: Quando usá-los - Juliana Chahoud
Desenvolvimento Mobile Híbrido, Nativo ou Web: Quando usá-los - Juliana ChahoudiMasters
 
Use MDD e faça as máquinas trabalharem para você - Andreza Leite
 Use MDD e faça as máquinas trabalharem para você - Andreza Leite Use MDD e faça as máquinas trabalharem para você - Andreza Leite
Use MDD e faça as máquinas trabalharem para você - Andreza LeiteiMasters
 
Entendendo os porquês do seu servidor - Talita Bernardes
Entendendo os porquês do seu servidor - Talita BernardesEntendendo os porquês do seu servidor - Talita Bernardes
Entendendo os porquês do seu servidor - Talita BernardesiMasters
 
Backend performático além do "coloca mais máquina lá" - Diana Arnos
Backend performático além do "coloca mais máquina lá" - Diana ArnosBackend performático além do "coloca mais máquina lá" - Diana Arnos
Backend performático além do "coloca mais máquina lá" - Diana ArnosiMasters
 
Dicas para uma maior performance em APIs REST - Renato Groffe
Dicas para uma maior performance em APIs REST - Renato GroffeDicas para uma maior performance em APIs REST - Renato Groffe
Dicas para uma maior performance em APIs REST - Renato GroffeiMasters
 
7 dicas de desempenho que equivalem por 21 - Danielle Monteiro
7 dicas de desempenho que equivalem por 21 - Danielle Monteiro7 dicas de desempenho que equivalem por 21 - Danielle Monteiro
7 dicas de desempenho que equivalem por 21 - Danielle MonteiroiMasters
 
Quem se importa com acessibilidade Web? - Mauricio Maujor
Quem se importa com acessibilidade Web? - Mauricio MaujorQuem se importa com acessibilidade Web? - Mauricio Maujor
Quem se importa com acessibilidade Web? - Mauricio MaujoriMasters
 
Service Mesh com Istio e Kubernetes - Wellington Figueira da Silva
Service Mesh com Istio e Kubernetes - Wellington Figueira da SilvaService Mesh com Istio e Kubernetes - Wellington Figueira da Silva
Service Mesh com Istio e Kubernetes - Wellington Figueira da SilvaiMasters
 
Erros: Como eles vivem, se alimentam e se reproduzem? - Augusto Pascutti
Erros: Como eles vivem, se alimentam e se reproduzem? - Augusto PascuttiErros: Como eles vivem, se alimentam e se reproduzem? - Augusto Pascutti
Erros: Como eles vivem, se alimentam e se reproduzem? - Augusto PascuttiiMasters
 
Elasticidade e engenharia de banco de dados para alta performance - Rubens G...
Elasticidade e engenharia de banco de dados para alta performance  - Rubens G...Elasticidade e engenharia de banco de dados para alta performance  - Rubens G...
Elasticidade e engenharia de banco de dados para alta performance - Rubens G...iMasters
 
Construindo aplicações mais confiantes - Carolina Karklis
Construindo aplicações mais confiantes - Carolina KarklisConstruindo aplicações mais confiantes - Carolina Karklis
Construindo aplicações mais confiantes - Carolina KarklisiMasters
 
Monitoramento de Aplicações - Felipe Regalgo
Monitoramento de Aplicações - Felipe RegalgoMonitoramento de Aplicações - Felipe Regalgo
Monitoramento de Aplicações - Felipe RegalgoiMasters
 

Mehr von iMasters (20)

O que você precisa saber para modelar bancos de dados NoSQL - Dani Monteiro
O que você precisa saber para modelar bancos de dados NoSQL - Dani MonteiroO que você precisa saber para modelar bancos de dados NoSQL - Dani Monteiro
O que você precisa saber para modelar bancos de dados NoSQL - Dani Monteiro
 
Postgres: wanted, beloved or dreaded? - Fabio Telles
Postgres: wanted, beloved or dreaded? - Fabio TellesPostgres: wanted, beloved or dreaded? - Fabio Telles
Postgres: wanted, beloved or dreaded? - Fabio Telles
 
Por que minha query esta lenta? - Suellen Moraes
Por que minha query esta lenta? - Suellen MoraesPor que minha query esta lenta? - Suellen Moraes
Por que minha query esta lenta? - Suellen Moraes
 
Relato das trincheiras: o dia a dia de uma consultoria de banco de dados - Ig...
Relato das trincheiras: o dia a dia de uma consultoria de banco de dados - Ig...Relato das trincheiras: o dia a dia de uma consultoria de banco de dados - Ig...
Relato das trincheiras: o dia a dia de uma consultoria de banco de dados - Ig...
 
ORMs heróis ou vilões dentro da arquitetura de dados? - Otávio gonçalves
ORMs heróis ou vilões dentro da arquitetura de dados? - Otávio gonçalvesORMs heróis ou vilões dentro da arquitetura de dados? - Otávio gonçalves
ORMs heróis ou vilões dentro da arquitetura de dados? - Otávio gonçalves
 
SQL e NoSQL trabalhando juntos: uma comparação para obter o melhor de ambos -...
SQL e NoSQL trabalhando juntos: uma comparação para obter o melhor de ambos -...SQL e NoSQL trabalhando juntos: uma comparação para obter o melhor de ambos -...
SQL e NoSQL trabalhando juntos: uma comparação para obter o melhor de ambos -...
 
Arquitetando seus dados na prática para a LGPD - Alessandra Martins
Arquitetando seus dados na prática para a LGPD - Alessandra MartinsArquitetando seus dados na prática para a LGPD - Alessandra Martins
Arquitetando seus dados na prática para a LGPD - Alessandra Martins
 
O papel do DBA no mundo de ciência de dados e machine learning - Mauro Pichil...
O papel do DBA no mundo de ciência de dados e machine learning - Mauro Pichil...O papel do DBA no mundo de ciência de dados e machine learning - Mauro Pichil...
O papel do DBA no mundo de ciência de dados e machine learning - Mauro Pichil...
 
Desenvolvimento Mobile Híbrido, Nativo ou Web: Quando usá-los - Juliana Chahoud
Desenvolvimento Mobile Híbrido, Nativo ou Web: Quando usá-los - Juliana ChahoudDesenvolvimento Mobile Híbrido, Nativo ou Web: Quando usá-los - Juliana Chahoud
Desenvolvimento Mobile Híbrido, Nativo ou Web: Quando usá-los - Juliana Chahoud
 
Use MDD e faça as máquinas trabalharem para você - Andreza Leite
 Use MDD e faça as máquinas trabalharem para você - Andreza Leite Use MDD e faça as máquinas trabalharem para você - Andreza Leite
Use MDD e faça as máquinas trabalharem para você - Andreza Leite
 
Entendendo os porquês do seu servidor - Talita Bernardes
Entendendo os porquês do seu servidor - Talita BernardesEntendendo os porquês do seu servidor - Talita Bernardes
Entendendo os porquês do seu servidor - Talita Bernardes
 
Backend performático além do "coloca mais máquina lá" - Diana Arnos
Backend performático além do "coloca mais máquina lá" - Diana ArnosBackend performático além do "coloca mais máquina lá" - Diana Arnos
Backend performático além do "coloca mais máquina lá" - Diana Arnos
 
Dicas para uma maior performance em APIs REST - Renato Groffe
Dicas para uma maior performance em APIs REST - Renato GroffeDicas para uma maior performance em APIs REST - Renato Groffe
Dicas para uma maior performance em APIs REST - Renato Groffe
 
7 dicas de desempenho que equivalem por 21 - Danielle Monteiro
7 dicas de desempenho que equivalem por 21 - Danielle Monteiro7 dicas de desempenho que equivalem por 21 - Danielle Monteiro
7 dicas de desempenho que equivalem por 21 - Danielle Monteiro
 
Quem se importa com acessibilidade Web? - Mauricio Maujor
Quem se importa com acessibilidade Web? - Mauricio MaujorQuem se importa com acessibilidade Web? - Mauricio Maujor
Quem se importa com acessibilidade Web? - Mauricio Maujor
 
Service Mesh com Istio e Kubernetes - Wellington Figueira da Silva
Service Mesh com Istio e Kubernetes - Wellington Figueira da SilvaService Mesh com Istio e Kubernetes - Wellington Figueira da Silva
Service Mesh com Istio e Kubernetes - Wellington Figueira da Silva
 
Erros: Como eles vivem, se alimentam e se reproduzem? - Augusto Pascutti
Erros: Como eles vivem, se alimentam e se reproduzem? - Augusto PascuttiErros: Como eles vivem, se alimentam e se reproduzem? - Augusto Pascutti
Erros: Como eles vivem, se alimentam e se reproduzem? - Augusto Pascutti
 
Elasticidade e engenharia de banco de dados para alta performance - Rubens G...
Elasticidade e engenharia de banco de dados para alta performance  - Rubens G...Elasticidade e engenharia de banco de dados para alta performance  - Rubens G...
Elasticidade e engenharia de banco de dados para alta performance - Rubens G...
 
Construindo aplicações mais confiantes - Carolina Karklis
Construindo aplicações mais confiantes - Carolina KarklisConstruindo aplicações mais confiantes - Carolina Karklis
Construindo aplicações mais confiantes - Carolina Karklis
 
Monitoramento de Aplicações - Felipe Regalgo
Monitoramento de Aplicações - Felipe RegalgoMonitoramento de Aplicações - Felipe Regalgo
Monitoramento de Aplicações - Felipe Regalgo
 

Kürzlich hochgeladen

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 

Kürzlich hochgeladen (20)

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 

Modernizing Legacy Applications in PHP, por Paul Jones

  • 1. It Was Like That When I Got Here: Steps Toward Modernizing A Legacy Codebase PHP Experience 2015 @pmjones mlaphp.com slideshare.net/pmjones88
  • 2. Messy Codebase • No router or front controller • Page scripts in document root
 (page-based) • Spaghetti include logic
 (include-oriented) • Global variables • No unit tests (never sure if a bug is really fixed)
  • 3. No Time To Make Things Better • Bugs to fix, right now • Features to implement, right now • Making your own life easier?
 Not a priority. • How did it get this bad?
 “It was like that when I got here.”
  • 4. Typical Page Script see editor for example
  • 5. The Great Thing About PHP ... • ... is that anyone can use it. • Have an idea? Implement it! • It works! Great success! • ... it “works.”
  • 6. 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.
  • 7. 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_debt
  • 8. Paying Off Technical Debt • A lot like paying off financial debt • Get the stuff first, but have to pay for it eventually • Must pay off technical debt not of our own choosing • Suffer as things are, or suffer through change
  • 9. Declare Bankruptcy • Rewrite from scratch — sexy! • Not making money. • Estimates are too optimistic. • End up with 2 bad architectures.
  • 10. Incremental Approach • Pay off smallest debt first • See immediate improvement — happiness! • Sequential small changes
 across codebase • Improve quality over time • “Refactoring” — sounds like work, but it actually works.
  • 11. Refactoring Process • Keep the application running • Consolidate classes for autoloading (PSR-0) • Convert globals to injected dependencies • Each change: test, commit, push, QA
  • 12. Consolidate Classes For Autoloading
  • 13. // 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();
 What Is Autoloading?
  • 14. PSR-0 • Also known as the “PEAR class-to-file standard” • 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.php
  • 15. 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');

  • 16. 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
  • 17. 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)
  • 18. Original Function function fetch_results()
 {
 global $db;
 $results = $db->fetch('whatever');
 return $results;
 }
 
 $results = fetch_results();

  • 19. Static Method class Example
 {
 public static function fetch_results()
 {
 global $db;
 $results = $db->fetch('whatever');
 return $results;
 }
 }
 
 $results = Example::fetch_results();

  • 20. Instance Method class Example
 {
 public function fetchResults()
 {
 global $db;
 $results = $db->fetch('whatever');
 return $results;
 }
 }
 
 $example = new Example;
 $results = $example->fetchResults();

  • 21. Convert Globals to Injected Dependencies
  • 22. Instantiating Dependencies In Methods class Example
 {
 public function fetchResults()
 {
 $db = new Database('username', 'password');
 return $db->fetch('whatever');
 }
 }

  • 23. Drawbacks Of Method Instantiation • New connection on each call • Cannot reuse connection • Parameter modification
  • 24. Global Dependencies // setup file
 $db = new Database('username', 'password');
 
 // example class file
 class Example
 {
 public function fetchResults()
 {
 global $db;
 return $db->fetch('whatever');
 }
 }

  • 25. Global Drawbacks class Evil
 {
 public function actionAtADistance()
 {
 global $db;
 unset($db);
 }
 }

  • 26. Dependency Injection • Instead of reaching out from inside the class to bring in dependencies ... • ... inject the dependency into the class from the outside. • Not “containers” just “technique”
  • 27. Starting Point: Global In Method class Example
 {
 public function fetchResults()
 {
 global $db;
 return $db->fetch('results');
 }
 }

  • 28. Step 1: Global In Constructor class Example
 {
 public function __construct()
 {
 global $db;
 $this->db = $db;
 }
 
 public function fetchResults()
 {
 return $this->db->fetch('results');
 }
 }

  • 29. Step 2: Dependency Injection class Example
 {
 public function __construct($db)
 {
 $this->db = $db;
 }
 
 public function fetchResults()
 {
 return $this->db->fetch('results');
 }
 }

  • 30. • Change new instantiations to pass parameters • Reveals hidden dependencies Step 3: Change Instantiation Calls // globals
 $example = new Example();
 
 // dependency injection ($db can be from setup)
 $db = new Database('username', 'password');
 $example = new Example($db);
  • 32. Initial Goals Completed ... • Consolidated into classes with PSR-0 and autoloading • Removed globals in favor of dependency injection • Kept it running the whole time • Paid off some technical debt, feeling good about work • Organizational structure for future work • Start writing unit tests
  • 33. ... But Much Remains • Using new keyword • Embedded SQL statements • Embedded domain logic • Embedded presentation logic • Embedded action logic • Embedded include calls • Router + front controller • DI container
  • 34. mlaphp.com Autoloaded, Dependency Injected, UnitTested, Layer Separated, Front Controlled Coupon for 25% Off: leanpub.com/mlaphp/c/ phpexperience2015