Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Separation of concerns - DPC 12

Joshua Thijssen
June 08, 2012
500

Separation of concerns - DPC 12

Joshua Thijssen

June 08, 2012
Tweet

Transcript

  1. Separation of concerns About Joshua  Joshua Thijssen, NoxLogic /

    Techademy  Freelance Consultant, Developer, Trainer  Development in PHP, Python, Perl, C, Java  [email protected]  @jaytaph
  2. Separation of concerns About Stephan  Stephan Hochdörfer, bitExpert AG

     Department Manager Research Labs  enjoying PHP since 1999  [email protected]  @shochdoerfer
  3. 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)
  4. 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
  5. 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']; }
  6. 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!
  7. 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!
  8. Separation of concerns <?php namespace 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']); } }
  9. 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); } }
  10. Separation of concerns <?php namespace 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
  11. 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
  12. Separation of concerns <?php interface ConnectorInterface { /** * Will

    return an array of the latest posts. * return array */ public function getLatestPosts() { } }
  13. 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; } }
  14. 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... } }
  15. 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!
  16. Separation of concerns <?php namespace 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']); }
  17. Separation of concerns <?php namespace 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); } }
  18. The value of separation 2. Application becomes more stable and

    easier to understand Separation of concerns
  19. 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
  20. Separation of concerns How to separate? Service Separation Frontend /

    UI Webservers REST API Datastore Solr Search Service
  21. 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
  22. Separation of concerns How to separate? Vertical Separation Presentation Layer

    Business Layer Resource Access Layer Presentation Layer Business Layer Resource Access Layer Presentation Layer Business Layer Resource Access Layer
  23. 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
  24. Separation of concerns How to separate? Aspect Separation <?php namespace

    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()); } }
  25. Separation of concerns Dependency Direction "High-level modules should not depend

    on low-level modules. Both should depend on abstractions." Robert C. Martin
  26. Separation of concerns Inverting Concerns Presentation Layer Business Layer Resource

    Access Layer Presentation Layer Business Layer Resource Access Layer UI Component
  27. 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.