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
- Ninja is old school
- 'What-if' startups
- Daily arts (edeDAa)
- 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
-
Sander Mak's 'Modules or microservices?' is a great talk where I first saw the ISS example for modular architectures.
- 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';
import { cache } from './../domain/cache';
/** initialize implementation files **/
import initImpl from './impl';
/** provides services **/
const { availableSeats,
reserveSeat,
confirmSeat,
cancelSeat,
} = initImpl(redisConfig, cache, ticketDb);
export const {
availableSeats,
reserveSeats,
confirmSeat,
cancelSeat
};
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';
import { cache } from './../domain/cache';
/** initialize implementation files **/
import initImpl from './impl';
/** provides services **/
const { availableSeats,
reserveSeat,
confirmSeat,
cancelSeat,
} = initImpl(redisConfig, cache, ...);
export const {
availableSeats,
reserveSeats,
confirmSeat,
cancelSeat
};
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,
confirmSeats,
cancelSeats,
};
}
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
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
Copy of Modular-services in a NodeJs Monolith
By Naval Saini
Copy of Modular-services in a NodeJs Monolith
An introduction to a dependency chaining library - ArchieJs
- 773