SlideShare a Scribd company logo
1 of 38
Developing web-
apps like it’s
2013
  a case-study of using node.js to build
         entreprise applications


                                           1
Who?
Laurent Van Basselaere
@Laurent_VB

I do stuff with code
at Arhs Developments


                         2
ARHS Developments



10 years, 300 people
Consulting & fixed price projects
Software (Java)
Business Intelligence

                                    3
testing




          4
Testing




          5
6
MS Access? SRSLY?
MS Access
Multiple copies
Single user
No remote use
Lame

                    7
Fatman FTW
MS Access Browser
Multiple versions Centralized
Single user Unlimited users
No remote use Everywhere
Lame Awesome

                                8
We wrote a web-app




                     9
Fatman tech stack
Bootstrap   async
Knockout    underscore
Express     moment
Node
Mongoose
MongoDB

                         10
Elegant MongoDB object modeling for
Node.js



ORM seemed desirable
Clean object model to use in app code


                                        11
Schema
var mongoose = require(‘mongoose’);
mongoose.connect(‘localhost’, ‘fatman’);

var ProjectSchema = new mongoose.Schema({
    id : String
  , name : String
  , users : [String]
});

var Project = mongoose.model('Project', ProjectSchema);




                                                          12
CREATE/EDIT
var project = new Project({
    id: ‘AKCT’
  , name: ‘GOCA Newsoft AKCT’
  , users: [‘vanbasla’, ‘grosjech’]
});

project.save(function (err){
    //… callback after save
});




                                      13
RETRIEVE
// find project by id
Project.where(‘id’, ‘AKCT’)
       .findOne(function(err, project) {
           // do something with search result
       });

// find my projects
Project.find({‘users’: username})
       .exec(function(err, projects){
           // do something with search results
       });




                                                 14
MORE Schema
function trim(value){
      return value ? value.trim() : value;
}
function lessThan80chars(value){
      return value.length <= 80;
}

var ProjectSchema = new mongoose.Schema({
      id : {type: String, required: true, unique: true}
    , name : {type: String, set: trim, validate: [
            lessThan80chars,
            'Value too long. Max 80 characters.']}});


                                                          15
Advanced
// statics
ProjectSchema.statics.findById = function(projectId, cb){
  Project.where('id', projectId).findOne(cb);
};

// methods
ProjectSchema.methods.issueTrackerEnabled = function() {
  return this.issueTracker != null;
};

// middleware
ProjectCaseSchema.pre(‘remove’, function(next) {
  // do something when a Project is deleted
  next();
});

                                                            16
In fatman
We use
     setters
     +
     pre-save middleware
to keep history of edits.


                            17
In fatman
// creates a setter for field
function setter(field) {
  return function setField(newValue) {
    this._oldValues = this._oldValues || {};
    this._oldValues[field] = this[field];
    return newValue;
  }
}

var TestCaseSchema = new Schema({
  id: {type:Number,index:true},
  description: {type:String, set: setter('description')},
  history: [Schema.Types.Mixed]
});

                                                            18
In fatman
// Populate history before save.
TestCaseSchema.pre('save', function (next) {
  var self = this
    , oldValues = this._oldValues || {};

 delete this._oldValues;

 this.modifiedPaths.forEach(function (field) {
   if (field in oldValues) {
     self.history.push({
       ‘old': oldValues[field],
       ‘new’: self[field]
     });
   }
 });

  next();
});


                                                 19
Express is a minimal and flexible
node.js web application framework.



Simple and modular
Node de-facto standard
Hello Express
var express = require('express'),
    consolidate = require('consolidate');

// create an express app
var app = express();

// configure view engine
app.engine('html', consolidate.handlebars);
app.set('views', __dirname + '/views');

// configure a route with an url parameter
app.get('/hello/:name', hello);

function hello(req, res, next){
    res.render('hello.html', {
        'name' : req.params.name
    });
}

