Β© 2015 Gideon de Villiers Used with permission
Node.js
At Disney?
by
Adam Eivy \[._.]/ @antic
updated: 2016.07.27
Talk Time: 25 minutes
Read Time: ~15 minutes
Contents
- βΉοΈAbout Disney / My Team
- π§Challenges
- π¨Open Source Approval
- π€Tools / Recommendations We Make
- πProblems We Solve With Node.js
- β Mistakes

Disney is huge!

Seattle skyline by Lena Eivy
Disney Technology Solutions and Services
Engineering Services Architecture
- Security / Performance / Scalability
- Developer Experience
- CI/CD
- Shared Solutions
- Advise / Recommend Standards

I believe
A great Developer Experience
is necessary for developers to do the Right Thingβ’
\[._.]/

Innovation Driven Company
To Support Grassroots
we
Build Tools, Share Solutions

The Problematic Carrot
β npm i -S buzzphrase
"dependencies": {
"buzzphrase": "^2.0.0"
}
Ideologically Awesome
Who doesn't want (Minor, Patch) updates?
\[^_^]/
Buzzphrase
CLI Mode
β npm install -g buzzphrase
β buzzphrase 2
distributed organizational engagement, independent of evolved behavioral channels
Module Mode
var buzzphrase = require('buzzphrase')
console.log('we are building', buzzphrase.getPhrase(2))
we are building extravehicular granular capabilities, in preparation for synchronized multi-layered convergence
ES2015 is Awesome!
ΛΜ‘Μ(ββΛαΊΛ)βββ=ΝΝΝΝΛ³Λΰ₯°Β°βΰ§ΉΰΉ
var phrase = require('./lib/phrase')
module.exports = function(iterations) {
return phrase(iterations)
}
β
import phrase from 'phrase'
export default (iterations = 1) => eval( 'phrase('+iterations+')' )

β git commit -m "$(buzzphrase 2)"
β git commit -m "$(buzzphrase 2)"
[master aa48511] syndicated functional value-add on behalf of balanced disintermediate interfaces
1 file changed, 15 insertions(+), 10 deletions(-)
β git tag 2.1.0 && git push && npm publish
β git tag 2.1.0 && git push && npm publish
Β―\_(γ)_/Β―



It isn't working on my machine...
β npm install
β cat package.json | jq .dependencies.buzzphrase
"^2.0.0"
β cat node_modules/buzzphrase/package.json | jq .version
"2.1.0"
β node -v
v0.10.36

OK, not really
Buzzphrase is infallable
and the maintainer is
the most responsible person on the internet
But this has happened

Even Using
~
notation
"dependencies": {
"bootstrap": "~3.3.0"
}
Broke Development Interface

Open Source Software Approval Committee
they don't like surprises

