2. Separation of concerns
About Joshua
Joshua Thijssen, NoxLogic / Techademy
Freelance Consultant, Developer, Trainer
Development in PHP, Python, Perl, C, Java
jthijssen@noxlogic.nl
@jaytaph
3. Separation of concerns
About Stephan
Stephan Hochdörfer, bitExpert AG
Department Manager Research Labs
enjoying PHP since 1999
S.Hochdoerfer@bitExpert.de
@shochdoerfer
4. 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)
5. 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
24. Separation of concerns
<?php
interface ConnectorInterface {
/**
* Will return an array of the latest posts.
* return array
*/
public function getLatestPosts() {
}
}
25. Separation of concerns
<?php
class 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;
}
}
26. Separation of concerns
<?php
class 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...
}
}
27. Separation of concerns
<?php
class FacebookConnectorV2 extends FacebookConnector {
protected function getAccessToken() {
return md5($this->handle);
}
}
Easy to extend, will not influence
the behaviour of other methods!
28. Separation of concerns
<?php
namespace AcmeDemoBundleController;
use SymfonyBundleFrameworkBundleControllerController;
use SensioBundleFrameworkExtraBundleConfigurationRoute;
use SensioBundleFrameworkExtraBundleConfigurationTemplate;
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']);
}
29. Separation of concerns
<?php
namespace AcmeDemoBundleController;
use SymfonyBundleFrameworkBundleControllerController;
use SensioBundleFrameworkExtraBundleConfigurationRoute;
use SensioBundleFrameworkExtraBundleConfigurationTemplate;
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);
}
}
44. 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
45. Separation of concerns
How to separate? Vertical Separation
Presentation Presentation Presentation
Layer Layer Layer
Business Business Business
Layer Layer Layer
Resource Resource Resource
Access Layer Access Layer Access Layer
46. 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
47. Separation of concerns
Cross-cutting concerns?
How to deal with security or logging
aspects?
48. Separation of concerns
How to separate? Aspect Separation
Aspects
Presentation Layer
Business Layer
Resource Access Layer
49. Separation of concerns
How to separate? Aspect Separation
<?php
namespace AcmeProductsAspects;
/**
* @FLOW3Aspect
*/
class LoggingAspect {
/**
* @FLOW3Inject
* @var AcmeLoggerLoggerInterface
*/
protected $logger;
/**
* @param TYPO3FLOW3AOPJoinPointInterface $joinPoint
* @FLOW3Before("method(AcmeProductsModelProduct->delete())")
*/
public function log(TYPO3FLOW3AOPJoinPointInterface $jp) {
$product = $jp->getMethodArgument('product');
$this->logger->info('Removing ' .
$product->getName());
}
}
51. Separation of concerns
Dependency Direction
"High-level modules should not
depend on low-level modules.
Both should depend on
abstractions."
Robert C. Martin
52. Separation of concerns
Inverting Concerns
Presentation
Layer
Business
Layer
Resource
Access Layer
53. Separation of concerns
Inverting Concerns
Presentation UI Presentation
Layer Component Layer
Business Business
Layer Layer
Resource Resource
Access Layer Access Layer
54. 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.