From d8e2705d0951851a5e04d4320e2bc76afdaffaa9 Mon Sep 17 00:00:00 2001 From: Yevhen Date: Thu, 14 Dec 2017 18:43:02 +0200 Subject: [PATCH 01/11] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3316bb54..7b00990f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +Original repository: https://github.com/ryanmcdermott/clean-code-javascript + # clean-code-javascript ## Table of Contents From 52c86f262999aedaa93657b0587357bd5313efb6 Mon Sep 17 00:00:00 2001 From: Yevhen Date: Fri, 15 Dec 2017 14:13:36 +0200 Subject: [PATCH 02/11] Update README.md --- README.md | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/README.md b/README.md index 7b00990f..37927e9a 100644 --- a/README.md +++ b/README.md @@ -987,44 +987,6 @@ account.setBalance(100); **[⬆ back to top](#table-of-contents)** -### Make objects have private members -This can be accomplished through closures (for ES5 and below). - -**Bad:** -```javascript - -const Employee = function(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 -``` - -**Good:** -```javascript -function 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 -``` -**[⬆ back to top](#table-of-contents)** - - ## **Classes** ### Prefer ES2015/ES6 classes over ES5 plain functions It's very difficult to get readable class inheritance, construction, and method From b1e80bd67a27008e2219e1fc39d39ca33895e098 Mon Sep 17 00:00:00 2001 From: Yevhen Date: Tue, 26 Dec 2017 13:23:39 +0200 Subject: [PATCH 03/11] Update README.md --- README.md | 154 ------------------------------------------------------ 1 file changed, 154 deletions(-) diff --git a/README.md b/README.md index 37927e9a..5781f0b1 100644 --- a/README.md +++ b/README.md @@ -988,160 +988,6 @@ account.setBalance(100); ## **Classes** -### Prefer ES2015/ES6 classes over ES5 plain functions -It's very difficult to get readable class inheritance, construction, and method -definitions for classical ES5 classes. If you need inheritance (and be aware -that you might not), then prefer ES2015/ES6 classes. However, prefer small functions over -classes until you find yourself needing larger and more complex objects. - -**Bad:** -```javascript -const Animal = function(age) { - if (!(this instanceof Animal)) { - throw new Error('Instantiate Animal with `new`'); - } - - this.age = age; -}; - -Animal.prototype.move = function move() {}; - -const Mammal = function(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 = function(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() {}; -``` - -**Good:** -```javascript -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() { /* ... */ } -} -``` -**[⬆ back to top](#table-of-contents)** - - -### Use method chaining -This pattern is very useful in JavaScript and you see it in many libraries such -as jQuery and Lodash. It allows your code to be expressive, and less verbose. -For that reason, I say, use method chaining and take a look at how clean your code -will be. In your class functions, simply return `this` at the end of every function, -and you can chain further class methods onto it. - -**Bad:** -```javascript -class Car { - constructor(make, model, color) { - this.make = make; - this.model = model; - this.color = color; - } - - setMake(make) { - this.make = make; - } - - setModel(model) { - this.model = model; - } - - setColor(color) { - this.color = color; - } - - save() { - console.log(this.make, this.model, this.color); - } -} - -const car = new Car('Ford','F-150','red'); -car.setColor('pink'); -car.save(); -``` - -**Good:** -```javascript -class Car { - constructor(make, model, color) { - this.make = make; - this.model = model; - this.color = color; - } - - setMake(make) { - this.make = make; - // NOTE: Returning this for chaining - return this; - } - - setModel(model) { - this.model = model; - // NOTE: Returning this for chaining - return this; - } - - setColor(color) { - this.color = color; - // NOTE: Returning this for chaining - return this; - } - - save() { - console.log(this.make, this.model, this.color); - // NOTE: Returning this for chaining - return this; - } -} - -const car = new Car('Ford','F-150','red') - .setColor('pink') - .save(); -``` -**[⬆ back to top](#table-of-contents)** - ### Prefer composition over inheritance As stated famously in [*Design Patterns*](https://en.wikipedia.org/wiki/Design_Patterns) by the Gang of Four, you should prefer composition over inheritance where you can. There are lots of From 42a834ec3f89cc2d6600d66968b43bcd0ebef833 Mon Sep 17 00:00:00 2001 From: Yevhen Date: Tue, 26 Dec 2017 13:38:13 +0200 Subject: [PATCH 04/11] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5781f0b1..e4049a12 100644 --- a/README.md +++ b/README.md @@ -1098,9 +1098,9 @@ class UserAuth { class UserSettings { - constructor(user) { + constructor(user, auth) { this.user = user; - this.auth = new UserAuth(user); + this.auth = auth; } changeSettings(settings) { From d23d91c2a4277cfc11fbf5e4ed5d8e4d012027fd Mon Sep 17 00:00:00 2001 From: Yevhen Date: Tue, 26 Dec 2017 13:43:25 +0200 Subject: [PATCH 05/11] Update README.md --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e4049a12..10300a11 100644 --- a/README.md +++ b/README.md @@ -1213,6 +1213,9 @@ classic Square-Rectangle example. Mathematically, a square is a rectangle, but if you model it using the "is-a" relationship via inheritance, you quickly get into trouble. +Note: This is a kind of a valid example but i would dive deeper into the topic. +Please read https://stackoverflow.com/questions/44442448/when-adhering-to-liskov-substitution-principle-lsp-can-a-child-class-implement best answer section. + **Bad:** ```javascript class Rectangle { @@ -1315,9 +1318,6 @@ renderLargeShapes(shapes); **[⬆ back to top](#table-of-contents)** ### Interface Segregation Principle (ISP) -JavaScript doesn't have interfaces so this principle doesn't apply as strictly -as others. However, it's important and relevant even with JavaScript's lack of -type system. ISP states that "Clients should not be forced to depend upon interfaces that they do not use." Interfaces are implicit contracts in JavaScript because of @@ -1329,6 +1329,8 @@ huge amounts of options is beneficial, because most of the time they won't need all of the settings. Making them optional helps prevent having a "fat interface". +!IMPORTANT Yevhen's Note: !!!!!!! I don't that it's a good example. I'm still thinking about a better example. !!!!! + **Bad:** ```javascript class DOMTraverser { @@ -1404,8 +1406,7 @@ It can accomplish this through DI. A huge benefit of this is that it reduces the coupling between modules. Coupling is a very bad development pattern because it makes your code hard to refactor. -As stated previously, JavaScript doesn't have interfaces so the abstractions -that are depended upon are implicit contracts. That is to say, the methods +The abstractions are depended upon are implicit contracts. That is to say, the methods and properties that an object/class exposes to another object/class. In the example below, the implicit contract is that any Request module for an `InventoryTracker` will have a `requestItems` method. From a87460767a9197a37c2f1cbd0a2456612a945bf3 Mon Sep 17 00:00:00 2001 From: Yevhen Date: Tue, 26 Dec 2017 13:44:52 +0200 Subject: [PATCH 06/11] Update README.md --- README.md | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/README.md b/README.md index 10300a11..eba2ac11 100644 --- a/README.md +++ b/README.md @@ -1965,25 +1965,3 @@ const actions = function() { }; ``` **[⬆ back to top](#table-of-contents)** - -## Translation - -This is also available in other languages: - - - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [fesnt/clean-code-javascript](https://github.com/fesnt/clean-code-javascript) - - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Uruguay.png) **Spanish**: [andersontr15/clean-code-javascript](https://github.com/andersontr15/clean-code-javascript-es) - - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese**: - - [alivebao/clean-code-js](https://github.com/alivebao/clean-code-js) - - [beginor/clean-code-javascript](https://github.com/beginor/clean-code-javascript) - - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [marcbruederlin/clean-code-javascript](https://github.com/marcbruederlin/clean-code-javascript) - - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [qkraudghgh/clean-code-javascript-ko](https://github.com/qkraudghgh/clean-code-javascript-ko) - - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [greg-dev/clean-code-javascript-pl](https://github.com/greg-dev/clean-code-javascript-pl) - - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: - - [BoryaMogila/clean-code-javascript-ru/](https://github.com/BoryaMogila/clean-code-javascript-ru/) - - [maksugr/clean-code-javascript](https://github.com/maksugr/clean-code-javascript) - - ![vi](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Vietnam.png) **Vietnamese**: [hienvd/clean-code-javascript/](https://github.com/hienvd/clean-code-javascript/) - - ![ja](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/clean-code-javascript/](https://github.com/mitsuruog/clean-code-javascript/) - - ![id](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Indonesia.png) **Indonesia**: - [andirkh/clean-code-javascript/](https://github.com/andirkh/clean-code-javascript/) - -**[⬆ back to top](#table-of-contents)** From 68a58b70bbef3641aa251cd3f89aafef33dce3c8 Mon Sep 17 00:00:00 2001 From: Yevhen Date: Tue, 26 Dec 2017 13:48:17 +0200 Subject: [PATCH 07/11] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index eba2ac11..fca52cb8 100644 --- a/README.md +++ b/README.md @@ -1105,10 +1105,13 @@ class UserSettings { changeSettings(settings) { if (this.auth.verifyCredentials()) { - // ... + this.user.updateSettings(settings); } } } + +new UserSettings(user, new UserAuth(user)) + ``` **[⬆ back to top](#table-of-contents)** From 710b0c8b5d9ae43def549394c2f0b33399fc3194 Mon Sep 17 00:00:00 2001 From: Yevhen Date: Tue, 26 Dec 2017 13:55:51 +0200 Subject: [PATCH 08/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fca52cb8..daf1c2fa 100644 --- a/README.md +++ b/README.md @@ -1332,7 +1332,7 @@ huge amounts of options is beneficial, because most of the time they won't need all of the settings. Making them optional helps prevent having a "fat interface". -!IMPORTANT Yevhen's Note: !!!!!!! I don't that it's a good example. I'm still thinking about a better example. !!!!! +!IMPORTANT Yevhen's Note: !!!!!!! I don't think that it's a good example. I'm still thinking about a better example. !!!!! **Bad:** ```javascript From d258978730bfb9b8198aaf1ea4f815f01cab6f75 Mon Sep 17 00:00:00 2001 From: Yevhen Date: Tue, 26 Dec 2017 14:56:34 +0200 Subject: [PATCH 09/11] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index daf1c2fa..4c4882d4 100644 --- a/README.md +++ b/README.md @@ -1218,6 +1218,7 @@ get into trouble. Note: This is a kind of a valid example but i would dive deeper into the topic. Please read https://stackoverflow.com/questions/44442448/when-adhering-to-liskov-substitution-principle-lsp-can-a-child-class-implement best answer section. +Note: If you want to know more about type variance, you can read this https://flow.org/en/docs/lang/variance/ explanation with examples in Flow. **Bad:** ```javascript From 10fec45803e1f824547bd84172473b45233e072b Mon Sep 17 00:00:00 2001 From: Yevhen Date: Tue, 26 Dec 2017 14:57:17 +0200 Subject: [PATCH 10/11] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4c4882d4..849a7663 100644 --- a/README.md +++ b/README.md @@ -1218,6 +1218,7 @@ get into trouble. Note: This is a kind of a valid example but i would dive deeper into the topic. Please read https://stackoverflow.com/questions/44442448/when-adhering-to-liskov-substitution-principle-lsp-can-a-child-class-implement best answer section. + Note: If you want to know more about type variance, you can read this https://flow.org/en/docs/lang/variance/ explanation with examples in Flow. **Bad:** From 45f1d61f94c5275ece4c3a42109c1004168fd7f2 Mon Sep 17 00:00:00 2001 From: Yevhen Date: Tue, 26 Dec 2017 15:21:01 +0200 Subject: [PATCH 11/11] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 849a7663..15424472 100644 --- a/README.md +++ b/README.md @@ -1219,6 +1219,8 @@ get into trouble. Note: This is a kind of a valid example but i would dive deeper into the topic. Please read https://stackoverflow.com/questions/44442448/when-adhering-to-liskov-substitution-principle-lsp-can-a-child-class-implement best answer section. +Note: Please also read this artical http://sergeyteplyakov.blogspot.com/2014/09/liskov-substitution-principle.html (RU) as more in-depth explanation. + Note: If you want to know more about type variance, you can read this https://flow.org/en/docs/lang/variance/ explanation with examples in Flow. **Bad:**