Hey, I want to use Node.js 4.4.6
submit a ticket with a spreadsheet
- What's the License?
- Usage Questions
- specific version
Security / OSS Requirement
Pin Versions
--save-exact or -E
β npm i -S -E buzzphrase@2.0.0
ALWAYS
β npm config set save-exact true
"dependencies": {
"buzzphrase": "2.0.0"
}
And Shrinkwrap
β npm shrinkwrap [--dev]
VS
β npm-shrinkwrap [--dev]
Use updtr + nsp check
β npm i -g updtr
β updtr
![\[._.]/ runs `npm test` between package updates](images/updtr.gif)
What version of Node.js are you running?
0.10.364.2.44.4.75.10.16.2.1
nvm stable
Β―\_(γ)_/Β―
Recommendation
β brew install node
^ installs 6.2.1, not LTS (yet)
Node Version Manager: NVM
β brew install nvm
# curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.2/install.sh | bash
β nvm install 4.4.7
β node -v
v4.4.7
β npm -v
2.15.8
β which node
/Users/antic/.nvm/versions/node/v4.4.7/bin/node
Add .nvmrc
β echo "4.4.7" > .nvmrc
β nvm use
Now using node v4.4.7 (npm v2.15.8)
.zshrc (shell-fu)
autoload -U add-zsh-hook
load-nvmrc() {
if [[ -f .nvmrc && -r .nvmrc ]]; then
nvm use &> /dev/null
elif [[ $(nvm version) != $(nvm version default) ]]; then
nvm use default &> /dev/null
fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc

Use Autochecker
β npm i -D -E autochecker
"scripts": {
"test": "./node_modules/mocha/bin/mocha",
"nodeversions": "node ./node_modules/autochecker/cli.js"
},
β npm run nodeversions

I want to use Node.js
4.4.64.4.7
and updated 15 modules...
submit another ticket with a spreadsheet
Automate with Node.js CLI tool
#!/usr/bin/env node
// read package.json
const fs = require('fs')
// check versions against approved OSS list
const request = require('request')
// the list doesn't have an API so we scrape it
const cheerio = require('cheerio')
// give the user progress update
const progress = require('progress')
// populate spreadsheet with items needing to be approved
const xlsx = require('xlsx-template')
β snoden
Usage: <command> [options]
Commands:
check βοΈ check this project for standards, security and OSS
update π¦ update this tool to the latest version
Options:
--dev π§ include devDependencies in npm shrinkwrap
--skip-clean β© skip breaking on dirty git repo state
--skip-gitignore π do not check for node_modules in .gitignore
--skip-npm β© skip npm install step (speeds up check if already done)
--skip-nsp β skip nsp (not recommended, enables offline test)
--skip-shrinkwrap β οΈ skip npm shrinkwrap (not recommended)
--skip-update π¦ skip updating node packages (using updtr)
--skip-xls β© skip excel spreadsheet creation (useful on build server)
-a, --auto β auto-fix issues without prompting or throwing errors
-b, --build π€ bot mode: skip corrective user prompts (throws errors)
Every Day
β snoden check
# submit OSS request
β snoden check
# submit OSS request

Drowning
the
Committee

but
It's getting better
Automation FTW
β snoden check
βοΈ \[._.]/ - Hi, I'm Snoden, the Standard Node.js Enforcer. Checking your package...
β
git workspace is clean
β
.nvmrc set to 4.4.7
β‘οΈ npm install
β
node_modules installed
β
dependencies packages are pinned
β
devDependencies packages are pinned
β‘οΈ updating package deps with updtr
β
packages up-to-date
β
npm-shrinkwrap found
β
.gitignore contains node_modules
β‘οΈ nsp check
β
(+) No known vulnerabilities found
compiling xlsx [====================================] 100% 0.0s

Why Do We Use Node.js?
Big on Java
but with Node.js
- JSON all the way down
- no (de)serialization
- speed of development
- awesome command-line apps
- TPS: 350 vs 3K per instance

50 Years of Back-End Services
- new apps all the time
-
make 20 calls to APIs - make 1 call to Node.js orchestration API
- 3 years ago:
- A service took 4 TPS
- Can node handle 8 TPS?
- ( Ν‘Β° ΝΚ Ν‘Β°) - LoL
1st DTSS Production Node.js
- Augment a Java REST API
- 1 Month Deadline
- 1 Developer + Node.js: 8 days
- 99% code coverage (Hapi.js + Joi + Lab)
- Performance: 2K TPS per node vs 450 TPS
- Speed of Change (amazing)

Cloud Infrastructure
CLI

Format CLI Output
/**
* output module: unify ouput formatting logic
* json, table, or yaml
*/
var _ = require('lodash')
var argv = require('yargs').argv
var prettyjson = require('prettyjson')
var Table = require('cli-table')
module.exports = function(data, columns) {
if (argv.json)
return console.log(JSON.stringify(data, null, 2))
if (argv.yaml)
return console.log(prettyjson.render(data))
var table = new Table({ head: columns })
[].push.apply(
table,
_.map(data, function(row){
return _.toArray(_.pick(row, columns))
})
)
console.log(table.toString())
};
l10n/i18n Service
Parsing and Returning JSON
{
"welcome": {
"filter": {
"FR": {
"adult": "You seem to be an adult in France.",
"child": "You seem to be a child in France.",
"teen": "You seem to be a teen in France.",
"default": "You seem to be in France."
}
}
}
}
?locale=en-CA&country=FR&age=child
{
"welcome": "You seem to be a child in France."
}
CDN Origin Asset Bundling
Turn 7 HTTP/1.1 requests into 1
And a Whole Lot More
9,439 git repos with a package.json
Simple Mistake
app.use(function(req, res, next) {
// ... do some things
})
oops
app.use(function(req, res, next) {
// ... do some things
next()
})
Bigger Mistake
const Hapi = require('hapi')
const server = new Hapi.Server(1337)
// complex response template (this is process memory!)
const bodySchema = require('./templates/response.schema')
server.route({
method: 'GET',
path: '/foo',
handler: function(request, reply){
bodySchema.data = 'foo data'
bodySchema.error.push({message: 'foo error'})
reply(bodySchema)
}
)
server.route({
method: 'GET',
path: '/bar',
handler: function(request, reply){
bodySchema.data = 'bar data'
bodySchema.error.push({message: 'bar error'})
reply(bodySchema)
}
)
server.start()
curl /foo
{
"data": "foo data",
"error": [{
"message": "foo error"
}]
}
curl /bar
{
"data": "bar data",
"error": [{
"message": "foo error"
}, {
"message": "bar error"
}]
}
Fixing with Hapi.js
const Hapi = require('hapi')
const server = new Hapi.Server(1337)
const cloneDeep = require('lodash.clonedeep')
const bodySchema = Object.freeze(require('./templates/response.schema'))
server.ext('onRequest', function (request, next) {
// We can ammend request.app.payload
// without polluting future requests
request.app.payload = cloneDeep(bodySchema)
next()
})
server.route({
method: 'GET',
path: '/foo',
handler: function(request, reply){
request.app.payload.data = 'change data in request memory!'
request.app.payload.error.push({message: 'request error'})
reply(request.app.payload)
}
)
server.start()

eslint didn't catch that!
so
your tests better notice

In Closing
Node.js
is
awesome