app.listen(1337);
console.log('Listening on port 1337');
controller
function list (req, res, next){
  Project.findById(req.params.projectId, function(err, project){
    if (err) return next(err);

      TestCase.find({‘project’: project}, function(err, testcases){
        if (err) return next(err);

        res.render(‘testcases.html’, {
          ‘project’: project,
          ‘testcases’: testcases
        });
      });
    });
}
controller
function show (req, res, next){
  Project.findById(req.params.projectId, function(err, project){
    if (err) return next(err);

      TestCase.findOne({‘project’:project, ‘id’:id}, function(err, tc){
        if (err) return next(err);

        res.render(‘testcase.html’, {
          ‘project’: project,
          ‘testcase’: tc
        });
      });
    });
}
controller
function save (req, res, next){
  Project.findById(req.params.projectId, function(err, project){
    if (err) return next(err);

      var tc = new TestCase(req.body);
      tc.project = project;
      tc.save(function(err, tc){
        if (err) return next(err);

        // redirect after post
        res.redirect(req.url);
      });
    });
}
MIDDLEWARE
function loadProject(req, res, next){
  Project.findById(req.params.projectId, function(err, project){
    if (err) return next(err);

      res.locals.project = project;
      next();
    });
}

// before all routes requiring a project
app.all('/:projectId/*', loadProject);
BETTER
function list (req, res, next){
  var project = res.locals.project;
  TestCase.find({‘project’:project}, function(err, testcases){
    if (err) return next(err);

      res.render(‘testcases.html’, {
        ‘testcases’: testcases
      });
    });
}
BETTer
function show (req, res, next){
  var project = res.locals.project;
  TestCase.findOne({‘project’:project, ‘id’:id}, function(err, tc){
    if (err) return next(err);

      res.render(‘testcase.html’, {
        ‘testcase’: tc
      });
    });
}
BETTer
function save (req, res, next){
  var tc = new TestCase(req.body);
  tc.project = res.locals.project;
  tc.save(function(err){
    if (err) return next(err);

      res.redirect(req.url);
    });
}
pyramid of doom
function search (req, res, next){
  Project.findById(projectId, function(err, project){
    if (err) return next(err);

     TestPlan.findByIdentifier(project, testPlanId, function(err, testPlan) {
       if (err) return next(err);

       var tags = getTagsFromRequest(req);
       TestCase.findByTag(testPlan, tags, function(err, tagQuery, testCases){
         if (err) return next(err);

         TestCase.countTags(tagQuery, function(err, tagsResult) {
           if (err) return next(err);

            res.render(‘search’, {
              ‘testCases’ : testCases,
              ‘tagsResult’ : tagsResult,
              ‘project’ : project,
              ‘testPlan’ : testPlan,
              ‘tags’ : tags
            });
          });
        });
      });
    });
}
Async.js

Async is a utility module which provides
straight-forward, powerful functions for
working with asynchronous JavaScript
pyramid NO MOREAsync.js

function search (req, res, next){
  async.waterfall([
    function(cb){
      Project.findById(projectId, cb);
    },
    function(cb, project){
      res.locals.project = project;
      TestPlan.findByIdentifier(project, testPlanId, cb);
    },
    function(cb, testPlan){
      res.locals.testPlan = testPlan;
      var tags = res.locals.tags = getTagsFromRequest(req);
      TestCase.findByTag(testPlan, tags, cb);
    },
    function(cb, tagQuery, testCases){
      res.locals.testCases = testCases;
      TestCase.countTags(tagQuery, cb);
    }
  ], function(err, tagsResult){
    if (err) return next(err);
    res.render(‘search’, tagsResult);
  });
}
MORE async                              Async.js

var ids = [‘AKCT’, ‘FATMAN’];
var projects = [];

ids.forEach(function(id){
  Project.findById(id, function(err, project){
    projects.push(project);
  });
});
res.render(‘projects’, {‘project’ : projects});



           WRONG
MORE async                              Async.js

var ids = [‘AKCT’, ‘FATMAN’];
var projects = [];

async.each(ids, function(id, next){
  Project.findById(id, function(err, project){
    projects.push(project);
    next();
  })
}, function(err){
  res.render(‘projects’, {‘projects’: projects});
});
MORE async                Async.js

Collections   Control flow

each          series
map           parallel
filter        whilst
reject        doWhilst
reduce        until
detect        doUntil
sortBy        waterfall
…             …
FATMAN
60 days dev
6 months prod
12 projects (2 to 10 users)
FATMAN
FATMAN
FATMAN

More Related Content

What's hot

Scalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureScalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureFDConf
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptjnewmanux
 
Object-Oriented Javascript
Object-Oriented JavascriptObject-Oriented Javascript
Object-Oriented Javascriptkvangork
 
