Clean Code Principles: Simple Tips from a Developer

A practical guide to writing maintainable code. Explore DRY, KISS, YAGNI, and other principles with real examples, plus recommended resources to dive deeper.

Clean CodeBest PracticesSoftware DevelopmentCode Quality

Writing code that works is one thing. Writing code that others (including future you) can understand and maintain is another. These are some principles I try to follow in my daily work as a developer.

Why Clean Code Matters

Clean code isn’t just about aesthetics—it’s about creating software that:

  • Reduces bugs by making logic clear and obvious
  • Speeds up development by making code easier to understand and modify
  • Improves collaboration by helping team members understand your code
  • Saves money by reducing maintenance costs over time

Here are some principles I find useful.

DRY - Don’t Repeat Yourself

When to use: Always. This is one of the most fundamental principles.

The DRY principle states that every piece of knowledge should have a single, unambiguous representation in your codebase. Duplication makes code harder to maintain and more prone to bugs.

Bad Example:

function calculateDiscountForRegularUser(price) {
  return price * 0.9; // 10% discount
}

function calculateDiscountForPremiumUser(price) {
  return price * 0.8; // 20% discount
}

function calculateDiscountForVIPUser(price) {
  return price * 0.7; // 30% discount
}

Good Example:

function calculateDiscount(price, discountRate) {
  return price * (1 - discountRate);
}

// Usage
const regularPrice = calculateDiscount(100, 0.1);
const premiumPrice = calculateDiscount(100, 0.2);
const vipPrice = calculateDiscount(100, 0.3);

KISS - Keep It Simple, Stupid

When to use: Always. Simplicity should be your default approach.

The KISS principle emphasizes that systems work best when they’re kept simple. Avoid unnecessary complexity and over-engineering. If you can solve a problem with fewer lines of code and less complexity, do it.

Bad Example:

function isEven(number) {
  if (number === 0) {
    return true;
  } else if (number === 1) {
    return false;
  } else if (number < 0) {
    return isEven(-number);
  } else {
    return isEven(number - 2);
  }
}

Good Example:

function isEven(number) {
  return number % 2 === 0;
}

YAGNI - You Aren’t Gonna Need It

When to use: Always, especially when starting new features.

Don’t add functionality until you actually need it. Building features “just in case” leads to bloated, complex code that’s harder to maintain.

Bad Example:

class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
    // Adding features we might need later
    this.preferences = {};
    this.history = [];
    this.cache = new Map();
    this.notifications = [];
  }
  
    // Methods we don't need yet...
}

Good Example:

class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
    // Add other features only when needed
  }
}

Single Responsibility Principle (SRP)

When to use: Always. Each function/class should do one thing well.

A function or class should have only one reason to change. If you’re using “and” to describe what your function does, it probably violates SRP.

Bad Example:

function processUserDataAndSendEmail(userData) {
  // Validate user data
  if (!userData.email) throw new Error('Invalid email');
  
  // Save to database
  database.save(userData);
  
  // Send welcome email
  emailService.send({
    to: userData.email,
    subject: 'Welcome!',
    body: 'Thanks for joining us'
  });
  
  // Log the action
    logger.info(`User ${userData.email} processed`);
}

Good Example:

function validateUser(userData) {
  if (!userData.email) throw new Error('Invalid email');
  return true;
}

function saveUser(userData) {
  return database.save(userData);
}

function sendWelcomeEmail(email) {
  return emailService.send({
    to: email,
    subject: 'Welcome!',
    body: 'Thanks for joining us'
  });
}

// Orchestrate in a separate function
async function registerUser(userData) {
  validateUser(userData);
  await saveUser(userData);
  await sendWelcomeEmail(userData.email);
  logger.info(`User ${userData.email} registered`);
}

Meaningful Names

When to use: Always. Names are everywhere in code.

Use names that reveal intention. A reader should understand what a variable, function, or class does without reading its implementation.

Bad Example:

const d = new Date();
const x = users.filter(u => u.a);
function calc(a, b) { return a * b * 0.8; }

Good Example:

const currentDate = new Date();
const activeUsers = users.filter(user => user.isActive);
function calculateDiscountedPrice(price, quantity) {
  const DISCOUNT_RATE = 0.8;
  return price * quantity * DISCOUNT_RATE;
}

Boy Scout Rule

When to use: Every time you touch code.

“Always leave the code better than you found it.” If you see messy code while working on something, clean it up—even if you didn’t write it.

This could mean:

  • Renaming a confusing variable
  • Extracting a complex expression into a well-named function
  • Adding a missing comment
  • Removing dead code

When Principles Conflict

Sometimes, clean code principles can seem to conflict. For example:

  • DRY vs KISS: Sometimes duplicating a small piece of code is simpler than creating an abstraction
  • YAGNI vs Planning: While you shouldn’t over-engineer, you should design for reasonable extensibility

In these cases, use your judgment based on:

  1. Current needs: What does the code need to do right now?
  2. Team context: What will your team find most maintainable?
  3. Project stage: Early prototypes can be messier; production code needs more care

Context-Specific Principles

Some principles apply more in certain situations:

For Performance-Critical Code:

  • Profile before optimizing
  • Sometimes you need to sacrifice readability for performance
  • Document why you’re breaking the rules

For APIs and Libraries:

  • Consistency matters more than individual elegance
  • Consider backward compatibility
  • Document extensively

For Prototypes:

  • YAGNI is even more important
  • It’s okay to be less strict about structure
  • But keep it readable—you might need to revisit it

Practical Tips for Writing Clean Code

  1. Write code for humans first: The computer will execute whatever you write. Focus on making it clear for the next developer (often future you).

  2. Use your IDE’s help: Modern IDEs can automatically format code, suggest better names, and detect code smells.

  3. Code reviews: Having others review your code catches issues and helps spread knowledge.

  4. Refactor regularly: Don’t wait for “the big refactor.” Improve code continuously as you work with it.

  5. Write tests: Tests document how code should work and give you confidence to refactor.

Conclusion

Clean code principles aren’t rigid rules—they’re guidelines based on decades of collective experience. The goal is always the same: write code that’s easy to understand, maintain, and modify.

Start with the basics (DRY, KISS, YAGNI, meaningful names) and gradually incorporate others as you gain experience. Remember: clean code is a skill that improves with practice.

The best code is code that your team can easily work with. When in doubt, optimize for clarity.

If you want to dive deeper into clean code practices, here are some resources I’ve found valuable:

Books:

  • Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin - The classic book on the subject. Practical advice with lots of examples.
  • The Pragmatic Programmer by Andrew Hunt and David Thomas - Goes beyond code quality to cover the mindset of effective developers.
  • Refactoring: Improving the Design of Existing Code by Martin Fowler - Essential guide to improving code without changing its behavior.

Online Resources:

  • Refactoring.Guru - Great visual explanations of code smells, refactoring techniques, and design patterns
  • Clean Code JavaScript - Clean Code concepts adapted specifically for JavaScript

These are just starting points. The best way to learn is by reading code, writing code, and getting feedback from others.


What clean code principles do you find most valuable? Feel free to reach out with your thoughts!

Enjoyed this article?

If you find this content helpful and would like to support the creation of more resources like this, consider buying me a coffee. Your support helps me continue researching, writing, and sharing knowledge with the community.