Unethical JavaScript - Giorgio Natili - Codemotion Rome 2017

Preview:

Citation preview

Unethical JSJS Misconceptions and Errors

Une

thic

al J

avaS

crip

t

IMAGE

2

@giorgionatili

On paper, Giorgio Natili is an engineering lead at Akamai Technologies where he spearheads the implementation of the new web apps for the security products line of AkamaiOn the job, Giorgio is a strong proponent of agile development practices whose passion for usable, maintainable and testable code is only surpassed by his determination to make things work.

@giorgionatiliUnethical JavaScript3

Agenda

Review the knowledge base that is behind this presentation

Definitions

� An overview of the hidden gems of JavaScript and V8

Misconceptions

A couple of recommendations to write effective and maintainable JavaScript

Conclusions

�An overview of effective plain JavaScript code style and techniques

Ethical JavaScript

Une

thic

al J

avaS

crip

t4

IntroUnethical, maintainable and readable are three important adjectives, let’s review them in the context of JavaScript

@giorgionatiliUnethical JavaScript5

Topics

General definition and how it is applicable to the context of JavaScript

Unethical

U The main principles of maintainable code, and how to apply them in JavaScript

Maintainable Code

M Readable code is the main key to write scalable softwares

Readability

R

@giorgionatiliUnethical JavaScript6

Unethical

Lacking moral principles; unwilling to adhere to proper rules of conduct

General Definition�

Not conforming to approved standards of social or professional behavior

More in Context�

Corrupt, illegal, improper, unfair, unprofessional, unscrupulous, wrong, etc.

Synonyms�

Which is the first step to make JavaScript Ethical?

@giorgionatiliUnethical JavaScript8

Maintainable Code

Code should not be rigid and not easy to change, even more, changes should be predictable

Not Rigid�

Maintainability is inversely proportional to the amount of time it takes a developer to make a change and the risk that change will break something

Measurable �

At the heart of maintainability is carefully constructed code that is easy to read

Long Story Short�

@giorgionatiliUnethical JavaScript9

Readability Principles

Give your objects and methods names that truly reflect the concept they are modeling, any nontechnical member of the team should be able to understand the object

Intention-Revealing Interfaces�

Calling a function should have a single outcome that is predictable due to the object’s Intention-Revealing Interface

Side-Effect-Free Functions �

Avoid to modify the same data structures from different parts of the code, try to minimize race conditions

Immutability �

Standalone objects are ideal because they are not coupled to any other code and they can be understood in isolation

Standalone Objects�

@giorgionatiliUnethical JavaScript10

Unreadable Code

const getAction = (newPayload, isRejected) => ({ type: `${type}_${isRejected ? REJECTED : FULFILLED}`, ...newPayload ? { payload: newPayload } : {}, ...!!meta ? { meta } : {}, ...isRejected ? { error: true } : {} });

Please, Meet the Maintainer

@giorgionatiliUnethical JavaScript12

More Readable

const getAction = (newPayload, isRejected) => ({ type: `${type}_${isRejected ? REJECTED : FULFILLED}`, ...( newPayload ? { payload: newPayload } : {} ), ...( !!meta ? { meta } : {} ), ...( isRejected ? { error: true } : {} ) });

Know your enemy and you can fight a hundred battles without disaster Breath…

Une

thic

al J

avaS

crip

t14

Inconsistency JavaScript is inconsistent by default, it’s one of the most misunderstood languages and it wasn't designed with the goal of being one of the most diffused programming language

@giorgionatiliUnethical JavaScript15

Topics

JavaScript is a language designed in few days and with different goals, hereby there are design flaws

Design Flaws

D The dynamic nature of the language creates interesting side effects when types get converted

Types Conversion

T A deep dive into one of the most ambiguous “data type” ever invented

Truthy & Falsy

W

Operator overloading can be dangerous, the + operator in JavaScript is a clear demonstration

The Plus (+) Operator

P How the value of the this keyword changes, it is a reference to the object that “owns” the executing code

Execution Context

EDifferences, similarities and gotchas of the two most important JavaScript’s data structures

Objects & Arrays

O

@giorgionatiliUnethical JavaScript16

Design Flaws

If someone forgets to declare a variable as local before using it, subtle gremlins can pop up in a program

Variables are global unless declared local�

Types are coerced unexpectedly by smart and fast run times

Messy Type Handling�

Null belongs to a kind of object [Object], mean the object is empty; undefined is a data type, that is not defined

null and undefined�

@giorgionatiliUnethical JavaScript17

Type Conversion

Type conversion behaves differently according to the type the interpreter is expecting and to the operator in the expression

Automatic Type Conversion

Most arithmetic operators in Javascript convert their arguments to numbers, the exception is the plus operator

Addictive Overload�

@giorgionatiliUnethical JavaScript18

