Slide 1

Slide 1 text

HOW THE CONCEPTS SCALE UP

Slide 2

Slide 2 text

HOW THE CONCEPTS SCALE UP

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

Routing

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

The Basics

Slide 16

Slide 16 text

The Basics App.Router.map(function()  {
    this.resource('app',  {  path:  ':app_id'  });
 });

Slide 17

Slide 17 text

application.handlebars loading.handlebars http://skylight.io/app/direwolf

Slide 18

Slide 18 text

application.handlebars app.handlebars http://skylight.io/app/direwolf appkit/routes/app.js   export  default  Ember.Route.extend({
    model:  function(params)  {
        return  this.store.find('app',
            params.app_id);
    }
 });

Slide 19

Slide 19 text

application.handlebars index.handlebars application.handlebars loading.handlebars application.handlebars app.handlebars

Slide 20

Slide 20 text

application.handlebars index.handlebars application.handlebars loading.handlebars application.handlebars app.handlebars fetch model...

Slide 21

Slide 21 text

application.handlebars index.handlebars application.handlebars loading.handlebars application.handlebars app.handlebars

Slide 22

Slide 22 text

application.handlebars index.handlebars application.handlebars loading.handlebars application.handlebars app.handlebars

Slide 23

Slide 23 text

Ember Routing • Coming in from the URL should have the same code path as navigating around the application after the model is loaded.

Slide 24

Slide 24 text

Nested App.Router.map(function()  {
    this.resource('app',  {  path:  ':app_id'  },  function()  {
        this.resource('endpoint',  {  path:  ':endpoint_id'  );
    });
 });

Slide 25

Slide 25 text

application.handlebars app.handlebars http://skylight.io/app/direwolf appkit/routes/app.js   export  default  Ember.Route.extend({
    model:  function(params)  {
        return  this.store.find('app',
            params.app_id);
    }
 });   appkit/routes/app/index.js   export  default  Ember.Route.extend({
    model:  function()  {
        return  this.modelFor('app')
            .get('endpoints');
  }
 }); app/index.handlebars 
 !  {{#each}}
      {{link-­‐to  title  this}}
  {{/each}}

Slide 26

Slide 26 text

application.handlebars app.handlebars http://skylight.io/app/direwolf/Agent%23status appkit/routes/app.js   export  default  Ember.Route.extend({
    model:  function(params)  {
        return  this.store.find('app',
            params.app_id);
    }
 });   appkit/routes/endpoint.js   export  default  Ember.Route.extend({
    model:  function(params)  {
      return  this.store.find('app',
            params.endpoint_id);
 }
 }); endpoint.handlebars

Slide 27

Slide 27 text

application.handlebars app.handlebars http://skylight.io/app/direwolf/Agent%23status appkit/routes/app.js   export  default  Ember.Route.extend({
    model:  function(params)  {
        return  this.store.find('app',
            params.app_id);
    }
 });   appkit/routes/endpoint.js   export  default  Ember.Route.extend({
    model:  function(params)  {
      return  this.store.find('app',
            params.endpoint_id);
 }
 }); endpoint.handlebars nav.handlebars

Slide 28

Slide 28 text

Ember Routing • Coming in from the URL should have the same code path as navigating around the application after the model is loaded. • There is a single, consistent place to put setup and teardown logic for each page on the screen. • Nesting is built-in. Virtually every application has nesting, and your Week 1 code should serve you well in Week 2.

Slide 29

Slide 29 text

The Setup Flow

Slide 30

Slide 30 text

Setup Flow export  default  Ember.Route.extend({      renderTemplate:  function()  {          this.render('nav',  {  outlet:  'nav'  });      },   !    redirect:  function()  {          var  user  =  this.modelFor('application'),                  apps  =  user.get('apps');   !        if  (!apps  ||  apps.get('length')  <  1)  {              this.replaceWith('setup');          }      }
 });

Slide 31

Slide 31 text

Ember Routing • Coming in from the URL should have the same code path as navigating around the application after the model is loaded. • There is a single, consistent place to put setup and teardown logic for each page on the screen. Think keyboard shortcuts. • Nesting is built-in. Virtually every application has nesting, and your Week 1 code should serve you well in Week 2.

Slide 32

Slide 32 text

Components

Slide 33

Slide 33 text

Components ~ HTML Functions {{time-­‐explorer  rightMargin=152
                                brushExtent=dateRange
                                      endpoint=model
                                  timeRanges=timeRanges    
                    selectedTimeRange=selectedTimeRange}}  

Slide 34

Slide 34 text

Component Implementation                              
            
                                                                                                                                       !
     +      -­‐      {{select-­‐popup  options=timeRanges  class="control"  value=selectedTimeRange}}  

Slide 35

Slide 35 text

Component Implementation

Slide 36

Slide 36 text

Isolation Manages Complexity

Slide 37

Slide 37 text

Well-Defined Boundaries

Slide 38

Slide 38 text

Components

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

