@MichaelLNorth
Modern CI/CD and
Asset Serving
Mike North
10/20/2015
@MichaelLNorth
About.me
• Job.new = CTO
• Job.old = UI Architect for Yahoo Ads & Data
• Organizer, Modern Web UI
• Ember.js, Ember-cli, Ember-data contributor
• OSS Enthusiast
Agenda
Manual
Integration
Continuous
Integration
Manual
Releases
Continuous
Deployment
Modern Asset
Serving
Integration
(working together)
@MichaelLNorth
Integration
MASTER
FEATURE BRANCHES
@MichaelLNorth
Integration Hell
• Merge Conflicts
• Duplicate Work
• Difficult to automate
• Detect problems late
• Lack of visibility
@MichaelLNorth
Continuous Integration (CI)
• Stay close to master
• Tests are automatically run on each small change
• Alert team when tests fail!
• Team keeps the pipeline healthy
Technology + People
@MichaelLNorth
Continuous Integration (CI)
• Hide (and merge) incomplete features
• It’s ok to stub things out in the beginning
• Modular design practices
• Bottom up
• Top down and stub
Staying close to master
@MichaelLNorth
Continuous Integration (CI)
Test each change - Push vs PR build
MASTER
FEATURE
BRANCH
HEAD
PULL REQUEST
“PUSH” BUILD “PR” BUILD
@MichaelLNorth
Continuous Integration (CI)
Test each change - Green Light?
✓ ✓
?
…later…
Never Tested
@MichaelLNorth
Continuous Integration (CI)
• Pipeline breaks? Treat like a critical bug
• Don’t pile on top of a break
• Assume things will fail
• Write tests that give you release confidence
Good team practices
@MichaelLNorth
Continuous Integration (CI)
Keep the pipeline fast
Trunk Staging Production
60m 10m
✘
60m to fix
@MichaelLNorth
Continuous Integration (CI)
Keep the pipeline fast
Trunk Staging Production
10m 60m
✘
10m to fix
@MichaelLNorth
Continuous Integration (CI)
Keep the pipeline fast
• Selenium is slow
• JS tests (QUnit, Mocha) — are fast
• Useless tests === tech debt
• Hitting a real API in your UI’s CI pipeline should be
kept at a minimum
@MichaelLNorth
Mocking an API
• Hijacks the XMLHttpRequest object
• Responds to requests with pre-defined fixtures
• Allows for passthrough on defined URLs
• Throws errors whenever unexpected requests
are sent
Pretender.js
Pretender
DefineJSONFixtureSetup“Server”
XHR
github.com/
pretenderjs/
pretender
Deployment
(the “shipping it” part)
@MichaelLNorth
Releases
• Manual releases are painful, expensive
demoralizing and risky
• Human testing scales terribly
@MichaelLNorth
Continuous Deployment (CD)
• Code goes from master to
production, w/o human
intervention required
• Heavy emphasis on
automated testing
• Release early and often!
@MichaelLNorth
Continuous Deployment (CD)
Good team practices
• Flow to production only when you want
• Report released changes back to the team
• Master === Production
• App versioning (SHA?)
@MichaelLNorth
Continuous Deployment (CD)
Canary Environment
Trunk Staging
Production
(Canary)
Production
(GA)
24h Wait
90%10%
Prod Verification
Tests
Unit, Functional,
Integration Tests
@MichaelLNorth
Continuous Deployment (CD)
• Increased reliability, visibility, velocity, flexibility,
focus, agility
• Reduced pressure to prematurely ship
• Deliver incremental value to users, early
• Consistency
Benefits
@MichaelLNorth
Continuous Deployment (CD)
…for single-page apps…
index.html
mystyle.css
app.js
vendor.js
CDN
REDIS
Asset Serving
(the “delivering it” part)
@MichaelLNorth
Asset Serving
• Often overlooked, but important part of SPA development
• What do we want?
• Fast initial page load
• Maintenance page, API is down page, etc…
• Notify users of new version available
• Canary environment
@MichaelLNorth
Asset Serving
• S3 is not a CDN - Latency matters!
• CSS, JS, Images should be cached, index.html
should not
Fast initial page load
index.html
mystyle-b41cd1a832.css
app-1ab41cd781.js
vendor-ab818d2175.js
@MichaelLNorth
Asset Serving
…for single-page apps…
Server
index.html
*.{js, css, png, etc…}
REDIS
@MichaelLNorth
Asset Serving
• Canary and “GA” environment are separate
versions
Canary Environment - Multi tenancy
index.html
mystyle-b41cd1a832.css
app-1ab41cd781.js
vendor-ab818d2175.js
index.html
mystyle-b41cd1a832.css
app-cbab412.js
vendor-abcd1d12.js
@MichaelLNorth
Asset Serving
• There’s a version for each
git SHA
• Via query param, you
can ask for a version
Canary Environment - Multi tenancy
myapp:a1b231c <html><head>…
myapp:d1241b <html><head>…
myapp:abc11db <html><head>…
http://myapp.com?key=bc147ba
@MichaelLNorth
Asset Serving
• There’s a version for each
git SHA
• Via query param, you
can ask for a version
• There are also some
named versions, that
refer to other versions
Canary Environment - Multi tenancy
myapp:current myapp:a1b231c
myapp:a1b231c <html><head>…
myapp:d1241b <html><head>…
myapp:canary myapp:d1241b
myapp:abc11db <html><head>…
@MichaelLNorth
Asset Serving
Canary Environment - Multi tenancy
myapp:current myapp:a1b231c
myapp:a1b231c <html><head>…
myapp:d1241b <html><head>…
myapp:canary myapp:d1241b
myapp:abc11db <html><head>…
host & paths app
localhost:3000/* myapp:current
lvh.me/* myapp:current
canary.lvh.me/* myapp:canary
Add a URL-to-App table to the mix
@MichaelLNorth
Asset Serving
Maintenance Mode
myapp:current maintenance:current
myapp:a1b231c <html><head>…
myapp:d1241b <html><head>…
myapp:canary myapp:d1241b
myapp:abc11db <html><head>…
maintenance:1dbabc1 <html><head>…
maintenance:current maintenance:1dbabc1
host & paths app
localhost:3000/* myapp:current
lvh.me myapp:current
canary.lvh.me myapp:canary
@MichaelLNorth
Asset Serving
Making a “PR Build” available
myapp:current maintenance:current
myapp:a1b231c <html><head>…
myapp:d1241b <html><head>…
myapp:canary myapp:d1241b
myapp:abc11db <html><head>…
maintenance:1dbabc1 <html><head>…
maintenance:current maintenance:1dbabc1
MASTER
FEATURE
BRANCH
HEAD
PULL
REQUEST
“PUSH” BUILD “PR” BUILD
myapp:bc147ba <html><head>…
http://myapp.com?key=bc147ba
@MichaelLNorth
Asset Serving
Notifying existing clients about deploys
myapp:current maintenance:current
myapp:a1b231c <html><head>…
myapp:d1241b <html><head>…
myapp:canary myapp:d1241b
myapp:abc11db <html><head>…
maintenance:1dbabc1 <html><head>…
maintenance:current maintenance:1dbabc1
myapp:bc147ba <html><head>…
A new version is here! Click below to start using it!
http://myapp.com?key=bc147ba
W
ebSocket
Pub/Sub
Slack, Github, etc…
…It’s coming…
https://github.com/mike-north/banker
• Manual testing and releasing can be awful at scale
• CI/CD is an investment worth making
• Don’t treat your SPA like an API
• Your asset serving layer can boost productivity!
• Check out mike-north/Banker soon for a turnkey
implementation!
TL;DR

CI/CD and Asset Serving for Single Page Apps