And a 5 min introduction to Archiejs - a library for writing modular code in Nodejs.

Modular-services in a Nodejs Monolith

I am

  • Fullstack - Startup - Penguin
  • ...

http://bit.ly/archiejs-demo

I am

  • Fullstack Startup Penguin
    • Not a Ninja
  • What-If startups
    • ...

http://bit.ly/archiejs-demo

I am

  • Full-stack Startup Penguin
    • Ninja is old school
  • 'What-if' startups
    • Daily arts (edeDAa)
    • ...

http://bit.ly/archiejs-demo

I am

  • Full-stack Startup Penguin
    • Penguins are team players
  • 'What-if' startups
    • Arts survived an year
    • HalfChess

http://bit.ly/archiejs-demo

halfchess.com

Comments / Criticisms / Feedbacks / Work /

Add me to your will

  • navalnovel@gmail.com
  • @navalsaini on twitter

http://bit.ly/archiejs-demo

Decompositional Techniques

  • Microservices    - micro, separate network, db
  • Modules             - few files, monolith, central db
  • Shared library   - npm modules

Startups

pre product-market fit,

experimental stuff

Mid-sized 

service companies or products with some traction

Unicorns

Big traction,

Consumer internet companies, etc

Reasons for building microservices

  • Are easier to scale
  • Improve team productivity
  • Many tools are available
  • Enforce good designed

Startups

 

~ 95%

Mid-sized

 

~ 5% 

Unicorns 

 

~ 0.01%

Reasons for NOT building microservices

  • Are easier to scale 
  • You would likely pivot

The Pivot Startup Curve

Reasons for NOT building microservices

  • Improve team productivity 
  • for bigger teams
SOA vs Mircroservice is about Agility in large teams; and not about scalability. 

Reasons for NOT building microservices

  • Many tools are available​​
  • “You need a mature operations team to manage lots of services, which are being redeployed regularly” - Martin Flower

Reasons for NOT building microservices

  • Enforces good design 
  • Difficult to predict correct boundaries from start

Monolith first - Martin flower

Advantages of Monolith 

over microservices

  • Faster to the market
  • Easier to refactor
  • Lower infra and dev costs initially

 

Monolith: 3      vs    Microservices: 0

A few months down the line...

Monolith vs Microservices

 

  • Agile development
  • Composable services

 

Monolith: 0      vs    Microservices: 2

Microservice vs Modular Monolith

  • Agile development
  • Composable services

 

Microservices: 2    vs   Modular Monolith: 5

  • Strong encapsulation
  • Well defined interfaces
  • Explicit dependencies 

Tenets of Modular Architecture

Messy Monolith

Micro-service

Modular Monolith

Micro-service

Special Thanks

  • Definition and design
  • Theory and code
  • Demo - breaking a modular app

Implementing Modular Architecture

  • Modules are self-contained, Interconnected units of business logic. 
  • A module has:-
    • Strong encapsulation
    • Well-defined interfaces
    • Explicit dependencies

Definition

Book ticket

Cache Lib

cache.js

Reserve ticket

Ticket Db

db-wrap.js

Implementation

booking.js

Booking Module

Setup

{ imports, config }

uses cache module

ticket DB module

Module Interface

Tests

/test/

Metadata package.json, index.js

  • Modularity is optimizing for
    • Readability
    • Reusablity
    • Maintainability
    • Agility

Modular Design

Domain

Aggregator

Booking

Customer (ie. user)

Authentication

Interface

Web-express

SMS-twilio

Messenger-chat

Ticket Booking App

Modular Directory Structure

Payments

Database

User

Venue

Ticket

Domain

Aggregator

Booking

Customer (ie. user)

Authentication

Interface

Web-express

SMS-twilio

Messenger-chat

Ticket Booking App

Modular Directory Structure

Payments

Database

User

Venue

Ticket

>> Readability

Domain

Aggregator

Booking

Customer (ie. user)

Authentication

Interface

Web-express

SMS-twilio

Messenger-chat

Ticket Booking App

Modular Directory Structure

Payments

Database

User

Venue

Ticket

>> Readability

>> Maintainability

Domain

Aggregator

Booking

Customer (ie. user)

Authentication

Interface

Web-express

SMS-twilio

Messenger-chat

Ticket Booking App

Modular Directory Structure

Payments

Database

User

Venue

Ticket

>> Readability

>> Maintainability

>> Reusability

Domain

Aggregator

Booking

Customer (ie. user)

Authentication

Interface

Ticket Booking App

Modular Directory Structure

India-Aggregator

US-Aggregator

Payments

Database

India-Payments

US-Payments

EU-Payments

>> Agility

or, Teamwork

Imports between directories

Disadvantages:-

  • Strong encapsulation is broken.
  • We end up with a good directory structure, but a spaghetti like code.

Book ticket

Cache Lib

(cache.js)

Reserve ticket

Ticket Db

(db-wrap.js)

Implementation logic

Booking Directory

Another

Directory / Module

  • Code
  • Configuration

