Summary of Clean Code by Robert C. Martin - Essential Guidelines for Better Software
Code is clean if it can be understood easily by everyone on the team. A comprehensive summary of Robert C. Martin's Clean Code principles and best practices.

Introduction
Code is clean if it can be understood easily – by everyone on the team. Clean code can be read and enhanced by a developer other than its original author. With understandability comes readability, changeability, extensibility and maintainability.
Robert C. Martin's "Clean Code" is a fundamental guide for writing maintainable, readable, and professional code. Here's a comprehensive summary of the key principles and practices.
General Rules
- Follow standard conventions - Consistency is key across your codebase
- Keep it simple stupid (KISS) - Simpler is always better. Reduce complexity as much as possible
- Boy scout rule - Leave the campground cleaner than you found it
- Always find root cause - Always look for the root cause of a problem
Design Rules
Keep configurable data at high levels
// Good: Configuration at the top level
const CONFIG = {
API_URL: 'https://api.example.com',
TIMEOUT: 5000,
}
class ApiService {
constructor(config = CONFIG) {
this.apiUrl = config.API_URL
this.timeout = config.TIMEOUT
}
}
Prefer polymorphism to if/else or switch/case
// Bad: Multiple if/else statements
function calculateArea(shape) {
if (shape.type === 'circle') {
return Math.PI * shape.radius * shape.radius
} else if (shape.type === 'rectangle') {
return shape.width * shape.height
}
}
// Good: Polymorphism
class Circle {
calculateArea() {
return Math.PI * this.radius * this.radius
}
}
class Rectangle {
calculateArea() {
return this.width * this.height
}
}
Additional Design Principles:
- Separate multi-threading code
- Prevent over-configurability
- Use dependency injection
- Follow Law of Demeter - A class should know only its direct dependencies
Understandability Tips
- Be consistent - If you do something a certain way, do all similar things in the same way
- Use explanatory variables
- Encapsulate boundary conditions - Put boundary processing in one place
- Prefer dedicated value objects to primitive types
- Avoid logical dependency - Don't write methods that depend on something else in the same class
- Avoid negative conditionals
Naming Rules
// Bad naming
let d // elapsed time in days
let users = []
function calc(u) {
return u.age * 365
}
// Good naming
let elapsedTimeInDays
let registeredUsers = []
function calculateDaysFromAge(user) {
return user.age * DAYS_PER_YEAR
}
Key naming principles:
- Choose descriptive and unambiguous names
- Make meaningful distinctions
- Use pronounceable names
- Use searchable names
- Replace magic numbers with named constants
- Avoid encodings and prefixes
Function Rules
// Bad: Large function doing multiple things
function processUserData(users) {
// Validate users
users.forEach((user) => {
if (!user.email || !user.name) {
throw new Error('Invalid user')
}
})
// Calculate statistics
let totalAge = 0
users.forEach((user) => (totalAge += user.age))
// Send emails
users.forEach((user) => {
sendEmail(user.email, 'Welcome!')
})
return { averageAge: totalAge / users.length }
}
// Good: Small functions doing one thing
function validateUsers(users) {
users.forEach(validateUser)
}
function calculateAverageAge(users) {
const totalAge = users.reduce((sum, user) => sum + user.age, 0)
return totalAge / users.length
}
function sendWelcomeEmails(users) {
users.forEach((user) => sendEmail(user.email, 'Welcome!'))
}
Function principles:
- Keep functions small
- Do one thing
- Use descriptive names
- Prefer fewer arguments
- Have no side effects
- Don't use flag arguments
Comments Rules
// Bad: Redundant comment
let age = 25 // Set age to 25
// Bad: Commented out code
// function oldFunction() {
// return 'deprecated';
// }
// Good: Explanation of intent
// Using binary search for O(log n) performance
function findUser(users, targetId) {
// Implementation here
}
// Good: Warning of consequences
// Don't run this in production - it will delete all data
function resetDatabase() {
// Implementation here
}
Comment guidelines:
- Always try to explain yourself in code first
- Don't be redundant
- Don't add obvious noise
- Don't comment out code - just remove it
- Use comments for explanation of intent and warnings
Source Code Structure
- Separate concepts vertically - Use blank lines to separate different concepts
- Related code should appear vertically dense
- Declare variables close to their usage
- Dependent functions should be close
- Similar functions should be close
- Place functions in downward direction
- Keep lines short
- Use whitespace to associate related things
Objects and Data Structures
// Good: Hide internal structure
class BankAccount {
#balance = 0
deposit(amount) {
this.#balance += amount
}
getBalance() {
return this.#balance
}
}
// Good: Prefer data structures for simple data
const userPreferences = {
theme: 'dark',
language: 'en',
notifications: true,
}
Object principles:
- Hide internal structure
- Prefer data structures for simple data
- Avoid hybrid structures (half object, half data)
- Keep objects small
- Do one thing
- Prefer non-static methods to static methods
Test Guidelines
// Good: One assert per test
describe('Calculator', () => {
it('should add two numbers correctly', () => {
const result = calculator.add(2, 3)
expect(result).toBe(5)
})
it('should handle negative numbers', () => {
const result = calculator.add(-2, 3)
expect(result).toBe(1)
})
})
Test principles:
- One assert per test
- Tests should be readable
- Tests should be fast
- Tests should be independent
- Tests should be repeatable
Code Smells to Avoid
- Rigidity - Software difficult to change; small changes cause cascading effects
- Fragility - Software breaks in many places due to single change
- Immobility - Cannot reuse parts of code in other projects
- Needless Complexity - Over-engineering solutions
- Needless Repetition - DRY principle violations
- Opacity - Code that's hard to understand
Quick Reference Checklist
Before committing code, ask yourself:
- ✓ Can another developer easily understand this?
- ✓ Are function and variable names descriptive?
- ✓ Are functions small and focused?
- ✓ Is the code properly structured?
- ✓ Are there unnecessary comments?
- ✓ Is the code as simple as possible?
Conclusion
Clean code is not written by following a set of rules. Clean code is written by programmers who care about their craft and take the time to make their code readable and maintainable.
Remember: "Any fool can write code that a computer can understand. Good programmers write code that humans can understand." - Martin Fowler
The investment in clean code pays dividends in reduced maintenance costs, fewer bugs, and improved team productivity. Start applying these principles today, and your future self (and teammates) will thank you.
Enjoyed this?
Get new posts as they land.
Keep reading

Proving Where Data Stops — How I Debug Multi-System Integrations
A shop field that never updates, a CDN that can't find its images, a sync that "randomly" skips entries. A method for multi-system integrations — instrument every hop, read the boundary evidence, hand over proof instead of opinions — with five real cases from the last weeks.

Personalized Products and Packaging Fees in Shopify
How I modeled printed cups with tiered prices and a logo upload in Shopify, and the options I weighed for passing a per-item packaging licence fee through to customers — with the pitfalls I hit.

Upgrading pg-boss 10 → 12 When There Is No Migration Path
pg-boss 12 cannot migrate a v10 schema - v11 moved job storage to partitioned tables and the migration chain starts after that cliff. Here's how I upgraded a production job queue anyway - drop the schema, rebuild queue state from my own tables, and the job-ownership guard the rollout taught me to add.