Skip to main content

Understanding Anti-Patterns in JavaScript

Anti-Patterns: Understanding Anti-Patterns



What exactly is an anti-pattern in application development?

View Answer:
Interview Response: An anti-pattern is an imperfect solution to a particular problem that results in an unintended result. To summarize, an anti-pattern is a lousy design worthy of documenting.

Can you define what an anti-pattern is in JavaScript?

View Answer:
Interview Response: An anti-pattern is a coding practice that is considered bad or ineffective in terms of design, performance, or maintenance. It is a common mistake that developers make when coding.

Technical Response: Nine Anti-Patterns you should know.

  1. Excessive variable definition in a global context pollutes the global namespace.

  2. Passing strings rather than functions to setTimeout or setInterval causes the internal usage of eval().

  3. Playing with native methods in the Object class prototype (this is a particularly bad anti-pattern).

  4. Using JavaScript inline because it is inflexible.

  5. The usage of document.write when native DOM alternatives, such as document.createElement, are preferable. Over the years, developers have misused document.write. Drawbacks include that it can overwrite the page we're on after the page loads, whereas document.createElement does not. It also doesn't work with XHTML, so using more DOM-friendly techniques like document.createElement is preferable.

  6. Incorrect Use of True and False Evaluation

  7. Naming Customs (Ninja Code)

  8. Changing the DOM in a loop

  9. New Array.prototype.reduce Object



What's the 'God Object' anti-pattern?

View Answer:
Interview Response: The 'God Object' anti-pattern refers to an object that knows too much or does too much, violating the principle of single responsibility and making code hard to maintain, understand, or extend.

Code Example:

Here's an example of a 'God Object' anti-pattern in JavaScript. This App object does too many things:

class App {
constructor(user) {
this.user = user;
this.db = new Database();
}

login() {
// login logic
}

logout() {
// logout logic
}

fetchUserFromDatabase() {
// database interaction logic
}

calculateUserStatistics() {
// complex calculations
}

renderUserProfile() {
// UI rendering logic
}

sendEmail() {
// Email sending logic
}

//... and so on for other methods
}

In this example, the App object is responsible for authentication, data retrieval, user statistics calculation, UI rendering, email sending, etc., which violates the Single Responsibility Principle (SRP) and makes the App object a 'God Object'.


How does the 'Spaghetti Code' anti-pattern manifest in JavaScript?

View Answer:
Interview Response: 'Spaghetti Code' in JavaScript is code without a clear structure, often resulting from neglecting function modularity, mixing logic and UI, and lacking documentation, making it difficult to understand and maintain.

Code Example:

Here is a JavaScript example that exhibits the 'Spaghetti Code' anti-pattern:

var globalData = [];

function fetchData() {
// Fetches data and populates globalData
}

function process() {
fetchData();
for (var i = 0; i < globalData.length; i++) {
if (globalData[i] > 10) {
for (var j = 0; j < globalData.length; j++) {
if (globalData[j] < 20) {
// More nested conditionals, loops and so on...
}
}
}
}
}

process();

This code is a bad practice because it relies on a global variable, has no clear structure, and features complex nesting making it hard to read, understand, and maintain. The functions fetchData and process are tightly coupled, and changes to one might unexpectedly impact the other.


What's the 'Callback Hell' anti-pattern?

View Answer:
Interview Response: 'Callback Hell' is a JavaScript anti-pattern where multiple nested callbacks make code hard to read and debug. It typically happens with asynchronous JavaScript operations and can lead to unmanageable code.

Code Example:

Sure, here's an example of the 'Callback Hell' anti-pattern in JavaScript:

function fetchData(callback) {
// Fetch data
callback(data);
}

function processData(data, callback) {
// Process data
callback(result);
}

function renderData(result, callback) {
// Render data
callback();
}

fetchData(function(data) {
processData(data, function(result) {
renderData(result, function() {
console.log('Done!');
});
});
});

In this code, callbacks are nested within callbacks, leading to a structure that's hard to read and maintain. This is often colloquially referred to as "pyramid of doom" due to the indentations forming a pyramid-like structure.


Can you explain the 'Global Variables' anti-pattern?

View Answer:
Interview Response: The 'Global Variables' anti-pattern in JavaScript involves extensive use of global variables, leading to potential naming conflicts, difficulty in debugging, and unexpected side effects, thereby compromising code maintainability and reliability.

Code Example:

Here's an example of the 'Global Variables' anti-pattern in JavaScript:

var globalVar1 = 'Hello, world!';
var globalVar2 = [1, 2, 3, 4, 5];
var globalVar3 = {foo: 'bar'};

