Große Systeme, loose Kopplung...
Stephan Hochdörfer, bitExpert AG
Große Systeme, loose Kopplung...
Über mich
Stephan Hochdörfer, bitExpert AG
Department Manager Research Labs
PHP Entwickler seit 1999
@shochdoerfer
"High-level modules should not depend on low-level modules.
Both should depend on abstractions."Robert C. Martin
Große Systeme, loose Kopplung...
Große Systeme, loose Kopplung...
High Level, Low Level...
User Controller
Datenbankverbindung (User DB)
Große Systeme, loose Kopplung...
High Level, Low Level...
User Controller
User Service
User Repository
Große Systeme, loose Kopplung...
Wie separieren? Horizontales Zerschneiden
Große Systeme, loose Kopplung...
Wie separieren? Horizontales Zerschneiden
Presentation Layer
Business Layer
Resource Access Layer
Große Systeme, loose Kopplung...
Wie separieren? Zerschneiden nach Services
Service Interface Layer
Business Layer
Resource Access Layer
Große Systeme, loose Kopplung...
Wie separieren? Zerschneiden in Services
Frontend
REST API
Datastore
Solr Search Service
Große Systeme, loose Kopplung...
Wie separieren? Vertikales Zerschneiden
Große Systeme, loose Kopplung...
Wie separieren? Vertikales Zerschneiden
ModulA ModulB ModulC
Große Systeme, loose Kopplung...
Wie separieren? Vertikal + Horizontal
PresentationLayer
BusinessLayer
ResourceAccess Layer
PresentationLayer
BusinessLayer
ResourceAccess Layer
PresentationLayer
BusinessLayer
ResourceAccess Layer
Große Systeme, loose Kopplung...
Wie separieren? Auf Aspekte achten
Große Systeme, loose Kopplung...
Wie separieren? Auf Aspekte achten
Presentation Layer
Business Layer
Resource Access Layer
Aspekte
Große Systeme, loose Kopplung...
Wie separieren? Auf Aspekte achten<?phpnamespace Acme\Products\Aspects;
/** * @FLOW3\Aspect */class LoggingAspect { /** * @FLOW3\Inject * @var \Acme\Logger\LoggerInterface */ protected $logger;
/** * @param \TYPO3\FLOW3\AOP\JoinPointInterface $joinPoint * @FLOW3\Before("method(Acme\Products\Model\Product->delete())") */ public function log(\TYPO3\FLOW3\AOP\JoinPointInterface $jp) { $product = $jp->getMethodArgument('product'); $this->logger->info('Removing ' . $product->getName()); }}
Große Systeme, loose Kopplung...
Wie erreicht man eine loose Kopplung?
Große Systeme, loose Kopplung...
Registry Pattern<?php
Registry::set('platzhalter', 'Lorem ipsum...');
echo Registry::get('platzhalter');
Große Systeme, loose Kopplung...
<?php
Registry::set('platzhalter', 'Lorem ipsum...');
Registry::set('platzhalter', new RandomObject());
Registry::set('platzhalter', array());
echo Registry::get('platzhalter');
Registry Pattern – nicht typsicher!
Große Systeme, loose Kopplung...
Registry Pattern<?php
class MyController { protected $myService; public function __construct() { $this>myService = Registry::get('MyService'); }
public function execute() { $this>myService>doStuff();
}}
Große Systeme, loose Kopplung...
Wie erreicht man eine loose Kopplung?
„When you put a class name in a string you ain't decoupling anything. You're
just hiding dependencies“@jensschauder
Große Systeme, loose Kopplung...
Service Locator<?php
class MyController { protected $myService; public function __construct() { $this>myService = ServiceLocator::getMyService(); }
public function execute() { $this>myService>doStuff();
}}
Große Systeme, loose Kopplung...
Wie richtig entkoppeln?
Dependencies explizit machen!
Große Systeme, loose Kopplung...
Wie richtig entkoppeln?
Große Systeme, loose Kopplung...
„Dependency Injection is akey element of agile architecture“
Ward Cunningham
Dependency Injection in 5 Slides
Große Systeme, loose Kopplung...
Dependency Injection in 5 Slides
Große Systeme, loose Kopplung...
new MyController(new MyService());
Dependency Injection in 5 Slides
Consumer
Große Systeme, loose Kopplung...
Dependency Injection in 5 Slides
Consumer Dependencies
Große Systeme, loose Kopplung...
Dependency Injection in 5 Slides
Consumer Dependencies Container
Große Systeme, loose Kopplung...
Dependency Injection in 5 Slides
Consumer Dependencies Container
Große Systeme, loose Kopplung...
Dependency Injection – Konfiguration (ein Weg)
Große Systeme, loose Kopplung...
<?xml version="1.0" ?><container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<services><service id="acme.talk.repo"
class="Acme\TalkBundle\Service\TalkRepository" />
<service id="acme.talk.service" class="Acme\TalkBundle\Service\TalkService">
<argument type="service" id="acme.talk.repo" /></service>
</services></container>
Große Systeme, loose Kopplung...
Dependency Injection
„Dependency Injection“ basiert auf „Separation of concerns“.
Große Systeme, loose Kopplung...
Dependency Injection
Und wie hilft mir das nun beim Skalieren?
Große Systeme, loose Kopplung...
Dependency Injection
Loose Kopplung für loose Services
Große Systeme, loose Kopplung...
Dependency Injection – Loose Kooplung<?php
class MyUserService { /** * @var IMyUserRepo */ protected $myUserRepo; public function __construct(
IMyUserRepo $myUserRepo) { $this>myUserRepo = $myUserRepo; } public function readUsers(Filter $filter) {
return $this>myUserRepo>read($filter); }}
Große Systeme, loose Kopplung...
Dependency Injection – Loose Kooplung<?php
interface IMyUserRepo {/** * Liest User aus dem Repository und gibt * diese zurück. * @param Filter $filter * @return array */public function read(Filter $filter);
}
Große Systeme, loose Kopplung...
Dependency Injection – Loose Kooplung<?php
class DBRepo implements IMyUserRepo {/** * @see IMyUserRepo.read() */public function read(Filter $filter);
}
class WebserviceRepo implements IMyUserRepo {/** * @see IMyUserRepo.read() */public function read(Filter $filter);
}
Große Systeme, loose Kopplung...
Merke
Je verteilter, desto skalierbarer!
Große Systeme, loose Kopplung...
Merke
Je verteilter, desto schwerer zu debuggen!
Große Systeme, loose Kopplung...
Merke
Daraus folgt:Je verteilter, desto mehr Log!
Große Systeme, loose Kopplung...
Merke
Performance im Auge behalten!
Große Systeme, loose Kopplung...
Hilfe meine Applikation ist zu groß
Große Systeme, loose Kopplung...
Hilfe meine Applikation ist zu groß
Aufteilung in Module oder (Hilfs-)Bibliotheken
Große Systeme, loose Kopplung...
Hilfe meine Applikation ist zu groß
Bibliothek als Blackbox: Nur Verwenden, Implementierung egal
Dependency Management
Große Systeme, loose Kopplung...
Composer in drei Schritten: 1. Einbinden
Große Systeme, loose Kopplung...
curl -s https://getcomposer.org/installer | php
Composer in drei Schritten: 2. Konfigurieren
Große Systeme, loose Kopplung...
{"require": {
"symfony/translation": "2.1.*","symfony/config": "2.1.*","symfony/yaml": "2.1.*","twig/twig": "1.6.0"
}}
Composer in drei Schritten: 3. Installieren
Große Systeme, loose Kopplung...
php composer.phar install
Composer – Dependencies aktualisieren
Große Systeme, loose Kopplung...
php composer.phar update
Dependency Management
Große Systeme, loose Kopplung...
Große Systeme, loose Kopplung...
Maven - Project Object Model
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd">
<groupId>com.acme</groupId><artifactId>myproject</artifactId><packaging>jar</packaging><version>0.0.1-SNAPSHOT</version><name>My project</name>
</project>
Große Systeme, loose Kopplung...
Maven - Dependencies
<dependencies><dependency>
<groupId>com.zend</groupId><artifactId>framework</artifactId><version>1.11.6-SNAPSHOT</version><type>jar</type><scope>compile</scope>
</dependency></dependencies>
Große Systeme, loose Kopplung...
Maven für PHP?
<pluginRepository><id>release-repo1.php-maven.org</id><name>PHP-Maven 2 Release Repository</name><url>http://repo1.php-maven.org/release</url><releases>
<enabled>true</enabled></releases>
</pluginRepository>
Große Systeme, loose Kopplung...
Maven(3) für PHP?
https://github.com/php-maven
Vielen Dank!