Top Banner
My trip to the BACK SIDE
60

My trip to the BACK SIDE - EN

Feb 18, 2017

Download

Internet

Nahuel Lema
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: My trip to the BACK SIDE - EN

My trip to the

BACK SIDE

Page 2: My trip to the BACK SIDE - EN

@LemaNahuel

I press keys on javascript

Page 3: My trip to the BACK SIDE - EN

That is FWTV?

FWTV is the first Latin WebTV channel with designed exclusively for the Internet, where viewers can interact with programs offered both live and on-demand, anytime, anywhere content.

https://www.fwtv.tv/

Page 4: My trip to the BACK SIDE - EN

@Obaca2015 Me

Page 5: My trip to the BACK SIDE - EN

A long time ago ... (2013-2014)

Page 6: My trip to the BACK SIDE - EN

fwtv.tv

fwtv.tv/api/*

fwtv.tv/admin/*

Heroku with 4 dynos

Page 7: My trip to the BACK SIDE - EN

● Monolithic project● +150 endpoints and growing● callback hell● Frozen dependencies (Node .08, Mongoose,

Redis, Express, etc)

● No Documentation or Tests● Filesystem is no more scalable● Very long Files (average from 1000 to 2500 lines)● ...

Page 8: My trip to the BACK SIDE - EN

... ART* 500 ms - 1000 ms or more … ¬¬

*Average Response Time

Page 9: My trip to the BACK SIDE - EN
Page 10: My trip to the BACK SIDE - EN

Preparing the ground for v2

Page 11: My trip to the BACK SIDE - EN

Se we start with the obvious steps

Page 12: My trip to the BACK SIDE - EN

api.

.tv

admin.

Page 13: My trip to the BACK SIDE - EN

Like miners we start to separate the projects

Page 14: My trip to the BACK SIDE - EN

● Tests implementation● Added documentación● Extreme implementation of EsLint and jsHint● Updated dependencies and Node to 0.12● Restructured the entire filesystem

○ routes/(public || private)/*.js

○ controllers/(public || private)/*.js

● Replaced all long files with small modules● ...

Page 15: My trip to the BACK SIDE - EN

… ART meeh … ¬¬

Page 16: My trip to the BACK SIDE - EN

… but now scale better!

Page 17: My trip to the BACK SIDE - EN

v2.0 > v2.1 - Go functional!

Page 18: My trip to the BACK SIDE - EN

Standardize the use of lodash● aprox 100 implementations of _.each()● more methods implemented as _.pluck(), _.

indexOf(), _.find(), _.without(), _.omit(), etc.

Page 19: My trip to the BACK SIDE - EN

_.each(req.body.genres, (genre) => {

if (_.isObject(genre)) {

newGenres.push(genre._id);

} else {

newGenres.push(genre);

}

});

var genres = req.body.genres,

genre = null,

i = 0,

l = genres && genres.length ? genres.length : 0;

for (i; i < l; i++) {

genre = genres[i];

if (typeof genre === 'object') {

newGenres.push(genre._id);

} else {

newGenres.push(genre);

}

}

For example:_.each()

Page 20: My trip to the BACK SIDE - EN

… ART with no improvements …

Page 21: My trip to the BACK SIDE - EN

… but the code is more readable!

Page 22: My trip to the BACK SIDE - EN

v2.1 > v2.2 - only what you need

Page 23: My trip to the BACK SIDE - EN

Implementation of “Extender”● Now you can specify which fields are required and

which are not.● Used especially for translations and data uses only

the API or the admin.

Page 24: My trip to the BACK SIDE - EN

For example:

function getTranslations() { if (LOCALE.indexOf('es') === -1) { return ',translations(' +LOCALE + '(description))'; }

return '';}

var fields = '?fields='; fields += 'landing'; fields += ',popularShows(_id,logo,slug,title,description,slogan' + getTranslations() + ')';

return $http.get(PATHS.HOME + fields);

Page 25: My trip to the BACK SIDE - EN

Query strings added to Page and Limit● Skip● Limit● LastId

Page 26: My trip to the BACK SIDE - EN

For example:

return $http.get(PATHS.SHOWS, {

params: {

limit: params.limit || 12,

lastId: params.lastId,

skip: params.skip

}

});

Page 27: My trip to the BACK SIDE - EN

… ART barely noticeable …

Page 28: My trip to the BACK SIDE - EN

… but the weight is lowered 100 kb - 250 kb to 1b-30 kb!

Page 29: My trip to the BACK SIDE - EN

v2.2 > v2.3 - the real meaning of parallel

Page 30: My trip to the BACK SIDE - EN

ASYNC● _.each() >

○ async.each()● callback hell >

○ async.waterfall() ○ async.parallel()

Page 31: My trip to the BACK SIDE - EN

For example:async.waterfall()

getHome(function(home) { setPopularAndLiveShows(home, function(popularShows, liveNow, newNow){ home.popularShows = popularShows; home.liveNow = liveNow; home.newNow = newNow;

setFeaturesVideos(home, function(featuredVideos){ home.featuredVideos = featuredVideos; helpers.handleResponse(res, null, home); }); });});

async.waterfall([function(cb) { getHome(function(home) { cb(null, home); });}, function(cb) { setPopularAndLiveShows(home, function(popularShows, liveNow, newNow) { home.popularShows = popularShows; home.liveNow = liveNow; home.newNow = newNow; cb(null, home); });}, function(home, cb) { setFeaturesVideos(home, function(featuredVideos){ home.featuredVideos = featuredVideos; cb(null, home); });}], function(err, home) { helpers.handleResponse(res, null, home);});

Page 32: My trip to the BACK SIDE - EN

For example:async.parallel()

async.parallel([function(cb) { setPopularVideos(home, likedProgramIds, function(popularVideos) { home.popularVideos = popularVideos; cb(null); }); }, function(cb) { setGenres(home, function(genres) { if(genres) { home.genres = genres; } cb(null, home); });}], function(err) { cb(null, home);});

Page 33: My trip to the BACK SIDE - EN

For example:async.each()

async.each(shows, function(show, cb) { ScheduledPromo.count({

program: show._id }).exec(function(err, scheduleds) { Program.findByIdAndUpdate(show._id, { $set: { 'hasElements.scheduled': !!scheduleds } }).exec(function(err) { cb(err); }); }); }, function(err) { helpers.handleResponse(res, null, { success: !err });});

Page 34: My trip to the BACK SIDE - EN

… ART incredible striking …

Page 35: My trip to the BACK SIDE - EN

… it is now 500 ms - 1000 ms to 150 ms - 300 ms!

Page 36: My trip to the BACK SIDE - EN

v2.2 > v3 - Sh*t just got real

Page 37: My trip to the BACK SIDE - EN

Upgrade to Node 4.* and npm dependencies

Page 38: My trip to the BACK SIDE - EN

… ART still the same …

Page 39: My trip to the BACK SIDE - EN

… but consumption of RAM of Heroku decreased significantly!

Page 40: My trip to the BACK SIDE - EN

v3 > v3.1 - sugar Marty ... syntaxis sugar everywhere

Page 41: My trip to the BACK SIDE - EN

Upgrade to Node 5.* and npm dependencies● Minimum implementation of ES6

○ EsLint + ES6

○ const y let

○ arrow functions

○ classes

Page 42: My trip to the BACK SIDE - EN

… ART unimproved and falling consumption of RAM ...

Page 43: My trip to the BACK SIDE - EN

… but the code is much more readable

Page 44: My trip to the BACK SIDE - EN

The journey so far● All up-to-date (Node && NPM)● Functional programming by lodash● Asynchronism, parallelism and callback hell resolved with

async

● ES6 minimally implemented● ART between 100 ms - 300 ms

Page 45: My trip to the BACK SIDE - EN

still something missing …

Page 46: My trip to the BACK SIDE - EN

… review all the access to MongoDB

Page 47: My trip to the BACK SIDE - EN

v3.1 > v3.2 - the final fight!

Page 48: My trip to the BACK SIDE - EN

The scenario:● Made with Mongoose● ~400 queries● most carried out by the front (.tv) and the

apps

Page 49: My trip to the BACK SIDE - EN

I’m Mr. Meeseeks!! Look at me!

Page 50: My trip to the BACK SIDE - EN

Step 1:● +400 queries 1 by 1:

○ .find() >

■ .findById() || .findOne()

○ .update() >

■ .findByIdAndUpdate() || .findOneAndUpdate()

○ .remove() >

■ .findByIdAndRemove() || .findOneAndRemove()

Page 51: My trip to the BACK SIDE - EN

For example:.find() > .findById()

Model.find({ _id: req.params.id }).populate('video grouping program genres').exec((err, doc) => { helpers.handleResponse(res, err, doc);});

Model.update({ _id: req.params.id }, {}).exec((err, doc) => { helpers.handleResponse(res, err, doc);});

Model.remove({ _id: req.params.id }).exec((err, doc) => { helpers.handleResponse(res, err, doc);});

Model.findById(req.params.id) .populate('video grouping program genres') .exec((err, doc) => { helpers.handleResponse(res, err, doc); });

Model.findByIdAndUpdate(req.params.id, {}, { new: true }) .exec((err, doc) => { helpers.handleResponse(res, err, doc); });

Model.findByIdAndRemove(req.params.id) .exec((err, doc) => { helpers.handleResponse(res, err, doc); });

Page 52: My trip to the BACK SIDE - EN

Step 2:● Implemented .lean() method on all .

find*() before .exec()

Page 53: My trip to the BACK SIDE - EN

For example:.lean()

Model.findById(req.params.id) .populate('video grouping program genres') .exec((err, doc) => { helpers.handleResponse(res, err, doc); });

Model.findByIdAndUpdate(req.params.id, {}, { new: true }) .exec((err, doc) => { helpers.handleResponse(res, err, doc); });

Model.findByIdAndRemove(req.params.id) .exec((err, doc) => { helpers.handleResponse(res, err, doc); });

Model.findById(req.params.id) .populate('video grouping program genres') .lean().exec((err, doc) => { helpers.handleResponse(res, err, doc); });

Model.findByIdAndUpdate(req.params.id, {}, { new: true }) .lean().exec((err, doc) => { helpers.handleResponse(res, err, doc); });

Model.findByIdAndRemove(req.params.id) .lean().exec((err, doc) => { helpers.handleResponse(res, err, doc); });

Page 54: My trip to the BACK SIDE - EN

ok, and now ...

Page 55: My trip to the BACK SIDE - EN

… the ART down to 5 ms - 35 ms!! MOTHERF*CKAAA!!!!

Page 56: My trip to the BACK SIDE - EN

Sum-up

Page 57: My trip to the BACK SIDE - EN

● Functional, clean and less code● Lightweight requests● Low consumption of RAM● Efficient queries● Same amount of dynos, greater capacity● Weekly NCU

Page 58: My trip to the BACK SIDE - EN

Questions?

Page 59: My trip to the BACK SIDE - EN

How many Mr. Meeseeks did you find?- 9- 13- 15

Page 60: My trip to the BACK SIDE - EN

Thanks!

@LemaNahuel