SlideShare a Scribd company logo
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
toString().padStart(width) : cell.padEnd(width); }).join(''))).join
}; const proportion = (max, val) => Math.round(val * 100 / max); co
calcProportion = table => { table.sort((row1, row2) => row2[DENSITY
row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table
forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL]))
return table; }; const getDataset = file => { const lines = fs.read
FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines
return lines.map(line => line.split(',')); }; const main = compose
(getDataset, calcProportion, renderTable); const fs = require('fs'
compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con
DENSITY_COL = 3; const renderTable = table => { const cellWidth = [
8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const
= cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p
(width); }).join(''))).join('n'); }; const proportion = (max, val)
Node.js in 2020 #2
Выйди и зайди нормально
Timur Shemsedinov
github.com/HowProgrammingWorks
github.com/tshemsedinov
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
toString().padStart(width) : cell.padEnd(width); }).join(''))).join
}; const proportion = (max, val) => Math.round(val * 100 / max); co
calcProportion = table => { table.sort((row1, row2) => row2[DENSITY
row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table
forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL]))
return table; }; const getDataset = file => { const lines = fs.read
FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines
return lines.map(line => line.split(',')); }; const main = compose
(getDataset, calcProportion, renderTable); const fs = require('fs'
compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con
DENSITY_COL = 3; const renderTable = table => { const cellWidth = [
8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const
= cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p
(width); }).join(''))).join('n'); }; const proportion = (max, val)
Проблемы
реальные и мнимые,
пути их решения и тупики
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
Что беспокоит умы:
● Какой фреймворк самый лучший?
● Какая структура папок правильная?
● Какую СУБД и ORM/ODM взять для работы?
● Как масштабировать сервер?
● Что быстрее, колбеки или промисы?
● Куда поместить ..., в модель или контроллер?
● Будем ли разделать на микросервисы?
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
Короткие ответы
● Фреймворк не важен, разделять делить слои
● Структуры данных важнее структуры папок
● Можно брать любую СУБД если это PG
● Масштабироваться? Вам точно это нужно?
● Колбеки и промисы влияют на <1% скорости
● Забудьте MVC, узнайте SOLOD, GRASP, GoF
● Проектируйте интерфейсы, не микросервисы
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
О чем лучше подумать
● Обработка ошибок
● Проектирование программных абстракций
● Зацепление и связность и закон Деметры
● GRASP принцип “Информационный эксперт”
● Очереди запросов и пулы объектов
● Как минимизировать I/O и CPU задачи
● Изоляция контекстов запросов
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
Слои
● Слой доступа к данным
● Слой сетевого взаимодействия
● Слой бизнес-логики
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
toString().padStart(width) : cell.padEnd(width); }).join(''))).join
}; const proportion = (max, val) => Math.round(val * 100 / max); co
calcProportion = table => { table.sort((row1, row2) => row2[DENSITY
row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table
forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL]))
return table; }; const getDataset = file => { const lines = fs.read
FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines
return lines.map(line => line.split(',')); }; const main = compose
(getDataset, calcProportion, renderTable); const fs = require('fs'
compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con
DENSITY_COL = 3; const renderTable = table => { const cellWidth = [
8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const
= cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p
(width); }).join(''))).join('n'); }; const proportion = (max, val)
GRASP, SOLID, GoF
Как это может быть
связано с JavaScript?
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
GRASP
General responsibility assignment software
patterns (распределение ответственности)
Книга “Применение UML и шаблонов
проектирования” // Крэг Ларман
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
GRASP: Coupling and cohesion
Cohesion (связность)
внутри модуля или
программного
компонента
Coupling (зацепление)
между модулями
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
GRASP:
General responsibility assignment software
patterns (распределение ответственности)
Low Coupling High Cohesion
Information Expert Creator
Controller Polymorphism
Pure Fabrication Indirection
Protected Variations
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
SOLID: задачи
Майкл Фэзерс (Michael Feathers)
Роберт Мартин (Robert Martin, Uncle Bob)
Что они дают:
● Облегчение модификации и расширения
● Улучшение владения кодом и TTM
● Способность быстро понимать друг друга
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
SOLID: 5 принципов
● The Single Responsibility Principle
● The Open Closed Principle
● The Liskov Substitution Principle
● The Interface Segregation Principle
● The Dependency Inversion Principle
(не путать c dependency injection и
inversion of control)
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
Шаблоны GoF
Gang of Four (GoF): Эрих Гамм, Ричард Хелм,
Ральф Джонсон, Джон Влиссидес
Design Patterns — Elements of Reusable
Object-Oriented Software (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
Классификация шаблонов
Порождающие: абстрактная фабрика,
строитель, фабричный метод, пул, синглтон...
Структурные: адаптер, мост, компоновщик,
декоратор или обертка, фасад, прокси...
Поведенческие: цепочка обязанностей,
команда, обсервер, итератор, стратегия…
Коммуникационные: cqs, cqrs, event sourcing...
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
toString().padStart(width) : cell.padEnd(width); }).join(''))).join
}; const proportion = (max, val) => Math.round(val * 100 / max); co
calcProportion = table => { table.sort((row1, row2) => row2[DENSITY
row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table
forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL]))
return table; }; const getDataset = file => { const lines = fs.read
FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines
return lines.map(line => line.split(',')); }; const main = compose
(getDataset, calcProportion, renderTable); const fs = require('fs'
compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con
DENSITY_COL = 3; const renderTable = table => { const cellWidth = [
8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const
= cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p
(width); }).join(''))).join('n'); }; const proportion = (max, val)
Node.js
Security in 2020
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
Node.js Security Aspects
● Concurrency model for I/O
● Common path traversal vulnerability
● SQL injection, XSRF, XSS etc.
● Resource leaks (memory, handlers, etc.)
● Passwords should be stored as hash with salt
● Load control (DoS/DDoS)
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
Security issues
● Dependencies: see your node_modules
■ Unreliable dependencies
■ Malicious modules from NPM
● Sandbox escaping (vm)
● Buffer vulnerabilities
● Regular expressions
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
Tools Node.js
● Linter may help
github.com/nodesecurity/eslint-plugin-security
● We have npm audit and it may even fix multiple
problems automatically npm audit fix
● Special tools: nsp, snyk
● Githib have built-in Security Alert
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
SQLI (SQL Injection)
Hello! See what they say about you:
http://bank-web-site.com/accounts?
name='marcus'%20OR%201=1%20--%20
https://bit.ly/2XZpJMt
“SELECT * from Accounts where name=” + name
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
XSRF (Cross-Site Request Forgery)
They can send you:
Hello! See what they say about you:
http://payment-system.com/api/transfer?
amount=1000&destination=card-number
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
XSS (Cross-Site Scripting)
They can send you:
Hello! See what they say about you:
http://control-panel.com/help.php?q=
%3Cscript%3Ealert('Hello');%3C/script%3E
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
CSP (Content Security Policy)
Browser have built-in layer to create
security policy to solve XSS problem
https://developer.mozilla.org/en-US/docs/
Web/HTTP/CSP
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
Path traversal
const serveFile = fileName => {
const filePath = path.join(STATIC_PATH, fileName);
return fs.createReadStream(filePath);
};
http.createServer((req, res) => {
const url = decodeURI(req.url);
serveFile(url).pipe(res);
}).listen(8000);
curl -v http://127.0.0.1:8000/%2e%2e/1-traversal.js
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
Path traversal fixed
const serveFile = fileName => {
const filePath = path.join(STATIC_PATH, fileName);
if (!filePath.startsWith(STATIC_PATH)) {
throw new Error(`Access denied: ${name}`);
}
return fs.createReadStream(filePath);
};
http.createServer((req, res) => {
const url = decodeURI(req.url);
serveFile(url).pipe(res);
}).listen(8000);
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’s next:
● httponly cookies
https://www.owasp.org/index.php/HttpOnly
● HTTP Headers:
● X-XSS-Protection
● X-Frame-Options
● X-Content-Type-Options
etc.
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
OWASP (Open Web App. Security Project)
See this site:
https://owasp.org/
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
toString().padStart(width) : cell.padEnd(width); }).join(''))).join
}; const proportion = (max, val) => Math.round(val * 100 / max); co
calcProportion = table => { table.sort((row1, row2) => row2[DENSITY
row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table
forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL]))
return table; }; const getDataset = file => { const lines = fs.read
FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines
return lines.map(line => line.split(',')); }; const main = compose
(getDataset, calcProportion, renderTable); const fs = require('fs'
compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con
DENSITY_COL = 3; const renderTable = table => { const cellWidth = [
8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const
= cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p
(width); }).join(''))).join('n'); }; const proportion = (max, val)
Node.js
Patterns and Antipatterns
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
Node.js antipatterns classification
● Structure and arch.
● Initialization
● Dependency issues
● Application state
● Middlewares
● Context isolation
● Security issues
● Asynchronity issues
● Blocking operations
● Memory leaks
● Databases and ORM
● Error handling
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
No layers, everything mixed
● Configuration and Dependency management
● Network protocols related code (http, tcp, tls…)
● Request parsing, Cookies, Sessions
● Logging, Routing, Business-logic
● I/O: fs, Database queries
● Generating responses and error generation
● Templating, etc.
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
Middlewares is an extremely bad idea for low
coupling and high cohesion
Middlewares changes:
● Socket state
● Db connection state
● Server state
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 create global state
let groupName;
app.use((req, res, next) => {
groupName = 'idiots'; next();
});
app.get('/user', (req, res) => {
if (groupName === 'idiots') {
res.end('I know you!');
}
});
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 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('I know you!');
}
});
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
Special place for the state: res.locals
app.use((req, res, next) => {
res.locals.groupName = 'idiots';
next();
});
app.get('/user', (req, res) => {
if (res.locals.groupName === 'idiots') {
res.end('I know you!');
}
});
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 mixin methods
app.get('/user/:id', (req, res, next) => {
req.auth = (login, password) => { /* auth */ };
next();
});
app.get('/user/:id', (req, res) => {
if (req.auth(req.params.id, '111')) {
res.end('I know you!');
}
});
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 require in middleware / handler
app.get((req, res, next) => {
req.db = new require('pg').Client();
req.db.connect();
next();
});
app.get('/user/:id', (req, res) => {
req.db.query('SELECT * from USERS', (e, r) => {
...
});
});
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 connect DB from handlers
app.get((req, res, next) => {
req.db = new Pool(config);
next();
});
app.get('/user/:id', (req, res) => {
req.db.query('SELECT * from USERS', (e, r) => {
});
});
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
Connection leaks is easy
const db = new Pool(config);
app.get('/user/:id', (req, res) => {
req.db.query('SELECT * from USERS', (err, r) => {
if (err) throw err;
// Prepare data to reply client
});
});
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 use blocking operations
● Sync calls like fs.readFileSync
● Console output like console.log
● Remember that require is synchronous
● Long loops (including for..of and for await)
● Serialization: JSON.parse, JSON.stringify
● Iteration: loops, Array.prototype.map, etc.
● CPU-intensive: zlib, crypto
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
Loop: for await of is blocking
(async () => {
let ticks = 0;
const timer = setInterval(() => ticks++, 10);
const numbers = new Array(1000000).fill(1);
let i = 0;
for await (const number of numbers) i++;
clearInterval(timer);
console.dir({ i, ticks });
})();
// { i: 1000, ticks: 0 }
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
AsyncArray (short version)
class AsyncArray extends Array {
[Symbol.asyncIterator]() {
let i = 0;
return {
next: () => new Promise(resolve => {
setTimeout(() => resolve({
value: this[i], done: i++ === this.length
}), 0);
})
};
}
} // github.com/HowProgrammingWorks/NonBlocking
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
Loop: for await of + AsyncArray
(async () => {
let ticks = 0;
const timer = setInterval(() => ticks++, 10);
const numbers = new AsyncArray(10000000).fill(1);
let i = 0;
for await (const number of numbers) i++;
clearInterval(timer);
console.dir({ i, ticks });
})();
// { i: 10000, ticks: 1163 }
https://github.com/HowProgrammingWorks/NonBlocking
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
Memory leaks
● References
■ Global variables
■ Mixins to built-in Classes
■ Singletons, Caches
● Closures / Function contexts
■ Recursive closures
■ Require in the middle of code
■ Functions in loops
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
Memory leaks
● OS and Language Objects
■ Descriptors: files, sockets...
■ Timers: setTimeout, setInterval
● Events / Subscription / Promises
■ EventEmitter
■ Callbacks, Not resolved promises
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
Links
github.com/HowProgrammingWorks/AbstractionLayers
github.com/HowProgrammingWorks/MemoryLeaks
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
toString().padStart(width) : cell.padEnd(width); }).join(''))).join
}; const proportion = (max, val) => Math.round(val * 100 / max); co
calcProportion = table => { table.sort((row1, row2) => row2[DENSITY
row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table
forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL]))
return table; }; const getDataset = file => { const lines = fs.read
FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines
return lines.map(line => line.split(',')); }; const main = compose
(getDataset, calcProportion, renderTable); const fs = require('fs'
compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con
DENSITY_COL = 3; const renderTable = table => { const cellWidth = [
8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const
= cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p
(width); }).join(''))).join('n'); }; const proportion = (max, val)
Use global, Luke!
for interfaces but
don’t use require for data
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
Почему нельзя global?
● Нельзя, потому, что нельзя
● Способствует протеканию состояния
● 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
Почему require не всегда хорошо?
● Если экспортировать структуру данных или
коллекцию (array, map, set) то же, что и global
● Если экспортировать синглтон класс,
это то же, что и global
● Миксинить к глобальным или загруженным
через require объектам, модифицировать
встроенные классы, это то же, что и 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
Связываем через интерфейсы
● Важно связывать программные компоненты
через интерфейсы или контракты, но не через
данные
● А как передаются ссылки на интерфейсы,
через global, require, object composition,
object aggregation, abject association,
события или еще как... это не столь важно...
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
toString().padStart(width) : cell.padEnd(width); }).join(''))).join
}; const proportion = (max, val) => Math.round(val * 100 / max); co
calcProportion = table => { table.sort((row1, row2) => row2[DENSITY
row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table
forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL]))
return table; }; const getDataset = file => { const lines = fs.read
FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines
return lines.map(line => line.split(',')); }; const main = compose
(getDataset, calcProportion, renderTable); const fs = require('fs'
compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con
DENSITY_COL = 3; const renderTable = table => { const cellWidth = [
8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const
= cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p
(width); }).join(''))).join('n'); }; const proportion = (max, val)
Errors
кто не обрабатывает
ошибки, тот
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
Callback-last, error-first
const fn = (arg1, arg2, callback) => {
if (...) callback(null, result);
else callback(new Error('message'));
};
fn(arg1, arg2, (err, result) => {
if (err) {
console.log(err.message);
return;
}
console.log(result);
});
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
Error ignoring
fn1(arg1, arg2, (err, res1) => {
fn2(res1, arg3, (err, res2) => {
fn3(res2, arg4, arg5, (err, res3) => {
doSomething(arg5, res3);
});
});
});
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
Error ignoring
const cb3 = (err, res3) => {
doSomething(arg6, res3);
};
const cb2 = (err, res2) => {
fn3(res2, arg4, arg5, cb3);
};
const cb1 = (err, res1) => {
fn2(res1, arg3, cb2);
};
fn1(arg1, arg2, cb1);
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
Promise.catch
doSomething(arg1, arg2)
.then(
data => { console.log({ data }); },
err => { console.log({ err }); }
);
doSomething(arg1, arg2)
.then(data => { console.log({ data }); })
.catch(err => { console.log({ err }); });
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
Promise.catch
doSomething(arg1, arg2)
.then(
data => { console.log({ data }); },
err => { console.log({ err }); }
);
doSomething(arg1, arg2)
.then(data => { console.log({ data }); })
.catch(err => { console.log({ err }); });
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
.then(fulfilled, rejected).catch(rejected)
doSomething(arg1, arg2)
.then(
data => { console.log({ data }); },
err => { console.log({ err }); }
)
.catch(err => { console.log({ err }); });
// Помним про .finally()
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
Error ignoring
(async () => {
const file1 = await readFile('file1.ext');
const file2 = await readFile('file2.ext');
console.dir({ file1, file2 });
})();
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
Error ignoring
(async () => {
try {
const file1 = await readFile('file1.ext');
const file2 = await readFile('file2.ext');
} catch (err) {
console.error(err);
}
})();
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
Catch unhandled errors
process.on('uncaughtException', err => {
console.log('on uncaughtException: ' + err.message);
process.exit(1);
});
process.on('warning', warning => {
console.log({ warning });
});
// UnhandledPromiseRejectionWarning: Error: msg...
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
Catch unhandled errors
process.on('rejectionHandled', promise => {
console.log({ rejectionHandled: { promise } });
});
process.on('multipleResolves', (type, p, reason) => {
console.log({
multipleResolves: { type, promise: p, reason }
});
});
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
toString().padStart(width) : cell.padEnd(width); }).join(''))).join
}; const proportion = (max, val) => Math.round(val * 100 / max); co
calcProportion = table => { table.sort((row1, row2) => row2[DENSITY
row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table
forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL]))
return table; }; const getDataset = file => { const lines = fs.read
FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines
return lines.map(line => line.split(',')); }; const main = compose
(getDataset, calcProportion, renderTable); const fs = require('fs'
compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con
DENSITY_COL = 3; const renderTable = table => { const cellWidth = [
8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const
= cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p
(width); }).join(''))).join('n'); }; const proportion = (max, val)
Data Access Layer
SQL, noSQL and Hybrid DB
Query builder, ORM & ODM
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
Ссылки
● Слой доступа к данным, курсор, транзакция
https://youtu.be/CRcSWtWVvrA
● Работа с базами данных в Node.js
на примере PostgreSQL
https://youtu.be/2tDvHQCBt3w
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
toString().padStart(width) : cell.padEnd(width); }).join(''))).join
}; const proportion = (max, val) => Math.round(val * 100 / max); co
calcProportion = table => { table.sort((row1, row2) => row2[DENSITY
row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table
forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL]))
return table; }; const getDataset = file => { const lines = fs.read
FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines
return lines.map(line => line.split(',')); }; const main = compose
(getDataset, calcProportion, renderTable); const fs = require('fs'
compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con
DENSITY_COL = 3; const renderTable = table => { const cellWidth = [
8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const
= cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p
(width); }).join(''))).join('n'); }; const proportion = (max, val)
Event sourcing
CQS, CQRS & Command
patterns for server scailing
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
Ссылки
● Паттерн Команда (Command)
https://youtu.be/vER0vYL4hM4
● CQS, CQRS, Event Sourcing
https://youtu.be/T2tRc80Q8Qw
https://youtu.be/kFNtKiK2SPs
https://youtu.be/xp5MVKEqxY4
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
toString().padStart(width) : cell.padEnd(width); }).join(''))).join
}; const proportion = (max, val) => Math.round(val * 100 / max); co
calcProportion = table => { table.sort((row1, row2) => row2[DENSITY
row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table
forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL]))
return table; }; const getDataset = file => { const lines = fs.read
FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines
return lines.map(line => line.split(',')); }; const main = compose
(getDataset, calcProportion, renderTable); const fs = require('fs'
compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con
DENSITY_COL = 3; const renderTable = table => { const cellWidth = [
8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const
= cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p
(width); }).join(''))).join('n'); }; const proportion = (max, val)
Node.js Starter Kit
no dependencies, 15-20 kb
with pg drivers + 1.2 mb
and ws + 0.24 mb
github.com
/HowProgrammingWorks
/NodejsStarterKit
Questions?
github.com/tshemsedinov
https://youtube.com/TimurShemsedinov
github.com/HowProgrammingWorks/Index
Весь курс по ноде (>35.5 часов)
https://habr.com/ru/post/485294/
t.me/HowProgrammingWorks
t.me/NodeUA
timur.shemsedinov@gmail.com