Conversion Madness

let pi = Math.PI, str = ""+ pi, // to string int = ~~pi, // to integer float = 1 * str, // to float bool = !!pi, // to boolean

@giorgionatiliUnethical JavaScript19

Truthy & Falsy

Like most computer languages, JavaScript supports Boolean data types

Boolean Data Types�

In addition, everything in JavaScript has an inherent Boolean value, generally known as either truthy or falsy

JavaScript Madeness �

When a value is truthy or falsy in JavaScript, it doesn’t mean that the value is true or false; it means that the value coerces to true or false when evaluated in a boolean context

Practically Speaking�

@giorgionatiliUnethical JavaScript20

Falsy Values

false void 0 (zero) "" (empty string) null undefined NaN

@giorgionatiliUnethical JavaScript21

Comparing Falsy Values

false == 0; // true false == ""; // true 0 == ""; // true null == false; // false null == null; // true undefined == undefined; // true undefined == null; // true NaN == null; // false NaN == NaN; // false

@giorgionatiliUnethical JavaScript22

The Falsehood of false

let hello = (value) => {

if (!value) { return `Bye ${value}`; } return `Hi ${value}`; }

hello(false); // 'Bye false' hello(null); // 'Bye null' hello([]); // 'Hi ' hello(new Boolean(false)); // 'Hi false'

@giorgionatiliUnethical JavaScript23

Say it again, please…

Write safer code by using the strict comparison operator (===)

@giorgionatiliUnethical JavaScript25

The Plus (+) Operator

This operator is used to concatenate strings or sum the numbers

Concatenate and Sum�

Considering that only strings and numbers can be added, the runtime apply data type conversions to keep the values around the operator consistent

Automatic Conversion�

@giorgionatiliUnethical JavaScript26

Automatic Conversion

let a = "12";

+a; // -> Number(a) -> 12 a + "hello"; // -> String(a) + "hello" -> 12hello "hello" + a; // -> "hello" + String(b) a + 6; // -> Number(a) + 6 6 + a; // -> 6 + Number(b)

let b = "wtf"; a + b; // -> ToPrimitive(a) + ToPrimitive(b) -> 12wtf

@giorgionatiliUnethical JavaScript27

ToPrimitive

ToPrimitive(input, PreferredType?)

• If input is primitive, return it as is

• Otherwise, if input is an object, calls obj.valueOf(); if the result is

primitive, return it

• Otherwise, call obj.toString(); if the result is a primitive, return it

• Otherwise, throw a TypeError

@giorgionatiliUnethical JavaScript28

Unexpected Behavior

[] + []; // -> '' [] + {}; // -> '[object Object]' {} + {}; // -> NaN {} + []; // -> 0 [1, 3, 5] + 1; // -> "1,3,51" 10 + true; // -> 11 8 + null; // -> 8 12 + undefined; // -> NaN

@giorgionatiliUnethical JavaScript29

Where is this?

let obj = { name: 'giorgio', sayHi: function(msg) { console.log(`Hi, I'm ${this.name}`, msg); } }, otherObject = { name: 'mario' }; let speak = obj.sayHi;

speak('nice to meet you'); // -> Hi, I'm nice to meet you speak.call(otherObject, 'nice to meet you'); // -> Hi, I'm mario nice to meet you speak.apply(obj, ['nice to meet you']); // -> Hi, I'm giorgio nice to meet you

@giorgionatiliUnethical JavaScript30

Object and Array

Every object in JavaScript is an associative array whose keys are strings; when an object other than a string is used as a key in JavaScript, no error occurs

Objects are Associative Arrays�

Arrays are a type of object (off course!) for storing multiple values in a single variable where each value gets numeric index

Arrays�

Array-like objects look like arrays, they have various numbered elements and a length property; but that’s where the similarity stops (aka document.forms)

Array-like Objects�

@giorgionatiliUnethical JavaScript31

Unexpected Behavior

let foo = new Object(); let bar = new Object; let map = {};

map[foo] = "foo"; map[bar] = "bar";

console.log(map[foo]); // -> "bar"

@giorgionatiliUnethical JavaScript32

WTF ?!?

Do you not destroy your enemies when you make them your friends?

Une

thic

al J

avaS

crip

t34

Plain JavaScriptAn overview of data structures, loops, execution context and hidden gems of JavaScript and its runtimes

@giorgionatiliUnethical JavaScript35

Topics

Implementing hash tables in JavaScript using ES6 API

Hash Tables

H Exploring the nasty truth about Arrays in JavaScript

Arrays

A Gotchas and improvements of loops in JavaScript

Loops

L

@giorgionatiliUnethical JavaScript36

Hash Tables

In JavaScript, all non-scalar objects behave as associative arrays; the object can use other objects or strings as keys

Hash Tables in JavaScript�

