Upload
stephan-hochdoerfer
View
1.538
Download
1
Tags:
Embed Size (px)
DESCRIPTION
Citation preview
Separation of Concerns
Separation of concerns
About Joshua
Joshua Thijssen, NoxLogic / Techademy
Freelance Consultant, Developer, Trainer
Development in PHP, Python, Perl, C, Java
@jaytaph
Separation of concerns
About Stephan
Stephan Hochdörfer, bitExpert AG
Department Manager Research Labs
enjoying PHP since 1999
@shochdoerfer
Separation of concerns
It is what I sometimes have called the separation of concerns, which [...] is
yet the only available technique for effective ordering of one's thoughts.
Edsger W. Dijkstra, "On the role of scientific thought" (1974)
Separation of concerns
SoC […] is the process of breaking a computer program into distinct
features that overlap in functionality as little as possible.
http://en.wikipedia.org/wiki/Separation_of_concerns
Separation of concerns
It`s all about focusing!
Separation of concerns
One step a time. Focus on the details!
Separation of concerns
<?php$items = array();$token = file_get_contents("https://graph.facebook.com/oauth/access_token?...");$feed = file_get_contents("https://graph.facebook.com/ident/feed?".$token);$feed = json_decode($feed, true);foreach($feed['data'] as $post) { if('123456789012' === $post['from']['id']) { $items[] = array( 'date' => strtotime($post['created_time']), 'message' => $post['message']); }}
$feed = file_get_contents("http://search.twitter.com/search.json?q=from:ident");$feed = json_decode($feed, true);foreach($feed['results'] as $tweet) { $items[] = array( 'date' => strtotime($tweet['created_at']), 'message' => $tweet['text']);}
foreach($items as $item) { echo $item['message'];}
Separation of concerns
<?php$items = array();$token = file_get_contents("https://graph.facebook.com/oauth/access_token?...");$feed = file_get_contents("https://graph.facebook.com/ident/feed?".$token);$feed = json_decode($feed, true);foreach($feed['data'] as $post) { if('123456789012' === $post['from']['id']) { $items[] = array( 'date' => strtotime($post['created_time']), 'message' => $post['message']); }}
$feed = file_get_contents("http://search.twitter.com/search.json?q=from:ident");$feed = json_decode($feed, true);foreach($feed['results'] as $tweet) { $items[] = array( 'date' => strtotime($tweet['created_at']), 'message' => $tweet['text']);}
foreach($items as $item) { echo $item['message'];}}
Controller part!
Separation of concerns
<?php$items = array();$token = file_get_contents("https://graph.facebook.com/oauth/access_token?...");$feed = file_get_contents("https://graph.facebook.com/ident/feed?".$token);$feed = json_decode($feed, true);foreach($feed['data'] as $post) { if('123456789012' === $post['from']['id']) { $items[] = array( 'date' => strtotime($post['created_time']), 'message' => $post['message']); }}
$feed = file_get_contents("http://search.twitter.com/search.json?q=from:ident");$feed = json_decode($feed, true);foreach($feed['results'] as $tweet) { $items[] = array( 'date' => strtotime($tweet['created_at']), 'message' => $tweet['text']);}
foreach($items as $item) { echo $item['message'];}
View part!
Separation of concerns
Very unstable. Not safe for changes....
Separation of concerns
„Make everything as simple as possible...“
Separation of concerns
Establish boundaries
Separation of concerns
What are the boundaries?
Presentation Layer
Separation of concerns
What are the boundaries?
Presentation Layer
Business Layer
Separation of concerns
What are the boundaries?
Presentation Layer
Business Layer
Resource Access Layer
Isolate functionality, break it apart!
Separation of concerns
Separation of concerns
<?phpnamespace Acme\DemoBundle\Controller;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class DemoController extends Controller { /** * @Route("/", name="_demo") * @Template() */ public function indexAction() {
$items = array();$token = file_get_contents("https://graph.facebook.com/oauth/access_to...");$feed = file_get_contents("https://graph.facebook.com/ident/feed?".$token);$feed = json_decode($feed, true);foreach($feed['data'] as $post) { if('123456789012' === $post['from']['id']) { $items[] = array( 'date' => strtotime($post['created_time']), 'message' => $post['message']); }}
Separation of concerns
$feed = file_get_contents("http://search.twitter.com/search.json?...");$feed = json_decode($feed, true);foreach($feed['results'] as $tweet) { $items[] = array( 'date' => strtotime($tweet['created_at']), 'message' => $tweet['text']);}
return array('items' => $items); }}
Focus on one responsibility a time!
Separation of concerns
Separation of concerns
<?phpnamespace Acme\DemoBundle\Controller;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class DemoController extends Controller { /** * @Route("/", name="_demo") * @Template() */ public function indexAction() {
$items = array();$token = file_get_contents("https://graph.facebook.com/oauth/access_to...");$feed = file_get_contents("https://graph.facebook.com/ident/feed?".$token);$feed = json_decode($feed, true);foreach($feed['data'] as $post) { if('123456789012' === $post['from']['id']) { $items[] = array( 'date' => strtotime($post['created_time']), 'message' => $post['message']); }}
Facebook connector
Separation of concerns
$feed = file_get_contents("http://search.twitter.com/search.json?...");$feed = json_decode($feed, true);foreach($feed['results'] as $tweet) { $items[] = array( 'date' => strtotime($tweet['created_at']), 'message' => $tweet['text']);}
return array('items' => $items); }}
Twitter connector
Interfaces as a contract
Separation of concerns
Separation of concerns
<?phpinterface ConnectorInterface { /** * Will return an array of the latest posts. * return array */ public function getLatestPosts() { }}
Separation of concerns
<?phpclass FacebookConnector implements ConnectorInterface { protected $handle; public function __construct($handle) { $this->handle = $handle; } public function getLatestPosts() { $items = array(); $token = file_get_contents("https://graph.facebook.com/oauth/access..."); $feed = file_get_contents("https://graph.facebook.com/.
$this->handle."/feed?".$token); $feed = json_decode($feed, true); foreach($feed['data'] as $post) { if('123456789012' === $post['from']['id']) {
$items[] = array( 'date' => strtotime($post['created_time']), 'message' => $post['message']);
} } return $items; }}
Separation of concerns
<?phpclass FacebookConnector implements ConnectorInterface { protected $handle; public function __construct($handle) { $this->handle = $handle; } public function getLatestPosts() { $token = $this->getAccessToken(); return $this->readPosts($token); }
protected function getAccessToken() { return file_get_contents("https://graph.facebook.com/oauth/access_?..."); }
protected function readPosts($token) { // read the post, filter all relevant and return them... }}
Separation of concerns
<?phpclass FacebookConnectorV2 extends FacebookConnector {
protected function getAccessToken() { return md5($this->handle); }}
Easy to extend, will not influence the behaviour of other methods!
Separation of concerns
<?phpnamespace Acme\DemoBundle\Controller;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class DemoController extends Controller { /** * @Route("/", name="_demo") * @Template() */ public function indexAction() {
$items = array();$fb = $this->get('FbConnector');$items += $fb->getLatestPosts();
$feed = file_get_contents("http://search.twitter.com/search.json?...");$feed = json_decode($feed, true);foreach($feed['results'] as $tweet) { $items[] = array( 'date' => strtotime($tweet['created_at']), 'message' => $tweet['text']);}
Separation of concerns
<?phpnamespace Acme\DemoBundle\Controller;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class DemoController extends Controller { /** * @Route("/", name="_demo") * @Template() */ public function indexAction() {
$items = array();$fb = $this->get('FbConnector');$items += $fb->getLatestPosts();
$twitter = $this->get('TwitterConnector');$items += $twitter->getLatestPosts();
return array('items' => $items); }}
Will improve the testability!
Separation of concerns
Will reduce tight coupling!
Separation of concerns
Will increase component reuse!
Separation of concerns
The value of separation
Why should I do it?
Separation of concerns
The value of separation
1. Getting rid of code duplication
Separation of concerns
The value of separation
2. Application becomes more stableand easier to understand
Separation of concerns
The value of separation
3. Single responsibility offers clear extension points
Separation of concerns
The value of separation
4. Increases the reusability of components
Separation of concerns
Separation of concerns
How to separate the concerns?
Separation of concerns
How to separate? Horizontal Separation
Presentation Layer
Business Layer
Resource Access Layer
Separation of concerns
How to separate? Horizontal Separation
./symfony |-app |---cache |---config |---Resources |-src |---Acme |-----DemoBundle |-------Controller |-------Resources |---------config |---------public |-----------css |-----------images |---------views |-----------Demo |-----------Welcome |-------Tests |---------Controller |-web
Separation of concerns
How to separate? Service Separation
Service Interface Layer
Business Layer
Resource Access Layer
Separation of concerns
How to separate? Service Separation
Frontend / UI Webservers
REST API
Datastore
Solr Search Service
Separation of concerns
How to separate? Vertical Separation
ModuleA ModuleB ModuleC
Separation of concerns
How to separate? Vertical Separation
./symfony |-app |---cache |---config |---Resources |-src |---Acme |-----AdminBundle |-------Controller |-------Resources |-------Tests |-----ProductsBundle |-------Controller |-------Resources |-------Tests |-----CustomersBundle |-------Controller |-------Resources |-------Tests |-web
Separation of concerns
How to separate? Vertical Separation
PresentationLayer
BusinessLayer
ResourceAccess Layer
PresentationLayer
BusinessLayer
ResourceAccess Layer
PresentationLayer
BusinessLayer
ResourceAccess Layer
Separation of concerns
How to separate? Vertical Separation
./symfony |-app |---cache |---config |---Resources |-src |---Acme |-----AdminBundle |-------Controller |-------Resources |-------Tests |-----ProductsBundle |-------Controller |-------Resources |-------Tests |-----CustomersBundle |-------Controller |-------Resources |-------Tests |-web
Cross-cutting concerns?
How to deal with security or logging aspects?
Separation of concerns
Separation of concerns
How to separate? Aspect Separation
Presentation Layer
Business Layer
Resource Access Layer
Aspects
Separation of concerns
How to separate? Aspect Separation<?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()); }}
Separation of concerns
Dependency Direction
Separation of concerns
Dependency Direction
"High-level modules should not depend on low-level modules.
Both should depend on abstractions."
Robert C. Martin
Separation of concerns
Inverting Concerns
PresentationLayer
BusinessLayer
ResourceAccess Layer
Separation of concerns
Inverting Concerns
PresentationLayer
BusinessLayer
ResourceAccess Layer
PresentationLayer
BusinessLayer
ResourceAccess Layer
UIComponent
Separation of concerns
Inverting Concerns
The goal of Dependency Injection is to separate the concerns of
obtaining the dependencies from the core concerns of a component.
Separation of concerns
What are the benefits? Let`s recap....
Separation of concerns
What are the benefits?
1. Facilitate reusability
Separation of concerns
What are the benefits?
2. Ensure the maintainability
Separation of concerns
What are the benefits?
3. Increasing the code quality
Separation of concerns
What are the benefits?
4. Enables everyone to understand the application
Separation of concerns
What are the benefits?
5. Allows developers to work on components in isolation
Thank you!
http://joind.in/6244