More Related Content

What's hot

Prototype programming in JavaScript
Prototype programming in JavaScriptPrototype programming in JavaScript
Prototype programming in JavaScript
Timur Shemsedinov
 
Asynchronous programming and mutlithreading
Asynchronous programming and mutlithreadingAsynchronous programming and mutlithreading
Asynchronous programming and mutlithreading
Timur Shemsedinov
 
Node.js in 2020
Node.js in 2020Node.js in 2020
Node.js in 2020
Timur Shemsedinov
 
Private cloud without vendor lock // Serverless
Private cloud without vendor lock // ServerlessPrivate cloud without vendor lock // Serverless
Private cloud without vendor lock // Serverless
Timur Shemsedinov
 
Programming Languages: comparison, history, future
Programming Languages: comparison, history, futureProgramming Languages: comparison, history, future
Programming Languages: comparison, history, future
Timur Shemsedinov
 
JavaScript в браузере: Web API (часть 1)
JavaScript в браузере: Web API (часть 1)JavaScript в браузере: Web API (часть 1)
JavaScript в браузере: Web API (часть 1)
Timur Shemsedinov
 
Web Locks API
Web Locks APIWeb Locks API
Web Locks API
Timur Shemsedinov
 
Node.js middleware: Never again!
Node.js middleware: Never again!Node.js middleware: Never again!
Node.js middleware: Never again!
Timur Shemsedinov
 