The truth is that hash tables don’t exist in JavaScript because an object by default inherits the methods of the Object data type

Inheritance Issue�

Creating an object with a null prototype is a solution to mitigate the inheritance issue

Mitigation�

@giorgionatiliUnethical JavaScript37

Objects Based Hash Tables

let hash = {}; hash['name'] = 'giorgio'; hash['surname'] = 'natili';

for(let i in hash) { console.log(`${i} ${hash[i]}`); }

console.log(typeof hash); // -> object console.log(hash.hasOwnProperty('surname')); // -> true console.log(!!hash['surname']); // -> true

@giorgionatiliUnethical JavaScript38

ES6 Hash Tables (Map)

let map = new Map() map.set('name', 'giorgio'); map.set('surname', 'natili');

map.forEach((item) => { console.log(item); })

console.log(map.get('name')); // -> giorgio console.log(map.get('surname')); // -> natili

Wait a minute, are you forgetting about Set?

@giorgionatiliUnethical JavaScript40

ES6 Hash Tables (Set)

let set = new Set(['giorgio', 'natili']) .add(42);

for (let x of set) { console.log(x); }

Jenniffer W. DoeMinimal X Template41

Map & Set

There is a strong symmetry between Map and Set, but these data structures should be used in the right scenario

Same same, but different

� Map and Set constructors and methods are both chainable

Chainable

Both Map and Set are available in a weak flavor that facilitate garbage collection and prevent potential memory leaks

Weak Collections

�Both Map and Set get designed with the iteration use case in mind, the entries() and values() methods represent the standard way to iterate over collections

Iterable

Hash Tables still not exist, but at least collections are predictable

@giorgionatiliUnethical JavaScript43

Arrays

In JavaScript, there isn’t an Array datatype, the result of the comparison typeof [] == 'object' is true

Existence

The numeric keys used to access the elements of an Array are strings

Keys�

The length property is not read only, by incrementing or decrementing it, you actually change the data structure

Length�

@giorgionatiliUnethical JavaScript44

Array Length

let data = ['First', 'Second', 'Third']; console.log(data.length, data); // -> 3, ["First", "Second", "Third"]

data.length--; console.log(data.length, data); // -> 2, ["First", "Second"]

data.length++; console.log(data.length, data); // -> 3, ["First", "Second", undefined]

@giorgionatiliUnethical JavaScript45

Looping and Iterating

The for-in statement by itself is not a "bad practice", however it can be mis-used, for example, to iterate over arrays or array-like objects data rather than on their properties

Looping Over Properties�

The for-of is the most concise, direct syntax for looping through array and array-like objects elements; it avoids all the pitfalls of for–in and works with break, continue, and return

Looping Over Data�

The map(), filter(), and reduce() methods are a key element to get a cleaner syntax to filter data structures

Mapping and Filtering�

@giorgionatiliUnethical JavaScript46

The for-in & for-of

let array = ['First', 'Second', 'Third']; array.name = "Cool!";

