Featured image of post Clean Code - A Software Engineer’s Perspective - Part I

Clean Code - A Software Engineer’s Perspective - Part I

As a software engineer with over years of experience, I've seen firsthand the impact that code quality can have on a project. Clean code is more than just a luxury — it's a necessity for maintainability, scalability, and collaboration. In this blog post, I'll delve into what clean code means, why it matters, and provide examples comparing bad code and clean code.

What is Clean Code?

Clean code is code that is easy to understand and easy to change. It follows a set of principles that promote readability and maintainability. Here are some key attributes of clean code:

  • Readable: Code should be easy to read and understand. It should communicate its intent clearly.
  • Simple: Simplicity in design and implementation minimizes complexity.
  • Consistent: Consistent naming conventions and formatting styles should be used throughout the codebase.

Why Clean Code Matters

  • Maintainability: Clean code is easier to maintain and update. This is crucial as software evolves over time.
  • Collaboration: When multiple developers work on the same codebase, clean code ensures everyone can understand and contribute effectively.
  • Bug Prevention: Clear and simple code reduces the likelihood of bugs and makes them easier to spot and fix.
  • Scalability: Clean code can be more easily scaled as the project grows.

Key Pain Points of Dirty Code

After several years working as a software engineer, I realize that dirty code can lead to numerous problems:

  • Maintenance Difficulties: Dirty code is hard to debug, extend, and maintain. It often lacks clear structure and documentation, making it challenging for developers to work with. This leads to longer development cycles and increased technical debt.
  • Collaboration Issues: When code is poorly written, it becomes difficult for other developers to understand and contribute effectively. This can lead to misunderstandings, errors, and reduced team productivity.
  • Increased Bugs: Poorly written code is more prone to bugs and errors. It’s harder to test and often leads to unexpected behavior, which can be costly to fix and can damage the user experience.
  • Performance Problems: Inefficient code structures can lead to performance bottlenecks, making the software slower and less responsive. This can be particularly problematic in high-load scenarios.

How to Write Clean Code

From my perspective, I conclude that to write better code, you should keep the following principles in mind:

  • Meaningful Names: Use descriptive names for variables, functions, and classes that convey their purpose.
  • Small Functions: Keep functions small and focused on a single task. This makes them easier to understand, test, and reuse.
  • Consistent Formatting: Follow a consistent style guide for indentation, spacing, and other formatting rules.
  • Comments and Documentation: Write clear comments and documentation to explain the code’s intent and logic. However, avoid redundant comments that state the obvious.
  • Error Handling: Implement robust error handling to ensure the application can gracefully handle unexpected situations.
  • Refactoring: Regularly refactor the code to improve its structure and eliminate redundancy. This helps keep the codebase clean and maintainable.

Naming - Assingine Names to Vairables, Functions and Classes

Naming is one of the most important aspects of writing clean code. Although it’s just a simple thing, It will appear almost everywhere in our codebase. Clear and descriptive names make the code easier to read and understand. As a software engineer, I’ve learned that well-chosen names can significantly improve the quality of the code.

Variable Names

Variables should have meaningful names that clearly indicate their purpose. Variables name shoud be a noun, or a true/false question if it store value is a Boolean. Avoid using single-letter names or abbreviations unless they are widely understood.

Nguồn: https://udemy.com

A user object(name,email,age) variable names example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Bad names example
Object u; // What does 'u' represent?
Object data;

// Okay names example
Object userData; // "userData" is a bit redundant
Object person; // "person" is too unspecific

// Good names example
Object user; // "user" is descriptive
Object customer; // "customer" is even more specific

User input validation result (true/false) variable names example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Bad names example
Boolean v; // "v" could be anything
Boolean val; // "val" could stand for "value"


// Okay names example
Boolean correct; 
Boolean validatedInput; // Both don't necessarily imply a true/false value

// Good names example
Boolean isCorrect; 
Boolean isValid; // Descriptive and value type is clear

Function Names

Functions should have names that describe their actions. Function name should be a verb performs an operation and provide more details withoutr introducing redundancy. For Function computes a Boolean it should answer a true/false question. A good function name tells you exactly what the function does without needing to read the implementation. For example:

Nguồn: https://udemy.com

Function to save user data to a database

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 // Bad names example
void process()
void handle() // Both are very unspecifice - what is being "processed"

 // Okay names example
void save()
void storeData() // at least we know that something is saved - but what?

// Good names example
void saveUser() // the intent is very clear - especially with the method

Function to validate the user input

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 // Bad names example
void process()
void save() // Unspecific "process" or even misleading "save"

 // Okay names example
void validateSave()
void check() // Both names are not 100% specific

// Good names example
void validate()
void isValid() // Both make sense - deppends on what the function does exactly

Class Names

Classes should have names that represent the objects they are modeling. Use nouns or noun phrases for class names. For example:

A class represent for a User

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Bad names example
class UEntity
class ObjA // Both are very unspecific


// Okay names example
class UserObj // Both class names have redundant information
class AppUser

// Good names example
class User // "User" is just fine - or "Admin" if it's a more specific kind or user
class Admin

A class represent for A Database

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Bad names example
class Data
class DataStorage // It's not clear that we're describing a database


// Okay names example
class Db // Not 100% specific
class Data

// Good names example
class Database 
class SQLDatabase // "Database" is good, "SQLDatabase" might be event better

Clean Code Structure, Commenting, and Formatting

Cleanm Code Structure