How to keep control and safety in the clouds
How to keep control and safety in the cloudsHow to keep control and safety in the clouds
How to keep control and safety in the clouds
Timur Shemsedinov
 
Asynchronous programming with java script and node.js
Asynchronous programming with java script and node.jsAsynchronous programming with java script and node.js
Asynchronous programming with java script and node.js
Timur Shemsedinov
 
Metarhia KievJS 22-Feb-2018
Metarhia KievJS 22-Feb-2018Metarhia KievJS 22-Feb-2018
Metarhia KievJS 22-Feb-2018
Timur Shemsedinov
 
JS Fest 2019 Node.js Antipatterns
JS Fest 2019 Node.js AntipatternsJS Fest 2019 Node.js Antipatterns
JS Fest 2019 Node.js Antipatterns
Timur Shemsedinov
 
Py3k
Py3kPy3k
Bytes in the Machine: Inside the CPython interpreter
Bytes in the Machine: Inside the CPython interpreterBytes in the Machine: Inside the CPython interpreter
Bytes in the Machine: Inside the CPython interpreter
akaptur
 
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!..."A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...akaptur
 
Lập trình Python cơ bản
Lập trình Python cơ bảnLập trình Python cơ bản
Lập trình Python cơ bản
Nguyen Thi Lan Phuong
 
