Logo
Published on

4 Clean Code Principles Every Developer Should Know

Mastering the KISS, DRY, SRP, and Boy Scout Rule Clean Code Principles

Authors
  • avatar
    Name
    Mike Tsamis
    Twitter

Throughout my journey as a senior software engineer, I've learned the importance of applying clean code principles. Following clean code principles is critical for producing code that is reliable, scalable, and flexible. When your code is easy to comprehend and maintain, it becomes much simpler for you and your team to make changes and add new features. This saves time and resources in the long run and helps prevent bugs which will increase the reliability of the software. By adhering to clean code principles, you can create higher-quality software faster and with fewer mistakes. It's a win-win for everyone involved!

In this blog post, I'll highlight 4 clean code principles that have helped me the most throughout my career. These clean code principles include:

  1. KISS (Keep it Simple Stupid)
  2. DRY (Don't Repeat Yourself)
  3. SRP (Single Responsibility Principle)
  4. The Boy Scout Rule

By applying just these 4 principles, you can enhance the quality, reliability, and readability of your code, which will help you work more efficiently as a software developer. Whether you're a beginner or a professional, these principles are necessary to produce clean, high-quality code.

Principle 1: Keep It Simple, Stupid (KISS)

When it comes to writing clean code, simplicity is key. Keeping your code simple makes it easier to understand, maintain, and test. This will reduce the number of bugs and improve the overall quality of your code. Let's look at two examples of how the KISS principle can be applied in your code:

Example 1: Use simple functions to avoid complexity

Instead of having a large and complex function with a lot of conditions or nested loops, consider splitting it into smaller, simpler functions that each complete a single task. For instance:

// Complex Code
function complexFunction(data) {
  let result = 0;
  for (const item of data) {
    if (item.type === 'number') {
      result += item.value;
    } else if (item.type === 'string') {
      result += parseInt(item.value, 10);
    } else {
      result += item.value.length;
    }
  }
  return result;
}

// Simplified Code
function processNumber(item) {
  return item.value;
}

function processString(item) {
  return parseInt(item.value, 10);
}

function processOther(item) {
  return item.value.length;
}

function simpleFunction(data) {
  let result = 0;
  for (const item of data) {
    if (item.type === 'number') {
      result += processNumber(item);
    } else if (item.type === 'string') {
      result += processString(item);
    } else {
      result += processOther(item);
    }
  }
  return result;
}

In this example, the complex code has a single function that processes a list of data items by checking their type and performing different actions depending on what it is. However, in the simplified code, there are 3 separate functions that each handle a specific data type. The main function simply calls the appropriate function based on the data type. By having each function defined with a clear and specific purpose, the code is a lot more straightforward to understand.

Example 2: Using clear and descriptive variable names

Another way to apply the KISS principle is to use clear and descriptive variable names. Instead of using abbreviations or single letters, choose names that clearly describe what the variable represents. For example:

// Bad Code
function fn(f, l) {
  return `${f} ${l}`;
}

// Good Code
function getFullName(firstName, lastName) {
  return `${firstName} ${lastName}`;
}

Using clear and descriptive variable/class/function names makes it a lot easier to understand what the code is doing. It will improve the efficiency of the development process, makes it easier for developers to work together as a team, and make the onboarding process for new developers a lot smoother.

Also, don't be afraid to refactor your code to make it simpler. If you find yourself adding more and more complexity to a particular function over time, it may be time to start fresh with a simpler approach. Remember, the simpler your code is, the easier it will be to work with in the long run. So try to keep things as (stupid) simple as possible!

Principle 2: Don't Repeat Yourself (DRY)

The DRY principle is a clean code principle which states that code should not contain duplicated or redundant information. This means that every piece of knowledge in the system should have a single, unambiguous representation (source of truth).

One way to adhere to the DRY principle is to use functions or methods to encapsulate and reuse code. For example, consider the following code:

function calculateTotal(items) {
  let total = 0;
  for (const item of items) {
    total += item.price * item.quantity;
  }
  return total;
}

function calculateTax(total) {
  return total * 0.07;
}

function calculateShipping(total) {
  return total < 50 ? 5 : 0;
}

function calculateGrandTotal(items) {
  const total = calculateTotal(items);
  const tax = calculateTax(total);
  const shipping = calculateShipping(total);
  return total + tax + shipping;
}

In this example, the "calculateGrandTotal" function calculates the final total for a list of items by calling 3 helper functions: "calculateTotal" to sum the item prices, "calculateTax" to add sales tax, and "calculateShipping" to add shipping costs. By separating these tasks into separate functions, the code is easier to understand, maintain, and test, as each function has a clear and specific purpose.

Another way to adhere to the DRY principle is to use variables or constants to store common values or calculations. For example, consider the following code:

const TAX_RATE = 0.07;
const SHIPPING_THRESHOLD = 50;
const SHIPPING_COST = 5;

function calculateGrandTotal(items) {
  let total = 0;
  for (const item of items) {
    total += item.price * item.quantity;
  }
  const tax = total * TAX_RATE;
  const shipping = total < SHIPPING_THRESHOLD ? SHIPPING_COST : 0;
  return total + tax + shipping;
}

In this example, the "calculateGrandTotal" function calculates the final total for a list of items using constants for the tax rate, shipping threshold, and shipping cost. By using constants, the code is easier to maintain and read, as the values are clearly defined and can be easily changed in one place. Code duplication can make it difficult to modify or extend code because you may need to make the same change in multiple places. Avoiding duplication can make your code more flexible and scalable.

To comply with the DRY clean code principle, try to write functions that encapsulate and reuse code. Also, use variables or constants to store common values/calculations: By using variables or constants, you can avoid duplication and make your code easier to read and maintain. In addition, avoid copy-pasting code when possible. Although we are all guilty of doing it when we are rushing to fix a bug in production, copy-pasting code is a common source of duplication and it can make your code harder to maintain/debug. Instead of copy-pasting, try to find a way to reuse or refactor the code. Lastly, instead of trying to reinvent the wheel, use libraries, frameworks, or tools to avoid duplication whenever possible. There are many libraries, frameworks, and tools available that can help you avoid duplication in your code.

Principle 3: Single Responsibility Principle (SRP)

SRP is a clean code principle where every class or module should have a single, well-defined responsibility. For instance, if a class is responsible for parsing a file, it should only be responsible for parsing the file. No additional logic. By following SRP, you can make your code more modular, maintainable, and testable.

Example: Using the SRP principle to design a class hierarchy

Suppose you're designing a class hierarchy for a messaging system. One approach might be to create a single class called "Message" that handles everything related to messaging such as sending, receiving, and storing messages. However, this approach violates SRP since the "Message" class would have multiple responsibilities. A better approach would be to create separate classes for each responsibility such as a "MessageSender" class, "MessageReceiver" class, and a "MessageStore" class. That way, each class has a single, well-defined responsibility.

// Violates the SRP principle
class Message {
  send() {...}
  receive() {...}
  format() {...}
  store() {...}
}

// Follows the SRP principle
class MessageSender {
  send() {...}
}

class MessageReceiver {
  receive() {...}
}

class MessageStore {
  store() {...}
}

Here are some tips for adhering to the SRP in your code:

  1. Identify the responsibilities of each class or module. When reviewing code, ask yourself what the class or module is responsible for and make sure it only has one responsibility.
  2. If a class or module has multiple responsibilities, consider extracting them into separate classes or modules.
  3. Use descriptive names for your classes and methods to clearly communicate their responsibilities.
  4. Avoid code duplication by extracting common functionality into separate methods or classes.

Principle 4: The Boy Scout Rule

The Boy Scout Rule is a clean code principle where you should leave the code you work on in a better state than you found it. This principle encourages developers to take ownership of their code and strive to continuously improve it. Some benefits of following the Boy Scout Rule in your code:

  1. Improved code quality. By constantly improving the code you work on, you can help prevent technical debt and maintain a high-quality codebase.
  2. Greater team collaboration: When everyone on a team follows the Boy Scout Rule, it helps create a culture of continuous improvement and encourages teamwork. When everyone on a team follows the Boy Scout Rule and works towards continuous improvement, it can create a positive and collaborative team culture.

Conclusion

In this post, we discussed the importance of utilizing clean code principles in software development. Every developer must know the KISS principle, DRY principle, Single Responsibility Principle (SRP), and the Boy Scout Rule. However, it's important to remember that clean code principles are not one-time fixes. They are a set of guidelines that should be followed throughout the development process to ensure that your code is always of the highest quality. It's also a team effort. Encourage your team to follow these clean code principles and create a culture of continuous improvement. Leading by example, you can create a collaborative and positive team culture where everyone is focused on producing high-quality code.

With practice and dedication, you and your team can master these principles and create code that is easy to understand, maintain, and grow. So take the time to learn about clean code principles and start applying them to your own projects. Your team, your clients, and your future self will thank you.

If you want to dive deeper into learning clean code principles or best practices in software development, I highly recommend reading "The Pragmatic Programmer" by David Thomas and Andrew Hunt. If you want a quick summary, I wrote a very extensive article outlining 101 key takeaways from this book here. I also recommend reading "Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin.