DEV Community

Cover image for Understanding Clean Code: Emergence ⚡️
Ali Samir
Ali Samir

Posted on

Understanding Clean Code: Emergence ⚡️

Chapter 12 of Clean Code, titled "Emergence," explores how clean, well-structured software emerges from adherence to fundamental design principles.

Emergence in software design refers to the process through which complex behavior or functionality arises from simple, well-understood rules.

Following these rules can help developers craft software that is easy to maintain, extend, and understand.


This chapter focuses on the Four Rules of Simple Design, emphasizing simplicity and testability for clean and efficient code.


📌 The Four Rules of Simple Design

  • Passes all tests
  • Reveals intention
  • No duplication
  • Minimizes the number of classes and methods

Let's break each of these rules down and see how they apply using JavaScript.


1. Passes All Tests

The foundation of clean, emergent software is that it must be functional.

All code should pass its tests, ensuring the expected behavior is preserved and new functionality doesn't introduce bugs.

In JavaScript, this is often achieved through writing unit tests with libraries like Jest or Mocha.

function add(a, b) {
  return a + b;
}

// Test (using Jest)
test('adds 1 + 2 to equal 3', () => {
  expect(add(1, 2)).toBe(3);
});
Enter fullscreen mode Exit fullscreen mode

By ensuring that the software passes all tests, you’re guaranteeing that the system works as intended.

Clean code begins with reliable tests. Without this, none of the other rules matter.


2. Reveals Intention

The code should communicate what it does. Well-named functions, variables, and classes can make your code easy to read and understand without needing comments.

Code that reveals its intention is self-explanatory.

Bad Naming:

function d(x) {
  return x * 2;
}
Enter fullscreen mode Exit fullscreen mode

Good Naming:

function doubleNumber(number) {
  return number * 2;
}
Enter fullscreen mode Exit fullscreen mode

In this case, doubleNumber() clearly reveals the intention of the function.

Anyone reading this code can immediately understand its purpose without additional explanations.

This practice not only reduces confusion but also improves maintainability.


3. No Duplication

Duplication in code is one of the biggest enemies of clean software. Repeated logic can lead to bugs and increased maintenance effort.

The goal is to reduce redundancy by abstracting common behaviors into reusable functions or modules.

Code Duplication:

function calculateAreaOfSquare(side) {
  return side * side;
}

function calculateAreaOfRectangle(length, width) {
  return length * width;
}
Enter fullscreen mode Exit fullscreen mode

Both functions are doing similar calculations. By refactoring, we can eliminate duplication.

No Duplication:

function calculateArea(shape) {
  if (shape.type === 'square') {
    return shape.side * shape.side;
  } else if (shape.type === 'rectangle') {
    return shape.length * shape.width;
  }
}
Enter fullscreen mode Exit fullscreen mode

By generalizing the function, we eliminate the repeated logic and make the code more maintainable.


4. Minimizes the Number of Classes and Methods

The last rule of simple design encourages minimizing the number of classes and methods without sacrificing clarity.

This means avoiding unnecessary complexity.

Each class or function should have a clear and focused responsibility, adhering to the Single Responsibility Principle (SRP).

Too Many Methods:

class User {
  constructor(name) {
    this.name = name;
  }

  getName() {
    return this.name;
  }

  setName(name) {
    this.name = name;
  }

  printWelcomeMessage() {
    console.log(`Welcome, ${this.name}!`);
  }

  // Additional unrelated methods
  getUserProfile() {
    // ... some logic
  }

  logActivity() {
    // ... some logic
  }
}
Enter fullscreen mode Exit fullscreen mode

This class has too many responsibilities. It should focus only on managing the user’s name.

Refactored:

class User {
  constructor(name) {
    this.name = name;
  }

  getName() {
    return this.name;
  }

  setName(name) {
    this.name = name;
  }
}

class Logger {
  static logActivity(user) {
    // ... some logic
    console.log(`${user.getName()} performed an activity.`);
  }
}
Enter fullscreen mode Exit fullscreen mode

By separating concerns, the code becomes simpler and easier to maintain.

Now, each class has a single responsibility, adhering to the principles of minimalism and simplicity.


Conclusion

The four rules of simple design—passing all tests, revealing intention, eliminating duplication, and minimizing the number of classes and methods—guide the creation of clean, maintainable, and emergent code.

By following these principles, complexity is kept in check, and your code becomes more adaptable to change.

Happy Coding!

Top comments (0)