Enforcing the rules of Modularity?

  • Code
  • Configuration

Enforcing the rules of Modularity?

like npm modules

additional abstraction and dependency injection

Only import the Main file (or index.js)

Rules enforced:-​​

 

  • We are allowed to import only index.js between module directories.
  • The index.js file exports and imports other modules.

 

/domains/booking/index.js

  /** fetch config **/

import { redisConfig } from './../../config/env';

  /** consumes services from modules **/

import { ticketDb } from './../../models';
...

  /** initialize implementation files **/

import initImpl from './impl'; 

const { availableSeats, 
        reserveSeat, 
        ...
      } = initImpl(redisConfig, cache, ticketDb);


  /** provides services **/

export const {
  availableSeats,
  reserveSeats,
  ...
};

Plain (NPM like) Modules Approach

Disadvantages:-

 

  • Directories are hardcoded in imports, giving lesser flexibility to plugin new modules.
  • Does not support async initializations.

/domains/booking/index.js

  /** fetch config **/

import { redisConfig } from './../../config/env';

  /** consumes services from modules **/

import { ticketDb } from './../../models';
...

  /** initialize implementation files **/

import initImpl from './impl'; 

const { availableSeats, 
        reserveSeat, 
        ...
      } = initImpl(redisConfig, cache, ticketDb);


  /** provides services **/

export const {
  availableSeats,
  reserveSeats,
  ...
};

ArchieJs Modules

Move linkages to configuration.

{
  "name": "booking",
  "version": "1.0.0",
  "description": "a ticket book...",
  "author": "ns@work.com",

  "plugin": {
    "consumes": [
      "db.Ticket",
      "cache"
    ],
    "provides": {
      "booking@v1": "booking_v1.js",
      "booking@v2": "booking_v2.js"
    }
  },

  "scripts": {
    "test": "mocha tests"
  }
}
let cache, ticketDb;
let blockDuration;

module.exports = function setup(imports, 
                             config) {
      /** config values **/
    blockDuration = config.blockDuration 
                             || 120;
      /** imports **/
    cache = imports['cache'];
    ticketsDb = imports['db.Ticket'];

      /** provides services **/    
    return {
      availableSeats,
      blockSeats,
      ...
    };
}

function availableSeats(params) {
    // do stuff
}

package.json

booking_v1.js

Index.js Modules

(Modules in code)

  • Strong encapsulation
  • Well defined interfaces
  • Explicit dependencies

ArchieJs Modules

(Modules in config)

Index.js Modules

  • No learning curve
  • Cannot plug-in/plug-out modules
    • Hardcoded directories
    • Sync Initialization
    • No lifecycle support
  • Cannot break-up into partitioned services
  • Difficult to develop tooling on

ArchieJs Modules

  • Has a learning curve
  • Can plug-in/plug-out modules
    • Uses service names
    • Sync/Async Initialization
    • Modules have lifecycle
  • Enhancers allow break-up of monoliths into partitioned services by altering configuration
  • Easy to develop tooling on

Key Differences

ArchieJS in 5 Mins​

  • One line pitch

  • History

  • How it works

  • Discussion

  • Demo

One line pitch

  • Archiejs moves the higher level dependencies of business logic outside of the implementation (.js) files into configuration (.json) files . This allows us to create better modular applications.

History

  • Derived from a library Archietech.js (2011-12); used in production by C9 (now a part of Amazon).
  • Production tested: ArchieJS (2016) is a rewrite & simplification of Archietect.js ; and therefore is production tested to an extent.
  • Minimal: It took about 10 days to code the library.

How it works

  • ArchieJS uses dependency injection to create the app.
  • All modules are listed in an array in dep-tree.js .
  • The array is passed to Archiejs APIs.
  • In step 1, ArchieJS resolver reads each module's package.json and loads the js files using commonJS (require).
  • In step 2, ArchieJs creates a dependency graph based on provides/consumes of each module and initializes modules as per the dependency graph.

Discussion - a quick recap

  • Strong Encapsulation
    • No 'import' between modules.

  • Well defined interfaces
    • Forces a greater thought to a reusable API design.
  • Explicit dependencies
    • Module dependency tree gives a birds-eye view of the project.

Demo - breaking up monolith

with reddis-kue pub/sub

  • /deptree.js
  • /modules/booking
  • /interfaces

The Monolith

1. mongod

2. redis-server

3. Node app

4. Testcases

Booking logs appear in Monolith

The Booking Service

2. redis-server

4. Web App

1. mongod

3. Booking Service

Testcases

Booking Service

Not covered in the talk...

  • Coupling in database - Monoliths to Micro-services
  • Advanced Archiejs features like Enhancers
  • Future path for Archiejs

Ask Naval Saini

@navalsaini on twitter

Visit ArchieJs

github.com/archiejs

Modular-services in a NodeJs Monolith

By Naval Saini

Modular-services in a NodeJs Monolith

An introduction to a dependency chaining library - ArchieJs

  • 1,785