Empty Help us keep the lights on. Enter your credit card information below, and we'll continue helping you make your Rails app the fastest it can be. Credit Card Card Number MM / YY CVC Save Credit Card We stole this graphic from GitHub for the wireframes; don't use in production! Credit Card Invalid This red glow is a placeholder until the final design is completed in Photoshop. Help us keep the lights on. Enter your credit card information below, and we'll continue helping you make your Rails app the fastest it can be. Credit Card 9999 9999 9999 9999 06 / 09 123 Save Credit Card The credit card you entered was invalid. When we can detect invalid information on the client (such as the Luhn checksum or expiry dates in the past), we should highlight the invalid field and display the error to the right of the Save button. Incomplete The Save button is dimmed until the entire form is filled out. Help us keep the lights on. Enter your credit card information below, and we'll continue helping you make your Rails app the fastest it can be. Credit Card MM / YY CVC Save Credit Card 4242 4242 4242 4242 Only one error should be displayed at a time. If there is more than one error, just show the first. {{billing-credit-card-form}} Component States Saved Clicking transitions to the Update Credit Card state. Update Thank you for being a Skylight customer. Credit Card Card Number MM / YY CVC Update Credit Card Cancel 4••• •••• •••• 4242 Expires 04/15 Update Credit Card Thank you for being a Skylight customer. Credit Card Saving Help us keep the lights on. Enter your credit card information below, and we'll continue helping you make your Rails app the fastest it can be. Credit Card 4242 4242 4242 4242 06 / 17 123 Saving… Error Saving Help us keep the lights on. Enter your credit card information below, and we'll continue helping you make your Rails app the fastest it can be. Credit Card 9999 9999 9999 9999 06 / 09 123 Save Credit Card The CVC you provided was incorrect. Because the server must validate any changes, the red glow should be removed and Save button enabled as soon as any changes to the field occur.

Slide 41

Slide 41 text

Feature Flags

Slide 42

Slide 42 text

Feature Flag Template {{#if  featureEnabled}}{{yield}}{{/if}}

Slide 43

Slide 43 text

Feature Flag JS export  default  Ember.Component.extend({      flag:  null,      inverse:  false,   !    init:  function()  {          this._super();          var  flag  =  this.get('flag');   !        Ember.defineProperty(this,  'featureEnabled',  Ember.computed(function()  {              var  value  =  this.get('config.flags.'+flag);              if  (this.get('inverse'))  {  value  =  !value;  }              return  value;          }).property('config.flags.'+flag,  'inverse'));      }   });

Slide 44

Slide 44 text

Injections

Slide 45

Slide 45 text

config/initializers/config.js.es6 /*      This  initializer  injections  global  configuration  options  onto  object  instances,  so  they  do  not
    need  to  rely  on  accessing  globals.   !    Currently  all  of  the  config  options  are  defined  in  config/environment.js,  but  this  may  change  over  time.   !    To  access  a  config  option  on,  e.g.,  a  model,  do:   !        this.config.flags.keyRequests;  //=>  false          this.config.defaultRanges  =  [  {  },  {  },  ...  ];   */   export  default  {      name:  "config",      initialize:  function(container,  application)  {          container.register('config:main',  Ember.Object.extend(CONF));   !        ['model',  'view',  'controller',  'route',  'component'].forEach(function(type)  {              container.injection(type,  'config',  'config:main');          });      }   };

Slide 46

Slide 46 text

environment.js var  FEATURE_FLAGS  =  {      keyRequests:  false,      appDashboard:  false   };   ! window.CONF  =  {    zeroClipboard:  {          moviePath:  "/assets/zeroclipboard/ZeroClipboard.swf",          trustedDomains:  ['*'],          allowScriptAccess:  "always"      },      trialDays:  30,      flags:  FEATURE_FLAGS,      defaultTimeRanges:  [          {  name:  'Last  6  hours',  timestamp:  'recent',  duration:  21600  },          {  name:  'Last  30  minutes',  timestamp:  'recent',  duration:  1800  },          {  name:  'Last  5  minutes',  timestamp:  'recent',  duration:  300  }      ]   };

Slide 47

Slide 47 text

ES6 Modules

Slide 48

Slide 48 text

ES6 Module import  $  from  'jquery';
 import  {  config  }  from  'app/config';
 
 var  viewA  =  Ember.Object.extend({
    //  ...
 });
 
 var  viewB  =  Ember.Object.extend({
    //  ...
 });
 
 export  viewA;
 export  viewB; define(['jquery',  'app/config',  'exports'],
    function($,  appConfig,  exports)  {
        var  config  =  appConfig.config;
 
        var  viewA  =  Ember.Object.extend({
            //  ...
        });
 
        var  viewB  =  Ember.Object.extend({
            //  ...
        });
 
        exports.viewA  =  viewA;
        exports.viewB  =  viewB;
    }); AMD Module

Slide 49

Slide 49 text

Improvements • Cyclic Dependencies • Named and Default exports together (including cycles!) • Much, much prettier syntax, with familiar semantics • Why not?

Slide 50

Slide 50 text

ES6 Module Transpiler • Maintained by Square • Supports almost all of ES6 modules • Emits AMD-, Node- or Globals-based output • Compatibility with existing AMD and Node modules (including default exports) • Ships out of the box with Ember App Kit

Slide 51

Slide 51 text

Ember's Concepts Grow With You

Slide 52

Slide 52 text

Ember's Concepts Grow With Your App

Slide 53

Slide 53 text

Week 1 ➡️ Week 2 ➡️ Week 50

Slide 54

Slide 54 text

SCALABLE CONCEPTS FOR AMBITIOUS WEB APPS

Slide 55

Slide 55 text

Thank You! @wycats plus.google.com/+YehudaKatz yehudakatz.com @tomdale plus.google.com/+TomDale tomdale.com