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

JavaScript application frameworks: the parts

JavaScript application frameworks: the parts

Nuts and bolts of JS application frameworks: how to write tools for messaging, extending objects, and changing state; how to safely integrate DOM or utility libraries and plugins; how to integrate CSS and templates; how to connect all the pieces; how to apply that knowledge to choosing an existing framework.

Garann Means

May 29, 2013
Tweet

More Decks by Garann Means

Other Decks in Technology

Transcript

  1. JavaScript
    Application
    Frameworks
    the parts
    |
    Garann Means @garannm

    View Slide

  2. in applications and frameworks, the code
    is the easy part
    the hard part is decision
    making

    View Slide

  3. and it is hard to build an app
    figuring out what it should do
    translating requirements to workflows
    making it all work together
    (even when you have good tools)

    View Slide

  4. any framework may need customization
    a framework is a basis
    your app may have slightly different needs
    different ways of handling the same concept may
    exist within the same app
    it may have no opinion on other concepts

    View Slide

  5. compare to jQuery:
    tons of functionality
    some core, some more esoteric
    discovering new features leads to better ways of
    doing things
    the most discoverable features are those we know
    should be there

    View Slide

  6. using a tool well means understanding
    the decisions it makes, and making good
    decisions about how to use it

    View Slide

  7. what should be there
    and what we should expect from it

    View Slide

  8. we expect framework methods to live on a
    prototype
    unlike a library, whose methods should usually not
    require an instance
    allows creation of objects set up to work together
    instantiation lets us keep related functionality
    together

    View Slide

  9. but we also need methods for the app
    containing the objects
    global initialization
    event broadcasting
    global state changes
    stateless utilities

    View Slide

  10. so it makes sense to start with a global
    ( f
    u
    n
    c
    t
    i
    o
    n
    ( F
    r
    m
    w
    r
    k ) {
    f
    u
    n
    c
    t
    i
    o
    n _
    i
    n
    i
    t
    (
    ) {
    }
    F
    r
    m
    w
    r
    k
    .
    t
    e
    s
    t = f
    u
    n
    c
    t
    i
    o
    n
    (
    ) {
    c
    o
    n
    s
    o
    l
    e
    .
    l
    o
    g
    ( "
    y
    u
    p
    " )
    ;
    }
    ;
    _
    i
    n
    i
    t
    (
    )
    ;
    }
    )
    ( w
    i
    n
    d
    o
    w
    .
    F
    r
    m
    w
    r
    k = {
    } )
    ;
    F
    r
    m
    w
    r
    k
    .
    t
    e
    s
    t
    (
    )
    ; /
    / y
    u
    p

    View Slide

  11. so thatG
    s nice.
    but it should do something

    View Slide

  12. we were going to instantiate some objects
    state
    data
    or both
    we don't want to have to create too many types

    View Slide

  13. one object we know we need
    f
    u
    n
    c
    t
    i
    o
    n _
    i
    n
    i
    t
    (
    ) {
    F
    r
    m
    w
    r
    k
    .
    a
    p
    p = n
    e
    w F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t
    (
    )
    ;
    }

    View Slide

  14. so letG
    s make that the default
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t = f
    u
    n
    c
    t
    i
    o
    n ( o
    b
    j ) {
    $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , t
    h
    i
    s
    , {
    s
    e
    l
    : "
    b
    o
    d
    y
    "
    }
    , o
    b
    j )
    ;
    i
    f ( t
    h
    i
    s
    .
    s
    e
    l ) {
    t
    h
    i
    s
    .
    e
    l = $
    ( t
    h
    i
    s
    .
    s
    e
    l )
    ;
    }
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    ;
    }
    ;

    View Slide

  15. hold up..
    whose $ is that

    View Slide

  16. utility libraries
    it's also good to understand libraries
    but this is not a talk on libraries
    make a smart choice providing the most you need
    but no more
    jQuery, Underscore, Zepto, etc.
    focus on connecting pieces, not writing essential
    tools

    View Slide

  17. including third-party libraries or tools
    can be appended to your core file
    other users don't need to import the additional script
    difficult to change or upgrade
    may conflict with other versions in use

    View Slide

  18. leaving it up to implementers
    other users need to import the script separately, in
    order
    framework should work with all supported versions
    may make sense to allow uses of library to be
    overriden

    View Slide

  19. a note about dependencies

    View Slide

  20. in this example, jQuery is used like so:
    ( f
    u
    n
    c
    t
    i
    o
    n
    ( F
    r
    m
    w
    r
    k
    , $ ) {
    .
    .
    .
    }
    )
    ( w
    i
    n
    d
    o
    w
    .
    F
    r
    m
    w
    r
    k = {
    }
    , w
    i
    n
    d
    o
    w
    .
    j
    Q
    u
    e
    r
    y )
    ;

    View Slide

  21. for a more modular approach, you might
    use require.js
    d
    e
    f
    i
    n
    e
    ( [ "
    j
    Q
    u
    e
    r
    y
    " ]
    , f
    u
    n
    c
    t
    i
    o
    n
    ( $ ) {
    .
    .
    .
    }
    )
    ;

    View Slide

  22. letG
    s get back to our base object
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t = f
    u
    n
    c
    t
    i
    o
    n ( o
    b
    j ) {
    $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , t
    h
    i
    s
    , {
    s
    e
    l
    : "
    b
    o
    d
    y
    "
    }
    , o
    b
    j )
    ;
    i
    f ( t
    h
    i
    s
    .
    s
    e
    l ) {
    t
    h
    i
    s
    .
    e
    l = $
    ( t
    h
    i
    s
    .
    s
    e
    l )
    ;
    }
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    ;
    }
    ;

    View Slide

  23. what do we expect from a data object
    a place to store data
    the ability to save and update itself
    notifications if it changes

    View Slide

  24. setting and changing data
    ideally, set on object creation
    but may need to be set on an empty object (like the
    app)
    should be possible to update one or more properties

    View Slide

  25. the data should be its own object
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t = f
    u
    n
    c
    t
    i
    o
    n ( o
    b
    j ) {
    $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , t
    h
    i
    s
    , {
    s
    e
    l
    : "
    b
    o
    d
    y
    "
    ,
    d
    a
    t
    a
    : {
    }
    }
    , o
    b
    j )
    ;
    i
    f ( t
    h
    i
    s
    .
    s
    e
    l ) {
    t
    h
    i
    s
    .
    e
    l = $
    ( t
    h
    i
    s
    .
    s
    e
    l )
    ;
    }
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    ;
    }
    ;

    View Slide

  26. we want control over how thatG
    s updated
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    s
    e
    t = _
    s
    e
    t = f
    u
    n
    c
    t
    i
    o
    n
    ( d
    a
    t
    a
    , v
    a
    l ) {
    i
    f ( t
    y
    p
    e
    o
    f d
    a
    t
    a =
    = "
    s
    t
    r
    i
    n
    g
    " ) {
    t
    h
    i
    s
    .
    d
    a
    t
    a
    [ d
    a
    t
    a ] = v
    a
    l
    ;
    } e
    l
    s
    e {
    f
    o
    r ( k
    e
    y i
    n d
    a
    t
    a ) {
    t
    h
    i
    s
    .
    d
    a
    t
    a
    [ k
    e
    y ] = d
    a
    t
    a
    [ k
    e
    y ]
    ;
    }
    }
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    ;
    }
    ;

    View Slide

  27. and a shortcut for the app itself
    F
    r
    m
    w
    r
    k
    .
    s
    e
    t = f
    u
    n
    c
    t
    i
    o
    n
    (
    ) {
    _
    s
    e
    t
    .
    a
    p
    p
    l
    y
    ( F
    r
    m
    w
    r
    k
    .
    a
    p
    p
    , a
    r
    g
    u
    m
    e
    n
    t
    s )
    ;
    }
    ;

    View Slide

  28. why not just have the implementer modify
    ÇobjÓ.data directly
    this is a cheap workaround to observing the objects
    can fire off events, update server
    allows for a predictable pattern
    allows us to do a little magic

    View Slide

  29. the downside is it means we also need a
    way to get data
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    g
    e
    t = _
    g
    e
    t = f
    u
    n
    c
    t
    i
    o
    n
    ( k
    e
    y ) {
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    .
    d
    a
    t
    a
    [ k
    e
    y ]
    ;
    }
    ;
    F
    r
    m
    w
    r
    k
    .
    g
    e
    t = f
    u
    n
    c
    t
    i
    o
    n
    (
    ) {
    r
    e
    t
    u
    r
    n _
    g
    e
    t
    .
    a
    p
    p
    l
    y
    ( F
    r
    m
    w
    r
    k
    .
    a
    p
    p
    , a
    r
    g
    u
    m
    e
    n
    t
    s )
    ;
    }
    ;

    View Slide

  30. we could also condense the two, jQuery-
    style
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    d
    a
    t
    a = _
    d
    a
    t
    a = f
    u
    n
    c
    t
    i
    o
    n
    ( d
    a
    t
    a
    , v
    a
    l ) {
    i
    f ( a
    r
    g
    u
    m
    e
    n
    t
    s
    .
    l
    e
    n
    g
    t
    h =
    = 1 &
    & t
    y
    p
    e
    o
    f d
    a
    t
    a =
    = "
    s
    t
    r
    i
    n
    g
    " ) {
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    .
    d
    a
    t
    a
    [ k
    e
    y ]
    ;
    } e
    l
    s
    e {
    .
    .
    .
    }
    ;

    View Slide

  31. once we have data, we have something to
    store
    data persistence tends to be boring to write
    we need several types of XHRs
    we want saving and updating to be as invisible as
    possible

    View Slide

  32. should we assume REST
    depends very much on your backend
    may be more JavaScripty to do CRUD from all
    endpoints:
    data with no ID: create
    ID only: read
    data and ID: update
    ID and string or number: delete
    but only if that fits the larger architecture

    View Slide

  33. letG
    s assume it does
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t = f
    u
    n
    c
    t
    i
    o
    n ( o
    b
    j ) {
    $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , t
    h
    i
    s
    , {
    s
    e
    l
    : "
    b
    o
    d
    y
    "
    ,
    d
    a
    t
    a
    : {
    }
    ,
    e
    n
    d
    p
    o
    i
    n
    t
    : n
    u
    l
    l
    }
    , o
    b
    j )
    ;
    i
    f ( t
    h
    i
    s
    .
    s
    e
    l ) {
    t
    h
    i
    s
    .
    e
    l = $
    ( t
    h
    i
    s
    .
    s
    e
    l )
    ;
    }
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    ;
    }
    ;

    View Slide

  34. we want to sync whenever an update
    happens
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    s
    e
    t = _
    s
    e
    t = f
    u
    n
    c
    t
    i
    o
    n
    ( d
    a
    t
    a
    , v
    a
    l ) {
    i
    f ( t
    y
    p
    e
    o
    f d
    a
    t
    a =
    = "
    s
    t
    r
    i
    n
    g
    " ) {
    t
    h
    i
    s
    .
    d
    a
    t
    a
    [ d
    a
    t
    a ] = v
    a
    l
    ;
    } e
    l
    s
    e {
    f
    o
    r ( k
    e
    y i
    n d
    a
    t
    a ) {
    t
    h
    i
    s
    .
    d
    a
    t
    a
    [ k
    e
    y ] = d
    a
    t
    a
    [ k
    e
    y ]
    ;
    }
    }
    i
    f ( t
    h
    i
    s
    .
    e
    n
    d
    p
    o
    i
    n
    t ) {
    t
    h
    i
    s
    .
    s
    y
    n
    c
    (
    )
    ;
    }
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    ;
    }
    ;

    View Slide

  35. additionally, we want explicit
    methods to delete or read an
    object
    please use your imagination for those
    Nremember that thing about CRUD being boring Ñ

    View Slide

  36. then, of course, we need a function to do
    the work
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    s
    y
    n
    c = f
    u
    n
    c
    t
    i
    o
    n
    ( d
    a
    t
    a
    , c
    m
    d ) {
    v
    a
    r i
    d = t
    y
    p
    e
    o
    f d
    a
    t
    a =
    = "
    n
    u
    m
    b
    e
    r
    " ? d
    a
    t
    a : u
    n
    d
    e
    f
    i
    n
    e
    d
    ,
    t
    h
    a
    t = t
    h
    i
    s
    ;
    $
    .
    p
    o
    s
    t
    ( t
    h
    i
    s
    .
    e
    n
    d
    p
    o
    i
    n
    t
    ,
    {
    i
    d
    : d
    a
    t
    a
    .
    i
    d |
    | i
    d
    ,
    c
    o
    m
    m
    a
    n
    d
    : c
    m
    d
    ,
    d
    a
    t
    a
    : i
    d ? u
    n
    d
    e
    f
    i
    n
    e
    d : d
    a
    t
    a
    }
    ,
    f
    u
    n
    c
    t
    i
    o
    n
    ( r
    e
    s ) {
    i
    f ( t
    y
    p
    e
    o
    f r
    e
    s =
    = "
    n
    u
    m
    b
    e
    r
    " ) {
    t
    h
    a
    t
    .
    d
    a
    t
    a
    .
    i
    d = r
    e
    s
    ;
    } e
    l
    s
    e i
    f ( r
    e
    s
    .
    i
    d ) {
    f
    o
    r ( k
    e
    y i
    n r
    e
    s ) {
    t
    h
    a
    t
    .
    d
    a
    t
    a
    [ k
    e
    y ] = d
    a
    t
    a
    [ k
    e
    y ]
    ;
    }
    }

    View Slide

  37. several decisions reflected there
    not RESTful, as discussed
    flexible signature for a single method without explicit
    flags
    most important: happens in the background

    View Slide

  38. weG
    ve been talking about objects
    but we want those objects to talk to a
    framework

    View Slide

  39. it would be nice to have notifications
    when object data is set
    when the data is synced with the server
    if an error occurs anywhere along the way

    View Slide

  40. messaging options
    document-level DOM events
    super-basic pub/sub
    promises
    third-party utilities with multiple options

    View Slide

  41. these are all legit.
    but weG
    re going to use the simplest

    View Slide

  42. we want events to be scoped to objects
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t = f
    u
    n
    c
    t
    i
    o
    n ( o
    b
    j ) {
    $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , t
    h
    i
    s
    , {
    s
    e
    l
    : "
    b
    o
    d
    y
    "
    ,
    d
    a
    t
    a
    : {
    }
    ,
    e
    n
    d
    p
    o
    i
    n
    t
    : n
    u
    l
    l
    ,
    e
    v
    e
    n
    t
    s
    : {
    }
    }
    , o
    b
    j )
    ;
    i
    f ( t
    h
    i
    s
    .
    s
    e
    l ) {
    t
    h
    i
    s
    .
    e
    l = $
    ( t
    h
    i
    s
    .
    s
    e
    l )
    ;
    }
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    ;
    }
    ;

    View Slide

  43. weG
    ll manage that cache with three
    methods
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    p
    u
    b = _
    p
    u
    b = f
    u
    n
    c
    t
    i
    o
    n
    ( n
    a
    m
    e
    , a
    r
    g
    s ) {
    v
    a
    r t
    h
    a
    t = t
    h
    i
    s
    ;
    i
    f ( t
    h
    i
    s
    .
    e
    v
    e
    n
    t
    s
    [ n
    a
    m
    e ] ) {
    $
    .
    e
    a
    c
    h
    ( t
    h
    i
    s
    .
    e
    v
    e
    n
    t
    s
    [ n
    a
    m
    e ]
    , f
    u
    n
    c
    t
    i
    o
    n
    (
    ) {
    t
    h
    i
    s
    .
    a
    p
    p
    l
    y
    ( t
    h
    a
    t
    , a
    r
    g
    s |
    | [
    ] )
    ;
    }
    )
    ;
    }
    }
    ;
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    s
    u
    b = _
    s
    u
    b = f
    u
    n
    c
    t
    i
    o
    n
    ( n
    a
    m
    e
    , c
    a
    l
    l
    b
    a
    c
    k ) {
    i
    f ( !
    t
    h
    i
    s
    .
    e
    v
    e
    n
    t
    s
    [ n
    a
    m
    e ] ) {
    t
    h
    i
    s
    .
    e
    v
    e
    n
    t
    s
    [ n
    a
    m
    e ] = [
    ]
    ;
    }
    t
    h
    i
    s
    .
    e
    v
    e
    n
    t
    s
    [ n
    a
    m
    e ]
    .
    p
    u
    s
    h
    ( c
    a
    l
    l
    b
    a
    c
    k )
    ;
    r
    e
    t
    u
    r
    n [ n
    a
    m
    e
    , c
    a
    l
    l
    b
    a
    c
    k ]
    ;
    }
    ;
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    u
    n
    s
    u
    b = _
    u
    n
    s
    u
    b = f
    u
    n
    c
    t
    i
    o
    n
    ( h
    a
    n
    d
    l
    e ) {
    v
    a
    r e
    v
    t
    s = t
    h
    i
    s
    .
    e
    v
    e
    n
    t
    s
    [ h
    a
    n
    d
    l
    e
    [ 0 ] ]
    ,
    hat tip to Pete Higgins

    View Slide

  44. now when something happens, we can
    publish an event
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    s
    e
    t = _
    s
    e
    t = f
    u
    n
    c
    t
    i
    o
    n
    ( d
    a
    t
    a
    , v
    a
    l ) {
    i
    f ( t
    y
    p
    e
    o
    f d
    a
    t
    a =
    = "
    S
    t
    r
    i
    n
    g
    " ) {
    t
    h
    i
    s
    .
    d
    a
    t
    a
    [ d
    a
    t
    a ] = v
    a
    l
    ;
    } e
    l
    s
    e {
    f
    o
    r ( k
    e
    y i
    n d
    a
    t
    a ) {
    t
    h
    i
    s
    .
    d
    a
    t
    a
    [ k
    e
    y ] = d
    a
    t
    a
    [ k
    e
    y ]
    ;
    }
    }
    t
    h
    i
    s
    .
    p
    u
    b
    ( "
    u
    p
    d
    a
    t
    e
    d
    "
    , t
    h
    i
    s
    .
    d
    a
    t
    a )
    ;
    i
    f ( t
    h
    i
    s
    .
    e
    n
    d
    p
    o
    i
    n
    t ) {
    t
    h
    i
    s
    .
    s
    y
    n
    c
    (
    )
    ;
    }
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    ;
    }
    ;

    View Slide

  45. or if the wrong thing happens, we can
    notify observers of the error
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    s
    y
    n
    c = f
    u
    n
    c
    t
    i
    o
    n
    ( d
    a
    t
    a
    , c
    m
    d ) {
    v
    a
    r i
    d = t
    y
    p
    e
    o
    f d
    a
    t
    a =
    = "
    n
    u
    m
    b
    e
    r
    " ? d
    a
    t
    a : u
    n
    d
    e
    f
    i
    n
    e
    d
    ,
    t
    h
    a
    t = t
    h
    i
    s
    ;
    $
    .
    p
    o
    s
    t
    ( t
    h
    i
    s
    .
    e
    n
    d
    p
    o
    i
    n
    t
    ,
    {
    i
    d
    : d
    a
    t
    a
    .
    i
    d |
    | i
    d |
    | u
    n
    d
    e
    f
    i
    n
    e
    d
    ,
    c
    o
    m
    m
    a
    n
    d
    : c
    m
    d |
    | u
    n
    d
    e
    f
    i
    n
    e
    d
    ,
    d
    a
    t
    a
    : i
    d ? u
    n
    d
    e
    f
    i
    n
    e
    d : d
    a
    t
    a
    }
    ,
    f
    u
    n
    c
    t
    i
    o
    n
    ( r
    e
    s ) {
    i
    f ( t
    y
    p
    e
    o
    f r
    e
    s =
    = "
    n
    u
    m
    b
    e
    r
    " ) {
    t
    h
    a
    t
    .
    d
    a
    t
    a
    .
    i
    d = r
    e
    s
    ;
    } e
    l
    s
    e i
    f ( r
    e
    s
    .
    i
    d ) {
    f
    o
    r ( k
    e
    y i
    n r
    e
    s ) {
    t
    h
    a
    t
    .
    d
    a
    t
    a
    [ k
    e
    y ] = d
    a
    t
    a
    [ k
    e
    y ]
    ;
    }
    }

    View Slide

  46. global events can be scoped to the app
    F
    r
    m
    w
    r
    k
    .
    p
    u
    b = f
    u
    n
    c
    t
    i
    o
    n
    (
    ) {
    _
    p
    u
    b
    .
    a
    p
    p
    l
    y
    ( F
    r
    m
    w
    r
    k
    .
    a
    p
    p
    , a
    r
    g
    u
    m
    e
    n
    t
    s )
    ;
    }
    ;
    F
    r
    m
    w
    r
    k
    .
    s
    u
    b = f
    u
    n
    c
    t
    i
    o
    n
    (
    ) {
    r
    e
    t
    u
    r
    n _
    s
    u
    b
    .
    a
    p
    p
    l
    y
    ( F
    r
    m
    w
    r
    k
    .
    a
    p
    p
    , a
    r
    g
    u
    m
    e
    n
    t
    s )
    ;
    }
    ;
    F
    r
    m
    w
    r
    k
    .
    u
    n
    s
    u
    b = f
    u
    n
    c
    t
    i
    o
    n
    (
    ) {
    _
    u
    n
    s
    u
    b
    .
    a
    p
    p
    l
    y
    ( F
    r
    m
    w
    r
    k
    .
    a
    p
    p
    , a
    r
    g
    u
    m
    e
    n
    t
    s )
    ;
    }
    ;

    View Slide

  47. notifications as an implementer
    controllers, presenters, viewmodels
    ideally, publishing events controlled by framework
    implementations merely listen
    but we have events we don't control coming from
    the DOM

    View Slide

  48. connecting to the view

    View Slide

  49. a JS framework should be decoupled from
    HTML and CSS
    maintainability
    modularity
    separation of concerns
    not using JS for things that don't require it

    View Slide

  50. note: this is JS frameworks
    client-side frameworks may be more
    tightly coupled, and do more view stuff

    View Slide

  51. elements of the view
    templates
    CSS
    DOM listeners
    potentially a data transformation layer

    View Slide

  52. an object might have more than one view,
    though
    for that we need states

    View Slide

  53. a new object type
    F
    r
    m
    w
    r
    k
    .
    S
    t
    a
    t
    e = f
    u
    n
    c
    t
    i
    o
    n
    ( o
    b
    j ) {
    $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , t
    h
    i
    s
    , {
    p
    a
    r
    e
    n
    t
    : F
    r
    m
    w
    r
    k
    .
    a
    p
    p
    ,
    t
    m
    p
    l
    : n
    u
    l
    l
    ,
    s
    e
    t
    t
    i
    n
    g
    s
    : {
    }
    ,
    c
    a
    l
    l
    b
    a
    c
    k
    : n
    u
    l
    l
    }
    , o
    b
    j )
    ;
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    ;
    }
    ;

    View Slide

  54. tied to the generic object
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t = f
    u
    n
    c
    t
    i
    o
    n ( o
    b
    j ) {
    $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , t
    h
    i
    s
    , {
    s
    e
    l
    : "
    b
    o
    d
    y
    "
    ,
    d
    a
    t
    a
    : {
    }
    ,
    e
    n
    d
    p
    o
    i
    n
    t
    : n
    u
    l
    l
    ,
    e
    v
    e
    n
    t
    s
    : {
    }
    ,
    s
    t
    a
    t
    e
    s
    : {
    }
    }
    , o
    b
    j )
    ;
    i
    f ( t
    h
    i
    s
    .
    s
    e
    l ) {
    t
    h
    i
    s
    .
    e
    l = $
    ( t
    h
    i
    s
    .
    s
    e
    l )
    ;
    }
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    ;
    }
    ;

    View Slide

  55. child objects force us to think about
    initialization
    we want implementers to be able to pass in literals
    but we want instances that can have prototype
    methods
    our options are:
    1. force states to be added explicitly
    2. filter states supplied on initialization

    View Slide

  56. this is a place where itG
    s nice to do some
    magic
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t = f
    u
    n
    c
    t
    i
    o
    n ( o
    b
    j ) {
    $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , t
    h
    i
    s
    , {
    s
    e
    l
    : "
    b
    o
    d
    y
    "
    ,
    d
    a
    t
    a
    : {
    }
    ,
    e
    n
    d
    p
    o
    i
    n
    t
    : n
    u
    l
    l
    ,
    e
    v
    e
    n
    t
    s
    : {
    }
    ,
    s
    t
    a
    t
    e
    s
    : {
    }
    }
    , o
    b
    j )
    ;
    i
    f ( t
    h
    i
    s
    .
    s
    e
    l ) {
    t
    h
    i
    s
    .
    e
    l = $
    ( t
    h
    i
    s
    .
    s
    e
    l )
    ;
    }
    f
    o
    r
    ( v
    a
    r s i
    n t
    h
    i
    s
    .
    s
    t
    a
    t
    e
    s ) {
    i
    f ( !
    t
    h
    i
    s
    .
    s
    t
    a
    t
    e
    s
    [ s ] i
    n
    s
    t
    a
    n
    c
    e
    o
    f F
    r
    m
    w
    r
    k
    .
    S
    t
    a
    t
    e ) {
    t
    h
    i
    s
    .
    s
    t
    a
    t
    e
    s
    [ s ] = n
    e
    w F
    r
    m
    w
    r
    k
    .
    S
    t
    a
    t
    e
    ( t
    h
    i
    s
    .
    s
    t
    a
    t
    e
    s
    [ s ] )
    ;
    }
    }

    View Slide

  57. once we have states we can switch between
    them
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    s
    t
    a
    t
    e = _
    s
    t
    a
    t
    e = f
    u
    n
    c
    t
    i
    o
    n
    ( n
    a
    m
    e ) {
    i
    f ( !
    n
    a
    m
    e ) {
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    .
    _
    c
    u
    r
    r
    e
    n
    t
    S
    t
    a
    t
    e =
    = "
    _
    d
    e
    f
    a
    u
    l
    t
    " ? n
    u
    l
    l : t
    h
    i
    s
    .
    _
    c
    u
    r
    r
    e
    n
    t
    S
    t
    a
    t
    e
    }
    i
    f ( t
    h
    i
    s
    .
    s
    t
    a
    t
    e
    s
    [ n
    a
    m
    e ] ) {
    t
    h
    i
    s
    .
    s
    t
    a
    t
    e
    s
    [ n
    a
    m
    e ]
    .
    r
    e
    n
    d
    e
    r
    (
    )
    ;
    t
    h
    i
    s
    .
    _
    c
    u
    r
    r
    e
    n
    t
    S
    t
    a
    t
    e = n
    a
    m
    e
    ;
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    .
    s
    t
    a
    t
    e
    s
    [ n
    a
    m
    e ]
    ;
    }
    }
    ;
    F
    r
    m
    w
    r
    k
    .
    s
    t
    a
    t
    e = f
    u
    n
    c
    t
    i
    o
    n
    (
    ) {
    _
    s
    t
    a
    t
    e
    .
    a
    p
    p
    l
    y
    ( F
    r
    m
    w
    r
    k
    .
    a
    p
    p
    , a
    r
    g
    u
    m
    e
    n
    t
    s )
    ;
    }
    ;

    View Slide

  58. and, since theyG
    re instances, use their
    methods
    bringing us back to templates

    View Slide

  59. very simple template rendering
    F
    r
    m
    w
    r
    k
    .
    S
    t
    a
    t
    e
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    r
    e
    n
    d
    e
    r = f
    u
    n
    c
    t
    i
    o
    n
    (
    ) {
    v
    a
    r d
    a
    t
    a = $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , {
    }
    , t
    h
    i
    s
    .
    p
    a
    r
    e
    n
    t
    .
    d
    a
    t
    a
    , t
    h
    i
    s
    .
    s
    e
    t
    t
    i
    n
    g
    s )
    ;
    t
    h
    i
    s
    .
    p
    a
    r
    e
    n
    t
    .
    e
    l
    .
    h
    t
    m
    l
    ( t
    h
    i
    s
    .
    t
    m
    p
    l
    ( d
    a
    t
    a ) )
    ;
    i
    f ( t
    h
    i
    s
    .
    c
    a
    l
    l
    b
    a
    c
    k ) {
    t
    h
    i
    s
    .
    c
    a
    l
    l
    b
    a
    c
    k
    .
    a
    p
    p
    l
    y
    ( t
    h
    i
    s
    , a
    r
    g
    u
    m
    e
    n
    t
    s )
    ;
    }
    }
    ;

    View Slide

  60. contains several assumptions:
    t
    m
    p
    l has already been compiled to a function
    a state will always replace the object it belongs to
    any partial templates are already accessible
    somehow
    the correct CSS is already loaded

    View Slide

  61. thatG
    s a lot
    can we make some of those more flexible or
    automatic

    View Slide

  62. easy fixes
    F
    r
    m
    w
    r
    k
    .
    S
    t
    a
    t
    e
    .
    p
    r
    o
    t
    o
    t
    y
    p
    e
    .
    r
    e
    n
    d
    e
    r = f
    u
    n
    c
    t
    i
    o
    n
    (
    ) {
    v
    a
    r d
    a
    t
    a = $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , {
    }
    , t
    h
    i
    s
    .
    p
    a
    r
    e
    n
    t
    .
    d
    a
    t
    a
    , t
    h
    i
    s
    .
    s
    e
    t
    t
    i
    n
    g
    s )
    ;
    i
    f ( t
    h
    i
    s
    .
    c
    s
    s ) {
    $
    ( "
    h
    e
    a
    d
    " )
    .
    a
    p
    p
    e
    n
    d
    ( '
    <
    s
    t
    y
    l
    e c
    l
    a
    s
    s
    =
    "
    ' + t
    h
    i
    s
    .
    _
    n
    a
    m
    e + '
    "
    >
    ' + t
    h
    i
    s
    .
    c
    s
    s +
    }
    t
    h
    i
    s
    .
    c
    o
    n
    t
    a
    i
    n
    e
    r ?
    t
    h
    i
    s
    .
    c
    o
    n
    t
    a
    i
    n
    e
    r
    .
    h
    t
    m
    l
    ( t
    h
    i
    s
    .
    t
    m
    p
    l
    ( d
    a
    t
    a ) ) :
    t
    h
    i
    s
    .
    p
    a
    r
    e
    n
    t
    .
    e
    l
    .
    h
    t
    m
    l
    ( t
    h
    i
    s
    .
    t
    m
    p
    l
    ( d
    a
    t
    a ) )
    ;
    i
    f ( t
    h
    i
    s
    .
    c
    a
    l
    l
    b
    a
    c
    k ) {
    t
    h
    i
    s
    .
    c
    a
    l
    l
    b
    a
    c
    k
    .
    a
    p
    p
    l
    y
    ( t
    h
    i
    s
    , a
    r
    g
    u
    m
    e
    n
    t
    s )
    ;
    }
    }
    ;

    View Slide

  63. loading templates and partials is trickier
    should be able to take a URL or a template element
    should know whether the template's already loaded
    should handle partials differently
    and know which partials it requires

    View Slide

  64. we should handle that in our constructor
    F
    r
    m
    w
    r
    k
    .
    S
    t
    a
    t
    e = f
    u
    n
    c
    t
    i
    o
    n
    ( o
    b
    j ) {
    $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , t
    h
    i
    s
    , {
    p
    a
    r
    e
    n
    t
    : F
    r
    m
    w
    r
    k
    .
    a
    p
    p
    ,
    t
    m
    p
    l
    : n
    u
    l
    l
    ,
    s
    e
    t
    t
    i
    n
    g
    s
    : {
    }
    ,
    c
    a
    l
    l
    b
    a
    c
    k
    : n
    u
    l
    l
    }
    , o
    b
    j )
    ;
    /
    / t
    m
    p
    l n
    e
    e
    d
    s t
    o b
    e c
    o
    m
    p
    i
    l
    e
    d
    i
    f ( t
    h
    i
    s
    .
    t
    m
    p
    l &
    & t
    y
    p
    e
    o
    f t
    h
    i
    s
    .
    t
    m
    p
    l !
    = "
    f
    u
    n
    c
    t
    i
    o
    n
    " ) {
    t
    h
    i
    s
    .
    t
    m
    p
    l = _
    c
    o
    m
    p
    i
    l
    e
    T
    m
    p
    l
    ( t
    h
    i
    s
    .
    t
    m
    p
    l
    , t
    h
    i
    s
    .
    p
    a
    r
    t
    i
    a
    l
    s )
    ;
    }
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    ;
    }
    ;

    View Slide

  65. and do the loading work, if necessary, in
    a static function
    v
    a
    r _
    t
    m
    p
    l
    C
    a
    c
    h
    e = {
    }
    ;
    f
    u
    n
    c
    t
    i
    o
    n _
    c
    o
    m
    p
    i
    l
    e
    T
    m
    p
    l
    ( t
    m
    p
    l
    S
    t
    r
    i
    n
    g
    , p
    a
    r
    t
    i
    a
    l
    s
    , n
    a
    m
    e ) {
    v
    a
    r t
    m
    p
    l
    N
    a
    m
    e = n
    a
    m
    e |
    | t
    m
    p
    l
    S
    t
    r
    i
    n
    g
    .
    r
    e
    p
    l
    a
    c
    e
    ( "
    \
    /
    "
    , "
    _
    " )
    .
    r
    e
    p
    l
    a
    c
    e
    ( "
    .
    "
    ,
    d
    e
    f = {
    }
    ;
    i
    f ( p
    a
    r
    t
    i
    a
    l
    s &
    & t
    y
    p
    e
    o
    f p
    a
    r
    t
    i
    a
    l
    s =
    = "
    o
    b
    j
    e
    c
    t
    " &
    & p
    a
    r
    t
    i
    a
    l
    s
    .
    l
    e
    n
    g
    t
    h ) {
    p
    a
    r
    t
    i
    a
    l
    s
    .
    f
    o
    r
    E
    a
    c
    h
    ( f
    u
    n
    c
    t
    i
    o
    n
    ( p ) {
    d
    e
    f
    [ p
    .
    n
    a
    m
    e ] = _
    t
    m
    p
    l
    C
    a
    c
    h
    e
    [ p
    .
    n
    a
    m
    e ]
    ;
    }
    )
    ;
    }
    i
    f ( _
    t
    m
    p
    l
    C
    a
    c
    h
    e
    [ t
    m
    p
    l
    N
    a
    m
    e ] ) {
    r
    e
    t
    u
    r
    n _
    t
    m
    p
    l
    C
    a
    c
    h
    e
    [ t
    m
    p
    l
    N
    a
    m
    e ]
    ;
    } e
    l
    s
    e i
    f ( $
    ( "
    b
    o
    d
    y
    " )
    .
    f
    i
    n
    d
    ( t
    m
    p
    l
    S
    t
    r
    i
    n
    g )
    .
    l
    e
    n
    g
    t
    h ) {
    r
    e
    t
    u
    r
    n _
    t
    m
    p
    l
    C
    a
    c
    h
    e
    [ t
    m
    p
    l
    N
    a
    m
    e ] = d
    o
    T
    .
    t
    e
    m
    p
    l
    a
    t
    e
    ( $
    ( t
    m
    p
    l
    S
    t
    r
    i
    n
    g )
    .
    h
    t
    m
    l
    } e
    l
    s
    e {
    $
    .
    g
    e
    t
    ( t
    m
    p
    l
    S
    t
    r
    i
    n
    g
    , f
    u
    n
    c
    t
    i
    o
    n
    ( t
    m
    p
    l ) {
    _
    t
    m
    p
    l
    C
    a
    c
    h
    e
    [ t
    m
    p
    l
    N
    a
    m
    e ] = d
    o
    T
    .
    t
    e
    m
    p
    l
    a
    t
    e
    ( t
    m
    p
    l
    , n
    u
    l
    l
    , d
    e
    f )
    ;

    View Slide

  66. we also need a way to add partials
    we can't expect partials to be tied to an object or
    state
    we need them to be available when the templates
    using them are compiled

    View Slide

  67. thus, the first method belonging
    exclusively to the application
    F
    r
    m
    w
    r
    k
    .
    a
    p
    p
    .
    r
    e
    g
    i
    s
    t
    e
    r
    T
    m
    p
    l = _
    r
    e
    g
    i
    s
    t
    e
    r
    T
    m
    p
    l = f
    u
    n
    c
    t
    i
    o
    n
    ( n
    a
    m
    e
    , t
    m
    p
    l
    S
    t
    r
    i
    n
    g ) {
    _
    c
    o
    m
    p
    i
    l
    e
    T
    m
    p
    l
    ( t
    m
    p
    l
    S
    t
    r
    i
    n
    g
    , n
    u
    l
    l
    , n
    a
    m
    e )
    ;
    }
    ;

    View Slide

  68. why not just use
    _
    c
    o
    m
    p
    i
    l
    e
    T
    m
    p
    l
    we could, but itG
    s nice to have a separate
    public interface

    View Slide

  69. it also helps reflect a different use
    F
    r
    m
    w
    r
    k
    .
    O
    b
    j
    e
    c
    t = f
    u
    n
    c
    t
    i
    o
    n ( o
    b
    j ) {
    $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , t
    h
    i
    s
    , {
    s
    e
    l
    : "
    b
    o
    d
    y
    "
    ,
    d
    a
    t
    a
    : {
    }
    ,
    e
    n
    d
    p
    o
    i
    n
    t
    : n
    u
    l
    l
    ,
    e
    v
    e
    n
    t
    s
    : {
    }
    ,
    s
    t
    a
    t
    e
    s
    : {
    }
    ,
    _
    c
    u
    r
    r
    e
    n
    t
    S
    t
    a
    t
    e
    : "
    _
    d
    e
    f
    a
    u
    l
    t
    "
    ,
    t
    m
    p
    l
    s
    : {
    }
    }
    , o
    b
    j )
    ;
    i
    f ( t
    h
    i
    s
    .
    s
    e
    l ) {
    t
    h
    i
    s
    .
    e
    l = $
    ( t
    h
    i
    s
    .
    s
    e
    l )
    ;
    }
    i
    f ( t
    h
    i
    s
    .
    t
    m
    p
    l
    s ) {
    f
    o
    r
    ( v
    a
    r t i
    n t
    h
    i
    s
    .
    t
    m
    p
    l
    s ) {
    _
    r
    e
    g
    i
    s
    t
    e
    r
    T
    m
    p
    l
    ( t
    , t
    h
    i
    s
    .
    t
    m
    p
    l
    s
    [ t ] )
    ;
    }

    View Slide

  70. real talk: that could be much better
    everything's easy until it's async
    external resources are likely to require async code
    this is an ideal place for promises
    ..which we'd get from yet another external resource

    View Slide

  71. we want a framework to also help
    manage dependencies
    what we have could work if dependencies are finite
    if they're generic, we'd be better off with something
    like Require.js
    something like that means we have to think of the
    framework differently

    View Slide

  72. taking Require as an example..
    our object types would be modules
    the app would be a specific dependency
    we could remove any code to load templates or CSS
    all this code would be required by implementations

    View Slide

  73. one more piece
    wiring up the DOM

    View Slide

  74. weG
    ve left a place for some implementation
    code
    F
    r
    m
    w
    r
    k
    .
    S
    t
    a
    t
    e = f
    u
    n
    c
    t
    i
    o
    n
    ( o
    b
    j ) {
    $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , t
    h
    i
    s
    , {
    p
    a
    r
    e
    n
    t
    : F
    r
    m
    w
    r
    k
    .
    a
    p
    p
    ,
    t
    m
    p
    l
    : n
    u
    l
    l
    ,
    s
    e
    t
    t
    i
    n
    g
    s
    : {
    }
    ,
    c
    a
    l
    l
    b
    a
    c
    k
    : n
    u
    l
    l
    }
    , o
    b
    j )
    ;
    /
    / t
    m
    p
    l n
    e
    e
    d
    s t
    o b
    e c
    o
    m
    p
    i
    l
    e
    d
    i
    f ( t
    h
    i
    s
    .
    t
    m
    p
    l &
    & t
    y
    p
    e
    o
    f t
    h
    i
    s
    .
    t
    m
    p
    l !
    = "
    f
    u
    n
    c
    t
    i
    o
    n
    " ) {
    t
    h
    i
    s
    .
    t
    m
    p
    l = _
    c
    o
    m
    p
    i
    l
    e
    T
    m
    p
    l
    ( t
    h
    i
    s
    .
    t
    m
    p
    l
    , t
    h
    i
    s
    .
    p
    a
    r
    t
    i
    a
    l
    s )
    ;
    }
    r
    e
    t
    u
    r
    n t
    h
    i
    s
    ;
    }
    ;

    View Slide

  75. some frameworks attempt to contain DOM
    interaction
    lists of selectors and events
    callbacks belong to the application or a controller
    this keeps everything nice and clean
    but doesn't add a whole lot of functionality

    View Slide

  76. what DOM functionality can a
    framework add
    re-rendering
    attaching DOM interactions to state changes
    forwarding DOM events to framework events

    View Slide

  77. the rest is nobodyG
    s business
    but the DOMG
    s

    View Slide

  78. what we need to trigger a state change
    an element to delegate to
    the selector and event
    the name of the state to switch to

    View Slide

  79. we want this wired up when our state is
    created
    F
    r
    m
    w
    r
    k
    .
    S
    t
    a
    t
    e = f
    u
    n
    c
    t
    i
    o
    n
    ( o
    b
    j ) {
    $
    .
    e
    x
    t
    e
    n
    d
    ( t
    r
    u
    e
    , t
    h
    i
    s
    , {
    p
    a
    r
    e
    n
    t
    : F
    r
    m
    w
    r
    k
    .
    a
    p
    p
    ,
    t
    m
    p
    l
    : n
    u
    l
    l
    ,
    s
    e
    t
    t
    i
    n
    g
    s
    : {
    }
    ,
    c
    a
    l
    l
    b
    a
    c
    k
    : n
    u
    l
    l
    ,
    t
    r
    i
    g
    g
    e
    r
    : n
    u
    l
    l
    }
    , o
    b
    j )
    ;
    /
    / t
    m
    p
    l n
    e
    e
    d
    s t
    o b
    e c
    o
    m
    p
    i
    l
    e
    d
    i
    f ( t
    h
    i
    s
    .
    t
    m
    p
    l &
    & t
    y
    p
    e
    o
    f t
    h
    i
    s
    .
    t
    m
    p
    l !
    = "
    f
    u
    n
    c
    t
    i
    o
    n
    " ) {
    t
    h
    i
    s
    .
    t
    m
    p
    l = _
    c
    o
    m
    p
    i
    l
    e
    T
    m
    p
    l
    ( t
    h
    i
    s
    .
    t
    m
    p
    l
    , t
    h
    i
    s
    .
    p
    a
    r
    t
    i
    a
    l
    s )
    ;
    }
    i
    f ( t
    h
    i
    s
    .
    t
    r
    i
    g
    g
    e
    r &
    & t
    h
    i
    s
    .
    t
    r
    i
    g
    g
    e
    r
    .
    l
    e
    n
    g
    t
    h ) {
    t
    h
    i
    s
    .
    t
    r
    i
    g
    g
    e
    r
    .
    f
    o
    r
    E
    a
    c
    h
    ( f
    u
    n
    c
    t
    i
    o
    n
    ( t ) {
    $
    ( t
    .
    c
    o
    n
    t
    a
    i
    n
    e
    r |
    | t
    h
    i
    s
    .
    p
    a
    r
    e
    n
    t
    .
    e
    l )
    .
    o
    n
    ( t
    .
    e
    v
    e
    n
    t
    , t
    .
    s
    e
    l
    e
    c
    t
    o
    r
    , t
    h
    i
    s
    }
    )
    ;
    }

    View Slide

  80. how about more generic events
    we may still want to fire events scoped to an object
    our publish method is public, so implementers can do
    that manually
    for something very small and unopinionated, that's
    probably enough

    View Slide

  81. but we should talk about
    opinions

    View Slide

  82. this example is more useful as a
    complement to something else
    lots of control in HTML or CSS
    a DOM library
    a datavis library
    a widget or component framework
    a client/server framework

    View Slide

  83. there are a lot of tools
    but only a handful of strategies for
    augmenting them

    View Slide

  84. with HTML/CSS
    framework provides initial data and rendering
    states can be exclusively data states, not visual
    state callbacks set up explicit data updates
    framework exists to store and sync data

    View Slide

  85. CSS specifically
    cause thatG
    s kind of hard
    CSS interactions are an alternative to JS
    we can observe animations (e.g. a
    n
    i
    m
    a
    t
    i
    o
    n
    S
    t
    a
    r
    t
    ,
    a
    n
    i
    m
    a
    t
    i
    o
    n
    E
    n
    d
    )
    but we can't directly observe something activating
    :
    t
    a
    r
    g
    e
    t
    , for example
    and we can't forward events from CSS to JS
    the most foolproof way to integrate with CSS is to
    listen for the same events

    View Slide

  86. with DOM-heavy libraries or plugins
    object DOM element is just the container
    stores data for child elements that aren't objects
    child elements created by object's template
    object's default state callback listens for library
    events and updates its data accordingly
    again, storing and syncing

    View Slide

  87. with components or widgets
    framework objects could be made less generic to be
    aware of library functions
    or the two can communicate from their controller
    code
    components should manage themselves, so
    framework only needs to worry about public
    notifications
    still storing and syncing, but at a higher level of
    remove

    View Slide

  88. with frameworks that handle the backend
    again, we can be less generic and rely on server-
    aware objects
    those may still need rendering and client-only
    messaging
    this time, we're observing third-party events coming
    not from the user but the server or the data
    handle the manipulation of data, leave the rest to
    the underlying framework

    View Slide

  89. in the real world, we usually
    only think about pieces of
    frameworks in conjunction
    with existing frameworks

    View Slide

  90. what to do with these ideas
    don't go write a new generic do-everything
    framework
    think about what pieces your app needs from a
    framework
    choose frameworks that are opionated about those
    things
    if you can't find a perfect fit, write a small wrapper
    that adds just what you need

    View Slide

  91. thanks!
    any questions
    |
    garann.com @garannm

    View Slide