Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ember: when the lights go on
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Aaron Chambers
September 24, 2014
Programming
0
200
ember: when the lights go on
My BSkyB Engineering Offsite presentation about our journey with Ember and beyond
Aaron Chambers
September 24, 2014
Tweet
Share
More Decks by Aaron Chambers
See All by Aaron Chambers
{{should-avoid this.renderModifiers butHow=true}}
achambers
0
190
one command to deploy them all
achambers
0
67
The Legend of Zelda: A {{link-to}} the past
achambers
0
71
ember-cli-deploy
achambers
0
92
git-branching
achambers
0
70
Other Decks in Programming
See All in Programming
見せてもらおうか、 OpenSearchの性能とやらを!
shunta27
1
160
Coding at the Speed of Thought: The New Era of Symfony Docker
dunglas
0
3.4k
車輪の再発明をしよう!PHP で実装して学ぶ、Web サーバーの仕組みと HTTP の正体
h1r0
2
450
Codexに役割を持たせる 他のAIエージェントと組み合わせる実務Tips
o8n
4
1.4k
Feature Toggle は捨てやすく使おう
gennei
0
390
最初からAWS CDKで技術検証してもいいんじゃない?
akihisaikeda
4
180
Redox OS でのネームスペース管理と chroot の実現
isanethen
0
480
へんな働き方
yusukebe
6
2.9k
Reactive ❤️ Loom: A Forbidden Love Story
franz1981
2
200
仕様漏れ実装漏れをなくすトレーサビリティAI基盤のご紹介
orgachem
PRO
7
3.6k
我々はなぜ「層」を分けるのか〜「関心の分離」と「抽象化」で手に入れる変更に強いシンプルな設計〜 #phperkaigi / PHPerKaigi 2026
shogogg
2
710
Symfonyの特性(設計思想)を手軽に活かす特性(trait)
ickx
0
110
Featured
See All Featured
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.5k
Music & Morning Musume
bryan
47
7.1k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
2.6k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
170
HDC tutorial
michielstock
1
590
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
2.8k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9k
Discover your Explorer Soul
emna__ayadi
2
1.1k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
97
We Have a Design System, Now What?
morganepeng
55
8k
sira's awesome portfolio website redesign presentation
elsirapls
0
200
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
660
Transcript
ember:&when&the&lights&go&on @grandazz github.com/achambers
None
how$ember$saved$my$life @grandazz github.com/achambers
how$ember$saved$my$life @grandazz github.com/achambers
ember:&when&the&lights&go&on @grandazz github.com/achambers
Wenguins
None
Noah%update
None
this%is%not an#ember#is#be(er#than#everything#else presenta(on
browser'dev'boiled'down (shamelessley)borrowed)from)@ryanflorence) interac(ng*with*data*stores rendering'data'to'ui responding*to*user*interac/on router&&&urls project(stuff:(file(organisa3on,(build(tools(etc
None
our$journey$with ember
lightbulb!moments
we#didn't#just#jump#in
we#needed#to validate the$switch
None
None
Service'Status
None
// app/assets/javascripts/application.js function bindViewMoreDetailsLinks() { $('.more-details').hide(); $('.view-more').click(function(e) { e.preventDefault(); var
viewMoreLink = $(this); var moreDetails = viewMoreLink.parents('.issue').find('.more-details'); if (moreDetails.is(':visible')) { moreDetails.hide(); viewMoreLink.text('More details'); } else { moreDetails.show(); viewMoreLink.text('Less details'); } viewMoreLink.toggleClass('opened'); }); }
// app/assets/javascripts/application.js function toggleElementsForEditors() { $.ajax({ url: '/sessions/current', dataType: 'json',
success: function(data) { var loggedInStatus = data.logged_in; toggleNewIssueLink(loggedInStatus); toggleHeader(loggedInStatus); toggleAdditionalLinks(loggedInStatus); toggleSidebar(loggedInStatus); toggleFooter(loggedInStatus); toggleEditIssueLinks(loggedInStatus); toggleResolveIssueLinks(loggedInStatus); } }); }
// app/assets/javascripts/application.js function toggleHeader(loggedInStatus) { $('#skycom-masthead-wrapper').toggleClass('hidden', loggedInStatus); } function toggleAdditionalLinks(loggedInStatus)
{ $('.additional-links').toggleClass('hidden', loggedInStatus); } function toggleSidebar(loggedInStatus) { $('.sidebar').toggleClass('hidden', loggedInStatus); } function toggleFooter(loggedInStatus) { $('#skycom-footer-wrapper').toggleClass('hidden', loggedInStatus); } function toggleEditIssueLinks(loggedInStatus) { $('.btn.edit-issue').toggleClass('hidden', !loggedInStatus); } function toggleResolveIssueLinks(loggedInStatus) { $('.btn.resolve-issue').toggleClass('hidden', !loggedInStatus); }
None
data$based$ui$manipula.on
// app/views/issues/index.html.haml function microfilterCheck() { var deferred = $.Deferred(); $.getJSON('/sessions/current',
function(json) { if (json.logged_in) { deferred.resolve() } else { Hub.runMicrofilterTest() .done(function() { deferred.reject(); }) .fail(function() { deferred.resolve(); }); } }); return deferred; }
// app/views/issues/index.html.haml function restrictionCheck() { var deferred = $.Deferred(); $.getJSON('/customers/current',
function(json) { if (json.customer.has_debt_restriction) { deferred.reject('debt'); } else if (json.customer.has_high_spend_restriction) { deferred.reject('spend'); } else { deferred.resolve(); } }, function() { deferred.resolve(); }); return deferred; }
// app/views/issues/index.html.haml $(function() { var microfilterDeferred = microfilterCheck() var restrictionDeferred
= restrictionCheck() $.when(microfilterDeferred, restrictionDeferred).always(function() { var args = Array.prototype.slice.call(arguments); if (restrictionDeferred.state() == 'rejected') { if (args.indexOf('spend') !== -1) { $('.high-spend-restriction-alert').removeClass('hidden'); } else if (args.indexOf('debt') !== -1) { $('.debt-restriction-alert').removeClass('hidden'); } } else if (microfilterDeferred.state() == 'rejected') { $('.microfilter-alert').removeClass('hidden'); } showIssues(); }); });
then%the%very%next%commit...
// app/views/issues/index.html.haml $(function() { IssuesIndexController.init(); });
None
controllers
// app/assets/javasctipts/User.js var User = { isAnEditor: function() { var
deferred = $.Deferred(); $.ajax({ dataType: 'json', url: '/sessions/current', success: function(data) { deferred.resolve(data.logged_in); }, error: function() { deferred.reject(); } }); return deferred.promise(); } }
// app/assets/javascripts/Diagnostics.js var Diagnostics = { run: function() { //run
some diagnostics goodness } } // app/assets/javascripts/CBS.js var CBS = { run: function() { //run some monstrosity of a service, //return a massive payload we don't need //and take forever to do so } }
None
models & interac(ng*with*data*stores
// app/assets/javascripts/views/IssueView.js (function() { window.IssuesView = { render: function() {
this._showIssues(); this._toggleStatusMessage(); } // ...snip... }; })(); // app/assets/javascripts/views/DebtAlertView.js (function() { window.DebtAlertView = { render: function() { this._showAlert(); this._hideProducts(); this._hideSidebar(); this._informScreenReader(); } // ...snip... }; })();
None
views
{!-- app/assets/javascripts/templates/outages.hbs --}} {{#each outages}} <article class="issue"> <h3>{{description}}</h3> <p> <span
class="label">Date issue was reported</span> </br> <strong>{{startedOn}}</strong> </p> </article> {{/each}}
None
templa'ng
we#started#to#build#our#own#framework
we#started#to#build#our#own#framework BADLY
Use$a$framework,$or$don't.$Either$ way,$you$will. —"Someone"Awesome
conven&on'over'configura&on this.resource('posts', { path: '/posts' }) PostsRoute PostsController PostsView posts.hbs
no#more#globals var Diagnostics = { run: function() { // do
stuff } }; window.IssuesIndexController = { init: function() { // do stuff; } };
no#more#globals ServiceStatus.GoIssuesController = Em.ArrayController.extend({ status: function() { //do stuff }.property('hasProblem')
}); ServiceStatus.Outage = DS.Model.extend({ //attributes here }); ServiceStatus.SsAccordionComponent = Em.Component.extend({ collapsed: false, //other properties here });
data$binding // models/tv_issue.js ServiceStatus.TvIssue = DS.Model.extend( name: DS.attr('string') ); //
controllers.tv_issues.js ServiceStatus.TvIssuesController = Em.ArrayController.extend({ }); <!-- templates/tv_issues.hbs --> <ul> <#each> <li>{{name}}</li> </each> </ul>
lightbulb(moments didn't&stop there
None
None
leave%your%assump-ons at#the#door
None
None
None
None
None
None
None
don't&fight&the&framework
If#something#feels#harder#than#it# should#be,#it#probably#is.#You're# probably#doing#it#wrong. —"Someone"Awesome
None
None
ui#error#logging
ui#error#logging Ember.onerror = handleError; Ember.RSVP.on('error', handleError); function handleError(error) { Em.$.ajax('/error',
{ type: 'POST', data: { stack: error.stack } }); }
None
None
build&tools
ember%cli npm install -g ember-cli
ember%cli file$organisa,on ember new my-project - /app - /components -
/controllers - /helpers - /models - /routes - /styles - /templates - /views - app.js - index.html - router.js - /config - /public - /tests
ember%cli es6$modules
ember%cli tes$ng
ember%cli asset%pipeline
ember%cli generators
ember%cli h"p$mock)server
ember%cli addons
None
None
separa&on)of ui#and#api
clearer&separa)on&between&data and$user$interac,on
think¬&of&your&api&in&terms&of&ui& interac2ons,&but&in&terms&of&data& and&rela2onships
your%app%is%a client'of'your'api
None
None
deployment
deploying*to*heroku and$serving$from$rails is#cool#and#all
but$we've$been$doing$that$for a"long"'me
we#can#do be#er
None
None
index.html app#1234.js app#5678.css
None
lets%push%this one$step$further
None
None
deployment*becomes*super*quick
just%push%some%sta,c%assets%to%S3 and$push$index.html$into$redis
not$to$men'on$cu*ng$over
None
None
pact%file%tes*ng
how$do$we$test$that$changes to#the#api
how$do$we$test$that$changes to#the#api don't&break&the&ui?
pact%(noun) A%formal%agreement%between% individuals%or%par8es. —%The%Google
the$rela(onship$of$the$web$app$consists$of: the$consumer$(ui) the$provider$(api)
Step%1%'%Define%the%consumer%expecta4ons
Step%2%'%Verify%expecta0ons%on%provider
imagine'if CBS verified'their'services'against'our'pact'files every%&me%they%released?
None
Thats&a&wrap
@grandazz github.com/achambers
any$ques)ons? @grandazz github.com/achambers
thankyou