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

Real World Dashboard

Ben Sheldon
May 13, 2014
94

Real World Dashboard

When Backbone.js stops being idiomatic, and starts being real.

Ben Sheldon

May 13, 2014
Tweet

Transcript

  1. ● Transparent: The consequences of change should be
    obvious in the code that is changing and in distant code
    that relies upon it.
    ● Reasonable: The cost of any change should be
    proportional to the benefits the change achieves
    ● Usable: Existing code should be usable in new and
    unexpected contexts
    ● Exemplary: The code itself should encourage those
    who change it to perpetuate these qualities.
    T.R.U.E. CODE
    http://www.poodr.com/

    View full-size slide

  2. “Fuck design patterns”
    “I don’t know. I just copied it.”
    “Is it bad, or is it you didn't write it?”
    CLASSIC

    View full-size slide

  3. The code itself should encourage those
    who change it to perpetuate these
    qualities.
    EXEMPLARY CODE
    http://randycoulman.com/blog/2013/04/09/exemplary-code/

    View full-size slide

  4. ANTI-DESIGN
    Design: making guesses about unknown requirements and writing
    speculative code in an attempt to preemptively meet them.
    Design == Over-Design
    PRO-DESIGN
    Design: the current arrangement of an application’s code
    Act of Design: using one’s knowledge of the consequences of
    various code arrangement techniques to solve the current problem in
    a way that accommodates the next (as yet undefined) change.
    “These disputes are not about
    core beliefs, they merely
    reflect a communication gap.”
    http://www.sandimetz.com/blog/2012/07/05/how-shall-we-define-design/

    View full-size slide

  5. “ERGONOMICS FOR
    YOUR MIND”

    View full-size slide

  6. REDUCE DUPLICATION
    apiUser: (path='', data={}, method='GET', callback) ->
    start = new Date().getTime()
    # … param munging omitted
    parameters =
    user: app.settings.user
    path: path
    unless _.isUndefined(data) or _.isFunction(data)
    parameters.data = data
    log.debug 'REQ', "#{method} user/#{path}", parameters
    request(method, '/pp.php')
    .send(parameters)
    .end((res) =>
    log.debug 'RES', "#{method} user/#{path}", res
    # If the response has a 5xx status code, record this.
    if res.status >= 500
    recordAPIFail(method, path, data, res)
    # Record how long the api request took.
    app.util.apiTiming(path, new Date().getTime() - start)
    if res.status >= 400
    if res.body?
    error = res.body
    else
    error = res.status
    else
    error = null
    if _.isFunction callback
    return callback error, res.body, res
    )
    makeSiteApiFunction: (siteId) ->
    return (path='', data={}, method = 'GET') ->
    start = new Date().getTime()
    # … param munging omitted
    parameters =
    site: siteId
    path: path
    unless _.isUndefined(data) or _.isFunction(data)
    parameters.data = data
    log.debug 'REQ', "#{method} site/#{path}", parameters
    request(method, '/pp.php')
    .send(parameters)
    .end((res) =>
    log.debug 'RES', "#{method} site/#{path}", res
    # Record how long the api request took.
    app.util.apiTiming(path, new Date().getTime() - start)
    # If the response has a 5xx status code, record this.
    if res.status >= 500
    recordAPIFail(method, path, data, res)
    if res.status >= 400
    error = res.status
    else
    error = null
    if _.isFunction callback
    return callback error, res.body, res
    )
    memoized
    different param
    slightly different error checking code
    same code, different order

    View full-size slide

  7. LISKOV SUBSTITUTION
    “User.what?”
    PRINCIPLE OF
    LEAST ASTONISHMENT

    View full-size slide

  8. MODULARITY
    window.app.util.analyticsTrack()
    window.app.util.userGet()
    window.app.util.userSet()
    window.app.util.makeSiteApi()
    window.app.util.apiUser()
    window.app.util.sendGraphite()
    window.app.util.getGravatar()
    window.app.util.apiTiming()
    window.app.util.getAccentColor()
    window.app.util.featureEnabled()
    window.app.util.parseSize()
    window.app.util.uuidFromEmail()
    window.app.util.createCSVDownload()
    window.app.util.isOnebox()
    window.app.util.validateEmail()
    window.app.util.pardotTrack()

    View full-size slide

  9. LAW OF DEMETER
    @site.collections.environments.get(workshop.get('workspace'))?.isBranch()
    app.me.get('organizations')?[app.ws.models.site.get('organization').organization]?.admin
    "#{ if app.ws.models.site.get('upstream')?.branch? then app.ws.models.site.get
    ('upstream')?.branch else 'master' }"

    View full-size slide

  10. HTML Poking
    Form-data Munging
    Updating Models/Collections
    Making API Calls
    SINGLE RESPONSIBILITY

    View full-size slide

  11. SINGLE RESPONSIBILITY

    View full-size slide

  12. Do (not “must”) Don’t (not “can’t”)
    Dependencies are injected or required() Access window.app deep in methods
    Export singletons Attach to window.app
    view.render() is idempotent View.render() appends to html
    API calls happen on models/collections Make API calls in View
    Use templates Concat/$.append html strings in Views
    Inject primitive values into templates Inject fat objects/models into templates
    Assign @options.property to @property in #initialize Access @options.property deep in other methods
    initialize() doesn't have side effects such as auto-
    render
    Make api calls in initialize or call render()
    Views should listen to model state and re-render Use jQuery to modify specific elements on events
    DASHBOARD EPIC

    View full-size slide

  13. Javascript MVC Styleguide
    http://blhttp://blog.sourcing.io/mvc-style-guideog.sourcing.io/mvc-
    style-guide
    Backbone Anti-Patterns
    http://blog.shinetech.com/2013/11/26/backbone-antipatterns/

    View full-size slide