Internal workshop es6_2015
Internal workshop es6_2015Internal workshop es6_2015
Internal workshop es6_2015
Miguel Ruiz Rodriguez
 
20190330 immutable data
20190330 immutable data20190330 immutable data
20190330 immutable data
Chiwon Song
 
Building HTML5 enabled web applications with Visual Studio 2011
Building HTML5 enabled web applications with Visual Studio 2011 Building HTML5 enabled web applications with Visual Studio 2011
Building HTML5 enabled web applications with Visual Studio 2011
Microsoft Developer Network (MSDN) - Belgium and Luxembourg
 

What's hot (20)

Prototype programming in JavaScript
Prototype programming in JavaScriptPrototype programming in JavaScript
Prototype programming in JavaScript
 
Asynchronous programming and mutlithreading
Asynchronous programming and mutlithreadingAsynchronous programming and mutlithreading
Asynchronous programming and mutlithreading
 
Node.js in 2020
Node.js in 2020Node.js in 2020
Node.js in 2020
 
Private cloud without vendor lock // Serverless
Private cloud without vendor lock // ServerlessPrivate cloud without vendor lock // Serverless
Private cloud without vendor lock // Serverless
 
Programming Languages: comparison, history, future
Programming Languages: comparison, history, futureProgramming Languages: comparison, history, future
Programming Languages: comparison, history, future
 
JavaScript в браузере: Web API (часть 1)
JavaScript в браузере: Web API (часть 1)JavaScript в браузере: Web API (часть 1)
JavaScript в браузере: Web API (часть 1)
 
Web Locks API
Web Locks APIWeb Locks API
Web Locks API
 
Node.js middleware: Never again!
Node.js middleware: Never again!Node.js middleware: Never again!
Node.js middleware: Never again!
 
How to keep control and safety in the clouds
How to keep control and safety in the cloudsHow to keep control and safety in the clouds
How to keep control and safety in the clouds
 
Asynchronous programming with java script and node.js
Asynchronous programming with java script and node.jsAsynchronous programming with java script and node.js
Asynchronous programming with java script and node.js
 
Metarhia KievJS 22-Feb-2018
Metarhia KievJS 22-Feb-2018Metarhia KievJS 22-Feb-2018
Metarhia KievJS 22-Feb-2018
 
JS Fest 2019 Node.js Antipatterns
JS Fest 2019 Node.js AntipatternsJS Fest 2019 Node.js Antipatterns
JS Fest 2019 Node.js Antipatterns
 
Duralexsedregex
DuralexsedregexDuralexsedregex
Duralexsedregex
 
Py3k
Py3kPy3k
Py3k
 
Bytes in the Machine: Inside the CPython interpreter
Bytes in the Machine: Inside the CPython interpreterBytes in the Machine: Inside the CPython interpreter
Bytes in the Machine: Inside the CPython interpreter
 
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!..."A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...
 
