From e8812779b574fb49b098227eeb0e23dba98a4672 Mon Sep 17 00:00:00 2001 From: Kostas Bariotis Date: Thu, 12 Jan 2017 11:50:55 +0200 Subject: [PATCH 01/40] Add Side Effects pt.2 --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 9504b922..856d9831 100644 --- a/README.md +++ b/README.md @@ -550,6 +550,32 @@ console.log(newName); // ['Ryan', 'McDermott']; ``` **[⬆ back to top](#table-of-contents)** +### Avoid Side Effects pt.2 +Side effects could also occur from inside a function. In Javascript, function arguments +are always passed by value except when they(functions) are passed reference values such as +objects and arrays. In that case, we should be carefull not to change any of these +argument's properties. A possible solution would be to always clone the variable, +edit it and return the clone. + +**Bad:** +```javascript +function userReducer(state, action) { + state.userProfile = action.payload; + return state; +} +``` + +**Good:** +```javascript +function userReducer(state, action) { + var s = Object.assign({}, state); + s.userProfile = action.payload; + return s; +} +``` + +**[⬆ back to top](#table-of-contents)** + ### Don't write to global functions Polluting globals is a bad practice in JavaScript because you could clash with another library and the user of your API would be none-the-wiser until they get an From 6774f750f2a1f19137eabba255b1133a05499c26 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Thu, 12 Jan 2017 17:16:48 -0800 Subject: [PATCH 02/40] fix async/await example There's no need to `await` a call to `require`, and they might sooner be written in single lines to mimic the style used for the previous examples. --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9504b922..f687689a 100644 --- a/README.md +++ b/README.md @@ -1726,11 +1726,8 @@ require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Marti ```javascript async function getCleanCodeArticle() { try { - const request = await require('request-promise'); - const response = await request.get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin'); - const fileHandle = await require('fs-promise'); - - await fileHandle.writeFile('article.html', response); + const response = await require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin'); + await require('fs-promise').writeFile('article.html', response); console.log('File written'); } catch(err) { console.error(err); From e94afcf3cfa16b3776a6a09bc9557007e679294b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Aragone=CC=80s?= Date: Sat, 14 Jan 2017 17:30:25 +0100 Subject: [PATCH 03/40] Change literal for a constant --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 34438930..86fb49f4 100644 --- a/README.md +++ b/README.md @@ -628,9 +628,11 @@ const programmerOutput = [ } ]; +const INITIAL_VALUE = 0; + const totalOutput = programmerOutput .map((programmer) => programmer.linesOfCode) - .reduce((acc, linesOfCode) => acc + linesOfCode, 0); + .reduce((acc, linesOfCode) => acc + linesOfCode, INITIAL_VALUE); ``` **[⬆ back to top](#table-of-contents)** From 84f8ea6f8dc2d9693a290f13c1bce8d05766689f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crisoforo=20Gaspar=20Hern=C3=A1ndez?= Date: Sat, 14 Jan 2017 11:50:51 -0600 Subject: [PATCH 04/40] Simplify "Use searchable names" example (#121) * Simplify "Use searchable names" example There is no need to create an arrow function to execute a function inside of the timeout. * Remove `this` to avoid context problems --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 16ee1a4c..8b76fc5c 100644 --- a/README.md +++ b/README.md @@ -80,9 +80,7 @@ can help identify unnamed constants. **Bad:** ```javascript // What the heck is 86400000 for? -setTimeout(() => { - this.blastOff(); -}, 86400000); +setTimeout(blastOff, 86400000); ``` @@ -91,9 +89,7 @@ setTimeout(() => { // Declare them as capitalized `const` globals. const MILLISECONDS_IN_A_DAY = 86400000; -setTimeout(() => { - this.blastOff(); -}, MILLISECONDS_IN_A_DAY); +setTimeout(blastOff, MILLISECONDS_IN_A_DAY); ``` **[⬆ back to top](#table-of-contents)** From 3364af5f98722eedc9f60c47e6c67bafad7acf43 Mon Sep 17 00:00:00 2001 From: Ryan McDermott Date: Sat, 14 Jan 2017 11:18:35 -0800 Subject: [PATCH 05/40] Remove stark warning against duplicate code, let's just strongly suggest to avoid it --- README.md | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8b76fc5c..00faeeab 100644 --- a/README.md +++ b/README.md @@ -362,13 +362,26 @@ function parseBetterJSAlternative(code) { **[⬆ back to top](#table-of-contents)** ### Remove duplicate code -Never ever, ever, under any circumstance, have duplicate code. There's no reason -for it and it's quite possibly the worst sin you can commit as a professional -developer. Duplicate code means there's more than one place to alter something -if you need to change some logic. JavaScript is untyped, so it makes having -generic functions quite easy. Take advantage of that! Tools like -[jsinspect](https://github.com/danielstjules/jsinspect) can help you find duplicate -code eligible for refactoring. +Do your absolute best to avoid duplicate code. Duplicate code is bad because it +means that there's more than one place to alter something if you need to change +some logic. + +Imagine if you run a restaurant and you keep track of your inventory: all your +tomatoes, onions, garlic, spices, etc. If you have multiple lists that that +you keep this on, then all have to be updated when you serve a dish with +tomatoes in them. If you only have one list, there's only one place to update! + +Oftentimes you have duplicate code because you have two or more slightly +different things, that share a lot in common, but their differences force you +to have two or more separate functions that do much of the same things. Removing +duplicate code means creating an abstraction that can handle this set of +different things with just one function/module/class. + +Getting the abstraction right is critical, that's why you should follow the +SOLID principles laid out in the *Classes* section. Bad abstractions can be +worse than duplicate code, so be careful! Having said this, if you can make +a good abstraction, do it! Don't repeat yourself, otherwise you'll find yourself +updating multiple places anytime you want to change one thing. **Bad:** ```javascript From aa71b3068c3daeeaa8fb2e0ce4a8c8e2549a9a15 Mon Sep 17 00:00:00 2001 From: krzysztof-grzybek Date: Sat, 14 Jan 2017 21:19:37 +0100 Subject: [PATCH 06/40] modify open/closed principle --- README.md | 74 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 00faeeab..53c08f1b 100644 --- a/README.md +++ b/README.md @@ -1022,38 +1022,84 @@ class UserSettings { As stated by Bertrand Meyer, "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification." What does that mean though? This principle basically states that you should allow users to -extend the functionality of your module without having to open up the `.js` -source code file and manually manipulate it. +add new functionalities without changing existing code. **Bad:** ```javascript -class AjaxRequester { +class AjaxAdapter extends Adapter { constructor() { - // What if we wanted another HTTP Method, like DELETE? We would have to - // open this file up and modify this and put it in manually. - this.HTTP_METHODS = ['POST', 'PUT', 'GET']; + super(); + this.name = 'ajaxAdapter'; } +} - get(url) { - // ... +class NodeAdapter extends Adapter { + constructor() { + super(); + this.name = 'nodeAdapter'; + } +} + +class HttpRequester { + constructor(adapter) { + this.adapter = adapter; + } + + fetch(url) { + if (this.adapter.name === 'ajaxAdapter') { + return makeAjaxCall(url).then(response => { + // transform response and return + }); + } else if(this.adapter.name === 'httpNodeAdapter') { + return makeHttpCall(url).then(response => { + // transform response and return + }); + } } +} + +function makeAjaxCall(url) { + // request and return promise +} +function makeHttpCall(url) { + // request and return promise } ``` **Good**: ```javascript -class AjaxRequester { +class AjaxAdapter extends Adapter { constructor() { - this.HTTP_METHODS = ['POST', 'PUT', 'GET']; + super(); + this.name = 'ajaxAdapter'; } - get(url) { - // ... + request(url) { + // request and return promise + } +} + +class NodeAdapter extends Adapter { + constructor() { + super(); + this.name = 'nodeAdapter'; } - addHTTPMethod(method) { - this.HTTP_METHODS.push(method); + request(url) { + // request and return promise + } +} + +class HttpRequester { + constructor(adapter) { + this.adapter = adapter; + } + + fetch(url) { + return this.adapter.request(url).then(response => { + // transform response and return + }); } } ``` From b1b37eb23421f54a705f00fe4be756dd39339158 Mon Sep 17 00:00:00 2001 From: Ryan McDermott Date: Sat, 14 Jan 2017 15:34:05 -0800 Subject: [PATCH 07/40] Make meaningful variable example even clearer --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53c08f1b..c1d80432 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ const yyyymmdstr = moment().format('YYYY/MM/DD'); **Good**: ```javascript -const yearMonthDay = moment().format('YYYY/MM/DD'); +const currentDate = moment().format('YYYY/MM/DD'); ``` **[⬆ back to top](#table-of-contents)** From ba3e34fcf443dfa235789b21cce916b27151b1c1 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Sun, 15 Jan 2017 05:49:55 +0200 Subject: [PATCH 08/40] fix some code style nits in examples --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c1d80432..7b0d0224 100644 --- a/README.md +++ b/README.md @@ -1047,11 +1047,11 @@ class HttpRequester { fetch(url) { if (this.adapter.name === 'ajaxAdapter') { - return makeAjaxCall(url).then(response => { + return makeAjaxCall(url).then((response) => { // transform response and return }); - } else if(this.adapter.name === 'httpNodeAdapter') { - return makeHttpCall(url).then(response => { + } else if (this.adapter.name === 'httpNodeAdapter') { + return makeHttpCall(url).then((response) => { // transform response and return }); } @@ -1097,7 +1097,7 @@ class HttpRequester { } fetch(url) { - return this.adapter.request(url).then(response => { + return this.adapter.request(url).then((response) => { // transform response and return }); } From ca1cd96574610e29ae8a84b98957bee05ae56f78 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Sun, 15 Jan 2017 16:14:30 +0200 Subject: [PATCH 09/40] remove duplicate word in 'Remove duplicate code' :) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b0d0224..ff4358d2 100644 --- a/README.md +++ b/README.md @@ -367,7 +367,7 @@ means that there's more than one place to alter something if you need to change some logic. Imagine if you run a restaurant and you keep track of your inventory: all your -tomatoes, onions, garlic, spices, etc. If you have multiple lists that that +tomatoes, onions, garlic, spices, etc. If you have multiple lists that you keep this on, then all have to be updated when you serve a dish with tomatoes in them. If you only have one list, there's only one place to update! From 5d209dafdf8a9b1e1e321421faea3360899aa900 Mon Sep 17 00:00:00 2001 From: Kostas Bariotis Date: Mon, 16 Jan 2017 11:56:40 +0200 Subject: [PATCH 10/40] Typo and rewording --- README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 856d9831..261d29ad 100644 --- a/README.md +++ b/README.md @@ -505,7 +505,7 @@ function createTempFile(name) { ``` **[⬆ back to top](#table-of-contents)** -### Avoid Side Effects +### Avoid Side Effects (part 1) A function produces a side effect if it does anything other than take a value in and return another value or values. A side effect could be writing to a file, modifying some global variable, or accidentally wiring all your money to a @@ -550,12 +550,11 @@ console.log(newName); // ['Ryan', 'McDermott']; ``` **[⬆ back to top](#table-of-contents)** -### Avoid Side Effects pt.2 -Side effects could also occur from inside a function. In Javascript, function arguments -are always passed by value except when they(functions) are passed reference values such as -objects and arrays. In that case, we should be carefull not to change any of these -argument's properties. A possible solution would be to always clone the variable, -edit it and return the clone. +### Avoid Side Effects (part 2) +Side effects could also occur from inside a function. In JavaScript, primitives are +passed by value and objects are passed by reference. In the later case, we should be +careful not to change any of these argument's properties. A possible solution would +be to always clone the variable, edit it and return the clone. **Bad:** ```javascript From daf2d6c70af72729866a11424a6e66646a1212ce Mon Sep 17 00:00:00 2001 From: Kostas Bariotis Date: Mon, 16 Jan 2017 12:03:50 +0200 Subject: [PATCH 11/40] Add caveats --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 261d29ad..8bf2c6c4 100644 --- a/README.md +++ b/README.md @@ -553,12 +553,16 @@ console.log(newName); // ['Ryan', 'McDermott']; ### Avoid Side Effects (part 2) Side effects could also occur from inside a function. In JavaScript, primitives are passed by value and objects are passed by reference. In the later case, we should be -careful not to change any of these argument's properties. A possible solution would -be to always clone the variable, edit it and return the clone. +careful not to change any of these argument's properties. + +A possible solution would be to always clone the variable, edit it and return the +clone. There would be cases where you actually want to modify the input object +and this should not be taken as a silver bullet. Furthermore, cloning big objects can +be very expensive in terms of performance. **Bad:** ```javascript -function userReducer(state, action) { +function (state, action) { state.userProfile = action.payload; return state; } From a4718d4d3ed5db2e2cca5a8b450c5af7d9f20e44 Mon Sep 17 00:00:00 2001 From: Kostas Bariotis Date: Mon, 16 Jan 2017 12:14:56 +0200 Subject: [PATCH 12/40] Change example --- README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8bf2c6c4..09d845cc 100644 --- a/README.md +++ b/README.md @@ -562,18 +562,21 @@ be very expensive in terms of performance. **Bad:** ```javascript -function (state, action) { - state.userProfile = action.payload; - return state; +const addItemToCart = function (cart, item) { + cart.push({ item: item, date: Date.now() }); + + return cart; } ``` **Good:** ```javascript -function userReducer(state, action) { - var s = Object.assign({}, state); - s.userProfile = action.payload; - return s; +const addItemToCart = function (cart, item) { + const c = Object.assign({}, cart); + + c.push({ item: item, date: Date.now() }); + + return c; } ``` From ec8dbd195c44972d4e0f1abf1c48fd7852781b45 Mon Sep 17 00:00:00 2001 From: Liran Brimer Date: Mon, 16 Jan 2017 16:14:24 +0200 Subject: [PATCH 13/40] fix is-a order in Prefer composition over inheritance description --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff4358d2..e07ebe4d 100644 --- a/README.md +++ b/README.md @@ -1582,7 +1582,7 @@ depends on your problem at hand, but this is a decent list of when inheritance makes more sense than composition: 1. Your inheritance represents an "is-a" relationship and not a "has-a" -relationship (Animal->Human vs. User->UserDetails). +relationship (Human->Animal vs. User->UserDetails). 2. You can reuse code from the base classes (Humans can move like all animals). 3. You want to make global changes to derived classes by changing a base class. (Change the caloric expenditure of all animals when they move). From fae51115b827f99534ab96f0eaf5bbd2609ae053 Mon Sep 17 00:00:00 2001 From: Kostas Bariotis Date: Mon, 16 Jan 2017 16:55:41 +0200 Subject: [PATCH 14/40] Update code example --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 09d845cc..2a8f488f 100644 --- a/README.md +++ b/README.md @@ -562,22 +562,22 @@ be very expensive in terms of performance. **Bad:** ```javascript -const addItemToCart = function (cart, item) { - cart.push({ item: item, date: Date.now() }); +const addItemToCart = (cart, item) => { + cart.push({ item, date: Date.now() }); return cart; -} +}; ``` **Good:** ```javascript -const addItemToCart = function (cart, item) { +const addItemToCart = (cart, item) => { const c = Object.assign({}, cart); - c.push({ item: item, date: Date.now() }); + c.push({ item, date: Date.now() }); return c; -} +}; ``` **[⬆ back to top](#table-of-contents)** From 17512c316379d2b93b35f00e2a1f1be6f87bc1e8 Mon Sep 17 00:00:00 2001 From: Collin Date: Mon, 16 Jan 2017 10:43:13 -0700 Subject: [PATCH 15/40] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff4358d2..37bc35a6 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ saveCityZipCode(address.match(cityZipCodeRegex)[1], address.match(cityZipCodeReg ```javascript const address = 'One Infinite Loop, Cupertino 95014'; const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/; -const [, city, zipCode] = address.match(cityZipCodeRegex); +const [, city, zipCode] = address.match(cityZipCodeRegex) || []; saveCityZipCode(city, zipCode); ``` **[⬆ back to top](#table-of-contents)** From 68447308a597925bc90838025bf655ac035a08f3 Mon Sep 17 00:00:00 2001 From: Ryan McDermott Date: Mon, 16 Jan 2017 20:15:50 -0800 Subject: [PATCH 16/40] Expand side effect part 2 discussion --- README.md | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6b666f6e..d7aa2a22 100644 --- a/README.md +++ b/README.md @@ -560,21 +560,41 @@ console.log(newName); // ['Ryan', 'McDermott']; **[⬆ back to top](#table-of-contents)** ### Avoid Side Effects (part 2) -Side effects could also occur from inside a function. In JavaScript, primitives are -passed by value and objects are passed by reference. In the later case, we should be -careful not to change any of these argument's properties. - -A possible solution would be to always clone the variable, edit it and return the -clone. There would be cases where you actually want to modify the input object -and this should not be taken as a silver bullet. Furthermore, cloning big objects can -be very expensive in terms of performance. +In JavaScript, primitives are passed by value and objects/arrays are passed by +reference. In the case of objects and arrays, if our function makes a change +in a shopping cart array, for example, by adding an item to purchase, +then any other function that uses that `cart` array will be affected by this +addition. That may be great, however it can be bad too. Let's imagine a bad +situation: + +The user clicks the "Purchase", button which calls a `purchase` function that +spawns a network request and sends the `cart` array to the server. Because +of a bad network connection, the `purchase` function has to keep retrying the +request. Now, what if in the meantime the user accidentally clicks "Add to Cart" +button on an item they don't actually want before the network request begins? +If that happens and the network request begins, then that purchase function +will send the accidentally added item because it has a reference to a shopping +cart array that the `addItemToCart` function modified by adding an unwanted +item. + +A great solution would be for the `addItemToCart` to always clone the `cart`, +edit it, and return the clone. This ensures that no other functions that are +holding onto a reference of the shopping cart will be affected by any changes. + +Two caveats to mention to this approach: +1. There might be cases where you actually want to modify the input object, +but when you adopt this programming practice you will find that those case +are pretty rare. Most things can be refactored to have no side effects! +2. Cloning big objects can be very expensive in terms of performance. Luckily, +this isn't a big issue in practice because there are +[https://facebook.github.io/immutable-js/](great libraries) that allow +this kind of programming approach to be fast and not as memory intensive as +it would be for you to manually clone objects and arrays. **Bad:** ```javascript const addItemToCart = (cart, item) => { cart.push({ item, date: Date.now() }); - - return cart; }; ``` @@ -582,9 +602,9 @@ const addItemToCart = (cart, item) => { ```javascript const addItemToCart = (cart, item) => { const c = Object.assign({}, cart); - + c.push({ item, date: Date.now() }); - + return c; }; ``` From ff6fdc1406930c0087f84b3d5a3b7c8177aa443f Mon Sep 17 00:00:00 2001 From: Ryan McDermott Date: Mon, 16 Jan 2017 20:19:08 -0800 Subject: [PATCH 17/40] Fix side effect part 2 list --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d7aa2a22..a51252cc 100644 --- a/README.md +++ b/README.md @@ -582,10 +582,11 @@ edit it, and return the clone. This ensures that no other functions that are holding onto a reference of the shopping cart will be affected by any changes. Two caveats to mention to this approach: -1. There might be cases where you actually want to modify the input object, + 1. There might be cases where you actually want to modify the input object, but when you adopt this programming practice you will find that those case are pretty rare. Most things can be refactored to have no side effects! -2. Cloning big objects can be very expensive in terms of performance. Luckily, + + 2. Cloning big objects can be very expensive in terms of performance. Luckily, this isn't a big issue in practice because there are [https://facebook.github.io/immutable-js/](great libraries) that allow this kind of programming approach to be fast and not as memory intensive as From 55ec74a1c87811f5cf11b944101ac476ba578c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Van=20der=20Auwermeulen=20Gr=C3=A9goire?= Date: Tue, 17 Jan 2017 17:59:14 +0100 Subject: [PATCH 18/40] Immutable error `cart` is an Array. the ES6 spread operator can be used : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index a51252cc..4c1b233f 100644 --- a/README.md +++ b/README.md @@ -602,11 +602,7 @@ const addItemToCart = (cart, item) => { **Good:** ```javascript const addItemToCart = (cart, item) => { - const c = Object.assign({}, cart); - - c.push({ item, date: Date.now() }); - - return c; + return [...cart, { item, date : Date.now() }]; }; ``` From 35a0cf8f77d6a7895f1ed0ea54eaabb27bf38ac0 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Wed, 18 Jan 2017 06:46:16 +0200 Subject: [PATCH 19/40] fix confusing example Ref: https://github.com/ryanmcdermott/clean-code-javascript/pull/151 --- README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4c1b233f..9fcb0b9e 100644 --- a/README.md +++ b/README.md @@ -219,17 +219,16 @@ function createMenu(title, body, buttonText, cancellable) { **Good**: ```javascript -const menuConfig = { - title: 'Foo', - body: 'Bar', - buttonText: 'Baz', - cancellable: true -}; - function createMenu(config) { // ... } +createMenu({ + title: 'Foo', + body: 'Bar', + buttonText: 'Baz', + cancellable: true +}); ``` **[⬆ back to top](#table-of-contents)** From 4d082341ed9f54cb2e119e67dddf414ea1b32078 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 18 Jan 2017 20:34:36 -0200 Subject: [PATCH 20/40] Fix minor markdown error --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9fcb0b9e..f7aed990 100644 --- a/README.md +++ b/README.md @@ -587,7 +587,7 @@ are pretty rare. Most things can be refactored to have no side effects! 2. Cloning big objects can be very expensive in terms of performance. Luckily, this isn't a big issue in practice because there are -[https://facebook.github.io/immutable-js/](great libraries) that allow +[great libraries](https://facebook.github.io/immutable-js/) that allow this kind of programming approach to be fast and not as memory intensive as it would be for you to manually clone objects and arrays. From 4f6d14183662074189863fe1fcf5b8a593bb9d5f Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 18 Jan 2017 20:43:08 -0200 Subject: [PATCH 21/40] Add translation section Add translation section same format AirBnb style, with Brazilian Portuguese and Chinese translations --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index f7aed990..b4c71d70 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ 8. [Error Handling](#error-handling) 9. [Formatting](#formatting) 10. [Comments](#comments) + 11. [Translation](#translation) ## Introduction ![Humorous image of software quality estimation as a count of how many expletives @@ -2152,3 +2153,12 @@ 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) + - ![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) + +**[⬆ back to top](#table-of-contents)** \ No newline at end of file From d41598d12273a36f071cb6036c0a7dcab30d5c43 Mon Sep 17 00:00:00 2001 From: Ryan McDermott Date: Wed, 18 Jan 2017 17:58:37 -0800 Subject: [PATCH 22/40] Add German translation --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b4c71d70..e5ba38d0 100644 --- a/README.md +++ b/README.md @@ -2160,5 +2160,6 @@ 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) - ![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) - -**[⬆ back to top](#table-of-contents)** \ No newline at end of file + - ![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) + +**[⬆ back to top](#table-of-contents)** From b22ab6bc8b0ce247dd29d396082645322ee7c982 Mon Sep 17 00:00:00 2001 From: "myoungho.Pak" Date: Thu, 19 Jan 2017 16:24:07 +0900 Subject: [PATCH 23/40] Add korean translation --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e5ba38d0..992ae472 100644 --- a/README.md +++ b/README.md @@ -2161,5 +2161,6 @@ 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) - ![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) - ![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) **[⬆ back to top](#table-of-contents)** From 62dfd20314345e2596a778c3cd5ac546cbed90b5 Mon Sep 17 00:00:00 2001 From: Eduardo Sganzerla Date: Thu, 19 Jan 2017 23:40:52 -0200 Subject: [PATCH 24/40] Fix some **Good**: to **Good:** (#145) Fix **Good**: to **Good:** --- README.md | 83 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 992ae472..61669f58 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # clean-code-javascript ## Table of Contents @@ -48,7 +49,7 @@ improvement. Beat up the code instead! const yyyymmdstr = moment().format('YYYY/MM/DD'); ``` -**Good**: +**Good:** ```javascript const currentDate = moment().format('YYYY/MM/DD'); ``` @@ -63,7 +64,7 @@ getClientData(); getCustomerRecord(); ``` -**Good**: +**Good:** ```javascript getUser(); ``` @@ -85,7 +86,7 @@ setTimeout(blastOff, 86400000); ``` -**Good**: +**Good:** ```javascript // Declare them as capitalized `const` globals. const MILLISECONDS_IN_A_DAY = 86400000; @@ -103,7 +104,7 @@ const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/; saveCityZipCode(address.match(cityZipCodeRegex)[1], address.match(cityZipCodeRegex)[2]); ``` -**Good**: +**Good:** ```javascript const address = 'One Infinite Loop, Cupertino 95014'; const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/; @@ -129,7 +130,7 @@ locations.forEach((l) => { }); ``` -**Good**: +**Good:** ```javascript const locations = ['Austin', 'New York', 'San Francisco']; locations.forEach((location) => { @@ -160,7 +161,7 @@ function paintCar(car) { } ``` -**Good**: +**Good:** ```javascript const Car = { make: 'Honda', @@ -185,7 +186,7 @@ function createMicrobrewery(name) { ``` -**Good**: +**Good:** ```javascript function createMicrobrewery(breweryName = 'Hipster Brew Co.') { // ... @@ -218,7 +219,7 @@ function createMenu(title, body, buttonText, cancellable) { } ``` -**Good**: +**Good:** ```javascript function createMenu(config) { // ... @@ -253,7 +254,7 @@ function emailClients(clients) { } ``` -**Good**: +**Good:** ```javascript function emailClients(clients) { clients @@ -282,7 +283,7 @@ const date = new Date(); addToDate(date, 1); ``` -**Good**: +**Good:** ```javascript function addMonthToDate(month, date) { // ... @@ -324,7 +325,7 @@ function parseBetterJSAlternative(code) { } ``` -**Good**: +**Good:** ```javascript function tokenize(code) { const REGEXES = [ @@ -416,7 +417,7 @@ function showManagerList(managers) { } ``` -**Good**: +**Good:** ```javascript function showList(employees) { employees.forEach((employee) => { @@ -462,7 +463,7 @@ function createMenu(config) { createMenu(menuConfig); ``` -**Good**: +**Good:** ```javascript const menuConfig = { title: 'Order', @@ -502,7 +503,7 @@ function createFile(name, temp) { } ``` -**Good**: +**Good:** ```javascript function createFile(name) { fs.create(name); @@ -545,7 +546,7 @@ splitIntoFirstAndLastName(); console.log(name); // ['Ryan', 'McDermott']; ``` -**Good**: +**Good:** ```javascript function splitIntoFirstAndLastName(name) { return name.split(' '); @@ -668,7 +669,7 @@ for (let i = 0; i < programmerOutput.length; i++) { } ``` -**Good**: +**Good:** ```javascript const programmerOutput = [ { @@ -701,7 +702,7 @@ if (fsm.state === 'fetching' && isEmpty(listNode)) { } ``` -**Good**: +**Good:** ```javascript function shouldShowSpinner(fsm, listNode) { return fsm.state === 'fetching' && isEmpty(listNode); @@ -726,7 +727,7 @@ if (!isDOMNodeNotPresent(node)) { } ``` -**Good**: +**Good:** ```javascript function isDOMNodePresent(node) { // ... @@ -765,7 +766,7 @@ class Airplane { } ``` -**Good**: +**Good:** ```javascript class Airplane { // ... @@ -811,7 +812,7 @@ function travelToTexas(vehicle) { } ``` -**Good**: +**Good:** ```javascript function travelToTexas(vehicle) { vehicle.move(this.currentLocation, new Location('texas')); @@ -842,7 +843,7 @@ function combine(val1, val2) { } ``` -**Good**: +**Good:** ```javascript function combine(val1, val2) { return val1 + val2; @@ -867,7 +868,7 @@ for (let i = 0, len = list.length; i < len; i++) { } ``` -**Good**: +**Good:** ```javascript for (let i = 0; i < list.length; i++) { // ... @@ -895,7 +896,7 @@ inventoryTracker('apples', req, 'www.inventory-awesome.io'); ``` -**Good**: +**Good:** ```javascript function newRequestModule(url) { // ... @@ -938,7 +939,7 @@ const bankAccount = new BankAccount(); bankAccount.balance -= 100; ``` -**Good**: +**Good:** ```javascript class BankAccount { constructor(balance = 1000) { @@ -993,7 +994,7 @@ delete employee.name; console.log(`Employee name: ${employee.getName()}`); // Employee name: undefined ``` -**Good**: +**Good:** ```javascript const Employee = function (name) { this.getName = function getName() { @@ -1039,7 +1040,7 @@ class UserSettings { } ``` -**Good**: +**Good:** ```javascript class UserAuth { constructor(user) { @@ -1116,7 +1117,7 @@ function makeHttpCall(url) { } ``` -**Good**: +**Good:** ```javascript class AjaxAdapter extends Adapter { constructor() { @@ -1223,7 +1224,7 @@ const rectangles = [new Rectangle(), new Rectangle(), new Square()]; renderLargeRectangles(rectangles); ``` -**Good**: +**Good:** ```javascript class Shape { setColor(color) { @@ -1331,7 +1332,7 @@ const $ = new DOMTraverser({ ``` -**Good**: +**Good:** ```javascript class DOMTraverser { constructor(settings) { @@ -1418,7 +1419,7 @@ const inventoryTracker = new InventoryTracker(['apples', 'bananas']); inventoryTracker.requestItems(); ``` -**Good**: +**Good:** ```javascript class InventoryTracker { constructor(items, requester) { @@ -1576,7 +1577,7 @@ car.setModel('F-150'); car.save(); ``` -**Good**: +**Good:** ```javascript class Car { constructor() { @@ -1659,7 +1660,7 @@ class EmployeeTaxData extends Employee { } ``` -**Good**: +**Good:** ```javascript class EmployeeTaxData { constructor(ssn, salary) { @@ -1726,7 +1727,7 @@ describe('MakeMomentJSGreatAgain', () => { }); ``` -**Good**: +**Good:** ```javascript const assert = require('assert'); @@ -1775,7 +1776,7 @@ require('request').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin', (req ``` -**Good**: +**Good:** ```javascript require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin') .then((response) => { @@ -1813,7 +1814,7 @@ require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Marti ``` -**Good**: +**Good:** ```javascript async function getCleanCodeArticle() { try { @@ -1931,7 +1932,7 @@ class animal {} class Alpaca {} ``` -**Good**: +**Good:** ```javascript const DAYS_IN_WEEK = 7; const DAYS_IN_MONTH = 30; @@ -1992,7 +1993,7 @@ const review = new PerformanceReview(user); review.perfReview(); ``` -**Good**: +**Good:** ```javascript class PerformanceReview { constructor(employee) { @@ -2058,7 +2059,7 @@ function hashIt(data) { } ``` -**Good**: +**Good:** ```javascript function hashIt(data) { @@ -2088,7 +2089,7 @@ doStuff(); // doSoMuchStuff(); ``` -**Good**: +**Good:** ```javascript doStuff(); ``` @@ -2111,7 +2112,7 @@ function combine(a, b) { } ``` -**Good**: +**Good:** ```javascript function combine(a, b) { return a + b; @@ -2141,7 +2142,7 @@ const actions = function() { }; ``` -**Good**: +**Good:** ```javascript $scope.model = { menu: 'foo', From 209f944c579e637912964d8efa1d9052b78b9e4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89des=20Bal=C3=A1zs?= Date: Sat, 21 Jan 2017 02:37:44 +0000 Subject: [PATCH 25/40] Changed Function arguments section to include destructuring --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 97a0a464..653db4ff 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,17 @@ Since JavaScript allows us to make objects on the fly, without a lot of class boilerplate, you can use an object if you are finding yourself needing a lot of arguments. +To make it more obvious what properties does the function expect, use the es6 +destructuring syntax. This has a couple of advantages: + +1. When someone looks at the function signature, it's immediately clear what +properties are used. +2. Since the function doesn't have the reference to the actual argument, the +user of the function can be sure that no other properties are used by anything +down the call chain. +3. Linters (like eslint) can warn you about unused properties, while this would +be impossible without destructuring. + **Bad:** ```javascript function createMenu(title, body, buttonText, cancellable) { @@ -221,7 +232,7 @@ function createMenu(title, body, buttonText, cancellable) { **Good:** ```javascript -function createMenu(config) { +function createMenu({ title, body, buttonText, cancellable }) { // ... } From a8c2046167535fb82b20bacb99cf829b6debbd5f Mon Sep 17 00:00:00 2001 From: Ryan McDermott Date: Sat, 21 Jan 2017 11:57:06 -0800 Subject: [PATCH 26/40] Improve language of function arguments subsection --- README.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 653db4ff..f77cb853 100644 --- a/README.md +++ b/README.md @@ -202,26 +202,27 @@ makes testing your function easier. Having more than three leads to a combinatorial explosion where you have to test tons of different cases with each separate argument. -Zero arguments is the ideal case. One or two arguments is ok, and three should -be avoided. Anything more than that should be consolidated. Usually, if you have +One or two arguments is the ideal case, and three should be avoided if possible. +Anything more than that should be consolidated. Usually, if you have more than two arguments then your function is trying to do too much. In cases where it's not, most of the time a higher-level object will suffice as an argument. -Since JavaScript allows us to make objects on the fly, without a lot of class +Since JavaScript allows you to make objects on the fly, without a lot of class boilerplate, you can use an object if you are finding yourself needing a lot of arguments. -To make it more obvious what properties does the function expect, use the es6 -destructuring syntax. This has a couple of advantages: +To make it obvious what properties the function expects, you can use the es6 +destructuring syntax. This has a few advantages: 1. When someone looks at the function signature, it's immediately clear what -properties are used. -2. Since the function doesn't have the reference to the actual argument, the -user of the function can be sure that no other properties are used by anything -down the call chain. -3. Linters (like eslint) can warn you about unused properties, while this would -be impossible without destructuring. +properties are being used. +2. Destructuring also clones the specified primitive values of the argument +object passed into the function. This can help prevent side effects. Note: +objects and arrays that are destructured from the argument object are NOT +cloned. +3. Linters can warn you about unused properties, which would be impossible +without destructuring. **Bad:** ```javascript From 59d4182738cc4644756b1b19f5cbc47460f1e5de Mon Sep 17 00:00:00 2001 From: MarkWaldron Date: Sat, 21 Jan 2017 19:01:19 -0500 Subject: [PATCH 27/40] Fix class method call in getter/setter example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f77cb853..a1dfd01e 100644 --- a/README.md +++ b/README.md @@ -962,7 +962,7 @@ class BankAccount { // It doesn't have to be prefixed with `get` or `set` to be a getter/setter set balance(amount) { - if (verifyIfAmountCanBeSetted(amount)) { + if (this.verifyIfAmountCanBeSetted(amount)) { this._balance = amount; } } From dd791e9724a67c20d5640f34422157bb048998f9 Mon Sep 17 00:00:00 2001 From: Erick Cardenas-Mendez Date: Mon, 23 Jan 2017 13:13:33 -0500 Subject: [PATCH 28/40] README.md: change 'peddle' to 'pedal' **Pedal** is the act of using bicycle pedals. *Peddle* means to travel around selling something. I think you meant the former. BTW, thanks for the great guide! --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a1dfd01e..254d7845 100644 --- a/README.md +++ b/README.md @@ -819,7 +819,7 @@ The first thing to consider is consistent APIs. ```javascript function travelToTexas(vehicle) { if (vehicle instanceof Bicycle) { - vehicle.peddle(this.currentLocation, new Location('texas')); + vehicle.pedal(this.currentLocation, new Location('texas')); } else if (vehicle instanceof Car) { vehicle.drive(this.currentLocation, new Location('texas')); } From 8f37510bab5dac8789003a61aa5e1f712484bb35 Mon Sep 17 00:00:00 2001 From: BoryaMogila Date: Mon, 23 Jan 2017 22:53:54 +0200 Subject: [PATCH 29/40] Add russian translation --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a1dfd01e..8f64e172 100644 --- a/README.md +++ b/README.md @@ -2177,5 +2177,7 @@ This is also available in other languages: - ![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) - ![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) + - ![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/) + **[⬆ back to top](#table-of-contents)** From beaaa370e40f286841cfe428d9d0638164b28385 Mon Sep 17 00:00:00 2001 From: davidvujic Date: Tue, 24 Jan 2017 13:10:19 +0100 Subject: [PATCH 30/40] Object instead of Class --- README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 056dbac6..0f049d9f 100644 --- a/README.md +++ b/README.md @@ -1010,13 +1010,17 @@ console.log(`Employee name: ${employee.getName()}`); // Employee name: undefined **Good:** ```javascript -const Employee = function (name) { - this.getName = function getName() { - return name; - }; -}; +function makeEmployee(name) { + function getName() { + return name; + } -const employee = new Employee('John Doe'); + return { + getName + }; +} + +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 From 37d929c5b617cbcba62699001c7742d1fefc0c4c Mon Sep 17 00:00:00 2001 From: davidvujic Date: Tue, 24 Jan 2017 15:03:06 +0100 Subject: [PATCH 31/40] refactor: inline function --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0f049d9f..f11506bf 100644 --- a/README.md +++ b/README.md @@ -1011,13 +1011,11 @@ console.log(`Employee name: ${employee.getName()}`); // Employee name: undefined **Good:** ```javascript function makeEmployee(name) { - function getName() { - return name; - } - - return { - getName - }; + return { + getName() { + return name; + }, + }; } const employee = makeEmployee('John Doe'); From 471371e4c7745612b6413ed56087b956daee22f0 Mon Sep 17 00:00:00 2001 From: Ryan McDermott Date: Wed, 25 Jan 2017 21:01:48 -0800 Subject: [PATCH 32/40] Add note about default arguments --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index f11506bf..cebc95fe 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,10 @@ function paintCar(car) { **[⬆ back to top](#table-of-contents)** ### Use default arguments instead of short circuiting or conditionals +Default arguments are often cleaner than short circuiting. Be aware that if you +use them, your function will only provide default values for `undefined` +arguments. Other "falsy" values such as `''`, `""`, `false`, `null`, `0`, and +`NaN`, will not be replaced by a default value. **Bad:** ```javascript From bfd763a0a12ad1d5cbdddc4735c2dae1e8e0283c Mon Sep 17 00:00:00 2001 From: Huei Tan Date: Thu, 26 Jan 2017 13:26:17 +0100 Subject: [PATCH 33/40] Update the example from "Single concept per test" --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cebc95fe..219b867c 100644 --- a/README.md +++ b/README.md @@ -1734,7 +1734,7 @@ describe('MakeMomentJSGreatAgain', () => { date = new MakeMomentJSGreatAgain('1/1/2015'); date.addDays(30); - date.shouldEqual('1/31/2015'); + assert.equal('1/31/2015', date); date = new MakeMomentJSGreatAgain('2/1/2016'); date.addDays(28); @@ -1755,7 +1755,7 @@ describe('MakeMomentJSGreatAgain', () => { it('handles 30-day months', () => { const date = new MakeMomentJSGreatAgain('1/1/2015'); date.addDays(30); - date.shouldEqual('1/31/2015'); + assert.equal('1/31/2015', date); }); it('handles leap year', () => { From 47dbe9dce21949853efced046e112c395ac0232b Mon Sep 17 00:00:00 2001 From: Anna Date: Sat, 28 Jan 2017 00:05:13 -0200 Subject: [PATCH 34/40] Explicit function name (#177) * Explicitly describing a function #175 * Keeping consistency by using singular nouns --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 219b867c..b52518f9 100644 --- a/README.md +++ b/README.md @@ -435,7 +435,7 @@ function showManagerList(managers) { **Good:** ```javascript -function showList(employees) { +function showEmployeeList(employees) { employees.forEach((employee) => { const expectedSalary = employee.calculateExpectedSalary(); const experience = employee.getExperience(); From a624d544fe8ec46992c97a321bf7cc37d2085cb1 Mon Sep 17 00:00:00 2001 From: davidvujic Date: Mon, 30 Jan 2017 13:16:28 +0100 Subject: [PATCH 35/40] refactor: Liskov Substitution - width/height/length as constructor parameters --- README.md | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index b52518f9..6199955b 100644 --- a/README.md +++ b/README.md @@ -1252,22 +1252,14 @@ class Shape { } render(area) { - // ... + // .. } } class Rectangle extends Shape { - constructor() { + constructor(width, height) { super(); - this.width = 0; - this.height = 0; - } - - setWidth(width) { this.width = width; - } - - setHeight(height) { this.height = height; } @@ -1277,12 +1269,8 @@ class Rectangle extends Shape { } class Square extends Shape { - constructor() { + constructor(length) { super(); - this.length = 0; - } - - setLength(length) { this.length = length; } @@ -1293,21 +1281,12 @@ class Square extends Shape { function renderLargeShapes(shapes) { shapes.forEach((shape) => { - switch (shape.constructor.name) { - case 'Square': - shape.setLength(5); - break; - case 'Rectangle': - shape.setWidth(4); - shape.setHeight(5); - } - - const area = shape.getArea(); - shape.render(area); - }); -} + const area = shape.getArea(); + shape.render(area); + }); + } -const shapes = [new Rectangle(), new Rectangle(), new Square()]; +const shapes = [new Rectangle(4, 5), new Rectangle(4, 5), new Square(5)]; renderLargeShapes(shapes); ``` **[⬆ back to top](#table-of-contents)** From 90e9b243628f1baffd32352b5bb965cc98e67a27 Mon Sep 17 00:00:00 2001 From: davidvujic Date: Mon, 30 Jan 2017 13:18:07 +0100 Subject: [PATCH 36/40] fix: typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6199955b..5cca67d8 100644 --- a/README.md +++ b/README.md @@ -1252,7 +1252,7 @@ class Shape { } render(area) { - // .. + // ... } } From 69aac0446f7402bb331ef9843d1f0975cdb67a29 Mon Sep 17 00:00:00 2001 From: davidvujic Date: Wed, 1 Feb 2017 09:18:14 +0100 Subject: [PATCH 37/40] getters and setters as functions, also without the get/set keywords --- README.md | 59 ++++++++++++++++++++++++------------------------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 5cca67d8..f8a58b56 100644 --- a/README.md +++ b/README.md @@ -927,9 +927,7 @@ inventoryTracker('apples', req, 'www.inventory-awesome.io'); ## **Objects and Data Structures** ### Use getters and setters -JavaScript doesn't have interfaces or types so it is very hard to enforce this -pattern, because we don't have keywords like `public` and `private`. As it is, -using getters and setters to access data on objects is far better than simply +Using getters and setters to access data on objects could be better than simply looking for a property on an object. "Why?" you might ask. Well, here's an unorganized list of reasons why: @@ -938,56 +936,51 @@ to look up and change every accessor in your codebase. * Makes adding validation simple when doing a `set`. * Encapsulates the internal representation. * Easy to add logging and error handling when getting and setting. -* Inheriting this class, you can override default functionality. * You can lazy load your object's properties, let's say getting it from a server. **Bad:** ```javascript -class BankAccount { - constructor() { - this.balance = 1000; - } -} +function makeBankAccount() { + // ... -const bankAccount = new BankAccount(); + return { + balance: 0, + // ... + }; +} -// Buy shoes... -bankAccount.balance -= 100; +const account = makeBankAccount(); +account.balance = 100; ``` **Good:** ```javascript -class BankAccount { - constructor(balance = 1000) { - this._balance = balance; - } +function makeBankAccount() { + // this one is private + let balance = 0; - // It doesn't have to be prefixed with `get` or `set` to be a getter/setter - set balance(amount) { - if (this.verifyIfAmountCanBeSetted(amount)) { - this._balance = amount; - } + // a "getter", made public via the returned object below + function getBalance() { + return balance; } - get balance() { - return this._balance; + // a "setter", made public via the returned object below + function setBalance(amount) { + // ... validate before updating the balance + balance = amount; } - verifyIfAmountCanBeSetted(val) { + return { // ... - } + getBalance, + setBalance, + }; } -const bankAccount = new BankAccount(); - -// Buy shoes... -bankAccount.balance -= shoesPrice; - -// Get balance -let balance = bankAccount.balance; - +const account = makeBankAccount(); +account.setBalance(100); ``` **[⬆ back to top](#table-of-contents)** From 60a5a14891328c169154883cb074f0c01093dd3b Mon Sep 17 00:00:00 2001 From: hienvd Date: Sat, 4 Feb 2017 12:50:34 +0700 Subject: [PATCH 38/40] Add vietnamese translation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f8a58b56..3fcc2403 100644 --- a/README.md +++ b/README.md @@ -2156,6 +2156,6 @@ This is also available in other languages: - ![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) - ![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/) - + - ![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/) **[⬆ back to top](#table-of-contents)** From 0358273e70ef5780d9d1ce9bf92f25872a100815 Mon Sep 17 00:00:00 2001 From: Roman Ponomarev Date: Sat, 4 Feb 2017 12:11:15 +0300 Subject: [PATCH 39/40] Adds second and actual russian translation --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f8a58b56..74d8d251 100644 --- a/README.md +++ b/README.md @@ -2155,7 +2155,8 @@ This is also available in other languages: - ![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) - ![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) - - ![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/) - + - ![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) **[⬆ back to top](#table-of-contents)** From a59d78b42c2bf67f497655c2c5b988921680579d Mon Sep 17 00:00:00 2001 From: Roman Ponomarev Date: Sat, 4 Feb 2017 12:29:18 +0300 Subject: [PATCH 40/40] Fixes some typo issues --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f8a58b56..429a444b 100644 --- a/README.md +++ b/README.md @@ -216,7 +216,7 @@ Since JavaScript allows you to make objects on the fly, without a lot of class boilerplate, you can use an object if you are finding yourself needing a lot of arguments. -To make it obvious what properties the function expects, you can use the es6 +To make it obvious what properties the function expects, you can use the ES2015/ES6 destructuring syntax. This has a few advantages: 1. When someone looks at the function signature, it's immediately clear what @@ -578,7 +578,7 @@ console.log(newName); // ['Ryan', 'McDermott']; ### Avoid Side Effects (part 2) In JavaScript, primitives are passed by value and objects/arrays are passed by -reference. In the case of objects and arrays, if our function makes a change +reference. In the case of objects and arrays, if your function makes a change in a shopping cart array, for example, by adding an item to purchase, then any other function that uses that `cart` array will be affected by this addition. That may be great, however it can be bad too. Let's imagine a bad @@ -1456,7 +1456,7 @@ inventoryTracker.requestItems(); ### 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 classes. However, prefer small functions over +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:**