Vue.js + Django - configuración para desarrollo con webpack y HMR
Vue.js + Django - configuración para desarrollo con webpack y HMRVue.js + Django - configuración para desarrollo con webpack y HMR
Vue.js + Django - configuración para desarrollo con webpack y HMRJavier Abadía
 
What's new in jQuery 1.5
What's new in jQuery 1.5What's new in jQuery 1.5
What's new in jQuery 1.5Martin Kleppe
 
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListenerNode.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListenerIslam Sharabash
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSAdam L Barrett
 
AngularJS Services
AngularJS ServicesAngularJS Services
AngularJS ServicesEyal Vardi
 
Workshop 12: AngularJS Parte I
Workshop 12: AngularJS Parte IWorkshop 12: AngularJS Parte I
Workshop 12: AngularJS Parte IVisual Engineering
 
Angular 1 + es6
Angular 1 + es6Angular 1 + es6
Angular 1 + es6장현 한
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016Manoj Kumar
 
Slaven tomac unit testing in angular js
Slaven tomac   unit testing in angular jsSlaven tomac   unit testing in angular js
Slaven tomac unit testing in angular jsSlaven Tomac
 
Groovy Ecosystem - JFokus 2011 - Guillaume Laforge
Groovy Ecosystem - JFokus 2011 - Guillaume LaforgeGroovy Ecosystem - JFokus 2011 - Guillaume Laforge
Groovy Ecosystem - JFokus 2011 - Guillaume LaforgeGuillaume Laforge
 
CLS & asyncListener: asynchronous observability for Node.js
CLS & asyncListener: asynchronous observability for Node.jsCLS & asyncListener: asynchronous observability for Node.js
CLS & asyncListener: asynchronous observability for Node.jsForrest Norvell
 
Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Eyal Vardi
 
What's up with Prototype and script.aculo.us?
What's up with Prototype and script.aculo.us?What's up with Prototype and script.aculo.us?
What's up with Prototype and script.aculo.us?Christophe Porteneuve
 
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJSJavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJSphilogb
 

What's hot (20)

Scalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureScalable Angular 2 Application Architecture
Scalable Angular 2 Application Architecture
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScript
 
Object-Oriented Javascript
Object-Oriented JavascriptObject-Oriented Javascript
Object-Oriented Javascript
 
AngularJs
AngularJsAngularJs
AngularJs
 
Vue.js + Django - configuración para desarrollo con webpack y HMR
Vue.js + Django - configuración para desarrollo con webpack y HMRVue.js + Django - configuración para desarrollo con webpack y HMR
Vue.js + Django - configuración para desarrollo con webpack y HMR
 
What's new in jQuery 1.5
What's new in jQuery 1.5What's new in jQuery 1.5
What's new in jQuery 1.5
 
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListenerNode.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 
Zenly - Reverse geocoding
Zenly - Reverse geocodingZenly - Reverse geocoding
Zenly - Reverse geocoding
 
AngularJS Services
AngularJS ServicesAngularJS Services
AngularJS Services
 
Workshop 12: AngularJS Parte I
Workshop 12: AngularJS Parte IWorkshop 12: AngularJS Parte I
Workshop 12: AngularJS Parte I
 
Angular 1 + es6
Angular 1 + es6Angular 1 + es6
Angular 1 + es6
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
 
Slaven tomac unit testing in angular js
Slaven tomac   unit testing in angular jsSlaven tomac   unit testing in angular js
Slaven tomac unit testing in angular js
 
Groovy Ecosystem - JFokus 2011 - Guillaume Laforge
Groovy Ecosystem - JFokus 2011 - Guillaume LaforgeGroovy Ecosystem - JFokus 2011 - Guillaume Laforge
Groovy Ecosystem - JFokus 2011 - Guillaume Laforge
 
CLS & asyncListener: asynchronous observability for Node.js
CLS & asyncListener: asynchronous observability for Node.jsCLS & asyncListener: asynchronous observability for Node.js
CLS & asyncListener: asynchronous observability for Node.js
 
Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0
 
What's up with Prototype and script.aculo.us?
What's up with Prototype and script.aculo.us?What's up with Prototype and script.aculo.us?
What's up with Prototype and script.aculo.us?
 
meet.js - QooXDoo
meet.js - QooXDoomeet.js - QooXDoo
meet.js - QooXDoo
 
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJSJavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
 

Similar to Developing web-apps like it's 2013

Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsFrancois Zaninotto
 
RESTful API In Node Js using Express
RESTful API In Node Js using Express RESTful API In Node Js using Express
RESTful API In Node Js using Express Jeetendra singh
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js frameworkBen Lin
 
Unit Testing Express and Koa Middleware in ES2015
Unit Testing Express and Koa Middleware in ES2015Unit Testing Express and Koa Middleware in ES2015
Unit Testing Express and Koa Middleware in ES2015Morris Singer
 
Build web application by express
Build web application by expressBuild web application by express
Build web application by expressShawn Meng
 
Heroku pop-behind-the-sense
Heroku pop-behind-the-senseHeroku pop-behind-the-sense
Heroku pop-behind-the-senseBen Lin
 
Writing RESTful web services using Node.js
Writing RESTful web services using Node.jsWriting RESTful web services using Node.js
Writing RESTful web services using Node.jsFDConf
 
0 to App faster with NodeJS and Ruby
0 to App faster with NodeJS and Ruby0 to App faster with NodeJS and Ruby
0 to App faster with NodeJS and RubyRebecca Mills
 
Cassandra Day Chicago 2015: 0 to App Faster with Node.js and Ruby
Cassandra Day Chicago 2015: 0 to App Faster with Node.js and RubyCassandra Day Chicago 2015: 0 to App Faster with Node.js and Ruby
Cassandra Day Chicago 2015: 0 to App Faster with Node.js and RubyDataStax Academy
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs偉格 高
 
NoSQL meets Microservices - Michael Hackstein
NoSQL meets Microservices - Michael HacksteinNoSQL meets Microservices - Michael Hackstein
NoSQL meets Microservices - Michael Hacksteindistributed matters
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Reliable Javascript
Reliable Javascript Reliable Javascript
Reliable Javascript Glenn Stovall
 
Building Web Apps with Express
Building Web Apps with ExpressBuilding Web Apps with Express
Building Web Apps with ExpressAaron Stannard
 
Dependency Management with RequireJS
Dependency Management with RequireJSDependency Management with RequireJS
Dependency Management with RequireJSAaronius
 
Build Web Apps using Node.js
Build Web Apps using Node.jsBuild Web Apps using Node.js
Build Web Apps using Node.jsdavidchubbs
 

Similar to Developing web-apps like it's 2013 (20)

Intro to Ember.JS 2016
Intro to Ember.JS 2016Intro to Ember.JS 2016
Intro to Ember.JS 2016
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
RESTful API In Node Js using Express
RESTful API In Node Js using Express RESTful API In Node Js using Express
RESTful API In Node Js using Express
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
 
Unit Testing Express and Koa Middleware in ES2015
Unit Testing Express and Koa Middleware in ES2015Unit Testing Express and Koa Middleware in ES2015
Unit Testing Express and Koa Middleware in ES2015
 
Reduxing like a pro
Reduxing like a proReduxing like a pro
Reduxing like a pro
 
Build web application by express
Build web application by expressBuild web application by express
Build web application by express
 
Heroku pop-behind-the-sense
Heroku pop-behind-the-senseHeroku pop-behind-the-sense
Heroku pop-behind-the-sense
 
Writing RESTful web services using Node.js
Writing RESTful web services using Node.jsWriting RESTful web services using Node.js
Writing RESTful web services using Node.js
 
0 to App faster with NodeJS and Ruby
0 to App faster with NodeJS and Ruby0 to App faster with NodeJS and Ruby
0 to App faster with NodeJS and Ruby
 
Cassandra Day Chicago 2015: 0 to App Faster with Node.js and Ruby
Cassandra Day Chicago 2015: 0 to App Faster with Node.js and RubyCassandra Day Chicago 2015: 0 to App Faster with Node.js and Ruby
Cassandra Day Chicago 2015: 0 to App Faster with Node.js and Ruby
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs
 
NoSQL meets Microservices - Michael Hackstein
NoSQL meets Microservices - Michael HacksteinNoSQL meets Microservices - Michael Hackstein
NoSQL meets Microservices - Michael Hackstein
 
Express JS
Express JSExpress JS
Express JS
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Reliable Javascript
Reliable Javascript Reliable Javascript
Reliable Javascript
 