A well-structured codebase is easier to navigate and maintain. Group related functions and classes together, and use packages or modules to organize your code logically. Avoid deeply nested structures and keep your codebase flat and easy to explore.

Bad code structure example with multiple nested if condtion

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class OrderProcessor {
    void processOrder() {
        if (order.isValid()) {
            // ...
            if (payment.isSuccessful()) {
                // ...
                if (inventory.isAvailable()) {
                    // ...
                }
            }
        }
    }
}

Clean Code Example with seperate if condition

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class OrderProcessor {
    void processOrder() {
        if (!order.isValid()) {
            return;
        }
        if (!payment.isSuccessful()) {
            return;
        }
        if (!inventory.isAvailable()) {
            return;
        }
        // ...
    }
}

Clean Commenting

Comments should explain why the code does something, not what it does. Use comments sparingly and ensure they add value. Good comments provide context or explain complex logic, while redundant comments should be avoided.

Nguồn: https://udemy.com

Example bad commenting with to many redundant information

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// (c) Maximilian Schwarzmüller / Academind GmbH
// Created in 2020

// ***************
// GLOBALS
// ***************
let sqlDriver: any;
let mongoDbDriver: any;

// ***************
// CLASSES
// ***************
// Acts as an adapter, connecting models to various database engines (SQL, MongoDB)
class Database {
  private dbDriver: any; // the database engine to which we connect

  loadDatabaseDriver(driver: string) {
    if (driver === 'sql') {
      // Connect to the SQL Driver if "driver" is set to SQL
      this.dbDriver = sqlDriver;
    } else {
      // Otherwise, connect to MongoDB
      this.dbDriver = mongoDbDriver;
    }
  }

  connect() {
    this.dbDriver.connect(); // This may fail and throw an error
  }

  insertData(data: any) {
    this.dbDriver.insert(data); // updates a user
  }

  findOne(id: string) {
    // Todo: Needs to be implemented
  }

  // findMany(filter: any) {
  //   this.dbDriver.find(filter);
  // }
}

Example for good commenting with only comments for TODO notes, warning and legal information

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
let sqlDriver: any;
let mongoDbDriver: any;

class DatabaseAdapter {
  private dbEngine: any;

  loadDatabaseDriver(engine: string) {
    if (engine === 'sql') {
      this.dbEngine = sqlDriver;
    } else {
      this.dbEngine = mongoDbDriver;
    }
  }

  connect() {
    this.dbEngine.tryConnect();
  }

  insertData(data: any) {
    this.dbEngine.insert(data);
  }

  findOne(id: string) {
    // Todo: Needs to be implemented
  }
}


// accepts [text]@[text].[text], i.e. it simply requires an "@" and a dot
const emailRegex = /\S+@\S+\.\S+/;

// Only works in browser environment
localStorage.setItem('user', '[email protected]');

Clean Formatting

Consistent formatting improves code readability. Use a consistent indentation style, space around operators, and follow language-specific conventions. Tools like linters and formatters can help enforce these standards.

There are two typical type of formatting. The first one is “Vertical Formatting” and the second one is “Horizontal formatting”

Vertical Formatting

Vertical formatting refers to how the code is organized top-to-bottom. Aim to keep your code compact and avoid unnecessary blank lines, while still using whitespace to separate logical sections and make the code more readable.

Example for Vertical Formatting

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// Bad formatting
public class User {




    private String name;





    private int age;





    public String getName() {



        return name;



    }




    public void setName(String name) {



        this.name = name;



    }


}
// Good formatting
public class User {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Horizontal Formatting

Horizontal formatting focuses on the width of the code. Lines of code should not be too long; they should fit within a standard width (usually 80-100 characters). This makes the code easier to read without horizontal scrolling and ensures that it fits well on screens.

Example for Horizontal Formatting

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Bad Formatting
public class OrderProcessor { public void processOrder() { if (order.isValid()) { if (payment.isSuccessful()) { if (inventory.isAvailable()) { // process the order } } } } }

// Good Formatting
public class OrderProcessor {
    public void processOrder() {
        if (order.isValid()) {
            if (payment.isSuccessful()) {
                if (inventory.isAvailable()) {
                    // process the order
                }
            }
        }
    }
}

Nguồn: https://udemy.com

Summary and Checklist

Summary

Writing clean code is crucial for maintaining a healthy codebase. It improves readability, maintainability, and reduces the likelihood of bugs. Clean code practices involve using meaningful names, maintaining a clear structure, and following consistent formatting and commenting standards.

Checklist for Clean Code:

  • Use meaningful and descriptive names for variables, functions, and classes.
  • Keep functions small and focused on a single task.
  • Follow consistent formatting and indentation rules.
  • Write comments that explain the why, not the what.
  • Implement robust error handling.
  • Regularly refactor code to improve its structure and readability. By adhering to these principles, you can write clean code that is not only functional but also elegant and maintainable, ensuring long-term success in your software projects.

What’s next for Part II

In next blog post, we will delve into the intricacies of defining clean functions and methods, as well as managing control structures and handling errors effectively. We’ll explore how to create functions that are not only concise and focused but also easy to understand and maintain. Additionally, we’ll discuss best practices for structuring control flows and ensuring robust error management to enhance the reliability and readability of your code.

STAY TUNED TO ELEVATE YOUR CODING STANDARDS AND EMBRACE CLEANER!

HAPPY CODING!

Reference: https://udemy.com - Clean Code course by Academind

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy