2017 Edition
On patterns...
When you trust your patterns and you loyally abide by them, then the only problems you will have will be so big you can't miss them
Module Description
Dependencies
System Deps
NPM Deps
Project Deps
Export Statement
/**
* @fileOverview Create Camp Configuration mutation.
*/
const crypto = require('crypto');
const url = require('url');
const { coroutine } = require('bluebird');
const { GraphQLError } = require('graphql/error');
const {
GraphQLString,
GraphQLNonNull,
} = require('graphql');
const campConfigTypes = require('../types/camp-config.type');
const campConfigModel = require('../models/camp-config.model');
const accountModel = require('../../account/model');
const log = require('../../../logger').getChild(__filename);
const {
mutation,
mutationInputType,
mutationPayloadType,
isAdmin,
} = require('../../../schema/helpers');
const {
RecordIDType,
CurrencyInputType,
} = require('../../../schema/types');
/**
* Create Camp Configuration mutation.
*
* @type {Object}
*/
const mut = module.exports = {};
Spread statements after whole module ones
/**
* @fileOverview Cors Middleware.
*/
var util = require('util');
var fs = require('fs');
var Promise = require('bluebird');
var _ = require('lodash');
var Middleware = require('./middleware');
var helpers = require('../util/helpers');
1.
2.
3.
/**
* Check if provided viewer can mutate the defined album.
*
* @param {Object} viewer The viewer account object.
* @param {string} albumUuid The album uuid to be mutated.
* @param {string} mutationName A human readable unique name to identify
* the mutation.
* @return {Promise(Object)} A Promise with two keys:
* @param {Object} albumToUpdate The album to be updated.
* @param {Object} albumOwner The album owner.
* @throws {GraphQLError} if no privileges.
*/
albumPrivs.canMutate = Promise.method(function (viewer, albumUuid,
mutationName) {
Google Closure Annotations ~loosely used
https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler
const Cors = module.exports = function(){
Middleware.apply(this, arguments);
};
util.inherits(Cors, Middleware);
const cors = module.exports = {};
/**
* The Cors Middleware.
*
* @contructor
* @extends {cc.Middleware}
*/
const Cors = module.exports = function(){
Middleware.apply(this, arguments);
};
util.inherits(Cors, Middleware);
/**
* CORS Middleware
*
* @param {Object} req The request Object.
* @param {Object} res The response Object.
* @param {Function(Error=)} next pass ctrl.
*/
Cors.prototype.allowCrossDomain = function(req, res, next) {...};
Don't freak out! solution incoming...
/**
* The Cors Middleware.
*
*/
const cors = module.exports = {};
/**
* CORS Middleware
*
* @param {Object} req The request Object.
* @param {Object} res The response Object.
* @param {Function(Error=)} next pass ctrl.
*/
cors.use = function (req, res, next) { ... };
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var MiddlewareBase = module.exports = function() {
EventEmitter.apply(this, arguments);
this.foo = 1;
};
util.inherits(MiddlewareBase, EventEmitter);
middleware-base.midd.js
var util = require('util');
var MiddleWareBase = require('./middleware-base.midd');
var Cors = module.exports = function() {
MiddlewareBase.apply(this, arguments);
console.log(this.foo); // 1
};
util.inherits(Cors, MiddlewareBase);
cors.midd.js
Cors.prototype.use = function(req, res, next) {
// good
doSomeAsync(this._handleAsync.bind(this));
// bad
doSomeAsync(this._handleAsync);
};
Cors.prototype.use = function(req, res, next) {
// good
doSomeAsync((res) => {
console.log(res);
});
};
// VERY bad
Cors.prototype.use = (req, res, next) => {
}
function readNews (cb) {
// Bad - context is not required here
fetchNews((news) => {
cb(null, news);
});
}
Cors.prototype.use = function(req, res, next) {
while(true) { // highly repetitive operation
// good
var self = this;
doSomeAsync(function(result) {
self._handleAsync(result);
});
// bad
doSomeAsync(this._handleAsync.bind(this));
}
};
var EventEmitter = require('events').EventEmitter;
var cip = require('cip');
var CeventEmitter = cip.cast(EventEmitter);
module.exports = CeventEmitter.extend();
Base Constructors using CIP
const cip = require('cip');
const Ctor module.exports = cip.extend();
Base Usage
const cip = require('cip');
const Ctor module.exports = cip.extend();
/** In another module far far away ... */
const Ctor = require('../foo/ctor');
const CtorChild = module.exports = Ctor.extend(function () {
/* Constructor */
});
Inheritance using CIP
const MiddlewareBase = require('./middleware-base.midd');
const Cors = module.exports = MiddlewareBase.extendSingleton(function () {
/* Ctor */
});
/** ... in another module far far away... */
const cors = require('../middleware/cors.midd').getInstance();
cors.use();
Singletons
var MiddlewareBase = require('./middleware-base.midd');
var MiddlewareTraits = require('./middleware-traits.midd');
var Cors = module.exports = MiddlewareBase.extend(function () {
/* Ctor */
});
Cors.mixin(MiddlewareTraits);
Mixins!
var Cors = require('./cors.midd');
var SuperCors = module.exports = Cors.extend(function () {
/* Ctor */
});
Inheritance Goes on...
Promises
const Promise = require('bluebird');
/* ... */
ClipEntity.prototype.fetchVideos = function() {
return new Promise(function(resolve, reject) {
fs.read(file, function(err, res) {
if (err) {
reject(err);
} else {
resolve(res);
}
});
});
};
Promises
const Promise = require('bluebird');
/* ... */
ClipEntity.prototype.showVideos = Promise.method(function() {
return this.fetchVideos();
});
Promises
const Promise = require('bluebird');
/* ... */
Foo.prototype.bar = Promise.coroutine(function* () {
const videos = yield this.fetchVideos();
return videos;
});
Promises
Foo.prototype.bar = function () {
throw new Error('Unexpected');
});
const Promise = require('bluebird');
Foo.prototype.bar = Promise.method(function() {
throw new Error('Unexpected');
});
When invoked, kiss your server goodbye!
Everything is under control
Promises
Well... yea... you can't wrap your ES2015 Class methods...
Promises
return dropboxTokenModel.get(this.uid)
.bind(this)
.then(this._processAccessToken)
.then(this._checkDropboxAccess)
.then(this._startProcess)
.then(this._generateResponse)
.then(this._save)
.then(this._createDownloadJobs)
.then(this._purgeSyncFilesForKafka)
.catch((err) => {
log.error('start() :: Processing Failed:', err);
throw err;
});
Summarize your business logic
Promises
// use a temporary custom context for promise execution chain.
const context = {
albumToUpdate: null,
albumOwner: null,
};
return Promise.resolve(albumModel.Album.fetch(viewer, albumUuid))
.bind(context)
.then(function (albumToUpdate) {
if (!albumToUpdate) {
throw new GraphQLError('Album not found');
}
this.albumToUpdate = albumToUpdate;
return accountModel.Account.fetchById(viewer, albumToUpdate.creator_id);
})
Custom context
Sanitize unknown promises
Promises
ClipEntity.prototype._process = function(data) {
var clipProcessEnt = new ClipProcessEnt(data);
return clipProcessEnt.parseFiles()
.bind(clipProcessEnt)
.then(clipProcessEnt.isFileVideo)
.then(clipProcessEnt.storeClip)
.then(clipProcessEnt.storeThumb)
.then(clipProcessEnt.updateDatabase)
.then(clipProcessEnt.removeSourceFiles)
.return(data)
.catch(clipProcessEnt.rollback);
};
Promises
ClipEntity.prototype._process = function(data) {
var clipProcessEnt = new ClipProcessEnt(data);
var promises = [];
promises.push(clipProcessEnt.isFileVideo());
promises.push(clipProcessEnt.storeClip());
promises.push(clipProcessEnt.storeThumb());
promises.push(clipProcessEnt.updateDatabase());
return Promise.all(promises)
.catch(clipProcessEnt.rollback);
};
Promises
ClipEntity.prototype._process = function(data) {
var clipProcessEnt = new ClipProcessEnt(data);
var promises = [];
promises.push(clipProcessEnt.isFileVideo());
promises.push(clipProcessEnt.storeClip());
promises.push(clipProcessEnt.storeThumb());
promises.push(clipProcessEnt.updateDatabase());
return Promise.all(promises, {concurrency: 10})
.catch(clipProcessEnt.rollback);
};
The Patterns employed, is what draws the line between a talented engineer and a copy paste warrior
Thank you
Questions?