SlideShare a Scribd company logo
Node.js Middleware
Never again!
Timur Shemsedinov
Chief Technology Architect at Metarhia
Lecturer at Kiev Polytechnic Institute
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
What is middleware?
● Connect contract
(req: Request, res: Response, next: NextFunction)
(req: Request, res: Response)
● Koa contract
async (ctx: Context, next: NextFunction): Promise
async (ctx: Context): Promise
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middlewares and Controller
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res)
(req, res, next)
(req, res, next)
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
What is middleware?
● Mixin provocation
● Reference pollution and shared state provocation
● Race condition provocation
● Abstraction leak provocation
● Fat controller and layers mix provocation
● High coupling provocation
● Error ignoring provocation
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
req, res
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Pass ref outer
const sockets = new Map();
app.use((req, res, next) => {
...
sockets.set(userId, req.socket);
...
next();
});
for (const socket of sockets) {
doSomethingWithSocket(socket);
}
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
instance.method(req, res, ...);
instance.method(req.socket, ...);
instance.field = req.headers;
instance.emit('request', req);
const f1 = method.bind(req);
const f2 = method(req)(res);
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
const client = new Client(req, res);
abstraction.method(client);
instance.field = client;
client.doSomething(instance);
emitter.emit('connected', client);
func(client).then(...).then(...)...;
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
calls
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
events
calls
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
events
calls
global
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
events
calls
global
fields
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Pass ref everywhere
const ee = new EventEmitter();
app.use((req, res, next) => {
ee.emit('timeout', res);
next();
});
ee.on('timeout', res) => {
setTimeout(() => {
if (!res.writableEnded) res.end('timeout');
}, 5000);
});
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Reference pollution
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next)
(req, res)
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Race, data corruption
let userId;
app.use((req, res, next) => {
userId = ...;
next();
});
app.get('/resource', (req, res) => {
if (checkAccess('/resource', userId) === GRANTED) {
res.end('You have an access');
}
});
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Mixin pollutions
Middleware
Middleware
Middleware(req, res, next)
Controller
(req, res, next)
(req, res, next) (req, res)
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: mixin to req, res, ctx
app.use((req, res, next) => {
res.groupName = 'idiots';
next();
});
app.get('/user', (req, res) => {
if (res.groupName === 'idiots') {
res.end('Welcome, my dear friend!');
}
});
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: mixin to req, res, ctx
app.use((req, res, next) => {
res.locals.groupName = 'idiots';
next();
});
app.get('/user', (req, res) => {
if (res.locals.groupName === 'idiots') {
res.end('Welcome, my dear friend!');
}
});
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Fat controller
Middleware
Middleware
Middleware Controller
● Access db
● Logging
● Parse headers
● Cache
● Business-logic
● Validation
● Serialization
(req, res, next)
(req, res)
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Don’t mix in a single function
● Data access (database connection)
● Business-logic and domain model
● Routing, logging, configuration
● Health and server state reporting
● Working with sockets, headers, cookies, etc.
● Serialization and deserialization
● Templating, caching, cryptography, sessions
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware: Fat controller
router.get('/user/:id', (req, res) => {
if (blacklist.has(res.socket.remoteAddress)) {...}
const id = parseInt(req.params.id);
if (!isValidateUserId(id)) return res.status(500);
const query = 'SELECT * FROM users WHERE id = $1';
pool.query(query, [id], (err, data) => {
if (err) {...}
logger.write(`access user: ${id}`);
res.status(200).json(data.rows);
});
});
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Middleware provocates antipatterns
● Pass-through parameters,
Too many parameters, Data clump
● Accumulate and fire
● Temporary field, State mixins, Shared state,
Global state, State in outer contexts
● Inappropriate intimacy
● High coupling (also see high cohesion pattern)
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Layered (onion) architecture
Data Access Layer
Middleware
Middleware
Controller
(req, res, next)
(req, res, next)
(req, res, next)
(req, res)
Service
domain
model
app
servicesuse cases
controllers
infrastructure
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
We need patterns and principles
● DIP (dependency inversion principle)
IoC (Inversion of control)
DI (dependency injection)
● Chain of responsibility (GoF)
● Law of demeter
● SRP (Single responsibility, SOLID)
● Low coupling (GRASP)
const fs = require('fs'); const compose = (...funcs) => x => funcs.
reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab
table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma
=> (row.map((cell, i) => { const width = cellWidth[i]; return i ? c
Keep attention on
● Domain in the middle
● Context isolation
● Layered (onion) architecture
● Don’t depend on frameworks
● Don’t move logic between model and controller
● Always work on abstraction leaking
● Protect data with parallel primitives
github.com/tshemsedinov
youtube.com/TimurShemsedinov
github.com/HowProgrammingWorks/Index
Весь курс по ноде и JS (186 лекций)
https://habr.com/ru/post/485294/
t.me/HowProgrammingWorks
t.me/NodeUA
timur.shemsedinov@gmail.com

More Related Content

PDF
Введение в SQL
PDF
Введение в программирование (1 часть)
PDF
Базы данных в 2020
PDF
Programming Languages: comparison, history, future
PDF
Haskell study 4
PPTX
Building a PII scrubbing layer
PDF
Prototype programming in JavaScript
PDF
Haskell study 5
Введение в SQL
Введение в программирование (1 часть)
Базы данных в 2020
Programming Languages: comparison, history, future
Haskell study 4
Building a PII scrubbing layer
Prototype programming in JavaScript
Haskell study 5

Similar to Node.js middleware: Never again! (20)

PDF
Serverless Clouds (FaaS) and request context isolation in Node.js
PDF
Private cloud without vendor lock // Serverless
PDF
Web Locks API
PDF
Asynchronous programming and mutlithreading
PDF
Node.js in 2020 - part 1
PDF
Patterns and antipatterns
PDF
How to keep control and safety in the clouds
PDF
How are Race Conditions in single threaded JavaScript possible?
PDF
Новое в JavaScript: ES.Next, ECMAScript 2020, ES11, ES10, ES9, ES8, ES7, ES6,...
PDF
Race-conditions-web-locks-and-shared-memory
PDF
Node.js in 2020 - part 2
PDF
Node.js in 2020
PDF
Node.js in 2020 - part 3
PDF
JavaScript в браузере: Web API (часть 1)
PPTX
Oh Composable World!
PDF
Everything is composable
PPTX
Seminar PSU 10.10.2014 mme
PDF
Reactive programming with RxJS - ByteConf 2018
PDF
Futures e abstração - QCon São Paulo 2015
PDF
PythonOOP
Serverless Clouds (FaaS) and request context isolation in Node.js
Private cloud without vendor lock // Serverless
Web Locks API
Asynchronous programming and mutlithreading
Node.js in 2020 - part 1
Patterns and antipatterns
How to keep control and safety in the clouds
How are Race Conditions in single threaded JavaScript possible?
Новое в JavaScript: ES.Next, ECMAScript 2020, ES11, ES10, ES9, ES8, ES7, ES6,...
Race-conditions-web-locks-and-shared-memory
Node.js in 2020 - part 2
Node.js in 2020
Node.js in 2020 - part 3
JavaScript в браузере: Web API (часть 1)
Oh Composable World!
Everything is composable
Seminar PSU 10.10.2014 mme
Reactive programming with RxJS - ByteConf 2018
Futures e abstração - QCon São Paulo 2015
PythonOOP
Ad

More from Timur Shemsedinov (15)

PDF
How to use Chat GPT in JavaScript optimizations for Node.js
PDF
IT Revolution in 2023-2024: AI, GPT, business transformation, future professi...
PDF
Multithreading in Node.js and JavaScript
PDF
Node.js threads for I/O-bound tasks
PDF
Node.js Меньше сложности, больше надежности Holy.js 2021
PDF
Rethinking low-code
PDF
Hat full of developers
PDF
FwDays 2021: Metarhia Technology Stack for Node.js
PDF
Node.js for enterprise - JS Conference
PDF
Node.js for enterprise 2021 - JavaScript Fwdays 3
PDF
Node.js in 2021
PDF
Information system structure and architecture
PDF
Почему хорошее ИТ-образование невостребовано рыночком
PDF
Node.js security
PDF
JS Fest 2019 Node.js Antipatterns
How to use Chat GPT in JavaScript optimizations for Node.js
IT Revolution in 2023-2024: AI, GPT, business transformation, future professi...
Multithreading in Node.js and JavaScript
Node.js threads for I/O-bound tasks
Node.js Меньше сложности, больше надежности Holy.js 2021
Rethinking low-code
Hat full of developers
FwDays 2021: Metarhia Technology Stack for Node.js
Node.js for enterprise - JS Conference
Node.js for enterprise 2021 - JavaScript Fwdays 3
Node.js in 2021
Information system structure and architecture
Почему хорошее ИТ-образование невостребовано рыночком
Node.js security
JS Fest 2019 Node.js Antipatterns
Ad

Recently uploaded (20)

PPTX
history of c programming in notes for students .pptx
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
Nekopoi APK 2025 free lastest update
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
PTS Company Brochure 2025 (1).pdf.......
PPTX
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
AI in Product Development-omnex systems
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PPTX
Transform Your Business with a Software ERP System
PDF
Softaken Excel to vCard Converter Software.pdf
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
history of c programming in notes for students .pptx
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Internet Downloader Manager (IDM) Crack 6.42 Build 41
2025 Textile ERP Trends: SAP, Odoo & Oracle
How to Migrate SBCGlobal Email to Yahoo Easily
Nekopoi APK 2025 free lastest update
Odoo Companies in India – Driving Business Transformation.pdf
PTS Company Brochure 2025 (1).pdf.......
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Which alternative to Crystal Reports is best for small or large businesses.pdf
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
AI in Product Development-omnex systems
VVF-Customer-Presentation2025-Ver1.9.pptx
Adobe Illustrator 28.6 Crack My Vision of Vector Design
Transform Your Business with a Software ERP System
Softaken Excel to vCard Converter Software.pdf
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)

Node.js middleware: Never again!

  • 1. Node.js Middleware Never again! Timur Shemsedinov Chief Technology Architect at Metarhia Lecturer at Kiev Polytechnic Institute
  • 2. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c What is middleware? ● Connect contract (req: Request, res: Response, next: NextFunction) (req: Request, res: Response) ● Koa contract async (ctx: Context, next: NextFunction): Promise async (ctx: Context): Promise
  • 3. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middlewares and Controller Middleware Middleware Middleware(req, res, next) Controller (req, res) (req, res, next) (req, res, next)
  • 4. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c What is middleware? ● Mixin provocation ● Reference pollution and shared state provocation ● Race condition provocation ● Abstraction leak provocation ● Fat controller and layers mix provocation ● High coupling provocation ● Error ignoring provocation
  • 5. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res)
  • 6. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res) req, res
  • 7. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Pass ref outer const sockets = new Map(); app.use((req, res, next) => { ... sockets.set(userId, req.socket); ... next(); }); for (const socket of sockets) { doSomethingWithSocket(socket); }
  • 8. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res) instance.method(req, res, ...); instance.method(req.socket, ...); instance.field = req.headers; instance.emit('request', req); const f1 = method.bind(req); const f2 = method(req)(res);
  • 9. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res) const client = new Client(req, res); abstraction.method(client); instance.field = client; client.doSomething(instance); emitter.emit('connected', client); func(client).then(...).then(...)...;
  • 10. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res) calls
  • 11. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res) events calls
  • 12. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res) events calls global
  • 13. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res) events calls global fields
  • 14. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res)
  • 15. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res)
  • 16. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res)
  • 17. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res)
  • 18. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Pass ref everywhere const ee = new EventEmitter(); app.use((req, res, next) => { ee.emit('timeout', res); next(); }); ee.on('timeout', res) => { setTimeout(() => { if (!res.writableEnded) res.end('timeout'); }, 5000); });
  • 19. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Reference pollution Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res)
  • 20. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Race, data corruption let userId; app.use((req, res, next) => { userId = ...; next(); }); app.get('/resource', (req, res) => { if (checkAccess('/resource', userId) === GRANTED) { res.end('You have an access'); } });
  • 21. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Mixin pollutions Middleware Middleware Middleware(req, res, next) Controller (req, res, next) (req, res, next) (req, res)
  • 22. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: mixin to req, res, ctx app.use((req, res, next) => { res.groupName = 'idiots'; next(); }); app.get('/user', (req, res) => { if (res.groupName === 'idiots') { res.end('Welcome, my dear friend!'); } });
  • 23. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: mixin to req, res, ctx app.use((req, res, next) => { res.locals.groupName = 'idiots'; next(); }); app.get('/user', (req, res) => { if (res.locals.groupName === 'idiots') { res.end('Welcome, my dear friend!'); } });
  • 24. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Fat controller Middleware Middleware Middleware Controller ● Access db ● Logging ● Parse headers ● Cache ● Business-logic ● Validation ● Serialization (req, res, next) (req, res)
  • 25. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Don’t mix in a single function ● Data access (database connection) ● Business-logic and domain model ● Routing, logging, configuration ● Health and server state reporting ● Working with sockets, headers, cookies, etc. ● Serialization and deserialization ● Templating, caching, cryptography, sessions
  • 26. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware: Fat controller router.get('/user/:id', (req, res) => { if (blacklist.has(res.socket.remoteAddress)) {...} const id = parseInt(req.params.id); if (!isValidateUserId(id)) return res.status(500); const query = 'SELECT * FROM users WHERE id = $1'; pool.query(query, [id], (err, data) => { if (err) {...} logger.write(`access user: ${id}`); res.status(200).json(data.rows); }); });
  • 27. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Middleware provocates antipatterns ● Pass-through parameters, Too many parameters, Data clump ● Accumulate and fire ● Temporary field, State mixins, Shared state, Global state, State in outer contexts ● Inappropriate intimacy ● High coupling (also see high cohesion pattern)
  • 28. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Layered (onion) architecture Data Access Layer Middleware Middleware Controller (req, res, next) (req, res, next) (req, res, next) (req, res) Service
  • 30. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c We need patterns and principles ● DIP (dependency inversion principle) IoC (Inversion of control) DI (dependency injection) ● Chain of responsibility (GoF) ● Law of demeter ● SRP (Single responsibility, SOLID) ● Low coupling (GRASP)
  • 31. const fs = require('fs'); const compose = (...funcs) => x => funcs. reduce((x, fn) => fn(x), x); const DENSITY_COL = 3; const renderTab table => { const cellWidth = [18, 10, 8, 8, 18, 6]; return table.ma => (row.map((cell, i) => { const width = cellWidth[i]; return i ? c Keep attention on ● Domain in the middle ● Context isolation ● Layered (onion) architecture ● Don’t depend on frameworks ● Don’t move logic between model and controller ● Always work on abstraction leaking ● Protect data with parallel primitives
  • 32. github.com/tshemsedinov youtube.com/TimurShemsedinov github.com/HowProgrammingWorks/Index Весь курс по ноде и JS (186 лекций) https://habr.com/ru/post/485294/ t.me/HowProgrammingWorks t.me/NodeUA timur.shemsedinov@gmail.com