#BosWebPerf
Boston Web Performance Group, December 2015    
UI Rendering
at Wayfair
Architecting for
Performance at Scale
#BosWebPerf
Who Are We
Adam Baratz
@adambaratz  
Andrew Rota
@andrewrota  
Matt DeGennaro
@thedeeg
#BosWebPerf
Wayfair
Wayfair.com is an online destination for all things
home
Selection of more than seven million home items from
7,000+ suppliers
eCommerce company since 2002
Several large websites running a shared codebase
PHP backend for customer­facing pages
2,000,000+ lines of code for custom eCommerce platform
2,000+ JavaScript modules
#BosWebPerf
Web UI rendering
 
Server
Build up HTML for
views
Flush HTML to
browser
Client
Update HTML on
user interactions
#BosWebPerf
Performance that Scales
In general, faster code has less abstraction
More scalable code has more abstractions
#BosWebPerf
Performance that Scales
In general, faster code has less abstraction
More scalable code has more abstractions
­ 
Make it correct, make it clear, make it concise, make
it fast. In that order.“
Wes Dyer
#BosWebPerf
Where We Started
jQuery and other DOM manipulation libraries on the
client
Serving HTML straight from PHP scripts
#BosWebPerf
This was a problem for growth
Global conflicts were a problem
Was not scalable
Reusable components were difficult to create
#BosWebPerf
...also a problem for performance
Relied on developer knowledge for speed
Code was as fast as its slowest functionality
#BosWebPerf
First Steps
Towards
Abstraction
#BosWebPerf
On the server
#BosWebPerf
PHP MVC
Instigated by burgeoning mobile business
Controllers curated data, PHP views presented
View Classes introduced to further separate
concerns
#BosWebPerf
On the client...
#BosWebPerf
Unopinionated Unimplemented framework
Reusable Views and Models
DOM updates were done with jQuery
­ 
Backbone  is  an  unopinionated  framework  that
provides structure to your code.“
Thomas Boyt
#BosWebPerf
Performance was still lacking
JS read from DOM to determine state
Mutations at startup were common
Markup was maintained both in PHP view and JS
mutations
Lack of framework knowledge and capability meant
low­level code was still being used
#BosWebPerf
Abstraction scalability was still a problem
Without strict framework guidelines developers
wrote multiple ad­hoc abstractions, especially on
the JS side
Components written for one section didn't
necessarily work elsewhere
#BosWebPerf
Bridging the
Client/Server
Gap
#BosWebPerf
Templates
Templating language that ran on server and client
Mustache was chosen
Stack support
One source of markup runs on all environments
#BosWebPerf
Mustache ­ Pure PHP Pain Points
Partial loading
{{#products}}
{{>product}}
{{/products
#BosWebPerf
Mustache ­ Pure PHP Pain Points
Context resolution 
{{inner}}
{{#outer}}{{inner}}{{/outer}}
{
"inner": 1,
"outer": {
"inner": 2
}
}
#BosWebPerf
Mustache ­ C++ Performance
#BosWebPerf
Mustache ­ Client
Precompiled hogan.js templates
#BosWebPerf
Where we are
now
#BosWebPerf
Today's UI Rendering Stack
Mustache Templates
C++ on server, precompiled for client
Server Client
#BosWebPerf
On the client...
#BosWebPerf
Tungsten.js
#BosWebPerf
Application Logic
DOM Updates
Templates
#BosWebPerf
App
Logic
DOM
Updates
Templates
Retained   API for developers
...but no more DOM manipulation
Added more powerful "framework" features
Backbone.js
var AppView = View.extend({
childViews: {
'js-new-todo': NewItemView,
'js-todo-item': TodoItemView
},
events: {
'click .js-toggle-all': 'handleClickToggleAll'
'click .js-clear-completed': 'handleClickClearComple
}
});
#BosWebPerf
App
Logic
DOM
Updates
Templates
Handles taking the output from template and
updating the page
Uses the   library for updating the
DOM
...but could use any DOM updating library
( , etc.)
virtual­dom
Incremental DOM
#BosWebPerf
App
Logic
DOM
Updates
Templates
Uses   templates
Data + Template → DOM
Rendered on both client and server
Mustache
<div id="main">
<input class="js-toggle-all" type="checkbox">
<ul id="todo-list">
{{#todoItems}}
{{> todo_item}}
{{/todoItems}}
</ul>
</div>
#BosWebPerf
On the
server...
#BosWebPerf
Mustache_Data
Next iteration of view classes
Better encapsulation
Stronger schema and security
Clearer client contract
#BosWebPerf
Mustache_Data
class Simple_View extends Mustache_Data {
public $product_model;
public function product_name() {
return $this->product_model->name;
}
protected function template_name() {
return 'path/to/template';
}
}
#BosWebPerf
What's Next?
#BosWebPerf
Where we're going
Mustache_Data <=> Component
Increasing Cohesion
Sharing validation and other data across client­server
Lambdas in php­mustache
#BosWebPerf
Takeaways
#BosWebPerf
Abstraction isn't a zero­sum game
#BosWebPerf
Abstraction isn't a zero­sum game
­ Edsger W. Dijkstra
The purpose of abstraction is [...] to create
a new semantic level in which one can be
absolutely precise.
“
#BosWebPerf
The problem of "rendering" can't be isolated
to client or server
#BosWebPerf
"We're never done"
Performance + abstraction is an iterative
process
#BosWebPerf
Performance is a means to an end
#BosWebPerf
Tungsten.js at 
Mustache extension at
github.com/wayfair/tungstenjs
github.com/jbboehr/php­mustache
#BosWebPerf
Questions?

UI Rendering at Wayfair