for (let p in array) { console.log(p); // -> 0, 1, 2, name } for (let p of array) { console.log(p); // -> "First", "Second", "Third" }

@giorgionatiliUnethical JavaScript47

Not so bad

Une

thic

al J

avaS

crip

t48

Poor NamingPoor naming is a cross language issue, anyway, JavaScript dynamic nature deeply influence naming conventions.

@giorgionatiliUnethical JavaScript49

Topics

Poor variable names are one of the root causes of bugs and regressions

Variables

V A function is an action, poor function names make your code difficult to understand

Functions

F Classes try to group traits and behaviors of a software, poor naming brings to unmaintainable models

Classes

C

Modules are another tool to group reusable code, poor modules naming seriously impact code readability

Modules

M

@giorgionatiliUnethical JavaScript50

Variables

let data = ['First', 'Second', 'Third']; let total = data.length;

let that = this;

let e1, e2; e1 = document.getElementById('value1').innerHTML; e1 = document.getElementById('value2').innerHTML;

if (e1 > e2) {

// Do something }

@giorgionatiliUnethical JavaScript51

Functions

function showFailureTextDiv(flag) {

if (parseInt(flag) == 0) { document.getElementById('FailureTextDiv').style.display = "block"; }else { document.getElementById('FailureTextDiv').style.display = "none"; } return; }

@giorgionatiliUnethical JavaScript52

Classes

@giorgionatiliUnethical JavaScript53

Modules

import { utils } from 'utils/utils.js';

@giorgionatiliUnethical JavaScript54

Somewhere During Code Review

Une

thic

al J

avaS

crip

t55

Ethical JS Writing idiomatic JavaScript is the first step to write ethical code, on top of this it’s mandatory to apply best practices and master the platform

�ethical

@giorgionatiliUnethical JavaScript56

Topics

Review in practice how to master the execution context of JavaScript

Execution Context

M

Rethink how use a function, return always a value and minimize side effects

Functional

F

Evolve the code base to have a more manageable software

ESNext API

A Code readability starts with good names, and a clean syntax

Clean Syntax

D

A quick overview of a couple of libraries that can help improving your JavaScript

Libraries

L

@giorgionatiliUnethical JavaScript57

Mastering Execution Context

Never pass the context around by trapping it in variables that get enclosed in a closure, use the Function and Reflect API instead

Take Advantage of the Context

Be accurate when passing arguments to functions executed within a different context, avoid null values proliferating around the code base

Arguments �

@giorgionatiliUnethical JavaScript58

Execution Context

let func = () => { return arguments.length; } func.apply(void 0, null); // -> 0 Reflect.apply(func, void 0, null); // -> TypeError

let obj = document.createElement('object'); typeof obj; // -> "function", can be called

obj.apply; // -> undefined, no Function.prototype Reflect.apply(obj, thisArg, argList); // -> works properly

@giorgionatiliUnethical JavaScript59

Reflect vs Object

The Reflect module is a more natural place for many of the reflection methods previously defined on Object

Reflection

Many operations in Reflect are similar to ES5 operations defined on Object, such as Reflect.getOwnPropertyDescriptor and Reflect.defineProperty; anyway, the return value is usually more meaningful

Return Values �

@giorgionatiliUnethical JavaScript60

Clean Syntax

Never pass the context around by trapping it in variables that get enclosed in a closure, use the Function and Reflect API instead

Use the Context�

Be accurate when passing arguments to functions executed within a different context, avoid null values proliferating around the code base

Arguments �

The map(), filter(), and reduce() methods are a key element to get a cleaner syntax to filter data structures

Mapping and Filtering�

@giorgionatiliUnethical JavaScript61

Parens, Braces, Linebreaks

// Examples of really cramped syntax

if(condition) doSomething();

while(condition) iterating++;

for(var i=0;i<100;i++) someIterativeFn();

// Use whitespace to promote readability

if ( condition ) { // statements }

while ( condition ) { // statements }

for ( var i = 0; i < 100; i++ ) { // statements }

@giorgionatiliUnethical JavaScript62

Assignments, Declarations, Function

// Bad var foo = "", bar = ""; var qux;

function foo() { // some statements here var bar = "", qux; }

// Good var foo = ""; var bar = ""; var qux;

function foo() { var bar = "", qux; // all statements after the variables declarations. }

@giorgionatiliUnethical JavaScript63

Early Returns

function returnLate( foo ) { var ret;

if ( foo ) { ret = "foo"; } else { ret = "bar"; } return ret; }

function returnEarly( foo ) {

if ( foo ) { return "foo"; } return "bar"; }

@giorgionatiliUnethical JavaScript64

Mastering Coercions

// coercions

string === number; // -> false string === number + ""; // -> true +string === number; // -> true bool === number; // -> false +bool === number; // -> true bool === string; // -> false bool === !!string; // -> true

// evaluate truthiness

if ( array.length > 0 ) if ( array.length ) // -> Better

if ( array.length === 0 ) if ( !array.length ) // -> Better

if ( string !== "" ) if ( string ) // -> Better

@giorgionatiliUnethical JavaScript65

Be Functional

It’s not a buzzword, it’s a true different way to think about data structures and functions

Buzzword �

Functions are side effects free and always return a value

Functions�

Threat your model as a single source of truth

Immutability �

@giorgionatiliUnethical JavaScript66

Plato

@giorgionatiliUnethical JavaScript67

RxJS

RxJS is an implementation of the Observer pattern on steroids, it hides the complexity of loops and observing / subscribing

Hide Complexity�

It provides built in operators to debounce, take, throttle, etc. data streams

Built-in Operators�

By hiding the complexity, RxJS provide a pragmatic approach to declarative programming

Declarative Approach �

@giorgionatiliUnethical JavaScript68

Declarative Programming

const task_stream = // Makes a stream of all the tasks in the database getTasks(). // Get tasks only for this user filter((task) => task.user_id == user_id). // Get tasks that are uncompleted filter((task) => !task.completed). // Only get name of task map((task) => task.name)

Une

thic

al J

avaS

crip

t69

Conclusions

�ethical

Always write code as the maintainer is a psychopath that knows where you live

Try to oversimplify modules, and to keep the code simple

Never fight for a standard, fight only for maintainability and readability

Write easy to test code, when tests get complicated there are design flaws

When there’s no way to avoid complexity, hide it with an abstraction layer

http://www.jsfuck.com/

@giorgionatiliUnethical JavaScript76

Thanks!

Write Ethical JS

Modern API

Track the Tech Debt

Remove Unneeded Code

There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult..

-C.A.R. Hoare