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