JS trends uncovered
x 0
JavaScript & OOP
Typescript
React
Redux
Express
MERN
The computer industry is the only industry that is more fashion-driven than women's fashion.
OOP in JS
If you have first-class functions, all these OOP patterns are just 3-liners not deserving names
Dan Abramov
Why we need classes and OOP in JS?
Why do we need classes in JS?
class Rabbit {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, i am ${this.name}`);
}
}
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype.sayHello = function() {
console.log(`Hello, i am ${this.name}`);
}
Looks even shorter?
Now lets add some inheritance
class Rabbit {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, i am ${this.name}`);
}
}
class OddRabbit extends Rabbit {
construnctor(name) {
super(name);
}
howLongIsForver() {
console.log(`Sometimes, just a second.`)
}
}
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype.sayHello = function() {
console.log(`Hello, i am ${this.name}`);
}
function OddRabbit(name) {
Rabbit.call(this, name);
}
OddRabbit.prototype = Object
.create(Rabbit.prototype);
OddRabbit.prototype
.howLongIsForver = function() {
console.log(`Sometimes, just a second.`)
}
Classes are familiar for new people
but the thing is classes in JS are not at all like classes in other languages!
class Rabbit {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, i am ${this.name}`);
}
}
const r = new Rabbit('Oleg');
r.sayHello()
// Hello, i am Oleg
Rabbit.prototype.sayHello = () => console.log('Hey');
r.sayHello()
// Hey
Class defines an instantiable type
Prototype is a living instance
Lack of features
Context binding
Problems behind JS classes
Optimization
JavaScript is not a class-based object-oriented language
Inheritance
Using inheritance is not the only way to extend a class behavior. But definitely is the most dangerous and harmful one.
// singleton.js
export default Object.freeze({ ...data });
// decorator.js
function decorated(fn) {
return function(...args) {
console.log('With logger', ...args);
return fn(...args)
}
}
//strategy.js
function(strategy) {
this.strategy = strategy;
};
Greeter.prototype.greet = function() {
return this.strategy();
};
new Greeter(myStrategy).greet();
// templateMethod.js
// your homework :)
Use composition (through constructor dependency injection) to put things together and prevent complexity.
Design patterns
Many popular frameworks encourage it to use classes and you should probably avoid writing weird non-standard code on principle alone.
Disclaimer
Bad programmers worry about the code. Good programmers worry about data structures and their relationships
is awesome!
Why do we love TypeScript?
Autocomplete
Refactoring
More safe
Self doocumentation
TypeScript trends
Isn't it overhyped?
Property 'someProp' does not exist on type 'STNValue<ModelInstanceTypeProps<ModelPropertiesDeclarationToProperties<{ someProp: ISimpleType<boolean>; someType: ICustomType; }>>, IModelType<ModelPropertiesDeclarationToProperties<{ someProp: ISimpleType<boolean>; someType: ICustomType; }>, {}, _NotCustomized, _NotCustomized>>'.
TypeScript error tip
export function reduce<V, A>(accumulator: (acc: V | A, value: V, index: number) => A, seed?: any): OperatorFunction<V, V | A> {
return operate(scanInternals(accumulator, seed, arguments.length >= 2, false, true));
}
TypeScript readability
Types in runtime
@Module({
imports: [CatsModule],
providers: [
{
provide: CatsService,
useClass: MyClass,
},
];
})
export class AppModule {}
// Controller file next
@Controller()
export class CatsController {
constructor(connection: CatsService) {
// Oh no, the CatsService might be any object
}
}
Nest.js DI example
type Metadata = {};
type UserMetadata = Map<string, Metadata>;
const cache: UserMetadata = new Map();
// later
const cacheCopy: UserMetadata = { ...cache };
cacheCopy.get('foo');
Spread operator
the spread operator doesn't copy prototypes
interface A {
x: number;
}
let a: A = { x: 3 }
let b: { x: number | string } = a;
b.x = "unsound";
let x: number = a.x; // unsound
a.x.toFixed(0); // WTF is it?
Typing system
No compilation errors neither
TypeScript is not bad!
but it's not a silver bullet
Why do most developers fear to make continuous changes to their code? They are afraid they’ll break it! Why are they afraid they’ll break it? Because they don’t have tests
Robert C. Martin
Is React actually reactive?
Reactivity is a programming paradigm that allows us to adjust to changes in a declarative manner
let name = 'Cat';
const App = () => (
<div>{ name }</div>
);
name = 'Dog'
To make it reactive we have to use third-party tools
React example
Redux
Dan Abramov doesn't like Redux and the whole global store idea
Redux Google trend worldwide for the last year
October 2019
October 2020
25%
50%
75%
100%
25%
Why the popularity has decreased?
Learning curve
Boilerplate code
Performance
Central store
No built-in way to handle side-effects
State of JS 2020
Should we stop using Redux?
Is it dead ?
Use react features/hooks instead ?
TL;DR
Is Redux dead, dying, deprecated, or about to be replaced?
No.
Use Redux when
You need a single source of truth
You want to maintain an undo history
You need a serializable state/actions
Travel between the state history in development
Provide alternative UI without disturbing too much of the business logic
Express.js
Unopinionated framework
Can you live without Express.js?
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const pg = require('pg');
const hash = require('./hash.js');
const PORT = 8000;
const app = express();
const pool = new pg.Pool({
host: '127.0.0.1',
port: 5432,
database: 'example',
user: 'marcus',
password: 'marcus',
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/user', (req, res) => {
console.log(`${req.socket.remoteAddress} GET /user`);
pool.query('SELECT * FROM users', (err, data) => {
if (err) throw err;
res.status(200).json(data.rows);
});
});
app.post('/user', async (req, res) => {
const { login, password } = req.body;
const user = JSON.stringify({ login, password });
console.log(`${req.socket.remoteAddress} POST /user ${user}`);
const sql = 'INSERT INTO users (login, password) VALUES ($1, $2)';
const passwordHash = await hash(password);
pool.query(sql, [login, passwordHash], (err, data) => {
if (err) throw err;
res.status(201).json({ created: data.insertId });
});
});
app.get('/user/:id', (req, res) => {
const id = parseInt(req.params.id);
console.log(`${req.socket.remoteAddress} GET /user/${id}`);
pool.query('SELECT * FROM users WHERE id = $1', [id], (err, data) => {
if (err) throw err;
res.status(200).json(data.rows);
});
});
app.put('/user/:id', async (req, res) => {
const id = parseInt(req.params.id);
const { login, password } = req.body;
const user = JSON.stringify({ login, password });
console.log(`${req.socket.remoteAddress} PUT /user/${id} ${user}`);
const sql = 'UPDATE users SET login = $1, password = $2 WHERE id = $3';
const passwordHash = await hash(password);
pool.query(sql, [login, passwordHash, id], (err, data) => {
if (err) throw err;
res.status(201).json({ modified: data.insertId });
});
});
app.delete('/user/:id', (req, res) => {
const id = parseInt(req.params.id);
console.log(`${req.socket.remoteAddress} DELETE /user/${id}`);
pool.query('DELETE FROM users WHERE id = $1', [id], (err, data) => {
if (err) throw err;
res.status(200).json({ deleted: data.insertId });
});
});
app.listen(PORT, () => {
console.log(`Listen on port ${PORT}`);
});
Timur Shemsedinov example of bad code using express
Clean architecture
What about using it correctly?
Chain of Responsibility
& middlewares
It motivates devs to use mixins
var express = require('express');
var app = express();
var requestTime = function (req, res, next) {
req.requestTime = Date.now();
next();
};
app.use(requestTime);
app.get('/', function (req, res) {
var responseText = 'Hello World!';
responseText += 'Requested at: ' + req.requestTime + '';
res.send(responseText);
});
app.listen(3000);
Official guide
Last time updated 1Y ago
Autocannon performance comparison link
Express
Bare Node
You can achieve the same experience with a few simple lines on the bare Node.js
Simplicity is a great virtue but it requires hard work to achieve it and education to appreciate it. And to make matters worse: complexity sells better
Edsger W. Dijkstra
What have we learned?
Bad programmers worry about the code. Good programmers worry about data structures and their relationships
The computer industry is the only industry that is more fashion-driven than women's fashion.
Why do most developers fear to make continuous changes to their code? They are afraid they’ll break it! Why are they afraid they’ll break it? Because they don’t have tests
Simplicity is a great virtue but it requires hard work to achieve it and education to appreciate it. And to make matters worse: complexity sells better
In most cases we can live without OOP
TypeScript is not that safe
React is not reactive
Redux doesn't have to be used on most project
Time to stop using Express
Thank you!
2021
Slides
JS Dev in the Wonderland
By Vladimir Vyshko
JS Dev in the Wonderland
- 969