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

BEAR.Sunday (2017)

BEAR.Sunday (2017)

A resource orientated framework using the DI /AOP/REST Triangle

Akihito Koriyama

October 17, 2016
Tweet

More Decks by Akihito Koriyama

Other Decks in Technology

Transcript

  1. A resource orientated framework
    using the DI /AOP/REST Triangle
    BEAR.Sunday (2017)

    View Slide

  2. View Slide

  3. BEAR.Sunday is an application framework.
    But it offers no libraries.
    (We have good stuff)

    View Slide

  4. instead, it offers three object frameworks.

    View Slide

  5. What is framework ?

    View Slide

  6. “imposes a set of design constraints on end-user code.”

    View Slide

  7. View Slide

  8. View Slide

  9. 3.hypermedia framework

    View Slide

  10. DI benefits
    • Dependency inversion principle (DIP)
    • Object instantiation / usage separation

    View Slide

  11. DIP
    • Code should depend on
    things that are at the same
    or higher level of
    abstraction
    • High level policy should not
    depend on low level details

    View Slide

  12. “The principle of dependency inversion is at the
    root of many of the benefits claimed for object-
    oriented technology.
    Its proper application is necessary for the creation
    of reusable frameworks”

    View Slide

  13. Ray.DI
    dependency injection framework

    View Slide

  14. /**
    * @Inject
    */
    public function setRenderer(RenderInterface $renderer)
    {
    ...
    1.annotate at injection point
    class RendererModule extends AbstractModule
    {
    protected function configure()
    {
    $this->bind('RenderInterface')
    ->to('HalRenderer')
    ->in(Scope::SINGLETON);
    }
    $injector = new Injector(new RendererModule);
    2 bind abstraction to concretion
    3.create an injector

    View Slide

  15. /**
    * @Inject
    */
    public function setRenderer(RenderInterface $renderer)
    {
    ...
    1.annotate at injection point
    class RendererModule extends AbstractModule
    {
    protected function configure()
    {
    $this->bind('RenderInterface')
    ->to('HalRenderer')
    ->in(Scope::SINGLETON);
    }
    $injector = new Injector(new RendererModule);
    2. bind abstraction to concretion
    3.create an injector

    View Slide

  16. $injector = new Injector(new HalRendererModule);
    /**
    * @Inject
    */
    public function setRenderer(RenderInterface $renderer)
    {
    ...
    1.annotate at injection point
    class RendererModule extends AbstractModule
    {
    protected function configure()
    {
    $this->bind('RenderInterface')
    ->to('HalRenderer')
    ->in(Scope::SINGLETON);
    }
    2 bind abstraction to concretion
    3.create an injector

    View Slide

  17. $user = $injector->getInstance('UserInterface');

    4. Get the object with dependent
    User Render
    er
    Renderer Interface
    depends
    A
    B

    View Slide

  18. QSPDFEVSBM
    PCKFDUPSJFUOFE
    DPNQJMF
    SVOUJNF
    Implement the structure, not a procedure

    View Slide

  19. class RendererModule extends AbstractModule
    {
    protected function configure()
    {
    $this
    ->bind('RenderInterface')
    ->to('HalRenderer')
    ->in(Scope::SINGLETON);
    }
    }
    Use concrete class only in compile

    View Slide

  20. $renderer = $injector->getInstance('UserInterface');

    Only abstraction in runtime
    /**
    * @Inject
    */
    public function __construct(RenderInterface $renderer)
    {

    View Slide

  21. DI Best practice
    “Your code should deal directly with the Injector
    as little as possible. Instead, you want to bootstrap
    your application by injecting one root object.”

    View Slide

  22. Application = one root object

    View Slide

  23. Application class

    View Slide

  24. View Slide

  25. Application is root object
    retrieved with injector:





    app name
    app context

    View Slide

  26. Application has dependency.

    View Slide

  27. Dependency has dependency
    and so on..
    Object is either contain or belonged

    View Slide

  28. You get a application object graph.
    huge, but can be stored one single root value $app

    View Slide

  29. "QQMJDBUJPODBOCFTFSJBMJ[FE
    $app can be serialized and stored
    Injection is reused beyond requests.

    View Slide

  30. $app
    Object
    i/f
    i/f
    Object
    i/f i/f
    Object
    Router
    Response
    JSON
    XM
    L
    1st framework: DI Framework
    • DI framework w/ binding DSL
    • compile / runtime separation
    • use only “socket” in runtime
    • application is single big one value
    • implement structure, not behavior

    View Slide

  31. Aspect Oriented Programing

    View Slide

  32. What is AOP?
    Cache
    Log
    Auth
    A programming paradigm that aims to increase modularity
    by allowing the separation of cross-cutting concerns

    View Slide

  33. /**
    * @Cacheable
    */

    class Post
    {
    public function onGet($id)
    {
    // ...
    $this->body = $stmt->fetchAll(PDO::FETCH_ASSOC);
    return $this;
    }
    class Post extends AppModel {
    public function newest() {
    $result = Cache::read('newest_posts', 'longterm');
    if (!$result) {
    $result = $this->find('all');
    Cache::write('newest_posts', $result, 'longterm');
    }
    return $result;
    }
    }

    View Slide

  34. M
    C
    I I
    AOP

    View Slide

  35. M
    C
    Cache
    Cache is called by method invocation,

    If the cache is warm the model is never called.
    $obj->read(2);
    Miss !

    View Slide

  36. Aspects
    Core Concern Cross Cutting Concern
    Separation

    View Slide

  37. Rock Concert Example

    View Slide

  38. interface MethodInterceptor
    {
    public function invoke(MethodInvocation $invocation);
    }

    View Slide

  39. class Transactional implements MethodInterceptor
    {
    public function invoke(MethodInvocation $invocation)
    {
    $object = $invocation->getThis();
    $ref = new ReflectionProperty($object, 'db');
    $ref->setAccessible(true);
    $db = $ref->getValue($object);
    $db->beginTransaction();
    try {
    $invocation->proceed();
    $db->commit();
    } catch (Exception $e) {
    $db->rollback();
    }
    }
    }
    Transactional interceptor
    Core Concern
    Cross Cutting Concern

    View Slide

  40. class CacheInterceptor implements MethodInterceptor
    {
    public function invoke(MethodInvocation $invocation)
    {
    $obj = $invocation->getThis();
    $args = $invocation->getArguments();
    $id = get_class($obj) . serialize($args);
    $saved = $this->cache->fetch($id);
    if ($saved) {
    return $saved;
    }
    $result = $invocation->proceed();
    $this->cache->save($id, $result);
    return $result;
    }
    }
    Core Concern
    Cross Cutting Concern
    Cache interceptor

    View Slide

  41. 4JNQMZBOOPUBUF
    UIFODSFBUFZPVSCJOEJOH
    #JOE

    View Slide

  42. Layering by context
    • MVC, Is 3 enough ?

    View Slide

  43. API
    Client

    View Slide

  44. API Log
    Client Valid Auth

    View Slide

  45. API Log
    !7BMJE
    BENJO %&-&5&
    Client Valid Auth

    View Slide

  46. Aspect layering by context
    Model
    Cache
    Form
    Transaction
    Auth
    Validation

    View Slide

  47. class SandboxResourcePageIndexRay0000000071f9ab280000000033fb446fAop extends
    Sandbox\Resource\Page\Index implements Ray\Aop\WeavedInterface
    {
    private $rayAopIntercept = true;
    public $rayAopBind;
    public function onGet()
    {
    // native call
    if (!isset($this->rayAopBind[__FUNCTION__])) {
    return call_user_func_array('parent::' . __FUNCTION__, func_get_args());
    }
    // proceed source method from interceptor
    if (!$this->rayAopIntercept) {
    $this->rayAopIntercept = true;
    return call_user_func_array('parent::' . __FUNCTION__, func_get_args());
    }
    // proceed next interceptor
    $this->rayAopIntercept = false;
    $interceptors = $this->rayAopBind[__FUNCTION__];
    $annotation = isset($this->rayAopBind->annotation[__FUNCTION__]) ? $this->rayAopBind
    >annotation[__FUNCTION__] : null;
    $invocation = new \Ray\Aop\ReflectiveMethodInvocation(array($this, __FUNCTION__),
    func_get_args(), $interceptors, $annotation);
    return $invocation->proceed();
    }
    Under the hood: Method interception sub class is created
    in order enable this interception and keep type safety.

    View Slide

  48. Runtime injection by aspect
    • method / parameter lookup
    • test friendly

    View Slide

  49. 2nd framework: Aspect Oriented Framework
    • AOP alliance standard
    • Layering by context
    • Type safe
    • Runtime injection

    View Slide

  50. View Slide

  51. Hypermedia framework for object as a service
    It allows objects to have RESTful web service benefits
    such as client-server, uniform interface, statelessness,
    resource expression with mutual connectivity and
    layered components.

    View Slide

  52. CLI
    Web

    View Slide

  53. Embedded Resource

    View Slide

  54. View Slide

  55. Linked Resource

    View Slide

  56. View Slide

  57. View Slide

  58. Web Context Parameter

    View Slide

  59. Resource Parameter

    View Slide

  60. https://www.infoq.com/jp/articles/webber-rest-workflow
    Figure1 The Customer State Machine
    Figure 2 The Barista's State Machine
    Hypermedia as the Engine of Application State

    View Slide

  61. Hypermedia as the Engine of Application State

    View Slide

  62. Order Payment
    hyper reference: payment
    Hypermedia Driven API

    View Slide

  63. Content-Type: application/hal+json

    View Slide

  64. https://www.infoq.com/jp/news/2014/03/amazon-hal-appstream

    View Slide

  65. The key of success of web
    • URI
    • Unified Interface
    • Hyperlink

    View Slide

  66. • API is hub
    • API is core value
    API driven development
    DB Mobil
    e
    Web
    API
    Cloud
    Moc
    k
    URI
    API
    API

    View Slide

  67. http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html

    View Slide

  68. Layered Resource
    UI
    Mobile
    Web
    Page Resource
    App script
    App Resource
    Entity

    View Slide

  69. View Slide

  70. View Slide

  71. 1. Entry file

    View Slide

  72. 2. Application script
    ᶃ create root object with context
    ᶄ 304 ?
    ᶅ create request
    ᶆ invoke request
    ᶇ transfer

    View Slide

  73. 3. Resource state

    View Slide

  74. 3. Representation state transfer

    View Slide

  75. Performance
    • annotation ? dependency injection ? 

    method interception ? DSL ? named parameter ?
    • Fast
    • cache all compiled object
    • generate raw factory code
    • http friendly architecture

    View Slide

  76. Scale
    • “model proxy” pattern
    • ‘app://self/blog/entry’ can be anything.
    • contextual injection makes db scale easy
    • assisted injection

    View Slide

  77. Hard spot / Soft spot
    • DI configure hard spot. QFSTZTUFN
    • Aop configure softspot, change on request


    View Slide

  78. Connecting frameworks
    • DI - object as dependency
    • AOP - domain logic to application logic
    • Hypermedia - resource to resource

    View Slide

  79. Abstraction frameworks
    • DSL
    • Annotation
    • URI
    • Interface
    • Aspects
    • Hypermedia

    View Slide

  80. AOP (Gregor Kiczales) DI (Martin Fowler) REST (Roy Fielding)
    OOP (Allan Kay) Annotation (Anders Hejlsberg) Guice (Bob Lee)

    View Slide

  81. View Slide

  82. “Zen” framework

    View Slide

  83. Thanks.
    http://www.flickr.com/photos/stevehoad/4678289858/
    @mackstar
    @koriym

    View Slide