function doSomething() {
globalVar1 = 'Changed';
// Other manipulations using global variables
}

function doSomethingElse() {
globalVar2.push(6);
// Other manipulations using global variables
}

doSomething();
doSomethingElse();

console.log(globalVar1); // Output: 'Changed'
console.log(globalVar2); // Output: [1, 2, 3, 4, 5, 6]

In this example, globalVar1, globalVar2, and globalVar3 are global variables. They can be accessed and modified from anywhere in the code, making it difficult to manage their state and leading to potential bugs and confusion. The functions doSomething and doSomethingElse both manipulate the global variables, so it's hard to understand and predict the effects of these functions without knowing what they do internally.


What's the 'Copy and Paste Programming' anti-pattern?

View Answer:
Interview Response: 'Copy and Paste Programming' anti-pattern refers to duplicating code instead of reusing or abstracting it, leading to larger codebase, redundancy, and increased maintenance difficulties due to duplicated bugs and changes.

Code Example:

Here's an example of the 'Copy and Paste Programming' anti-pattern in JavaScript:

function calculateAreaSquare(side) {
return side * side; // Logic for square area
}

function calculateAreaRectangle(length, breadth) {
return length * breadth; // Duplicate logic for rectangle area
}

console.log(calculateAreaSquare(5)); // Output: 25
console.log(calculateAreaRectangle(5, 5)); // Output: 25

In this example, the multiplication logic to calculate the area is duplicated in the functions calculateAreaSquare and calculateAreaRectangle. This is a simple case, but imagine if the logic was complex and repeated in multiple places, making the code harder to maintain and prone to errors. A more efficient approach would be to create a reusable function.

Code Solution:

Here is a better solution using a reusable function to avoid the 'Copy and Paste Programming' anti-pattern:

function calculateArea(length, breadth = length) {
return length * breadth;
}

console.log(calculateArea(5)); // Output: 25 (square)
console.log(calculateArea(5, 5)); // Output: 25 (rectangle)

In this improved version, the function calculateArea is made more generic to calculate the area of both a square and a rectangle. By setting breadth = length as a default parameter, the function can handle both cases, eliminating the need for duplicated logic. This makes the code easier to maintain, reduces the risk of errors, and promotes reusability.


Can you tell me about the 'Magic Numbers' anti-pattern?

View Answer:
Interview Response: The 'Magic Numbers' anti-pattern involves using numbers directly in code without explanation or context, making it harder to understand, maintain, and change. Such numbers should be replaced with named constants.

Code Example:

Here's an example of the 'Magic Numbers' anti-pattern and its solution in JavaScript:

Magic Numbers Anti-pattern:

function calculateArea(radius) {
return 3.14159 * radius * radius; // What does 3.14159 represent?
}
console.log(calculateArea(5)); // Output: 78.53975

Solution:

const PI = 3.14159;  // Define a named constant for the magic number

function calculateArea(radius) {
return PI * radius * radius; // Much clearer!
}

console.log(calculateArea(5)); // Output: 78.53975

In the first example, it's not immediately clear what 3.14159 represents. This is an example of a 'magic number'. The improved code replaces this magic number with a named constant PI, making it much clearer what this number represents and why it's being used. The named constant is also easier to maintain and change if necessary.


How does the 'Monkey Patching' anti-pattern affect code quality?

View Answer:
Interview Response: 'Monkey Patching' is an anti-pattern where built-in classes are modified at runtime, potentially introducing inconsistent behavior, making debugging difficult, and causing incompatibility issues with other parts of the code or libraries.

Code Example:

Monkey Patching Anti-pattern:

// Modifying the built-in Array prototype
Array.prototype.first = function() {
return this[0];
}

var myArray = [1, 2, 3];
console.log(myArray.first()); // Output: 1

Solution:

// Define a function that accepts an array instead
function getFirst(array) {
return array[0];
}

var myArray = [1, 2, 3];
console.log(getFirst(myArray)); // Output: 1

In the first example, the built-in Array prototype is modified to add a first method. This can cause unexpected behavior if other parts of your code or libraries also attempt to modify Array, and can make debugging difficult.

The improved code defines a separate getFirst function that accepts an array as a parameter. This avoids modifying the Array prototype and any potential conflicts or issues that could arise from doing so.


Can you explain the 'Cargo Cult Programming' anti-pattern?

View Answer:
Interview Response: 'Cargo Cult Programming' is an anti-pattern where code or design patterns are used without understanding how they work, leading to ineffective and potentially harmful usage, often resulting in inefficient and unmaintainable code.