Clean Code - Robert C. Martin
Main focuses
- Default values
- Number of arguments
- Function splitting
- Object creation
- Immutability
- Global functions
- typeof vs Typescript
- prototype vs High order functions
- prototype vs ES6 class
- Concurrency
Default values
```js
const createMicrobrewery = (name) => {
const breweryName = name || "Hipster Brew Co.";
// ...
}
```
Default values
```js
const createMicrobrewery = (name = "Hipster Brew Co.") => {
// ...
}
```
Number of arguments
```js
const createMenu = (title, body, buttonText, cancellable) => {
// ...
}
createMenu("Foo", "Bar", "Baz", true);
```
Number of arguments
```js
const createMenu = ({ title, body, buttonText, cancellable }) => {
// ...
}
createMenu({
title: "Foo",
body: "Bar",
buttonText: "Baz",
cancellable: true
});
```
Function splitting
```js
const emailClients = (clients) => {
clients.forEach(client => {
const clientRecord = database.lookup(client);
if (clientRecord.isActive()) {
email(client);
}
});
}
```
Function splitting
```js
const emailActiveClients = (clients) => {
clients.filter(isActiveClient).forEach(email);
}
const isActiveClient = (client) => {
const clientRecord = database.lookup(client);
return clientRecord.isActive();
}
```
Object creation
```js
const menuConfig = {
title: null,
body: "Bar",
cancellable: true
};
const createMenu = (config) => {
config.title = config.title || "Foo";
config.body = config.body || "Bar";
config.cancellable = config.cancellable !== undefined ? config.cancellable : true;
}
createMenu(menuConfig);
```
Object creation
```js
const menuConfig = {
title: "Order",
// User did not include 'body' key
cancellable: true
};
const createMenu = (config) => {
const finalConfig = Object.assign({
title: "Foo",
body: "Bar",
cancellable: true
}, config);
return finalConfig;
}
createMenu(menuConfig);
```
Immutability
```js
const addItemToCart = (cart, item) => {
cart.push({ item, date: Date.now() });
};
```
Immutability
```js
const addItemToCart = (cart, item) => {
return [...cart, { item, date: Date.now() }];
};
```
Global functions
```js
Array.prototype.diff = function diff(comparisonArray) {
const hash = new Set(comparisonArray);
return this.filter(elem => !hash.has(elem));
};
```
Global functions
```js
class SuperArray extends Array {
diff(comparisonArray) {
const hash = new Set(comparisonArray);
return this.filter(elem => !hash.has(elem));
}
}
```
typeof vs Typescript
```js
function combine(val1, val2) {
if (
(typeof val1 === "number" && typeof val2 === "number") ||
(typeof val1 === "string" && typeof val2 === "string")
) {
return val1 + val2;
}
throw new Error("Must be of type String or Number");
}
```
typeof vs Typescript
```js
function combine(val1: number | string, val2: number | string) {
return val1 + val2;
}
```
prototype vs High order functions
```js
const Employee = (name) => {
this.name = name;
};
Employee.prototype.getName = function getName() {
return this.name;
};
const employee = new Employee("John Doe");
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
delete employee.name;
console.log(`Employee name: ${employee.getName()}`); // Employee name: undefined
```
prototype vs High order functions
```js
const makeEmployee = (name) => {
return {
getName() {
return name;
}
};
}
const employee = makeEmployee("John Doe");
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
delete employee.name;
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
```
prototype vs ES6 class
```js
const Animal = (age) => {
if (!(this instanceof Animal)) {
throw new Error("Instantiate Animal with `new`");
}
this.age = age;
};
Animal.prototype.move = function move() {};
const Mammal = (age, furColor) => {
if (!(this instanceof Mammal)) {
throw new Error("Instantiate Mammal with `new`");
}
Animal.call(this, age);
this.furColor = furColor;
};
Mammal.prototype = Object.create(Animal.prototype);
Mammal.prototype.constructor = Mammal;
Mammal.prototype.liveBirth = function liveBirth() {};
const Human = (age, furColor, languageSpoken) => {
if (!(this instanceof Human)) {
throw new Error("Instantiate Human with `new`");
}
Mammal.call(this, age, furColor);
this.languageSpoken = languageSpoken;
};
Human.prototype = Object.create(Mammal.prototype);
Human.prototype.constructor = Human;
Human.prototype.speak = function speak() {};
```
prototype vs ES6 class
```js
class Animal {
constructor(age) {
this.age = age;
}
move() {
/* ... */
}
}
class Mammal extends Animal {
constructor(age, furColor) {
super(age);
this.furColor = furColor;
}
liveBirth() {
/* ... */
}
}
class Human extends Mammal {
constructor(age, furColor, languageSpoken) {
super(age, furColor);
this.languageSpoken = languageSpoken;
}
speak() {
/* ... */
}
}
```
Concurrency
```js
get("https://en.wikipedia.org/wiki/Robert_Cecil_Martin", (requestErr, response, body) => {
if (requestErr) {
console.error(requestErr);
} else {
writeFile("article.html", body, writeErr => {
if (writeErr) {
console.error(writeErr);
} else {
console.log("File written");
}
});
}
});
```
Concurrency
```js
get("https://en.wikipedia.org/wiki/Robert_Cecil_Martin").then(body => {
return writeFile("article.html", body);
}).then(() => {
console.log("File written");
}).catch(err => {
console.error(err);
});
```
Concurrency
```js
async function getCleanCodeArticle() {
try {
const body = await get("https://en.wikipedia.org/wiki/Robert_Cecil_Martin");
await writeFile("article.html", body);
console.log("File written");
} catch (err) {
console.error(err);
}
}
getCleanCodeArticle()
```
Questions