Lập trình Python cơ bản
Lập trình Python cơ bảnLập trình Python cơ bản
Lập trình Python cơ bản
 
Internal workshop es6_2015
Internal workshop es6_2015Internal workshop es6_2015
Internal workshop es6_2015
 
20190330 immutable data
20190330 immutable data20190330 immutable data
20190330 immutable data
 
Building HTML5 enabled web applications with Visual Studio 2011
Building HTML5 enabled web applications with Visual Studio 2011 Building HTML5 enabled web applications with Visual Studio 2011
Building HTML5 enabled web applications with Visual Studio 2011
 

Similar to Node.js in 2020 - part 2

Oh Composable World!
Oh Composable World!Oh Composable World!
Oh Composable World!
Brian Lonsdorf
 
Everything is composable
Everything is composableEverything is composable
Everything is composable
Victor Igor
 
Basic R Data Manipulation
Basic R Data ManipulationBasic R Data Manipulation
Basic R Data Manipulation
Chu An
 
Seminar PSU 10.10.2014 mme
Seminar PSU 10.10.2014 mmeSeminar PSU 10.10.2014 mme
Seminar PSU 10.10.2014 mme
Vyacheslav Arbuzov
 
A quick introduction to R
A quick introduction to RA quick introduction to R
A quick introduction to R
Angshuman Saha
 
Christian Gill ''Functional programming for the people''
Christian Gill ''Functional programming for the people''Christian Gill ''Functional programming for the people''
Christian Gill ''Functional programming for the people''
OdessaJS Conf
 
Transducers in JavaScript
Transducers in JavaScriptTransducers in JavaScript
Transducers in JavaScript
Pavel Forkert
 
Reactive programming with RxJS - ByteConf 2018
Reactive programming with RxJS - ByteConf 2018Reactive programming with RxJS - ByteConf 2018
Reactive programming with RxJS - ByteConf 2018
Tracy Lee
 
Futures e abstração - QCon São Paulo 2015
Futures e abstração - QCon São Paulo 2015Futures e abstração - QCon São Paulo 2015
Futures e abstração - QCon São Paulo 2015
Leonardo Borges
 
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+ConFoo
 
Introduction to R
Introduction to RIntroduction to R
Introduction to R
Sander Kieft
 
JavaScript - Agora nervoso
JavaScript - Agora nervosoJavaScript - Agora nervoso
JavaScript - Agora nervoso
Luis Vendrame
 
Артём Акуляков - F# for Data Analysis
Артём Акуляков - F# for Data AnalysisАртём Акуляков - F# for Data Analysis
Артём Акуляков - F# for Data Analysis
SpbDotNet Community
 
Spark workshop
Spark workshopSpark workshop
Spark workshop
Wojciech Pituła
 

Similar to Node.js in 2020 - part 2 (19)

Oh Composable World!
Oh Composable World!Oh Composable World!
Oh Composable World!
 
Everything is composable
Everything is composableEverything is composable
Everything is composable
 
Basic R Data Manipulation
Basic R Data ManipulationBasic R Data Manipulation
Basic R Data Manipulation
 
Seminar PSU 10.10.2014 mme
Seminar PSU 10.10.2014 mmeSeminar PSU 10.10.2014 mme
Seminar PSU 10.10.2014 mme
 
A quick introduction to R
A quick introduction to RA quick introduction to R
A quick introduction to R
 
Christian Gill ''Functional programming for the people''
Christian Gill ''Functional programming for the people''Christian Gill ''Functional programming for the people''
Christian Gill ''Functional programming for the people''
 
Transducers in JavaScript
Transducers in JavaScriptTransducers in JavaScript
Transducers in JavaScript
 
Reactive programming with RxJS - ByteConf 2018
Reactive programming with RxJS - ByteConf 2018Reactive programming with RxJS - ByteConf 2018
Reactive programming with RxJS - ByteConf 2018
 
Futures e abstração - QCon São Paulo 2015
Futures e abstração - QCon São Paulo 2015Futures e abstração - QCon São Paulo 2015
Futures e abstração - QCon São Paulo 2015
 
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
 
Introduction to R
Introduction to RIntroduction to R
Introduction to R
 
JavaScript - Agora nervoso
JavaScript - Agora nervosoJavaScript - Agora nervoso
JavaScript - Agora nervoso
 
Mysql
MysqlMysql
Mysql
 
Mysql
MysqlMysql
Mysql
 
Mysql
MysqlMysql
Mysql
 
Scala Collections
Scala CollectionsScala Collections
Scala Collections
 
Scala collections
Scala collectionsScala collections
Scala collections
 
Артём Акуляков - F# for Data Analysis
Артём Акуляков - F# for Data AnalysisАртём Акуляков - F# for Data Analysis
Артём Акуляков - F# for Data Analysis
 
Spark workshop
Spark workshopSpark workshop
Spark workshop
 

More from Timur Shemsedinov

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

More from Timur Shemsedinov (15)

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

Recently uploaded

Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Shahin Sheidaei
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
Philip Schwarz
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
Adele Miller
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
XfilesPro
 
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Globus
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Globus
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
Donna Lenk
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
rickgrimesss22
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
abdulrafaychaudhry
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
Shane Coughlan
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Neo4j
 
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Globus
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
Matt Welsh
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
Aftab Hussain
 
How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
Globus
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
Globus
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
Globus
 

Recently uploaded (20)

Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
 
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
 
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
 
How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
 