Building Web Apps with Express
Building Web Apps with ExpressBuilding Web Apps with Express
Building Web Apps with Express
 
Dependency Management with RequireJS
Dependency Management with RequireJSDependency Management with RequireJS
Dependency Management with RequireJS
 
Build Web Apps using Node.js
Build Web Apps using Node.jsBuild Web Apps using Node.js
Build Web Apps using Node.js
 
NoSQL meets Microservices
NoSQL meets MicroservicesNoSQL meets Microservices
NoSQL meets Microservices
 

Recently uploaded

DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamUiPathCommunity
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Zilliz
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Angeliki Cooney
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Zilliz
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfOrbitshub
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Victor Rentea
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...apidays
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...apidays
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxRemote DBA Services
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdfSandro Moreira
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...apidays
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 

Recently uploaded (20)

DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 

Developing web-apps like it's 2013

  • 1. Developing web- apps like it’s 2013 a case-study of using node.js to build entreprise applications 1
  • 2. Who? Laurent Van Basselaere @Laurent_VB I do stuff with code at Arhs Developments 2
  • 3. ARHS Developments 10 years, 300 people Consulting & fixed price projects Software (Java) Business Intelligence 3
  • 6. 6
  • 7. MS Access? SRSLY? MS Access Multiple copies Single user No remote use Lame 7
  • 8. Fatman FTW MS Access Browser Multiple versions Centralized Single user Unlimited users No remote use Everywhere Lame Awesome 8
  • 9. We wrote a web-app 9
  • 10. Fatman tech stack Bootstrap async Knockout underscore Express moment Node Mongoose MongoDB 10
  • 11. Elegant MongoDB object modeling for Node.js ORM seemed desirable Clean object model to use in app code 11
  • 12. Schema var mongoose = require(‘mongoose’); mongoose.connect(‘localhost’, ‘fatman’); var ProjectSchema = new mongoose.Schema({ id : String , name : String , users : [String] }); var Project = mongoose.model('Project', ProjectSchema); 12
  • 13. CREATE/EDIT var project = new Project({ id: ‘AKCT’ , name: ‘GOCA Newsoft AKCT’ , users: [‘vanbasla’, ‘grosjech’] }); project.save(function (err){ //… callback after save }); 13
  • 14. RETRIEVE // find project by id Project.where(‘id’, ‘AKCT’) .findOne(function(err, project) { // do something with search result }); // find my projects Project.find({‘users’: username}) .exec(function(err, projects){ // do something with search results }); 14
  • 15. MORE Schema function trim(value){ return value ? value.trim() : value; } function lessThan80chars(value){ return value.length <= 80; } var ProjectSchema = new mongoose.Schema({ id : {type: String, required: true, unique: true} , name : {type: String, set: trim, validate: [ lessThan80chars, 'Value too long. Max 80 characters.']}}); 15
  • 16. Advanced // statics ProjectSchema.statics.findById = function(projectId, cb){ Project.where('id', projectId).findOne(cb); }; // methods ProjectSchema.methods.issueTrackerEnabled = function() { return this.issueTracker != null; }; // middleware ProjectCaseSchema.pre(‘remove’, function(next) { // do something when a Project is deleted next(); }); 16
  • 17. In fatman We use setters + pre-save middleware to keep history of edits. 17
  • 18. In fatman // creates a setter for field function setter(field) { return function setField(newValue) { this._oldValues = this._oldValues || {}; this._oldValues[field] = this[field]; return newValue; } } var TestCaseSchema = new Schema({ id: {type:Number,index:true}, description: {type:String, set: setter('description')}, history: [Schema.Types.Mixed] }); 18
  • 19. In fatman // Populate history before save. TestCaseSchema.pre('save', function (next) { var self = this , oldValues = this._oldValues || {}; delete this._oldValues; this.modifiedPaths.forEach(function (field) { if (field in oldValues) { self.history.push({ ‘old': oldValues[field], ‘new’: self[field] }); } }); next(); }); 19
  • 20. Express is a minimal and flexible node.js web application framework. Simple and modular Node de-facto standard
  • 21. Hello Express var express = require('express'), consolidate = require('consolidate'); // create an express app var app = express(); // configure view engine app.engine('html', consolidate.handlebars); app.set('views', __dirname + '/views'); // configure a route with an url parameter app.get('/hello/:name', hello); function hello(req, res, next){ res.render('hello.html', { 'name' : req.params.name }); } app.listen(1337); console.log('Listening on port 1337');
  • 22. controller function list (req, res, next){ Project.findById(req.params.projectId, function(err, project){ if (err) return next(err); TestCase.find({‘project’: project}, function(err, testcases){ if (err) return next(err); res.render(‘testcases.html’, { ‘project’: project, ‘testcases’: testcases }); }); }); }
  • 23. controller function show (req, res, next){ Project.findById(req.params.projectId, function(err, project){ if (err) return next(err); TestCase.findOne({‘project’:project, ‘id’:id}, function(err, tc){ if (err) return next(err); res.render(‘testcase.html’, { ‘project’: project, ‘testcase’: tc }); }); }); }
  • 24. controller function save (req, res, next){ Project.findById(req.params.projectId, function(err, project){ if (err) return next(err); var tc = new TestCase(req.body); tc.project = project; tc.save(function(err, tc){ if (err) return next(err); // redirect after post res.redirect(req.url); }); }); }
  • 25. MIDDLEWARE function loadProject(req, res, next){ Project.findById(req.params.projectId, function(err, project){ if (err) return next(err); res.locals.project = project; next(); }); } // before all routes requiring a project app.all('/:projectId/*', loadProject);
  • 26. BETTER function list (req, res, next){ var project = res.locals.project; TestCase.find({‘project’:project}, function(err, testcases){ if (err) return next(err); res.render(‘testcases.html’, { ‘testcases’: testcases }); }); }
  • 27. BETTer function show (req, res, next){ var project = res.locals.project; TestCase.findOne({‘project’:project, ‘id’:id}, function(err, tc){ if (err) return next(err); res.render(‘testcase.html’, { ‘testcase’: tc }); }); }
  • 28. BETTer function save (req, res, next){ var tc = new TestCase(req.body); tc.project = res.locals.project; tc.save(function(err){ if (err) return next(err); res.redirect(req.url); }); }
  • 29. pyramid of doom function search (req, res, next){ Project.findById(projectId, function(err, project){ if (err) return next(err); TestPlan.findByIdentifier(project, testPlanId, function(err, testPlan) { if (err) return next(err); var tags = getTagsFromRequest(req); TestCase.findByTag(testPlan, tags, function(err, tagQuery, testCases){ if (err) return next(err); TestCase.countTags(tagQuery, function(err, tagsResult) { if (err) return next(err); res.render(‘search’, { ‘testCases’ : testCases, ‘tagsResult’ : tagsResult, ‘project’ : project, ‘testPlan’ : testPlan, ‘tags’ : tags }); }); }); }); }); }
  • 30. Async.js Async is a utility module which provides straight-forward, powerful functions for working with asynchronous JavaScript
  • 31. pyramid NO MOREAsync.js function search (req, res, next){ async.waterfall([ function(cb){ Project.findById(projectId, cb); }, function(cb, project){ res.locals.project = project; TestPlan.findByIdentifier(project, testPlanId, cb); }, function(cb, testPlan){ res.locals.testPlan = testPlan; var tags = res.locals.tags = getTagsFromRequest(req); TestCase.findByTag(testPlan, tags, cb); }, function(cb, tagQuery, testCases){ res.locals.testCases = testCases; TestCase.countTags(tagQuery, cb); } ], function(err, tagsResult){ if (err) return next(err); res.render(‘search’, tagsResult); }); }
  • 32. MORE async Async.js var ids = [‘AKCT’, ‘FATMAN’]; var projects = []; ids.forEach(function(id){ Project.findById(id, function(err, project){ projects.push(project); }); }); res.render(‘projects’, {‘project’ : projects}); WRONG
  • 33. MORE async Async.js var ids = [‘AKCT’, ‘FATMAN’]; var projects = []; async.each(ids, function(id, next){ Project.findById(id, function(err, project){ projects.push(project); next(); }) }, function(err){ res.render(‘projects’, {‘projects’: projects}); });
  • 34. MORE async Async.js Collections Control flow each series map parallel filter whilst reject doWhilst reduce until detect doUntil sortBy waterfall … …
  • 35. FATMAN 60 days dev 6 months prod 12 projects (2 to 10 users)