ESCAPING
DEPENDENCY HELL
Michael Haeuslmann - PHP UG Munich 2016
Source: Escape from Hell Constantine by Rommeu
ESCAPING GERMAN
WINTER?
Michael Haeuslmann - PHP UG Munich 2016
Source: Escape from Hell Constantine by Rommeu
PART I: DISCUSSION
WHAT IS DEPENDENCY HELL?
WHAT IS A DEPENDENCY?
... a dependency signifies a supplier/client
relationship between model elements
where the modification of a supplier may
impact the client model elements
- UML Specification v2.5
WHY SHOULD WE CARE?
MICHAEL HAEUSLMANN (@MICHAELHAEU)
FREELANCER (PHPRAGMATIC.COM)
married, love to travel, board games, ...
developing in PHP for ~8 years
professional work in PHP (mostly legacy apps)
open source for all the exciting stuff
Buuuut ...
I don't want to be a freelancer anymore ...
... sooooo ...
WE KNOW WE'RE IN
DEPENDENCY HELL.
HOW DO WE ESCAPE?
COMPLEX VS. COMPLICATED
Bubble Sort?
COMPLEX VS. COMPLICATED
Bubble Sort?
COMPLEX VS. COMPLICATED
Cache Invalidation?
COMPLEX VS. COMPLICATED
Cache Invalidation?
COMPLEX VS. COMPLICATED
Cache Invalidation?
COMPLEX VS. COMPLICATED
Cache Invalidation?
COMPLEX VS. COMPLICATED
Cache Invalidation?
COMPLEX VS. COMPLICATED
Web Applications?
COMPLEX VS. COMPLICATED
Web Applications?
COMPLEX VS. COMPLICATED
It doesn't have to be complicated
WHAT DO WE DO ABOUT IT?
Read the code and take notes?
We don't want to do everything ourselves
use a tool →
Managing dependencies in the right way helps with:
Complexity, maintenance and understandability
PART II: ANALYSE
WHAT SHOULD DEPENDENCY ANALYSIS TELL
US?
Where should we start refactoring?
Why does [SomeClass] always break?
What does our architecture actually look like?
Is our architecture the way it should be?
TOOLS
PHP DEPEND BY MANUEL PICHLER
many metrics 
many metrics 
hard to maintain
too vague
TOOLS
PHP DEPEND BY MANUEL PICHLER
TOOLS
detects even the sneakiest dependencies
generates dependency visualizations
hackable (grep, sed, awk, ...)
for the nerds: written using functional style
supports PHP 5.2 to 7.1
FEATURES
Text
For quick feedback, debugging, UNIX pipes etc.
Visualisations (UML & DSM & dot)
Detailed dependency & architectural analysis
(Metrics)
DEPHPEND - TEXT OUTPUT
$> wget http://phar.dephpend.com/dephpend.phar
$> composer global require dephpend/dephpend:dev­master
$> dephpend help text
      _      _____  _    _ _____               _
     | |    |  __ | |  | |  __              | |
   __| | ___| |__) | |__| | |__) |__ _ __   __| |
  / _` |/ _   ___/|  __  |  ___/ _  '_  / _` |
 | (_| |  __/ |    | |  | | |  |  __/ | | | (_| |
  __,_|___|_|    |_|  |_|_|   ___|_| |_|__,_| version 0.1
  Usage:
  text [options] [­­]  ()...
$> dephpend text ~/workspace/dephpend/src
MihaeuPhpDependenciesUtilAbstractMap ­­> MihaeuPhpDependenciesUtilCollection
MihaeuPhpDependenciesUtilDI ­­> MihaeuPhpDependenciesAnalyserAnalyser
...
(*) make sure XDebug is not enabled or use php -n
DEPHPEND - TEXT OUTPUT
$> dephpend text ~/workspace/dephpend/src ­­no­classes | sort
MihaeuPhpDependenciesAnalyser ­­> MihaeuPhpDependenciesDependencies
MihaeuPhpDependenciesAnalyser ­­> MihaeuPhpDependenciesOS
MihaeuPhpDependenciesAnalyser ­­> MihaeuPhpDependenciesUtil
MihaeuPhpDependenciesAnalyser ­­> PhpParser
MihaeuPhpDependenciesAnalyser ­­> PhpParserNode
MihaeuPhpDependenciesAnalyser ­­> PhpParserNodeExpr
MihaeuPhpDependenciesAnalyser ­­> PhpParserNodeName
MihaeuPhpDependenciesAnalyser ­­> PhpParserNodeStmt
MihaeuPhpDependenciesAnalyser ­­> PhpParserNodeVisitor
...
$> dephpend text ~/workspace/dephpend/src ­­no­classes 
    | grep ­e 'Analyser ­­> .*OS'
MihaeuPhpDependenciesAnalyser ­­> MihaeuPhpDependenciesOS
DEPHPEND - TEXT OUTPUT
Make it yours!
#!/usr/bin/env sh
php build/dephpend.phar text ~/workspace/dephpend/src ­­no­classes | grep 
    ­e 'Analyser ­­> .*OS' 
    ­e 'OS ­­> .*Analyser'
if [ "$?" ­eq 0 ]; then
    echo 'Architecture violation!'
    exit 1
fi
DEPHPEND - TEXT OUTPUT
<?php
$output = shell_exec('dephpend text '
    .'~/workspace/myMVCFramework/src ­­no­classes');
$constraints = [
    'Model.* ­­> .*View',
    'View.*  ­­> .*Model',
];
if (preg_match('/('.implode(')|(', $constraints).')/x', $output)) {
    echo 'Architecture violation'.PHP_EOL;
    exit(1);
}
DEPHPEND - UML (SORT OF)
dePHPend packages
$> dephpend uml ~/workspace/dephpend/src ­­no­classes ­­output=uml.png
Escaping Dependency Hell v2
DEPHPEND - UML (SORT OF)
Symfony components
$> php ­d memory_limit=512M dephpend.phar uml 
    ~/workspace/symfony/src/Symfony/Component 
    ­­no­classes                
    ­­depth 3         # SymfonyComponentHttpKernelControllerArgumentResolver
                      # →  SymfonyComponentHttpKernel
    ­­exclude­regex='/Test/'     # SymfonyComponentHttpFoundationTests
    ­­output=uml.png
DEPHPEND - UML (SORT OF)
Symfony components
DEPHPEND - UML (SORT OF)
Symfony HTTP Kernel
DEPENDENCY STRUCTURE MATRIX
(DSM)
large graphs are unreadable
same data as graph diagrams (e.g. UML class diagram)
quick overview for large apps
DEPHPEND DSM
NDEPEND EXAMPLE
Escaping Dependency Hell v2
Escaping Dependency Hell v2
Escaping Dependency Hell v2
Escaping Dependency Hell v2
PART III: FIX
WHAT DO WE WANT?
We want code which is ...
... easier to understand
... easier to maintain
... easier to test
OBSCURE/NASTY DEPENDENCIES
Some dependencies cannot be detected by any tool
(or developer):
Fake collections (array)
Overuse of scalar values (int, string, ...)
Temporal dependencies, etc.
BE EXPLICIT!
Implicit dependencies are hard to understand/manage!
function sendNewsletter(
    array $customers,
    string $message
);
function sendNewsletter(
    CustomerCollection $customers,
    Message $message
);
WHICH ALLOCATES MORE RAM?
ARRAY
$customer = [
    'id'    => 123,
    'name'  => 'John Doe',
    'city'  => 'Example City',
];
                            
CUSTOM CLASS
class Customer {
    /** @var int */
    private $id;
    /** @var string */
    private $name;
    /** @var string */
    private $city;
}
                            
Winner (less RAM): custom class
Proof: http://www.slideshare.net/patrick.allaert/php-data-structures-and-the-impact-of-php-7-on-
them-php-days-2015
DON'T MAKE ME LOOK IT UP
/**
 * @param mixed $email
 * @param string|Email|array $email
 */
function addEmail($email) {
    if (is_array($email)) {
        // pray everything inside the array actually is an email
        foreach ($email as $singleEmail) addEmail($singleEmail);
    } else if (is_string($email)) {
        addEmail(new Email($email));
    } else if ($email instanceof Email) {
        this­>emails[] = email;
    } else {
        throw new InvalidArgumentException('Bad argument type');
    }
}
DON'T MAKE ME LOOK IT UP
function addEmail(Email $email) {
  $this­>emails[] = $email;
}
function addEmailString(string $email) {
  $this­>addEmail(new Email($email));
}
function addEmailArray(array $emails) {
  foreach ($emails as $email) { /** @var Email $email */
    if (is_string($email)) $this­>addEmailstring($email);
    else if ($email instanceof Email) $this­>addEmail($email);
    else throw new InvalidArgumentException('Bad argument type');
  }
}
function addEmailCollection(EmailCollection $emails) {
  $emails­>each(function (Email $email) {
    $this­>addEmail($email);
  });
}
DON'T MAKE ME LOOK IT UP
function addEmail(Email $email) {
  $this­>emails[] = $email;
}
function addEmailCollection(EmailCollection $emails) {
  $emails­>each(function (Email $email) {
    $this­>addEmail($email);
  });
}
function addEmailString(string $email) {
  $this­>addEmail(new Email($email));
}
function addEmailArray(array $emails) {
  foreach ($emails as $email) { /** @var Email $email */
    if (is_string($email)) $this­>addEmailstring($email);
    else if ($email instanceof Email) $this­>addEmail($email);
    else throw new InvalidArgumentException('Bad argument type');
  }
}
PRINCIPLES OF OO: SOLID
Single responsibility principle
Open/closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
DEPENDENCY INVERSION
BAD:
class CustomerRepository {
    public function __construct() {
        $this­>db = new MySQLDatabase(new DefaultConfig());
    }
}
BETTER:
class CustomerRepository {
    public function __construct(MySQLDatabase $db) {
        $this­>db = $db;
    }
}
GOOD:
class CustomerRepository {
    public function __construct(Database $db) {
        $this­>db = $db;
    }
}
Easier to understand and test, less likely to break
DEPENDENCY INJECTION
CONTAINERS
$container = new PimpleContainer();
$container['cstmrrepo'] = function ($database) {
    return new CustomerRepository($database);
};
$cstmrRepo = $container['cstmrrepo'];
Too easy?
obscure dependencies using YAML
add another 3rd party library
add overhead by parsing meta format
/sarcasm
AVOID IMPLICIT DEPENDENCIES IN FAVOR OF
EXPLICIT ONES
// why not do it yourselves?
class DependencyInjectionContainer {
    // eager load
    public function getCustomerRepository() : CustomerRepository {
        return new CustomerRepository($this­>otherDeps);
    }
    // OR: lazy load
    public function getCustomerRepository() : CustomerRepository {
        if (null === $this­>customerRepository) {
            $this­>customerRepository =
                new CustomerRepository($this­>otherDeps);
        }
        return $this­>customerRepository;
    }
}
$dependencyInjectionContainer­>getCustomerRepository();
SERVICE LOCATOR
class CustomerRepository {
    public function __construct(ServiceLocator $serviceLocator) {
        $this­>db = $serviceLocator­>getDb();
    }
}
new CustomerRepository($serviceLocator);
Same or similar implementation, but different usage:
CHOOSE DEPENDENCY INJECTION
CONTAINERS OVER SERVICE LOCATORS
Service Locator provides access to everything
Might as well use globals...
(but not really)
Target class knows more than it should
= more reasons to change (=break)
Always choose REAL Dependency Injection
'MEMBER SYMONFY HTTPKERNEL?
WHERE TO GO FROM HERE?
improve visualizations
command for constraint checks
caching
better Test & CI integration
Contributions, ideas, feedback, bug reports are welcome!
QUESTIONS
???
LINKS
http://www.slideshare.net/michael-haeuslmann/escaping-dependency-hell
https://dephpend.com
https://github.com/mihaeu/dephpend
HOW DOES IT WORK?
STATIC ANALYSIS
Transform the code to make parsing easier
Infer direct types (require, new, type hints, ...)
Infer indirect types (DICs, ...)
DYNAMIC ANALYSIS
profile the application
track function traces
collect all possible input values
STATIC ANALYSIS
Easy right?
use SomeNamespaceSomeClass;
class MyClass extends MyParent implements MyInterface {
    /**
     * @return AnotherClass
     */
    public function someFunction(SomeClass $someClass) : AnotherClass {
        StaticClass::staticFunction();
        return new AnotherClass();
    }
}
STATIC ANALYSIS
Or is it?
class MyClass {
    public function someMethod($dependency) {
        return call_user_func('globalFunction', $dependency);
    }
}
or:
DYNAMIC ANALYSIS
XDebug to the rescue!
; php.ini
zend_extension=/path/to/xdebug.so
[xdebug]
xdebug.profiler_enable = 1
xdebug.auto_trace=1
xdebug.collect_params=1
xdebug.collect_return=3
xdebug.collect_assignments=1
xdebug.trace_format=1
xdebug.trace_options=1
# https://github.com/mihaeu/dephpend/blob/develop/bin/dephpend
php­trace ­­dynamic=/path/to/trace­file.xt ­S localhost:8080
DYNAMIC ANALYSIS
TRACE START [2016­10­19 16:59:03]
1  0  0  0.000189  363984  {main}  1
        /home/mike/workspace/dephpend/bin/dephpend  0  0
2  1  0  0.000209  363984  get_declared_classes  0
        /home/mike/workspace/dephpend/bin/dephpend  80
                        ...
11  211058  0  3.503452  4856528 strpos  0
        /home/mike/workspace/dephpend/vendor/symfony/console/Formatter/OutputFormatter.php
        177  2  string(15111)  string(2)
                        ...
3  200813  R      long
      3.504303  238672
TRACE END   [2016­10­19 16:59:07]
                    
DYNAMIC ANALYSIS
Parse the trace file and merge with static results
$> dephpend text src               
        ­­dynamic=/path/to/trace­file.xt    
        ­­filter­from=YourNamespace         
        ­­exclude­regex='(Test)|(Mock)'
There are no secrets at runtime!
 @ m i c h a e l h a e u - PHP UG Munich 2016 -  h t t p s : / / d e p h p e n d . c o m
CREDITS
NDepend
Slide Coder Deviant Art
PDepend Artifacts
scaled DSM
http://www.ndepend.com/docs/dependency-
structure-matrix-dsm
http://rommeu.deviantart.com/art/Escape-from-Hell-
Constantine-204115701
pdepend.org
https://erik.doernenburg.com/2010/04/dependency-
structure-matrix/

More Related Content

PPTX
Estimation techniques for Scrum Teams
PDF
Sprint calendar
PPT
Agile estimation and planning peter saddington
PPTX
Analysis In Agile: It's More than Just User Stories
PPTX
Agile User Stories
PPTX
[HCM Scrum Breakfast] Agile estimation - Story points
PPTX
Scrum Product Owner
PPTX
User stories in agile software development
Estimation techniques for Scrum Teams
Sprint calendar
Agile estimation and planning peter saddington
Analysis In Agile: It's More than Just User Stories
Agile User Stories
[HCM Scrum Breakfast] Agile estimation - Story points
Scrum Product Owner
User stories in agile software development

What's hot (20)

PPT
What is Scrum
PDF
Organizational Trends and Patterns with Team Topologies @ LPCx Meetup, July 2021
PDF
Estimating with story points
PDF
Team Topologies in action - early results from industry - DOES London Virtual...
PDF
Conversational AI– Beyond the chatbot hype
PDF
Hacking the Creative Brain - Web Directions 2015
PPTX
Product discovery con frameworks de ux y agile inception
PDF
Scrum Cheat Sheet
PDF
Getting started with Site Reliability Engineering (SRE)
PPT
Writing Effective User Stories
PDF
Alinhando Discovery com Delivery usando Upstream Kanban
PDF
Beyond Engineering: The Future of Platforms @ CraftConf, May 2023
PDF
User story slicing exercise
PPTX
Kanban - Agilidade Fora da TI - Case Riachuelo
PDF
Scaled Agile Framework (SAFe) 4.5 Tutorial ...
PDF
Writing Good User Stories (Hint: It's not about writing)
PDF
Atelier Story Map
PPTX
Data driven coaching - Agile 2016 (troy magennis)
PDF
Scrum, Kanban, and DevOps Sitting in a Tree… - Big Apple Scrum Day 2018
PPTX
How to Break the Requirements into User Stories
What is Scrum
Organizational Trends and Patterns with Team Topologies @ LPCx Meetup, July 2021
Estimating with story points
Team Topologies in action - early results from industry - DOES London Virtual...
Conversational AI– Beyond the chatbot hype
Hacking the Creative Brain - Web Directions 2015
Product discovery con frameworks de ux y agile inception
Scrum Cheat Sheet
Getting started with Site Reliability Engineering (SRE)
Writing Effective User Stories
Alinhando Discovery com Delivery usando Upstream Kanban
Beyond Engineering: The Future of Platforms @ CraftConf, May 2023
User story slicing exercise
Kanban - Agilidade Fora da TI - Case Riachuelo
Scaled Agile Framework (SAFe) 4.5 Tutorial ...
Writing Good User Stories (Hint: It's not about writing)
Atelier Story Map
Data driven coaching - Agile 2016 (troy magennis)
Scrum, Kanban, and DevOps Sitting in a Tree… - Big Apple Scrum Day 2018
How to Break the Requirements into User Stories
Ad

Similar to Escaping Dependency Hell v2 (20)

PDF
Escaping Dependency Hell
PDF
Beginning with Composer - Dependency manager in php
PDF
Writing Testable Code
PDF
Composer: Dependency Manager for PHP
PDF
Tackling Tech Debt with Rector
PDF
Dependency management with Composer
PDF
Php Dependency Management with Composer ZendCon 2016
PDF
Php Dependency Management with Composer ZendCon 2017
PPTX
DDD (Debugger Driven Development)
PDF
Decoupled Libraries for PHP
PDF
Николай Паламарчук "Управление зависимостями в больших проектах"
PPTX
PHP Dependency Management with Composer
PDF
API Platform: Full Stack Framework Resurrection
PDF
From silex to symfony and viceversa
PPT
The Big Documentation Extravaganza
PDF
S.O.L.I.D. Principles
PDF
Edition of an enterprise software in PHP, feedback
PDF
Rebuilding our Foundation
DOCX
"The Power of Composer"
PDF
Fighting legacy with hexagonal architecture and frameworkless php
Escaping Dependency Hell
Beginning with Composer - Dependency manager in php
Writing Testable Code
Composer: Dependency Manager for PHP
Tackling Tech Debt with Rector
Dependency management with Composer
Php Dependency Management with Composer ZendCon 2016
Php Dependency Management with Composer ZendCon 2017
DDD (Debugger Driven Development)
Decoupled Libraries for PHP
Николай Паламарчук "Управление зависимостями в больших проектах"
PHP Dependency Management with Composer
API Platform: Full Stack Framework Resurrection
From silex to symfony and viceversa
The Big Documentation Extravaganza
S.O.L.I.D. Principles
Edition of an enterprise software in PHP, feedback
Rebuilding our Foundation
"The Power of Composer"
Fighting legacy with hexagonal architecture and frameworkless php
Ad

Recently uploaded (20)

PDF
Prof. Dr. KAYIHURA A. SILAS MUNYANEZA, PhD..pdf
PDF
Design of Material Handling Equipment Lecture Note
PDF
Accra-Kumasi Expressway - Prefeasibility Report Volume 1 of 7.11.2018.pdf
PPTX
ai_satellite_crop_management_20250815030350.pptx
PPTX
Module 8- Technological and Communication Skills.pptx
PPTX
A Brief Introduction to IoT- Smart Objects: The "Things" in IoT
PPTX
Feature types and data preprocessing steps
PDF
LOW POWER CLASS AB SI POWER AMPLIFIER FOR WIRELESS MEDICAL SENSOR NETWORK
PPTX
Amdahl’s law is explained in the above power point presentations
PDF
Java Basics-Introduction and program control
PDF
Introduction to Power System StabilityPS
PPTX
CONTRACTS IN CONSTRUCTION PROJECTS: TYPES
PPTX
Principal presentation for NAAC (1).pptx
PDF
Exploratory_Data_Analysis_Fundamentals.pdf
PPTX
wireless networks, mobile computing.pptx
PDF
Unit I -OPERATING SYSTEMS_SRM_KATTANKULATHUR.pptx.pdf
PDF
Unit1 - AIML Chapter 1 concept and ethics
PDF
Applications of Equal_Area_Criterion.pdf
PPTX
Sorting and Hashing in Data Structures with Algorithms, Techniques, Implement...
PPTX
Measurement Uncertainty and Measurement System analysis
Prof. Dr. KAYIHURA A. SILAS MUNYANEZA, PhD..pdf
Design of Material Handling Equipment Lecture Note
Accra-Kumasi Expressway - Prefeasibility Report Volume 1 of 7.11.2018.pdf
ai_satellite_crop_management_20250815030350.pptx
Module 8- Technological and Communication Skills.pptx
A Brief Introduction to IoT- Smart Objects: The "Things" in IoT
Feature types and data preprocessing steps
LOW POWER CLASS AB SI POWER AMPLIFIER FOR WIRELESS MEDICAL SENSOR NETWORK
Amdahl’s law is explained in the above power point presentations
Java Basics-Introduction and program control
Introduction to Power System StabilityPS
CONTRACTS IN CONSTRUCTION PROJECTS: TYPES
Principal presentation for NAAC (1).pptx
Exploratory_Data_Analysis_Fundamentals.pdf
wireless networks, mobile computing.pptx
Unit I -OPERATING SYSTEMS_SRM_KATTANKULATHUR.pptx.pdf
Unit1 - AIML Chapter 1 concept and ethics
Applications of Equal_Area_Criterion.pdf
Sorting and Hashing in Data Structures with Algorithms, Techniques, Implement...
Measurement Uncertainty and Measurement System analysis

Escaping Dependency Hell v2

  • 1. ESCAPING DEPENDENCY HELL Michael Haeuslmann - PHP UG Munich 2016 Source: Escape from Hell Constantine by Rommeu
  • 2. ESCAPING GERMAN WINTER? Michael Haeuslmann - PHP UG Munich 2016 Source: Escape from Hell Constantine by Rommeu
  • 5. WHAT IS A DEPENDENCY? ... a dependency signifies a supplier/client relationship between model elements where the modification of a supplier may impact the client model elements - UML Specification v2.5
  • 7. MICHAEL HAEUSLMANN (@MICHAELHAEU) FREELANCER (PHPRAGMATIC.COM) married, love to travel, board games, ... developing in PHP for ~8 years professional work in PHP (mostly legacy apps) open source for all the exciting stuff
  • 8. Buuuut ... I don't want to be a freelancer anymore ... ... sooooo ...
  • 9. WE KNOW WE'RE IN DEPENDENCY HELL. HOW DO WE ESCAPE?
  • 19. COMPLEX VS. COMPLICATED It doesn't have to be complicated
  • 20. WHAT DO WE DO ABOUT IT? Read the code and take notes? We don't want to do everything ourselves use a tool → Managing dependencies in the right way helps with: Complexity, maintenance and understandability
  • 22. WHAT SHOULD DEPENDENCY ANALYSIS TELL US? Where should we start refactoring? Why does [SomeClass] always break? What does our architecture actually look like? Is our architecture the way it should be?
  • 23. TOOLS PHP DEPEND BY MANUEL PICHLER many metrics  many metrics  hard to maintain too vague
  • 24. TOOLS PHP DEPEND BY MANUEL PICHLER
  • 25. TOOLS detects even the sneakiest dependencies generates dependency visualizations hackable (grep, sed, awk, ...) for the nerds: written using functional style supports PHP 5.2 to 7.1
  • 26. FEATURES Text For quick feedback, debugging, UNIX pipes etc. Visualisations (UML & DSM & dot) Detailed dependency & architectural analysis (Metrics)
  • 27. DEPHPEND - TEXT OUTPUT $> wget http://phar.dephpend.com/dephpend.phar $> composer global require dephpend/dephpend:dev­master $> dephpend help text       _      _____  _    _ _____               _      | |    |  __ | |  | |  __              | |    __| | ___| |__) | |__| | |__) |__ _ __   __| |   / _` |/ _   ___/|  __  |  ___/ _  '_  / _` |  | (_| |  __/ |    | |  | | |  |  __/ | | | (_| |   __,_|___|_|    |_|  |_|_|   ___|_| |_|__,_| version 0.1   Usage:   text [options] [­­]  ()... $> dephpend text ~/workspace/dephpend/src MihaeuPhpDependenciesUtilAbstractMap ­­> MihaeuPhpDependenciesUtilCollection MihaeuPhpDependenciesUtilDI ­­> MihaeuPhpDependenciesAnalyserAnalyser ... (*) make sure XDebug is not enabled or use php -n
  • 28. DEPHPEND - TEXT OUTPUT $> dephpend text ~/workspace/dephpend/src ­­no­classes | sort MihaeuPhpDependenciesAnalyser ­­> MihaeuPhpDependenciesDependencies MihaeuPhpDependenciesAnalyser ­­> MihaeuPhpDependenciesOS MihaeuPhpDependenciesAnalyser ­­> MihaeuPhpDependenciesUtil MihaeuPhpDependenciesAnalyser ­­> PhpParser MihaeuPhpDependenciesAnalyser ­­> PhpParserNode MihaeuPhpDependenciesAnalyser ­­> PhpParserNodeExpr MihaeuPhpDependenciesAnalyser ­­> PhpParserNodeName MihaeuPhpDependenciesAnalyser ­­> PhpParserNodeStmt MihaeuPhpDependenciesAnalyser ­­> PhpParserNodeVisitor ... $> dephpend text ~/workspace/dephpend/src ­­no­classes      | grep ­e 'Analyser ­­> .*OS' MihaeuPhpDependenciesAnalyser ­­> MihaeuPhpDependenciesOS
  • 29. DEPHPEND - TEXT OUTPUT Make it yours! #!/usr/bin/env sh php build/dephpend.phar text ~/workspace/dephpend/src ­­no­classes | grep      ­e 'Analyser ­­> .*OS'      ­e 'OS ­­> .*Analyser' if [ "$?" ­eq 0 ]; then     echo 'Architecture violation!'     exit 1 fi
  • 30. DEPHPEND - TEXT OUTPUT <?php $output = shell_exec('dephpend text '     .'~/workspace/myMVCFramework/src ­­no­classes'); $constraints = [     'Model.* ­­> .*View',     'View.*  ­­> .*Model', ]; if (preg_match('/('.implode(')|(', $constraints).')/x', $output)) {     echo 'Architecture violation'.PHP_EOL;     exit(1); }
  • 31. DEPHPEND - UML (SORT OF) dePHPend packages $> dephpend uml ~/workspace/dephpend/src ­­no­classes ­­output=uml.png
  • 33. DEPHPEND - UML (SORT OF) Symfony components $> php ­d memory_limit=512M dephpend.phar uml      ~/workspace/symfony/src/Symfony/Component      ­­no­classes                     ­­depth 3         # SymfonyComponentHttpKernelControllerArgumentResolver                       # →  SymfonyComponentHttpKernel     ­­exclude­regex='/Test/'     # SymfonyComponentHttpFoundationTests     ­­output=uml.png
  • 34. DEPHPEND - UML (SORT OF) Symfony components
  • 35. DEPHPEND - UML (SORT OF) Symfony HTTP Kernel
  • 36. DEPENDENCY STRUCTURE MATRIX (DSM) large graphs are unreadable same data as graph diagrams (e.g. UML class diagram) quick overview for large apps
  • 44. WHAT DO WE WANT? We want code which is ... ... easier to understand ... easier to maintain ... easier to test
  • 45. OBSCURE/NASTY DEPENDENCIES Some dependencies cannot be detected by any tool (or developer): Fake collections (array) Overuse of scalar values (int, string, ...) Temporal dependencies, etc.
  • 46. BE EXPLICIT! Implicit dependencies are hard to understand/manage! function sendNewsletter(     array $customers,     string $message ); function sendNewsletter(     CustomerCollection $customers,     Message $message );
  • 47. WHICH ALLOCATES MORE RAM? ARRAY $customer = [     'id'    => 123,     'name'  => 'John Doe',     'city'  => 'Example City', ];                              CUSTOM CLASS class Customer {     /** @var int */     private $id;     /** @var string */     private $name;     /** @var string */     private $city; }                              Winner (less RAM): custom class Proof: http://www.slideshare.net/patrick.allaert/php-data-structures-and-the-impact-of-php-7-on- them-php-days-2015
  • 48. DON'T MAKE ME LOOK IT UP /**  * @param mixed $email  * @param string|Email|array $email  */ function addEmail($email) {     if (is_array($email)) {         // pray everything inside the array actually is an email         foreach ($email as $singleEmail) addEmail($singleEmail);     } else if (is_string($email)) {         addEmail(new Email($email));     } else if ($email instanceof Email) {         this­>emails[] = email;     } else {         throw new InvalidArgumentException('Bad argument type');     } }
  • 49. DON'T MAKE ME LOOK IT UP function addEmail(Email $email) {   $this­>emails[] = $email; } function addEmailString(string $email) {   $this­>addEmail(new Email($email)); } function addEmailArray(array $emails) {   foreach ($emails as $email) { /** @var Email $email */     if (is_string($email)) $this­>addEmailstring($email);     else if ($email instanceof Email) $this­>addEmail($email);     else throw new InvalidArgumentException('Bad argument type');   } } function addEmailCollection(EmailCollection $emails) {   $emails­>each(function (Email $email) {     $this­>addEmail($email);   }); }
  • 50. DON'T MAKE ME LOOK IT UP function addEmail(Email $email) {   $this­>emails[] = $email; } function addEmailCollection(EmailCollection $emails) {   $emails­>each(function (Email $email) {     $this­>addEmail($email);   }); } function addEmailString(string $email) {   $this­>addEmail(new Email($email)); } function addEmailArray(array $emails) {   foreach ($emails as $email) { /** @var Email $email */     if (is_string($email)) $this­>addEmailstring($email);     else if ($email instanceof Email) $this­>addEmail($email);     else throw new InvalidArgumentException('Bad argument type');   } }
  • 51. PRINCIPLES OF OO: SOLID Single responsibility principle Open/closed principle Liskov substitution principle Interface segregation principle Dependency inversion principle
  • 53. Easier to understand and test, less likely to break
  • 55. AVOID IMPLICIT DEPENDENCIES IN FAVOR OF EXPLICIT ONES // why not do it yourselves? class DependencyInjectionContainer {     // eager load     public function getCustomerRepository() : CustomerRepository {         return new CustomerRepository($this­>otherDeps);     }     // OR: lazy load     public function getCustomerRepository() : CustomerRepository {         if (null === $this­>customerRepository) {             $this­>customerRepository =                 new CustomerRepository($this­>otherDeps);         }         return $this­>customerRepository;     } } $dependencyInjectionContainer­>getCustomerRepository();
  • 57. Same or similar implementation, but different usage: CHOOSE DEPENDENCY INJECTION CONTAINERS OVER SERVICE LOCATORS Service Locator provides access to everything Might as well use globals... (but not really) Target class knows more than it should = more reasons to change (=break) Always choose REAL Dependency Injection
  • 59. WHERE TO GO FROM HERE? improve visualizations command for constraint checks caching better Test & CI integration Contributions, ideas, feedback, bug reports are welcome!
  • 61. HOW DOES IT WORK? STATIC ANALYSIS Transform the code to make parsing easier Infer direct types (require, new, type hints, ...) Infer indirect types (DICs, ...) DYNAMIC ANALYSIS profile the application track function traces collect all possible input values
  • 63. STATIC ANALYSIS Or is it? class MyClass {     public function someMethod($dependency) {         return call_user_func('globalFunction', $dependency);     } }
  • 64. or: DYNAMIC ANALYSIS XDebug to the rescue! ; php.ini zend_extension=/path/to/xdebug.so [xdebug] xdebug.profiler_enable = 1 xdebug.auto_trace=1 xdebug.collect_params=1 xdebug.collect_return=3 xdebug.collect_assignments=1 xdebug.trace_format=1 xdebug.trace_options=1 # https://github.com/mihaeu/dephpend/blob/develop/bin/dephpend php­trace ­­dynamic=/path/to/trace­file.xt ­S localhost:8080
  • 65. DYNAMIC ANALYSIS TRACE START [2016­10­19 16:59:03] 1  0  0  0.000189  363984  {main}  1         /home/mike/workspace/dephpend/bin/dephpend  0  0 2  1  0  0.000209  363984  get_declared_classes  0         /home/mike/workspace/dephpend/bin/dephpend  80                         ... 11  211058  0  3.503452  4856528 strpos  0         /home/mike/workspace/dephpend/vendor/symfony/console/Formatter/OutputFormatter.php         177  2  string(15111)  string(2)                         ... 3  200813  R      long       3.504303  238672 TRACE END   [2016­10­19 16:59:07]                     
  • 66. DYNAMIC ANALYSIS Parse the trace file and merge with static results $> dephpend text src                        ­­dynamic=/path/to/trace­file.xt             ­­filter­from=YourNamespace                  ­­exclude­regex='(Test)|(Mock)' There are no secrets at runtime!
  • 67.  @ m i c h a e l h a e u - PHP UG Munich 2016 -  h t t p s : / / d e p h p e n d . c o m CREDITS NDepend Slide Coder Deviant Art PDepend Artifacts scaled DSM http://www.ndepend.com/docs/dependency- structure-matrix-dsm http://rommeu.deviantart.com/art/Escape-from-Hell- Constantine-204115701 pdepend.org https://erik.doernenburg.com/2010/04/dependency- structure-matrix/