Andrii Zhukov
Senior Software Engineer
at GlobalLogic
You can support our defenders with the help of
QR code for the purchase of
the thermal imager model
HikMicro GRYPHON GH25 or
its equivalent.
This fundraise is a personal
initiative and the Company
has neither organized, nor
is the beneficiary of the
fundraising.
This fundraise is a personal initiative and the Company
has neither organized, nor is
the beneficiary of the
fundraising.
PrivatBank card:
5168752017879597
Жуков Андрій Валерійович
Global variables: without key word, using var, etc.
Use strict mode
'use strict';
window.user = null;
// or
this.user = null;
setInterval, addEventListener, file descriptors, sockets, etc.
clearInterval, removeEventListener, close all descriptors.
Closures remember the surrounding context and can store large objects
function outer() {
const bigArray = [];
return () => {
for (let i = 0; i < 1000000; i++) {
bigArray.push(i);
}
console.log('doing something');
};
}
const closureFunc = outer();
closureFunc();
// some code
closureFunc();
DOM elements and their referrences
const allComments = [];
function removeComment() {
const postComments =
document.getElementById(
'post-comments'
);
allComments.push(postComments);
document.body.removeChild(postComments);
}
removeComment();
Other ways to leak memory
Cache
Map -> WeakMap
Observers
WeakRef
FinalizationRegistry
Single Responsibility Principle
export class DoEverything {
showComment() {...}
hideComment() {...}
saveComment() {...}
findEmailInComment() {...}
replaceUrlInComment() {...}
}
export class Comment {
show() {...}
hide) {...}
save() {...}
}
export class SomeLib {
findEmail() {...}
replaceUrl() {...}
}
Open Closed Principle
const posts = [
new Post('iPhone'),
new Post('BMW'),
new Post('Asus')
];
for(let i = 0; i < posts.length; i++) {
switch(posts[i].getCategory()) {
case 'car':
console.log('logic for car');
break;
case 'phone':
console.log('logic for phone');
break;
case 'laptop':
console.log('logic for laptop');
break;
}
}
class Post {
doSomeLogic() {
console.log('basic logic');
}
}
class CarPost extends Post {
doSomeLogic() {
console.log('logic for car');
}
}
class PhonePost extends Post {
doSomeLogic() {
console.log('logic for phone');
}
}
class LaptopPost extends Post {
doSomeLogic() {
console.log('logic for laptop');
}
}
const posts = [
new CarPost(),
new PhonePost(),
new LaptopPost()
];
for(let i=0; i < posts.length; i++){
posts[i].doSomeLogic();
}
Open Closed Principle
Liskov Substitution Principle
class Shape {
get area() {...}
}
class Rectangle extends Shape {
get area() {...}
}
class Square extends Shape {
get area() {...}
}
class Circle extends Shape {
get area() {...}
}
const shapes = [
new Rectangle(1, 2),
new Square(1, 2),
new Circle(2),
]
for (let s of shapes) {
console.log(s.area);
}
Interface Segregation Principle
class IPhone extends Phone {
call() { /*Implementation*/ }
publish() { /*Implementation*/ }
}
class Phone {
constructor() {
if (
this.constructor.name ===
'Phone'
) {
throw new Error(
'Phone class is absctract'
);
}
}
call() {
throw new Error(
'call is absctract'
);
}
publish() {
throw new Error(
'publish is absctract'
);
}
}
Interface Segregation Principle
class IPhone extends Phone {
call() { /*Implementation*/ }
}
class Phone {
constructor() {
if (
this.constructor.name ===
'Phone'
) {
throw new Error(
'Phone class is absctract'
);
}
}
call() {
throw new Error(
'call is absctract'
);
}
}
Dependency Inversion Principle
class PersistanceManager {
saveData(db, data) {
if (db instanceof FileSystem) {
db.writeToFile(data)
}
if (db instanceof ExternalDB) {
db.writeToDatabase(data)
}
if (db instanceof LocalPersistance) {
db.push(data)
}
}
}
class FileSystem {
writeToFile(data) {
// Implementation
}
}
class ExternalDB {
writeToDatabase(data) {
// Implementation
}
}
class LocalPersistance {
push(data) {
// Implementation
}
}
Dependency Inversion Principle
class PersistanceManager {
constructor() {
this.db = new FileSystem();
}
saveData(data) {
this.db.save(data)
}
}
class FileSystem {
save(data) { /* Implementation*/ }
}
class ExternalDB {
save(data) { /* Implementation*/ }
}
class LocalPersistance {
save(data) { /* Implementation*/ }
}
class PersistanceManager {
saveData(db, data) {
db.save(data)
}
}
class PersistanceManager {
constructor(Store) {
this.db = new Store();
}
saveData(data) {
this.db.save(data)
}
}
Don't Repeat Yourself
console.log('I will not repeat my code');
console.log('I will not repeat my code');
console.log('I will not repeat my code');
console.log('I will not repeat my code');
console.log('I will not repeat my code');
console.log('I will not repeat my code');
console.log('I will not repeat my code');
Keep It Short and Simple
You Aren't Going to Need It
Code formatting
Eslint
Prettier
Unit testing
Style guide, manifest to code, etc
Your code should be read like a book
DarthVader
BadUser
U
Sr
SomePrefixUser
U1
UserInfo or UserData
UserDiffuser
UserAbuser
UserLoser
UserBoozer
What are the correct names?
What are the correct names?
Classes, variables are nouns
Functions, methods are verbs
Classes are PascalCase
Variables, functions are camelCase
Using one notation in the team
Constants are UPPER_CASE_SNAKE_CASE
Use of keywords
Clear definition
Using one entity
Don't use the cases described earlier
What other solutions can we use?
OOP
Software Design Patterns
MVC
GRASP, etc
Many developers think when the program works their work is over
Write code so that it is cleaner than it was before
Don't hardcode
Write readable code
Add spaces, indents, etc.
Remove commented code
Remove dead code, unless of course you get paid for it
How can we do it?
git (github, gitlab, etc.)
prettier
eslint-config-airbnb, eslint-config-standard, etc.
eslint-config-prettier
eslint
How can we do it?
Divide into separate logical blocks
Remove duplicate code
Move the code into constants, libraries, etc.
Using new ES6+ features:
- Rest, spread
- Default arguments value, etc.
someFunction (proportionalTax, fiscal, controlling, regulating) {
const calculateTax = document.getElementById(('calculate-tax');
const salary = Number(document.getElementById('salary').textContent);
const comment = document.getElementsByClassName('comment', 'class');
calculateTax.innerHTML = proportionalTax + ':' +
'<br/>' + salary * .5 +
'<br/>Some information:<br/>' +
'- ' + fiscal + '<br/>' +
'- ' + controlling + '<br/>' +
'- ' + regulating;
const getHtmlElement = (htmlElement, type = 'id') => {
if (type === 'id') {
return document.getElementById(htmlElement);
} else if (type === 'class') {
return document.getElementsByClassName(htmlElement);
} else if (type === 'tag') {
return document.getElementsByTagName(htmlElement);
}
// or
return document.querySelector(htmlElement);
};
someFunction (proportionalTax, fiscal, controlling, regulating) {
const calculateTax = getHtmlElement('calculate-tax');
const salary = Number(getHtmlElement('salary').textContent);
const comment = getHtmlElement('comment', 'class');
calculateTax.innerHTML = proportionalTax + ':' +
'<br/>' + salary * .5 +
'<br/>Some information:<br/>' +
'- ' + fiscal + '<br/>' +
'- ' + controlling + '<br/>' +
'- ' + regulating;
}
const getHtmlElement = (htmlElement, type = 'id') => {
if (type === 'id') {
return document.getElementById(htmlElement);
} else if (type === 'class') {
return document.getElementsByClassName(htmlElement);
} else if (type === 'tag') {
return document.getElementsByTagName(htmlElement);
}
// or
return document.querySelector(htmlElement);
};
someFunction (proportionalTax, fiscal, controlling, regulating) {
const calculateTax = getHtmlElement('calculate-tax');
const salary = Number(getHtmlElement('salary').textContent);
const comment = getHtmlElement('comment', 'class');
calculateTax.innerHTML = `${proportionalTax}:
${salary} * ${.5}
Some information:
- ${fiscal}
- ${controlling}
- ${regulating}`;
}
const getHtmlElement = (htmlElement, type = 'id') => {
if (type === 'id') {
return document.getElementById(htmlElement);
} else if (type === 'class') {
return document.getElementsByClassName(htmlElement);
} else if (type === 'tag') {
return document.getElementsByTagName(htmlElement);
}
// or
return document.querySelector(htmlElement);
};
someFunction (...taxKeywords) {
const [proportionalTax, fiscal, controlling, regulating] = taxKeywords;
const calculateTax = getHtmlElement('calculate-tax');
const salary = Number(getHtmlElement('salary').textContent);
const comment = getHtmlElement('comment', 'class');
calculateTax.innerHTML = `${proportionalTax}:
${salary} * ${.5}
Some information:
- ${fiscal}
- ${controlling}
- ${regulating}`;
}
const TAX_PERCENTAGE = .5;
const htmlElementTypes = {
id: 'id',
class: 'class',
tag: 'tag'
}
const getHtmlElement = (htmlElement, type = 'id') => {
const { id, class, tag } = htmlElementTypes;
if (type === id) {
return document.getElementById(htmlElement);
} else if (type === class) {
return document.getElementsByClassName(htmlElement);
} else if (type === tag) {
return document.getElementsByTagName(htmlElement);
}
// or
return document.querySelector(htmlElement);
};
someFunction (...taxKeywords) {
const [proportionalTax, fiscal, controlling, regulating] = taxKeywords;
const calculateTax = getHtmlElement('calculate-tax');
const salary = Number(getHtmlElement('salary').textContent);
const comment = getHtmlElement('comment', 'class');
calculateTax.innerHTML = `${proportionalTax}:
${salary} * ${TAX_PERCENTAGE}
Some information:
- ${fiscal}
- ${controlling}
- ${regulating}`;
}
// constants.js
export const TAX_PERCENTAGE = .5;
// libs.js
const htmlElementTypes = {
id: 'id',
class: 'class',
tag: 'tag'
}
export const getHtmlElement = (htmlElement, type = 'id') => {
const { id, class, tag } = htmlElementTypes;
if (type === id) {
return document.getElementById(htmlElement);
} else if (type === class) {
return document.getElementsByClassName(htmlElement);
} else if (type === tag) {
return document.getElementsByTagName(htmlElement);
}
// or
return document.querySelector(htmlElement);
};
// app.js
import { TAX_PERCENTAGE } from 'constants.js';
import { getHtmlElement } from 'libs.js';
someFunction (...taxKeywords) {
const [proportionalTax, fiscal, controlling, regulating] = taxKeywords;
const calculateTax = getHtmlElement('calculate-tax');
const salary = Number(getHtmlElement('salary').textContent);
const comment = getHtmlElement('comment', 'class');
calculateTax.innerHTML = `${proportionalTax}:
${salary} * ${TAX_PERCENTAGE}
Some information:
- ${fiscal}
- ${controlling}
- ${regulating}`;
}
// constants.js
export const TAX_PERCENTAGE = .5;
// libs.js
const htmlElementTypes = {
id: 'id',
class: 'class',
tag: 'tag'
}
export const getHtmlElement = (htmlElement, type = 'id') => {
const { id, class, tag } = htmlElementTypes;
if (type === id) {
return document.getElementById(htmlElement);
} else if (type === class) {
return document.getElementsByClassName(htmlElement);
} else if (type === tag) {
return document.getElementsByTagName(htmlElement);
}
// or
return document.querySelector(htmlElement);
};
// app.js
import { TAX_PERCENTAGE } from 'constants.js';
import { getHtmlElement } from 'libs.js';
someFunction (taxKeywords) {
const { proportionalTax, fiscal, controlling, regulating } = taxKeywords;
const calculateTax = getHtmlElement('calculate-tax');
const salary = Number(getHtmlElement('salary').textContent);
const comment = getHtmlElement('comment', 'class');
calculateTax.innerHTML = `${proportionalTax}:
${salary} * ${TAX_PERCENTAGE}
Some information:
- ${fiscal}
- ${controlling}
- ${regulating}`;
}
Comments in code
It's better to remove comments for the code
Сode must be self-documented
It's bad when a comment requires a comment to its comment
Remove commented code
Classes in code
class Post {
name = 'Default post';
title;
description;
#id;
constructor() { ... }
set postInfo(post) {
const {title, description} = post;
if (title && description) {
this.title = title;
this.description = description;
}
}
get postInfo() {
return `Title: ${this.title}, description: ${this.description}`;
}
getName() {
return this.name;
}
setName(newName) {
this.name = newName;
}
getId() {
return this.#id;
}
#setId() {
this.#id = Math.random();
}
}
Methods in code
No more than 10 methods per class
The contents of the method must fit on the screen
Next method below where it is called
Short method name
Division of responsibility
Methods in code
First declare the variables then the rest of the code
Limited declaration of arguments in a function
Getter or setter
Pure functions
const sendActiveEmails = (customers) => {
customers.forEach((customer) => {
if (customer.status === 'active') {
sendEmail(customer);
}
});
};
const sendActiveEmails = (customers) => {
customers.filter(isActiveCustomer)
.forEach(sendEmail);
};
const isActiveCustomer = (customer) => {
// some code
return customer.status === 'active';
};
What else?
Simplify the complexity of the algorithm
Don't do an extra re-render of the HTML structure
Stop code execution where it's not needed
What should you pay attention to?
Fixing memory leaks
Good architectural decisions must be applied
Use correct naming in code
Don't forget about code optimization
Apply basic clean code tips
Learn and apply best practices in your code
You can support our defenders with the help of
QR code for the purchase of
the thermal imager model
HikMicro GRYPHON GH25 or
its equivalent.
This fundraise is a personal
initiative and the Company
has neither organized, nor
is the beneficiary of the
fundraising.
This fundraise is a personal initiative and the Company
has neither organized, nor is
the beneficiary of the
fundraising.
PrivatBank card:
5168752017879597
Жуков Андрій Валерійович
You can visit GlobalLogic site and search JavaScript
positions with the help of
QR code: