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);
});
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;
}
Good Naming:
function doubleNumber(number) {
return number * 2;
}
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;
}
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;
}
}
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
}
}
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.`);
}
}
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)