### Implementing DIP - Good Example (Dependency Injection) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example demonstrates adhering to the Dependency Inversion Principle by injecting the dependency (`requester`) into the `InventoryTracker` constructor, allowing for easy substitution of different request implementations and reducing coupling. ```javascript class InventoryTracker { constructor(items, requester) { this.items = items; this.requester = requester; } requestItems() { this.items.forEach(item => { this.requester.requestItem(item); }); } } class InventoryRequesterV1 { constructor() { this.REQ_METHODS = ["HTTP"]; } requestItem(item) { // ... } } class InventoryRequesterV2 { constructor() { this.REQ_METHODS = ["WS"]; } requestItem(item) { // ... } } // By constructing our dependencies externally and injecting them, we can easily // substitute our request module for a fancy new one that uses WebSockets. const inventoryTracker = new InventoryTracker( ["apples", "bananas"], new InventoryRequesterV2() ); inventoryTracker.requestItems(); ``` -------------------------------- ### Implementing DIP - Bad Example (Tight Coupling) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example demonstrates a violation of the Dependency Inversion Principle where the high-level module `InventoryTracker` directly depends on the concrete low-level module `InventoryRequester`, leading to tight coupling. ```javascript class InventoryRequester { constructor() { this.REQ_METHODS = ["HTTP"]; } requestItem(item) { // ... } } class InventoryTracker { constructor(items) { this.items = items; // BAD: We have created a dependency on a specific request implementation. // We should just have requestItems depend on a request method: `request` this.requester = new InventoryRequester(); } requestItems() { this.items.forEach(item => { this.requester.requestItem(item); }); } } const inventoryTracker = new InventoryTracker(["apples", "bananas"]); inventoryTracker.requestItems(); ``` -------------------------------- ### Testing - Good Example (Single Concept per Test) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example demonstrates the 'single concept per test' principle by separating assertions for different date boundary scenarios into individual `it` blocks, making each test focused, readable, and easier to maintain. ```javascript import assert from "assert"; describe("MomentJS", () => { it("handles 30-day months", () => { const date = new MomentJS("1/1/2015"); date.addDays(30); assert.equal("1/31/2015", date); }); it("handles leap year", () => { const date = new MomentJS("2/1/2016"); date.addDays(28); assert.equal("02/29/2016", date); }); it("handles non-leap year", () => { const date = new MomentJS("2/1/2015"); date.addDays(28); assert.equal("03/01/2015", date); }); }); ``` -------------------------------- ### Good Example: ES6 Class Inheritance Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example demonstrates class inheritance using the modern ES6 `class`, `extends`, and `super` keywords. This syntax is significantly more readable and concise than the older ES5 prototype-based approach for defining classes and inheritance hierarchies. ```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() { /* ... */ } } ``` -------------------------------- ### Setting Default Object Properties with Object.assign - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Illustrates a cleaner way to set default values for object properties. The bad example uses manual checks and assignments, which can be verbose. The good example uses Object.assign to merge a default configuration object with the provided configuration, resulting in more concise code. ```javascript const menuConfig = { title: null, body: "Bar", buttonText: null, cancellable: true }; function createMenu(config) { config.title = config.title || "Foo"; config.body = config.body || "Bar"; config.buttonText = config.buttonText || "Baz"; config.cancellable = config.cancellable !== undefined ? config.cancellable : true; } createMenu(menuConfig); ``` ```javascript const menuConfig = { title: "Order", // User did not include 'body' key buttonText: "Send", cancellable: true }; function createMenu(config) { let finalConfig = Object.assign( { title: "Foo", body: "Bar", buttonText: "Baz", cancellable: true }, config ); return finalConfig // config now equals: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true} // ... } createMenu(menuConfig); ``` -------------------------------- ### Remove dead code - Bad Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Shows an example of keeping unused functions (`oldRequestModule`) in the codebase, which adds clutter and makes the code harder to understand and maintain. ```javascript function oldRequestModule(url) { // ... } function newRequestModule(url) { // ... } const req = newRequestModule; inventoryTracker("apples", req, "www.inventory-awesome.io"); ``` -------------------------------- ### Bad Example: ES5 Class Inheritance Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This code illustrates the complex and verbose pattern required for classical inheritance in ES5 using constructor functions, `prototype`, `Object.create`, and `call`. It is difficult to read and maintain compared to modern syntax. ```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() {}; ``` -------------------------------- ### Using Callbacks for Asynchronous Operations (Bad) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example demonstrates using nested callbacks to handle asynchronous operations (an HTTP GET request followed by writing to a file). This pattern is discouraged due to excessive nesting, leading to 'callback hell', which makes code difficult to read and maintain. ```javascript import { get } from "request"; import { writeFile } from "fs"; 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"); } }); } } ); ``` -------------------------------- ### Bad Example: ES5 Public Members Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example demonstrates a common ES5 pattern for creating objects using constructor functions and prototypes. Properties assigned directly to `this` are public and can be easily modified or deleted from outside the object instance, breaking encapsulation. ```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 ``` -------------------------------- ### Bad Example: Using Positional Markers in JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This code snippet demonstrates the use of verbose positional marker comments (like //////////////////...) to delineate sections, which is considered unnecessary noise. ```javascript //////////////////////////////////////////////////////////////////////////////// // Scope Model Instantiation //////////////////////////////////////////////////////////////////////////////// $scope.model = { menu: "foo", nav: "bar" }; //////////////////////////////////////////////////////////////////////////////// // Action setup //////////////////////////////////////////////////////////////////////////////// const actions = function() { // ... }; ``` -------------------------------- ### Using Promises for Asynchronous Operations (Bad relative to Async/Await) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example, while better than callbacks, is presented as 'Bad' in the context of newer ES2017+ features. It shows the Promise-based approach using `.then()` chains, which can still be less intuitive than imperative-style async code provided by async/await. ```javascript import { get } from "request-promise"; import { writeFile } from "fs-extra"; 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); }); ``` -------------------------------- ### Good Example: ES5/ES6 Private Members with Closures Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example uses a factory function and a closure to create objects with private members. The `name` variable is enclosed within the `makeEmployee` function's scope and is only accessible to the `getName` method, preventing external modification or deletion. ```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 ``` -------------------------------- ### Handling Caught Errors in Try/Catch (Good) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example demonstrates better practices for handling errors caught in a `try...catch` block. Instead of just logging, it suggests more robust actions like using `console.error`, notifying the user, or reporting the error to a service, ensuring errors are addressed effectively. ```javascript try { functionThatMightThrow(); } catch (error) { // One option (more noisy than console.log): console.error(error); // Another option: notifyUserOfError(error); // Another option: reportErrorToService(error); // OR do all three! } ``` -------------------------------- ### Testing - Bad Example (Multiple Concepts per Test) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example shows a test case that violates the 'single concept per test' principle by including multiple assertions for different date boundary scenarios within a single `it` block, making the test less focused and harder to debug. ```javascript import assert from "assert"; describe("MomentJS", () => { it("handles date boundaries", () => { let date; date = new MomentJS("1/1/2015"); date.addDays(30); assert.equal("1/31/2015", date); date = new MomentJS("2/1/2016"); date.addDays(28); assert.equal("02/29/2016", date); date = new MomentJS("2/1/2015"); date.addDays(28); assert.equal("03/01/2015", date); }); }); ``` -------------------------------- ### Handling Rejected Promises in Catch (Good) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example illustrates better ways to handle rejected Promises in a `.catch()` block. It suggests actions beyond simple logging, such as using `console.error`, notifying the user, or reporting the error, ensuring that rejected Promises are handled with a clear strategy. ```javascript getdata() .then(data => { functionThatMightThrow(data); }) .catch(error => { // One option (more noisy than console.log): console.error(error); // Another option: notifyUserOfError(error); // Another option: reportErrorToService(error); // OR do all three! }); ``` -------------------------------- ### Good Example: ES6 Class With Method Chaining Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This class implements method chaining by returning `this` at the end of each setter method. This allows multiple method calls to be chained together on a single line, resulting in more expressive and less verbose code. ```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(); ``` -------------------------------- ### Removing Duplicate Code - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Demonstrates how to refactor similar functions into a single, more abstract function to avoid code duplication. The bad example shows two separate functions for different employee types, while the good example consolidates the logic into one function using a switch statement to handle type-specific details. ```javascript function showDeveloperList(developers) { developers.forEach(developer => { const expectedSalary = developer.calculateExpectedSalary(); const experience = developer.getExperience(); const githubLink = developer.getGithubLink(); const data = { expectedSalary, experience, githubLink }; render(data); }); } function showManagerList(managers) { managers.forEach(manager => { const expectedSalary = manager.calculateExpectedSalary(); const experience = manager.getExperience(); const portfolio = manager.getMBAProjects(); const data = { expectedSalary, experience, portfolio }; render(data); }); } ``` ```javascript function showEmployeeList(employees) { employees.forEach(employee => { const expectedSalary = employee.calculateExpectedSalary(); const experience = employee.getExperience(); const data = { expectedSalary, experience }; switch (employee.type) { case "manager": data.portfolio = employee.getMBAProjects(); break; case "developer": data.githubLink = employee.getGithubLink(); break; } render(data); }); } ``` -------------------------------- ### Avoiding Flag Parameters in Functions - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Explains why using boolean flags as function parameters is discouraged as it indicates the function does more than one thing. The bad example uses a flag to determine file creation path. The good example refactors this into two separate functions, each with a single responsibility. ```javascript function createFile(name, temp) { if (temp) { fs.create(`./temp/${name}`); } else { fs.create(name); } } ``` ```javascript function createFile(name) { fs.create(name); } function createTempFile(name) { createFile(`./temp/${name}`); } ``` -------------------------------- ### Don't over-optimize - Bad Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md An example of manual loop optimization (caching `list.length`) that was necessary in older JavaScript engines but is unnecessary in modern ones due to built-in optimizations, reducing readability. ```javascript // On old browsers, each iteration with uncached `list.length` would be costly // because of `list.length` recomputation. In modern browsers, this is optimized. for (let i = 0, len = list.length; i < len; i++) { // ... } ``` -------------------------------- ### Bad Example: ES6 Class Without Method Chaining Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This class defines setter methods that modify properties but do not return the instance (`this`). This requires calling each setter method on a new line, making the code less fluid and more verbose when setting multiple properties. ```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(); ``` -------------------------------- ### Adhering to ISP with Optional Nested Settings - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example demonstrates adherence to the Interface Segregation Principle. The DOMTraverser class accepts settings with optional properties nested within an 'options' object. This allows clients to provide only the settings they need, avoiding dependency on unused parts of the 'interface' (the settings object structure). ```javascript class DOMTraverser { constructor(settings) { this.settings = settings; this.options = settings.options; this.setup(); } setup() { this.rootNode = this.settings.rootNode; this.setupOptions(); } setupOptions() { if (this.options.animationModule) { // ... } } traverse() { // ... } } const $ = new DOMTraverser({ rootNode: document.getElementsByTagName("body"), options: { animationModule() {} } }); ``` -------------------------------- ### Using Promises for Asynchronous Operations (Good) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example refactors the previous callback-based code to use Promises. It chains asynchronous operations using `.then()` and handles errors with `.catch()`, resulting in flatter, more readable code compared to nested callbacks. It requires a library like `request-promise`. ```javascript import { get } from "request-promise"; import { writeFile } from "fs-extra"; 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); }); ``` -------------------------------- ### Using Async/Await for Asynchronous Operations (Good) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example demonstrates using ES2017+ async/await syntax for asynchronous operations. By declaring a function as `async`, you can use `await` to pause execution until a Promise resolves, allowing asynchronous code to be written in a more synchronous, imperative style, wrapped in a `try...catch` block for error handling. ```javascript import { get } from "request-promise"; import { writeFile } from "fs-extra"; 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() ``` -------------------------------- ### Good Example: Avoiding Positional Markers in JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This code snippet shows the same functionality without positional marker comments, relying on indentation, formatting, and variable/function names for structure, resulting in cleaner code. ```javascript $scope.model = { menu: "foo", nav: "bar" }; const actions = function() { // ... }; ``` -------------------------------- ### Function Abstraction - Single Level (Good) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Refactors the previous example by extracting lower-level operations (tokenizing, parsing) into separate functions. The main function now operates at a single, higher level of abstraction, calling the helper functions to perform the detailed steps. This improves readability, reusability, and testability. ```javascript function parseBetterJSAlternative(code) { const tokens = tokenize(code); const syntaxTree = parse(tokens); syntaxTree.forEach(node => { // parse... }); } function tokenize(code) { const REGEXES = [ // ... ]; const statements = code.split(" "); const tokens = []; REGEXES.forEach(REGEX => { statements.forEach(statement => { tokens.push(/* ... */); }); }); return tokens; } function parse(tokens) { const syntaxTree = []; tokens.forEach(token => { syntaxTree.push(/* ... */); }); return syntaxTree; } ``` -------------------------------- ### Function Single Responsibility - Separated Logic (Good) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Refactors the previous example into two functions: one to filter active clients and another (implicitly `email`) to handle the action. This adheres to the single responsibility principle, making each function focused, reusable, and easier to test. ```javascript function emailActiveClients(clients) { clients.filter(isActiveClient).forEach(email); } function isActiveClient(client) { const clientRecord = database.lookup(client); return clientRecord.isActive(); } ``` -------------------------------- ### Ignoring Caught Errors in Try/Catch (Bad) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example shows a `try...catch` block where the caught error is simply logged using `console.log`. This is considered 'Bad' practice because it doesn't provide a clear plan or code path for handling the error, potentially hiding issues or failing to react appropriately. ```javascript try { functionThatMightThrow(); } catch (error) { console.log(error); } ``` -------------------------------- ### Violating ISP with Fat Settings Object - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example demonstrates a violation of the Interface Segregation Principle. The DOMTraverser class requires a large settings object in its constructor, forcing clients to provide options like animationModule even when they are not needed for simple traversal, creating a 'fat interface'. ```javascript class DOMTraverser { constructor(settings) { this.settings = settings; this.setup(); } setup() { this.rootNode = this.settings.rootNode; this.settings.animationModule.setup(); } traverse() { // ... } } const $ = new DOMTraverser({ rootNode: document.getElementsByTagName("body"), animationModule() {} // Most of the time, we won't need to animate when traversing. // ... }); ``` -------------------------------- ### Ignoring Rejected Promises in Catch (Bad) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Similar to ignoring caught errors in `try/catch`, this example shows a Promise chain where the `.catch()` handler only logs the error using `console.log`. This is discouraged as it fails to properly handle or react to the rejected Promise, potentially masking failures. ```javascript getdata() .then(data => { functionThatMightThrow(data); }) .catch(error => { console.log(error); }); ``` -------------------------------- ### Adhering to LSP with Common Shape Base Class - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example demonstrates adherence to the Liskov Substitution Principle. Both Rectangle and Square inherit from a common Shape base class, each providing its own getArea implementation. This allows objects of type Rectangle and Square to be used interchangeably in the renderLargeShapes function without unexpected behavior. ```javascript class Shape { setColor(color) { // ... } render(area) { // ... } } class Rectangle extends Shape { constructor(width, height) { super(); this.width = width; this.height = height; } getArea() { return this.width * this.height; } } class Square extends Shape { constructor(length) { super(); this.length = length; } getArea() { return this.length * this.length; } } function renderLargeShapes(shapes) { shapes.forEach(shape => { const area = shape.getArea(); shape.render(area); }); } const shapes = [new Rectangle(4, 5), new Rectangle(4, 5), new Square(5)]; renderLargeShapes(shapes); ``` -------------------------------- ### Violating LSP with Rectangle/Square Inheritance - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This example demonstrates a violation of the Liskov Substitution Principle. A Square class inherits from Rectangle, but overriding setWidth and setHeight methods breaks the expected behavior when a Square object is substituted for a Rectangle object in the renderLargeRectangles function, leading to incorrect area calculation. ```javascript class Rectangle { constructor() { this.width = 0; this.height = 0; } setColor(color) { // ... } render(area) { // ... } setWidth(width) { this.width = width; } setHeight(height) { this.height = height; } getArea() { return this.width * this.height; } } class Square extends Rectangle { setWidth(width) { this.width = width; this.height = width; } setHeight(height) { this.width = height; this.height = height; } } function renderLargeRectangles(rectangles) { rectangles.forEach(rectangle => { rectangle.setWidth(4); rectangle.setHeight(5); const area = rectangle.getArea(); // BAD: Returns 25 for Square. Should be 20. rectangle.render(area); }); } const rectangles = [new Rectangle(), new Rectangle(), new Square()]; renderLargeRectangles(rectangles); ``` -------------------------------- ### Illustrating Good SRP - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Demonstrates adherence to SRP by separating authentication logic into a dedicated `UserAuth` class. The `UserSettings` class now only handles settings logic and uses composition to delegate authentication, reducing its reasons to change. ```javascript class UserAuth { constructor(user) { this.user = user; } verifyCredentials() { // ... } } class UserSettings { constructor(user) { this.user = user; this.auth = new UserAuth(user); } changeSettings(settings) { if (this.auth.verifyCredentials()) { // ... } } } ``` -------------------------------- ### Illustrating Good Composition - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Demonstrates the preferred approach using composition. The `Employee` class contains an instance of `EmployeeTaxData`, correctly modeling the "has-a" relationship and adhering to the principle. ```javascript class EmployeeTaxData { constructor(ssn, salary) { this.ssn = ssn; this.salary = salary; } // ... } class Employee { constructor(name, email) { this.name = name; this.email = email; } setTaxData(ssn, salary) { this.taxData = new EmployeeTaxData(ssn, salary); } // ... } ``` -------------------------------- ### Use getters and setters - Good Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Demonstrates using getter (`getBalance`) and setter (`setBalance`) functions to control access to the internal `balance` variable, allowing for encapsulation, validation, and easier addition of future logic. ```javascript function makeBankAccount() { // this one is private let balance = 0; // a "getter", made public via the returned object below function getBalance() { return balance; } // a "setter", made public via the returned object below function setBalance(amount) { // ... validate before updating the balance balance = amount; } return { // ... getBalance, setBalance }; } const account = makeBankAccount(); account.setBalance(100); ``` -------------------------------- ### Illustrating Good OCP - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Demonstrates adherence to OCP. Adapters implement a common `request` method. The `HttpRequester` delegates the request handling to the adapter instance, allowing new adapter types to be added without modifying the `HttpRequester` class itself. ```javascript class AjaxAdapter extends Adapter { constructor() { super(); this.name = "ajaxAdapter"; } request(url) { // request and return promise } } class NodeAdapter extends Adapter { constructor() { super(); this.name = "nodeAdapter"; } 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 }); } } ``` -------------------------------- ### Illustrating Bad SRP - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Shows a class `UserSettings` that violates the Single Responsibility Principle by handling both user settings logic (`changeSettings`) and user authentication logic (`verifyCredentials`). This gives the class multiple reasons to change. ```javascript class UserSettings { constructor(user) { this.user = user; } changeSettings(settings) { if (this.verifyCredentials()) { // ... } } verifyCredentials() { // ... } } ``` -------------------------------- ### Function Arguments - Using Object Destructuring (Good) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Demonstrates using object destructuring for function parameters when dealing with multiple arguments. This improves readability by making the expected properties explicit, simulates named parameters, and simplifies function calls. ```javascript function createMenu({ title, body, buttonText, cancellable }) { // ... } createMenu({ title: "Foo", body: "Bar", buttonText: "Baz", cancellable: true }); ``` -------------------------------- ### Use Consistent Vocabulary for Variables - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Maintain a consistent vocabulary across your codebase for the same type of variable or concept. Avoid using synonyms like 'userInfo', 'clientData', and 'customerRecord' if they all refer to the same underlying entity; pick one term and stick with it. ```javascript getUserInfo(); getClientData(); getCustomerRecord(); ``` ```javascript getUser(); ``` -------------------------------- ### Remove dead code - Good Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Demonstrates removing the unused function (`oldRequestModule`) to keep the codebase clean and focused, relying on version control for historical access if needed. ```javascript function newRequestModule(url) { // ... } const req = newRequestModule; inventoryTracker("apples", req, "www.inventory-awesome.io"); ``` -------------------------------- ### Use getters and setters - Bad Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Shows direct public access to an object's internal property (`balance`), which makes it difficult to add logic like validation, logging, or lazy loading later without modifying all access points. ```javascript function makeBankAccount() { // ... return { balance: 0 // ... }; } const account = makeBankAccount(); account.balance = 100; ``` -------------------------------- ### Using Default Parameters in JavaScript (Good) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Shows the preferred method of using ES6 default parameters (`=`) to provide a default value. This is cleaner and correctly applies the default only when the argument is strictly `undefined`. ```javascript function createMicrobrewery(name = "Hipster Brew Co.") { // ... } ``` -------------------------------- ### Using Default Parameters in JavaScript (Bad) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Demonstrates using the logical OR operator (`||`) to provide a default value for a function parameter. This approach has the drawback of treating all falsy values (like `0`, `false`, `""`, `null`) as if they were `undefined`, replacing them with the default. ```javascript function createMicrobrewery(name) { const breweryName = name || "Hipster Brew Co."; // ... } ``` -------------------------------- ### Returning New Array (Good) - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This snippet demonstrates a good practice for handling mutable data like arrays. Instead of modifying the original array parameter, the function uses the spread syntax (`...`) to create and return a *new* array that includes the original items plus the new item. This avoids side effects and preserves the integrity of the original data. ```javascript const addItemToCart = (cart, item) => { return [...cart, { item, date: Date.now() }]; }; ``` -------------------------------- ### Function Naming - Descriptive Name (Good) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Shows a function with a descriptive name (`addMonthToDate`) that clearly indicates its action and the unit being added. This improves code readability and makes the function's purpose immediately obvious without needing to read its body. ```javascript function addMonthToDate(month, date) { // ... } const date = new Date(); addMonthToDate(1, date); ``` -------------------------------- ### Avoid type-checking (part 2) - Good Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Shows the simpler approach without explicit type-checking, relying on JavaScript's dynamic typing. For static type safety, TypeScript is recommended as a better alternative to manual checks. ```javascript function combine(val1, val2) { return val1 + val2; } ``` -------------------------------- ### Avoid type-checking (part 1) - Bad Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Demonstrates type-checking based on `instanceof`, which is considered bad practice as it couples the function to specific implementations rather than interfaces or common methods. ```javascript function travelToTexas(vehicle) { if (vehicle instanceof Bicycle) { vehicle.pedal(this.currentLocation, new Location("texas")); } else if (vehicle instanceof Car) { vehicle.drive(this.currentLocation, new Location("texas")); } } ``` -------------------------------- ### Illustrating Bad OCP - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Shows a `HttpRequester` class that violates the Open/Closed Principle. Adding a new adapter type would require modifying the `fetch` method with another `else if` block, making the class closed for extension without modification. ```javascript class AjaxAdapter extends Adapter { constructor() { super(); this.name = "ajaxAdapter"; } } 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 === "nodeAdapter") { return makeHttpCall(url).then(response => { // transform response and return }); } } } function makeAjaxCall(url) { // request and return promise } function makeHttpCall(url) { // request and return promise } ``` -------------------------------- ### Avoid type-checking (part 2) - Bad Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Illustrates manual type-checking for primitive types (`number`, `string`) before performing an operation, which adds complexity and reduces readability compared to relying on JavaScript's dynamic typing or using TypeScript. ```javascript 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"); } ``` -------------------------------- ### Use Meaningful Variable Names - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Choose variable names that clearly indicate their purpose and content, avoiding cryptic abbreviations. This improves code readability and makes it easier for others (and your future self) to understand the code's intent without needing extra comments or context. ```javascript const yyyymmdstr = moment().format("YYYY/MM/DD"); ``` ```javascript const currentDate = moment().format("YYYY/MM/DD"); ``` -------------------------------- ### Enforcing Consistent Capitalization in JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Illustrates the importance of using consistent capitalization conventions for variables, constants, arrays, functions, and classes in JavaScript to improve code readability and convey meaning, especially in an untyped language. ```javascript const DAYS_IN_WEEK = 7; const daysInMonth = 30; const songs = ["Back In Black", "Stairway to Heaven", "Hey Jude"]; const Artists = ["ACDC", "Led Zeppelin", "The Beatles"]; function eraseDatabase() {} function restore_database() {} class animal {} class Alpaca {} ``` ```javascript const DAYS_IN_WEEK = 7; const DAYS_IN_MONTH = 30; const SONGS = ["Back In Black", "Stairway to Heaven", "Hey Jude"]; const ARTISTS = ["ACDC", "Led Zeppelin", "The Beatles"]; function eraseDatabase() {} function restoreDatabase() {} class Animal {} class Alpaca {} ``` -------------------------------- ### Conditional Logic via Polymorphism (Good Practice) - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This snippet demonstrates using polymorphism to handle type-specific behavior. Instead of a single method with a `switch`, different subclasses override a common method (`getCruisingAltitude`), each providing its specific implementation. This adheres to the 'one thing' principle and makes the code more extensible. ```javascript class Airplane { // ... } class Boeing777 extends Airplane { // ... getCruisingAltitude() { return this.getMaxAltitude() - this.getPassengerCount(); } } class AirForceOne extends Airplane { // ... getCruisingAltitude() { return this.getMaxAltitude(); } } class Cessna extends Airplane { // ... getCruisingAltitude() { return this.getMaxAltitude() - this.getFuelExpenditure(); } } ``` -------------------------------- ### Avoid type-checking (part 1) - Good Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Shows a better approach using polymorphism, where the `vehicle` object handles the movement logic internally via a common method (`move`), decoupling the function from specific vehicle types. ```javascript function travelToTexas(vehicle) { vehicle.move(this.currentLocation, new Location("texas")); } ``` -------------------------------- ### Don't over-optimize - Good Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md The standard, more readable loop syntax that relies on modern JavaScript engine optimizations, avoiding premature and often ineffective manual optimization. ```javascript for (let i = 0; i < list.length; i++) { // ... } ``` -------------------------------- ### Function Arguments - Too Many Parameters (Bad) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Illustrates a function with too many positional arguments. This makes the function signature hard to read, difficult to remember the order of parameters, and challenging to test due to the combinatorial explosion of possible argument combinations. ```javascript function createMenu(title, body, buttonText, cancellable) { // ... } createMenu("Foo", "Bar", "Baz", true); ``` -------------------------------- ### Pure Function (Good) - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This snippet shows a good practice where a function takes an input parameter and returns a new value derived from the input without modifying any external state or the input itself. This makes the function pure, predictable, and easier to test. ```javascript function splitIntoFirstAndLastName(name) { return name.split(" "); } const name = "Ryan McDermott"; const newName = splitIntoFirstAndLastName(name); console.log(name); // 'Ryan McDermott'; console.log(newName); // ['Ryan', 'McDermott']; ``` -------------------------------- ### Illustrating Bad Inheritance - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Demonstrates an incorrect use of inheritance where a "has-a" relationship (Employee has TaxData) is modeled as an "is-a" relationship (EmployeeTaxData is an Employee). This violates the principle of preferring composition for such relationships. ```javascript class Employee { constructor(name, email) { this.name = name; this.email = email; } // ... } // Bad because Employees "have" tax data. EmployeeTaxData is not a type of Employee class EmployeeTaxData extends Employee { constructor(ssn, salary) { super(); this.ssn = ssn; this.salary = salary; } // ... } ``` -------------------------------- ### Using Positive Conditionals (Good Practice) - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This snippet uses a function with a positive name (`isDOMNodePresent`) and uses its result directly in the `if` statement. This makes the condition straightforward and easy to understand. ```javascript function isDOMNodePresent(node) { // ... } if (isDOMNodePresent(node)) { // ... } ``` -------------------------------- ### Structuring Functions by Caller/Callee Proximity in JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Demonstrates organizing functions within a class or module so that functions calling others are placed vertically close, ideally above the functions they call, to improve readability and follow a top-down reading flow. ```javascript class PerformanceReview { constructor(employee) { this.employee = employee; } lookupPeers() { return db.lookup(this.employee, "peers"); } lookupManager() { return db.lookup(this.employee, "manager"); } getPeerReviews() { const peers = this.lookupPeers(); // ... } perfReview() { this.getPeerReviews(); this.getManagerReview(); this.getSelfReview(); } getManagerReview() { const manager = this.lookupManager(); } getSelfReview() { // ... } } const review = new PerformanceReview(employee); review.perfReview(); ``` ```javascript class PerformanceReview { constructor(employee) { this.employee = employee; } perfReview() { this.getPeerReviews(); this.getManagerReview(); this.getSelfReview(); } getPeerReviews() { const peers = this.lookupPeers(); // ... } lookupPeers() { return db.lookup(this.employee, "peers"); } getManagerReview() { const manager = this.lookupManager(); } lookupManager() { return db.lookup(this.employee, "manager"); } getSelfReview() { // ... } } const review = new PerformanceReview(employee); review.perfReview(); ``` -------------------------------- ### Function Abstraction - Multiple Levels (Bad) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Illustrates a function that operates at multiple levels of abstraction, handling high-level parsing logic alongside low-level details like splitting strings, iterating through regexes, and tokenizing/parsing steps within the same function body. ```javascript function parseBetterJSAlternative(code) { const REGEXES = [ // ... ]; const statements = code.split(" "); const tokens = []; REGEXES.forEach(REGEX => { statements.forEach(statement => { // ... }); }); const ast = []; tokens.forEach(token => { // lex... }); ast.forEach(node => { // parse... }); } ``` -------------------------------- ### Function Naming - Ambiguous Name (Bad) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Presents a function with an ambiguous name (`addToDate`) that doesn't clearly state what is being added (e.g., days, months, years). This forces the reader to inspect the function's implementation or documentation to understand its purpose. ```javascript function addToDate(date, month) { // ... } const date = new Date(); // It's hard to tell from the function name what is added addToDate(date, 1); ``` -------------------------------- ### Encapsulating Conditional Logic (Good Practice) - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This snippet demonstrates encapsulating conditional logic within a well-named function. This improves readability by abstracting the condition behind a descriptive function name, making the `if` statement's purpose immediately clear. ```javascript function shouldShowSpinner(fsm, listNode) { return fsm.state === "fetching" && isEmpty(listNode); } if (shouldShowSpinner(fsmInstance, listNodeInstance)) { // ... } ``` -------------------------------- ### Calculating Sum Functionally (Good Practice) - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This snippet calculates the total lines of code using the functional `Array.prototype.reduce` method. This approach is more concise, declarative, and idiomatic in functional programming styles, making the intent clearer. ```javascript const programmerOutput = [ { name: "Uncle Bobby", linesOfCode: 500 }, { name: "Suzie Q", linesOfCode: 1500 }, { name: "Jimmy Gosling", linesOfCode: 150 }, { name: "Gracie Hopper", linesOfCode: 1000 } ]; const totalOutput = programmerOutput.reduce( (totalLines, output) => totalLines + output.linesOfCode, 0 ); ``` -------------------------------- ### Avoid Mental Mapping with Variable Names - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Do not use single-letter or obscure variable names that require the reader to mentally map them to the concept they represent. Use descriptive names that immediately convey the variable's purpose, reducing cognitive load and improving understanding. ```javascript const locations = ["Austin", "New York", "San Francisco"]; locations.forEach(l => { doStuff(); doSomeOtherStuff(); // ... // ... // ... // Wait, what is `l` for again? dispatch(l); }); ``` ```javascript const locations = ["Austin", "New York", "San Francisco"]; locations.forEach(location => { doStuff(); doSomeOtherStuff(); // ... // ... // ... dispatch(location); }); ``` -------------------------------- ### Use Searchable Names for Constants - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Replace 'magic numbers' or hardcoded values with named constants. This makes the code's intent clearer and allows for easy searching and modification of the value throughout the project. Tools can help identify unnamed constants. ```javascript // What the heck is 86400000 for? setTimeout(blastOff, 86400000); ``` ```javascript // Declare them as capitalized named constants. const MILLISECONDS_PER_DAY = 60 * 60 * 24 * 1000; //86400000; setTimeout(blastOff, MILLISECONDS_PER_DAY); ``` -------------------------------- ### Calculating Sum Imperatively (Bad Practice) - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This snippet calculates the total lines of code using a traditional imperative `for` loop. While functional, this approach is more verbose and less declarative compared to functional programming alternatives like `reduce`. ```javascript const programmerOutput = [ { name: "Uncle Bobby", linesOfCode: 500 }, { name: "Suzie Q", linesOfCode: 1500 }, { name: "Jimmy Gosling", linesOfCode: 150 }, { name: "Gracie Hopper", linesOfCode: 1000 } ]; let totalOutput = 0; for (let i = 0; i < programmerOutput.length; i++) { totalOutput += programmerOutput[i].linesOfCode; } ``` -------------------------------- ### Commenting Only Complex Business Logic in JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Advocates for using comments sparingly, primarily to explain complex business logic or non-obvious code, rather than describing simple operations that are clear from the code itself, promoting self-documenting code. ```javascript function hashIt(data) { // The hash let hash = 0; // Length of string const length = data.length; // Loop through every character in data for (let i = 0; i < length; i++) { // Get character code. const char = data.charCodeAt(i); // Make the hash hash = (hash << 5) - hash + char; // Convert to 32-bit integer hash &= hash; } } ``` ```javascript function hashIt(data) { let hash = 0; const length = data.length; for (let i = 0; i < length; i++) { const char = data.charCodeAt(i); hash = (hash << 5) - hash + char; // Convert to 32-bit integer hash &= hash; } } ``` -------------------------------- ### Avoiding Journal Comments in JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Discourages the use of journal-style comments that track code changes, authors, and dates within the code file itself, recommending the use of version control commit history (`git log`) for tracking changes instead. ```javascript /** * 2016-12-20: Removed monads, didn't understand them (RM) * 2016-10-01: Improved using special monads (JP) * 2016-02-03: Removed type-checking (LI) * 2015-03-14: Added combine with type-checking (JR) */ function combine(a, b) { return a + b; } ``` ```javascript function combine(a, b) { return a + b; } ``` -------------------------------- ### Function Single Responsibility - Combined Logic (Bad) Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Shows a function that performs multiple tasks (looking up client records, checking if active, and emailing) within a single loop. This violates the single responsibility principle, making the function harder to understand, test, and reuse. ```javascript function emailClients(clients) { clients.forEach(client => { const clientRecord = database.lookup(client); if (clientRecord.isActive()) { email(client); } }); } ``` -------------------------------- ### Extending Array Prototype (Bad Practice) - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This snippet demonstrates a bad practice of extending native JavaScript prototypes directly. Modifying `Array.prototype` can lead to conflicts with other libraries that might extend the same prototype with different implementations, causing unexpected behavior or errors. ```javascript Array.prototype.diff = function diff(comparisonArray) { const hash = new Set(comparisonArray); return this.filter(elem => !hash.has(elem)); }; ``` -------------------------------- ### Extending Array with Class (Good Practice) - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This snippet shows a better approach to adding custom functionality to array-like objects by using ES6 classes to extend the native `Array`. This avoids polluting the global `Array.prototype` and encapsulates the custom method within a specific class, reducing the risk of conflicts. ```javascript class SuperArray extends Array { diff(comparisonArray) { const hash = new Set(comparisonArray); return this.filter(elem => !hash.has(elem)); } } ``` -------------------------------- ### Using Negative Conditionals (Bad Practice) - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This snippet uses a function with a negative name (`isDOMNodeNotPresent`) and then negates its result in an `if` statement. Double negatives can be confusing and harder to parse mentally. ```javascript function isDOMNodeNotPresent(node) { // ... } if (!isDOMNodeNotPresent(node)) { // ... } ``` -------------------------------- ### Removing Commented-Out Code in JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md Emphasizes the practice of deleting commented-out code from the codebase, relying on version control history (like Git) to retrieve previous versions if needed, keeping the current code clean and free of clutter. ```javascript doStuff(); // doOtherStuff(); // doSomeMoreStuff(); // doSoMuchStuff(); ``` ```javascript doStuff(); ``` -------------------------------- ### Avoid Redundant Context in Variable Names - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md If the context of a variable is already clear from its surrounding object or class, do not repeat that context in the variable name itself. This keeps names concise and avoids unnecessary repetition, improving readability. ```javascript const Car = { carMake: "Honda", carModel: "Accord", carColor: "Blue" }; function paintCar(car, color) { car.carColor = color; } ``` ```javascript const Car = { make: "Honda", model: "Accord", color: "Blue" }; function paintCar(car, color) { car.color = color; } ``` -------------------------------- ### Inline Conditional Logic (Bad Practice) - JavaScript Source: https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md This snippet shows conditional logic used directly within an `if` statement. While functional, complex inline conditions can reduce readability and make it harder to understand the specific scenario being checked. ```javascript if (fsm.state === "fetching" && isEmpty(listNode)) { // ... } ```