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

Separation of concerns - DPC 12

Joshua Thijssen
June 08, 2012
480

Separation of concerns - DPC 12

Joshua Thijssen

June 08, 2012
Tweet

Transcript

  1. Separation of Concerns

    View full-size slide

  2. Separation of concerns
    About Joshua
     Joshua Thijssen, NoxLogic / Techademy
     Freelance Consultant, Developer, Trainer
     Development in PHP, Python, Perl, C, Java
    [email protected]
     @jaytaph

    View full-size slide

  3. Separation of concerns
    About Stephan
     Stephan Hochdörfer, bitExpert AG
     Department Manager Research Labs
     enjoying PHP since 1999
    [email protected]
     @shochdoerfer

    View full-size slide

  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)

    View full-size slide

  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

    View full-size slide

  6. Separation of concerns
    It`s all about focusing!

    View full-size slide

  7. Separation of concerns
    One step a time. Focus on the details!

    View full-size slide

  8. Separation of concerns
    $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 full-size slide

  9. Separation of concerns
    $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!

    View full-size slide

  10. Separation of concerns
    $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!

    View full-size slide

  11. Separation of concerns
    Very unstable. Not safe for changes....

    View full-size slide

  12. Separation of concerns
    „Make everything as simple as possible...“

    View full-size slide

  13. Separation of concerns
    Establish boundaries

    View full-size slide

  14. Separation of concerns
    What are the boundaries?
    Presentation Layer

    View full-size slide

  15. Separation of concerns
    What are the boundaries?
    Presentation Layer
    Business Layer

    View full-size slide

  16. Separation of concerns
    What are the boundaries?
    Presentation Layer
    Business Layer
    Resource Access Layer

    View full-size slide

  17. Isolate functionality, break it apart!
    Separation of concerns

    View full-size slide

  18. Separation of concerns
    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']);
    }
    }

    View full-size slide

  19. 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);
    }
    }

    View full-size slide

  20. Focus on one responsibility a time!
    Separation of concerns

    View full-size slide

  21. Separation of concerns
    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

    View full-size slide

  22. 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

    View full-size slide

  23. Interfaces as a contract
    Separation of concerns

    View full-size slide

  24. Separation of concerns
    interface ConnectorInterface {
    /**
    * Will return an array of the latest posts.
    * return array
    */
    public function getLatestPosts() {
    }
    }

    View full-size slide

  25. Separation of concerns
    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;
    }
    }

    View full-size slide

  26. Separation of concerns
    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...
    }
    }

    View full-size slide

  27. Separation of concerns
    class FacebookConnectorV2 extends FacebookConnector {
    protected function getAccessToken() {
    return md5($this->handle);
    }
    }
    Easy to extend, will not influence
    the behaviour of other methods!

    View full-size slide

  28. Separation of concerns
    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']);
    }

    View full-size slide

  29. Separation of concerns
    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);
    }
    }

    View full-size slide

  30. Will improve the testability!
    Separation of concerns

    View full-size slide

  31. Will reduce tight coupling!
    Separation of concerns

    View full-size slide

  32. Will increase component reuse!
    Separation of concerns

    View full-size slide

  33. The value of separation
    Why should I do it?
    Separation of concerns

    View full-size slide

  34. The value of separation
    1. Getting rid of code duplication
    Separation of concerns

    View full-size slide

  35. The value of separation
    2. Application becomes more stable
    and easier to understand
    Separation of concerns

    View full-size slide

  36. The value of separation
    3. Single responsibility offers clear
    extension points
    Separation of concerns

    View full-size slide

  37. The value of separation
    4. Increases the reusability of
    components
    Separation of concerns

    View full-size slide

  38. Separation of concerns
    How to separate the concerns?

    View full-size slide

  39. Separation of concerns
    How to separate? Horizontal Separation
    Presentation Layer
    Business Layer
    Resource Access Layer

    View full-size slide

  40. 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

    View full-size slide

  41. Separation of concerns
    How to separate? Service Separation
    Service Interface Layer
    Business Layer
    Resource Access Layer

    View full-size slide

  42. Separation of concerns
    How to separate? Service Separation
    Frontend / UI Webservers
    REST API
    Datastore
    Solr Search Service

    View full-size slide

  43. Separation of concerns
    How to separate? Vertical Separation
    Module A Module B Module C

    View full-size slide

  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

    View full-size slide

  45. 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

    View full-size slide

  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

    View full-size slide

  47. Cross-cutting concerns?
    How to deal with security or logging
    aspects?
    Separation of concerns

    View full-size slide

  48. Separation of concerns
    How to separate? Aspect Separation
    Presentation Layer
    Business Layer
    Resource Access Layer
    Aspects

    View full-size slide

  49. Separation of concerns
    How to separate? Aspect Separation
    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());
    }
    }

    View full-size slide

  50. Separation of concerns
    Dependency Direction

    View full-size slide

  51. Separation of concerns
    Dependency Direction
    "High-level modules should not
    depend on low-level modules.
    Both should depend on
    abstractions."
    Robert C. Martin

    View full-size slide

  52. Separation of concerns
    Inverting Concerns
    Presentation
    Layer
    Business
    Layer
    Resource
    Access Layer

    View full-size slide

  53. Separation of concerns
    Inverting Concerns
    Presentation
    Layer
    Business
    Layer
    Resource
    Access Layer
    Presentation
    Layer
    Business
    Layer
    Resource
    Access Layer
    UI
    Component

    View full-size slide

  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.

    View full-size slide

  55. Separation of concerns
    What are the benefits? Let`s recap....

    View full-size slide

  56. Separation of concerns
    What are the benefits?
    1. Facilitate reusability

    View full-size slide

  57. Separation of concerns
    What are the benefits?
    2. Ensure the maintainability

    View full-size slide

  58. Separation of concerns
    What are the benefits?
    3. Increasing the code quality

    View full-size slide

  59. Separation of concerns
    What are the benefits?
    4. Enables everyone to understand
    the application

    View full-size slide

  60. Separation of concerns
    What are the benefits?
    5. Allows developers to work
    on components in isolation

    View full-size slide

  61. http://joind.in/6244

    View full-size slide