Node.js in 2020 - part 2

  • 1. 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 toString().padStart(width) : cell.padEnd(width); }).join(''))).join }; const proportion = (max, val) => Math.round(val * 100 / max); co calcProportion = table => { table.sort((row1, row2) => row2[DENSITY row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL])) return table; }; const getDataset = file => { const lines = fs.read FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines return lines.map(line => line.split(',')); }; const main = compose (getDataset, calcProportion, renderTable); const fs = require('fs' compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con DENSITY_COL = 3; const renderTable = table => { const cellWidth = [ 8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const = cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p (width); }).join(''))).join('n'); }; const proportion = (max, val) Node.js in 2020 #2 Выйди и зайди нормально Timur Shemsedinov github.com/HowProgrammingWorks github.com/tshemsedinov 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 toString().padStart(width) : cell.padEnd(width); }).join(''))).join }; const proportion = (max, val) => Math.round(val * 100 / max); co calcProportion = table => { table.sort((row1, row2) => row2[DENSITY row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL])) return table; }; const getDataset = file => { const lines = fs.read FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines return lines.map(line => line.split(',')); }; const main = compose (getDataset, calcProportion, renderTable); const fs = require('fs' compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con DENSITY_COL = 3; const renderTable = table => { const cellWidth = [ 8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const = cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p (width); }).join(''))).join('n'); }; const proportion = (max, val) Проблемы реальные и мнимые, пути их решения и тупики
  • 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 Что беспокоит умы: ● Какой фреймворк самый лучший? ● Какая структура папок правильная? ● Какую СУБД и ORM/ODM взять для работы? ● Как масштабировать сервер? ● Что быстрее, колбеки или промисы? ● Куда поместить ..., в модель или контроллер? ● Будем ли разделать на микросервисы?
  • 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 Короткие ответы ● Фреймворк не важен, разделять делить слои ● Структуры данных важнее структуры папок ● Можно брать любую СУБД если это PG ● Масштабироваться? Вам точно это нужно? ● Колбеки и промисы влияют на <1% скорости ● Забудьте MVC, узнайте SOLOD, GRASP, GoF ● Проектируйте интерфейсы, не микросервисы
  • 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 О чем лучше подумать ● Обработка ошибок ● Проектирование программных абстракций ● Зацепление и связность и закон Деметры ● GRASP принцип “Информационный эксперт” ● Очереди запросов и пулы объектов ● Как минимизировать I/O и CPU задачи ● Изоляция контекстов запросов
  • 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 Слои ● Слой доступа к данным ● Слой сетевого взаимодействия ● Слой бизнес-логики
  • 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 toString().padStart(width) : cell.padEnd(width); }).join(''))).join }; const proportion = (max, val) => Math.round(val * 100 / max); co calcProportion = table => { table.sort((row1, row2) => row2[DENSITY row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL])) return table; }; const getDataset = file => { const lines = fs.read FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines return lines.map(line => line.split(',')); }; const main = compose (getDataset, calcProportion, renderTable); const fs = require('fs' compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con DENSITY_COL = 3; const renderTable = table => { const cellWidth = [ 8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const = cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p (width); }).join(''))).join('n'); }; const proportion = (max, val) GRASP, SOLID, GoF Как это может быть связано с JavaScript?
  • 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 GRASP General responsibility assignment software patterns (распределение ответственности) Книга “Применение UML и шаблонов проектирования” // Крэг Ларман
  • 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 GRASP: Coupling and cohesion Cohesion (связность) внутри модуля или программного компонента Coupling (зацепление) между модулями
  • 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 GRASP: General responsibility assignment software patterns (распределение ответственности) Low Coupling High Cohesion Information Expert Creator Controller Polymorphism Pure Fabrication Indirection Protected Variations
  • 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 SOLID: задачи Майкл Фэзерс (Michael Feathers) Роберт Мартин (Robert Martin, Uncle Bob) Что они дают: ● Облегчение модификации и расширения ● Улучшение владения кодом и TTM ● Способность быстро понимать друг друга
  • 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 SOLID: 5 принципов ● The Single Responsibility Principle ● The Open Closed Principle ● The Liskov Substitution Principle ● The Interface Segregation Principle ● The Dependency Inversion Principle (не путать c dependency injection и inversion of control)
  • 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 Шаблоны GoF Gang of Four (GoF): Эрих Гамм, Ричард Хелм, Ральф Джонсон, Джон Влиссидес Design Patterns — Elements of Reusable Object-Oriented Software (23 шаблона)
  • 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 Классификация шаблонов Порождающие: абстрактная фабрика, строитель, фабричный метод, пул, синглтон... Структурные: адаптер, мост, компоновщик, декоратор или обертка, фасад, прокси... Поведенческие: цепочка обязанностей, команда, обсервер, итератор, стратегия… Коммуникационные: cqs, cqrs, event sourcing...
  • 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 toString().padStart(width) : cell.padEnd(width); }).join(''))).join }; const proportion = (max, val) => Math.round(val * 100 / max); co calcProportion = table => { table.sort((row1, row2) => row2[DENSITY row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL])) return table; }; const getDataset = file => { const lines = fs.read FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines return lines.map(line => line.split(',')); }; const main = compose (getDataset, calcProportion, renderTable); const fs = require('fs' compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con DENSITY_COL = 3; const renderTable = table => { const cellWidth = [ 8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const = cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p (width); }).join(''))).join('n'); }; const proportion = (max, val) Node.js Security in 2020
  • 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 Node.js Security Aspects ● Concurrency model for I/O ● Common path traversal vulnerability ● SQL injection, XSRF, XSS etc. ● Resource leaks (memory, handlers, etc.) ● Passwords should be stored as hash with salt ● Load control (DoS/DDoS)
  • 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 Security issues ● Dependencies: see your node_modules ■ Unreliable dependencies ■ Malicious modules from NPM ● Sandbox escaping (vm) ● Buffer vulnerabilities ● Regular expressions
  • 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 Tools Node.js ● Linter may help github.com/nodesecurity/eslint-plugin-security ● We have npm audit and it may even fix multiple problems automatically npm audit fix ● Special tools: nsp, snyk ● Githib have built-in Security Alert
  • 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 SQLI (SQL Injection) Hello! See what they say about you: http://bank-web-site.com/accounts? name='marcus'%20OR%201=1%20--%20 https://bit.ly/2XZpJMt “SELECT * from Accounts where name=” + name
  • 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 XSRF (Cross-Site Request Forgery) They can send you: Hello! See what they say about you: http://payment-system.com/api/transfer? amount=1000&destination=card-number
  • 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 XSS (Cross-Site Scripting) They can send you: Hello! See what they say about you: http://control-panel.com/help.php?q= %3Cscript%3Ealert('Hello');%3C/script%3E
  • 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 CSP (Content Security Policy) Browser have built-in layer to create security policy to solve XSS problem https://developer.mozilla.org/en-US/docs/ Web/HTTP/CSP
  • 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 Path traversal const serveFile = fileName => { const filePath = path.join(STATIC_PATH, fileName); return fs.createReadStream(filePath); }; http.createServer((req, res) => { const url = decodeURI(req.url); serveFile(url).pipe(res); }).listen(8000); curl -v http://127.0.0.1:8000/%2e%2e/1-traversal.js
  • 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 Path traversal fixed const serveFile = fileName => { const filePath = path.join(STATIC_PATH, fileName); if (!filePath.startsWith(STATIC_PATH)) { throw new Error(`Access denied: ${name}`); } return fs.createReadStream(filePath); }; http.createServer((req, res) => { const url = decodeURI(req.url); serveFile(url).pipe(res); }).listen(8000);
  • 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 What’s next: ● httponly cookies https://www.owasp.org/index.php/HttpOnly ● HTTP Headers: ● X-XSS-Protection ● X-Frame-Options ● X-Content-Type-Options etc.
  • 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 OWASP (Open Web App. Security Project) See this site: https://owasp.org/
  • 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 toString().padStart(width) : cell.padEnd(width); }).join(''))).join }; const proportion = (max, val) => Math.round(val * 100 / max); co calcProportion = table => { table.sort((row1, row2) => row2[DENSITY row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL])) return table; }; const getDataset = file => { const lines = fs.read FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines return lines.map(line => line.split(',')); }; const main = compose (getDataset, calcProportion, renderTable); const fs = require('fs' compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con DENSITY_COL = 3; const renderTable = table => { const cellWidth = [ 8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const = cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p (width); }).join(''))).join('n'); }; const proportion = (max, val) Node.js Patterns and Antipatterns
  • 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 Node.js antipatterns classification ● Structure and arch. ● Initialization ● Dependency issues ● Application state ● Middlewares ● Context isolation ● Security issues ● Asynchronity issues ● Blocking operations ● Memory leaks ● Databases and ORM ● Error handling
  • 29. 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 No layers, everything mixed ● Configuration and Dependency management ● Network protocols related code (http, tcp, tls…) ● Request parsing, Cookies, Sessions ● Logging, Routing, Business-logic ● I/O: fs, Database queries ● Generating responses and error generation ● Templating, etc.
  • 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 Middlewares Middlewares is an extremely bad idea for low coupling and high cohesion Middlewares changes: ● Socket state ● Db connection state ● Server state
  • 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 Don’t create global state let groupName; app.use((req, res, next) => { groupName = 'idiots'; next(); }); app.get('/user', (req, res) => { if (groupName === 'idiots') { res.end('I know you!'); } });
  • 32. 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 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('I know you!'); } });
  • 33. 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 Special place for the state: res.locals app.use((req, res, next) => { res.locals.groupName = 'idiots'; next(); }); app.get('/user', (req, res) => { if (res.locals.groupName === 'idiots') { res.end('I know you!'); } });
  • 34. 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 mixin methods app.get('/user/:id', (req, res, next) => { req.auth = (login, password) => { /* auth */ }; next(); }); app.get('/user/:id', (req, res) => { if (req.auth(req.params.id, '111')) { res.end('I know you!'); } });
  • 35. 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 require in middleware / handler app.get((req, res, next) => { req.db = new require('pg').Client(); req.db.connect(); next(); }); app.get('/user/:id', (req, res) => { req.db.query('SELECT * from USERS', (e, r) => { ... }); });
  • 36. 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 connect DB from handlers app.get((req, res, next) => { req.db = new Pool(config); next(); }); app.get('/user/:id', (req, res) => { req.db.query('SELECT * from USERS', (e, r) => { }); });
  • 37. 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 Connection leaks is easy const db = new Pool(config); app.get('/user/:id', (req, res) => { req.db.query('SELECT * from USERS', (err, r) => { if (err) throw err; // Prepare data to reply client }); });
  • 38. 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 use blocking operations ● Sync calls like fs.readFileSync ● Console output like console.log ● Remember that require is synchronous ● Long loops (including for..of and for await) ● Serialization: JSON.parse, JSON.stringify ● Iteration: loops, Array.prototype.map, etc. ● CPU-intensive: zlib, crypto
  • 39. 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 Loop: for await of is blocking (async () => { let ticks = 0; const timer = setInterval(() => ticks++, 10); const numbers = new Array(1000000).fill(1); let i = 0; for await (const number of numbers) i++; clearInterval(timer); console.dir({ i, ticks }); })(); // { i: 1000, ticks: 0 }
  • 40. 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 AsyncArray (short version) class AsyncArray extends Array { [Symbol.asyncIterator]() { let i = 0; return { next: () => new Promise(resolve => { setTimeout(() => resolve({ value: this[i], done: i++ === this.length }), 0); }) }; } } // github.com/HowProgrammingWorks/NonBlocking
  • 41. 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 Loop: for await of + AsyncArray (async () => { let ticks = 0; const timer = setInterval(() => ticks++, 10); const numbers = new AsyncArray(10000000).fill(1); let i = 0; for await (const number of numbers) i++; clearInterval(timer); console.dir({ i, ticks }); })(); // { i: 10000, ticks: 1163 } https://github.com/HowProgrammingWorks/NonBlocking
  • 42. 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 Memory leaks ● References ■ Global variables ■ Mixins to built-in Classes ■ Singletons, Caches ● Closures / Function contexts ■ Recursive closures ■ Require in the middle of code ■ Functions in loops
  • 43. 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 Memory leaks ● OS and Language Objects ■ Descriptors: files, sockets... ■ Timers: setTimeout, setInterval ● Events / Subscription / Promises ■ EventEmitter ■ Callbacks, Not resolved promises
  • 44. 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 Links github.com/HowProgrammingWorks/AbstractionLayers github.com/HowProgrammingWorks/MemoryLeaks
  • 45. 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 toString().padStart(width) : cell.padEnd(width); }).join(''))).join }; const proportion = (max, val) => Math.round(val * 100 / max); co calcProportion = table => { table.sort((row1, row2) => row2[DENSITY row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL])) return table; }; const getDataset = file => { const lines = fs.read FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines return lines.map(line => line.split(',')); }; const main = compose (getDataset, calcProportion, renderTable); const fs = require('fs' compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con DENSITY_COL = 3; const renderTable = table => { const cellWidth = [ 8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const = cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p (width); }).join(''))).join('n'); }; const proportion = (max, val) Use global, Luke! for interfaces but don’t use require for data
  • 46. 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 Почему нельзя global? ● Нельзя, потому, что нельзя ● Способствует протеканию состояния ● Global один на все приложение
  • 47. 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 Почему require не всегда хорошо? ● Если экспортировать структуру данных или коллекцию (array, map, set) то же, что и global ● Если экспортировать синглтон класс, это то же, что и global ● Миксинить к глобальным или загруженным через require объектам, модифицировать встроенные классы, это то же, что и global
  • 48. 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 Связываем через интерфейсы ● Важно связывать программные компоненты через интерфейсы или контракты, но не через данные ● А как передаются ссылки на интерфейсы, через global, require, object composition, object aggregation, abject association, события или еще как... это не столь важно...
  • 49. 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 toString().padStart(width) : cell.padEnd(width); }).join(''))).join }; const proportion = (max, val) => Math.round(val * 100 / max); co calcProportion = table => { table.sort((row1, row2) => row2[DENSITY row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL])) return table; }; const getDataset = file => { const lines = fs.read FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines return lines.map(line => line.split(',')); }; const main = compose (getDataset, calcProportion, renderTable); const fs = require('fs' compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con DENSITY_COL = 3; const renderTable = table => { const cellWidth = [ 8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const = cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p (width); }).join(''))).join('n'); }; const proportion = (max, val) Errors кто не обрабатывает ошибки, тот
  • 50. 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 Callback-last, error-first const fn = (arg1, arg2, callback) => { if (...) callback(null, result); else callback(new Error('message')); }; fn(arg1, arg2, (err, result) => { if (err) { console.log(err.message); return; } console.log(result); });
  • 51. 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 Error ignoring fn1(arg1, arg2, (err, res1) => { fn2(res1, arg3, (err, res2) => { fn3(res2, arg4, arg5, (err, res3) => { doSomething(arg5, res3); }); }); });
  • 52. 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 Error ignoring const cb3 = (err, res3) => { doSomething(arg6, res3); }; const cb2 = (err, res2) => { fn3(res2, arg4, arg5, cb3); }; const cb1 = (err, res1) => { fn2(res1, arg3, cb2); }; fn1(arg1, arg2, cb1);
  • 53. 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 Promise.catch doSomething(arg1, arg2) .then( data => { console.log({ data }); }, err => { console.log({ err }); } ); doSomething(arg1, arg2) .then(data => { console.log({ data }); }) .catch(err => { console.log({ err }); });
  • 54. 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 Promise.catch doSomething(arg1, arg2) .then( data => { console.log({ data }); }, err => { console.log({ err }); } ); doSomething(arg1, arg2) .then(data => { console.log({ data }); }) .catch(err => { console.log({ err }); });
  • 55. 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 .then(fulfilled, rejected).catch(rejected) doSomething(arg1, arg2) .then( data => { console.log({ data }); }, err => { console.log({ err }); } ) .catch(err => { console.log({ err }); }); // Помним про .finally()
  • 56. 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 Error ignoring (async () => { const file1 = await readFile('file1.ext'); const file2 = await readFile('file2.ext'); console.dir({ file1, file2 }); })();
  • 57. 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 Error ignoring (async () => { try { const file1 = await readFile('file1.ext'); const file2 = await readFile('file2.ext'); } catch (err) { console.error(err); } })();
  • 58. 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 Catch unhandled errors process.on('uncaughtException', err => { console.log('on uncaughtException: ' + err.message); process.exit(1); }); process.on('warning', warning => { console.log({ warning }); }); // UnhandledPromiseRejectionWarning: Error: msg...
  • 59. 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 Catch unhandled errors process.on('rejectionHandled', promise => { console.log({ rejectionHandled: { promise } }); }); process.on('multipleResolves', (type, p, reason) => { console.log({ multipleResolves: { type, promise: p, reason } }); });
  • 60. 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 toString().padStart(width) : cell.padEnd(width); }).join(''))).join }; const proportion = (max, val) => Math.round(val * 100 / max); co calcProportion = table => { table.sort((row1, row2) => row2[DENSITY row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL])) return table; }; const getDataset = file => { const lines = fs.read FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines return lines.map(line => line.split(',')); }; const main = compose (getDataset, calcProportion, renderTable); const fs = require('fs' compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con DENSITY_COL = 3; const renderTable = table => { const cellWidth = [ 8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const = cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p (width); }).join(''))).join('n'); }; const proportion = (max, val) Data Access Layer SQL, noSQL and Hybrid DB Query builder, ORM & ODM
  • 61. 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 Ссылки ● Слой доступа к данным, курсор, транзакция https://youtu.be/CRcSWtWVvrA ● Работа с базами данных в Node.js на примере PostgreSQL https://youtu.be/2tDvHQCBt3w
  • 62. 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 toString().padStart(width) : cell.padEnd(width); }).join(''))).join }; const proportion = (max, val) => Math.round(val * 100 / max); co calcProportion = table => { table.sort((row1, row2) => row2[DENSITY row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL])) return table; }; const getDataset = file => { const lines = fs.read FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines return lines.map(line => line.split(',')); }; const main = compose (getDataset, calcProportion, renderTable); const fs = require('fs' compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con DENSITY_COL = 3; const renderTable = table => { const cellWidth = [ 8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const = cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p (width); }).join(''))).join('n'); }; const proportion = (max, val) Event sourcing CQS, CQRS & Command patterns for server scailing
  • 63. 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 Ссылки ● Паттерн Команда (Command) https://youtu.be/vER0vYL4hM4 ● CQS, CQRS, Event Sourcing https://youtu.be/T2tRc80Q8Qw https://youtu.be/kFNtKiK2SPs https://youtu.be/xp5MVKEqxY4
  • 64. 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 toString().padStart(width) : cell.padEnd(width); }).join(''))).join }; const proportion = (max, val) => Math.round(val * 100 / max); co calcProportion = table => { table.sort((row1, row2) => row2[DENSITY row1[DENSITY_COL]); const maxDensity = table[0][DENSITY_COL]; table forEach(row => { row.push(proportion(maxDensity, row[DENSITY_COL])) return table; }; const getDataset = file => { const lines = fs.read FileSync(file, 'utf8').toString().split('n'); lines.shift(); lines return lines.map(line => line.split(',')); }; const main = compose (getDataset, calcProportion, renderTable); const fs = require('fs' compose = (...funcs) => x => funcs.reduce((x, fn) => fn(x), x); con DENSITY_COL = 3; const renderTable = table => { const cellWidth = [ 8, 8, 18, 6]; return table.map(row => (row.map((cell, i) => { const = cellWidth[i]; return i ? cell.toString().padStart(width) : cell.p (width); }).join(''))).join('n'); }; const proportion = (max, val) Node.js Starter Kit no dependencies, 15-20 kb with pg drivers + 1.2 mb and ws + 0.24 mb
  • 67. github.com/tshemsedinov https://youtube.com/TimurShemsedinov github.com/HowProgrammingWorks/Index Весь курс по ноде (>35.5 часов) https://habr.com/ru/post/485294/ t.me/HowProgrammingWorks t.me/NodeUA timur.shemsedinov@gmail.com