Writing Clean Code is a MUST

Writing Clean Code is a MUST

Imagine a messy room with clothes, books, and other items scattered everywhere. Finding something in that room would be tough, right? Now, think about writing messy code – it’s just as confusing, if not more! On the other hand, clean code is like an organized room: you can easily find what you need, understand what’s happening, and get things done faster.

Quick & Dirty Code: Writing code quickly without much planning might feel faster at first, but as the code grows, it becomes harder to maintain and troubleshoot, slowing down future work.

Thoughtful & Clean Code: Taking time to write organized, clear code might seem slower initially, but it remains easy to update and scale. This approach saves time in the long run and leads to better, more reliable software.

Clean code is an investment. It’s a habit that shows commitment to quality and a strong work ethic. In this article, I’ll share some best practices to help you keep your code clean and efficient.


?? What We'll Cover:

  1. Choose Meaningful Names
  2. Single Responsibility Principle (SRP)
  3. Eliminate Unnecessary Comments
  4. Code Readability
  5. Unit Testing
  6. Manage Dependencies Wisely
  7. Structure Your Project Effectively
  8. Avoid Hardcoding Values
  9. Keep Functions Short and Focused


1. Choose Descriptive Names

When naming variables, functions, and classes, use names that clearly convey their purpose.

Instead of naming a variable b, use something like numberOfUsers. This makes your code self-explanatory, reducing the need for extra comments. Meaningful names remove ambiguity and make the code more intuitive for others.

Example:

?? Naming Tips:

  • Variables: Use descriptive nouns, such as userAge or totalAmount, to clearly represent the data.
  • Functions: Use action verbs like calculateTotal() or fetchUserData() to indicate the function's purpose.
  • Classes: Use singular nouns, like User or Order, to represent the entities they model.


2. Single Responsibility Principle (SRP)

This makes your functions short, focused, and easier to read, test, and maintain.

Think of it like a toolbox where each tool has a specific job—clean code functions should work the same way.

For example, a function named calculateTotal should only calculate the total. Adding extra tasks to it will make the code more complex and harder to maintain.

Here’s why focusing functions is crucial: If you need to calculate a total and include extra info (like who calculated it and when), create a separate function for that. Don’t overload calculateTotal with unnecessary tasks. Keep it simple and clear.

Good Example:

?? Why This Is Good:

Each function has a clear, focused task. calculateTotal is responsible only for the math, while createCalculationRecord handles the extra details. This separation allows for easier maintenance—if you need to change the total calculation, you only update calculateTotal, and if you need to modify the record format, you only update createCalculationRecord. It keeps your code clean and flexible.

Bad Example:

?? Why This Is Bad:

The function name calculateTotalAndReturnRecord indicates it's doing multiple things. If you only need the calculation, you can't reuse this function without also getting the record part. This makes the code less flexible and harder to update or test each task independently. It's a sign that the function is violating the SRP.


3. Eliminate Unnecessary Comments

Good code should be self-explanatory and clear enough to understand without excessive comments. Focus on writing code that speaks for itself.

Comments are useful for explaining complex logic or unique approaches, but too many can clutter your code and make it harder to read.


?? When to Use Comments:

  • To explain why something is done in a specific way.
  • When dealing with complex algorithms or calculations.
  • To note potential limitations or edge cases.


4. Code Readability

Readable code uses proper indentation, line breaks, and spaces to stay neat and organized.

Think of it like writing a story: paragraphs make reading easier by breaking up large chunks of text. In code, line breaks do the same thing.

In VSCode, tools like Prettier is great for automatically applying clean code formatting across various languages.

PhpStorm and IntelliJ come with powerful built-in formatters that support customizable rules and follow coding standards. These tools ensure consistent and readable code with minimal manual effort.


5. Unit Testing

Unit tests ensure that each part of your code works as expected.

By testing small, individual units like functions ??, you can catch bugs early and prevent them from affecting other areas of the code.

In essence, unit tests act as mini quality checks for each part of your code, verifying they perform as intended.


Real-World Example:

Let’s consider testing a complex JavaScript object with multiple methods, such as a Calculator class.

This will highlight the importance of keeping each method focused on a single task and why unit testing ensures each one functions correctly.

Here’s a simple Calculator class with methods for basic arithmetic operations: addition, subtraction, multiplication, and division.

As you can see, each method in the Calculator class handles one specific operation. The divide method includes additional logic to manage division by zero, preventing errors.

Next, we’ll write unit tests to verify that each method works as expected.


?? Writing Unit Tests for Each Method

To test the Calculator class, we’ll create unit tests that cover both normal cases and edge cases. Here’s how we can set up tests for each method:

  1. Addition (add method): We test that add(2, 3) returns 5, and add(-1, 1) returns 0. If these tests pass, we know the addition logic is correct.
  2. Subtraction (subtract method): We verify that subtract(5, 3) returns 2, and subtract(0, 0) returns 0. These checks ensure accurate subtraction.
  3. Multiplication (multiply method): We test with both positive and negative values, confirming that multiply(2, 3) returns 6, and multiply(-1, 2) returns -2.
  4. Division (divide method): We confirm that dividing 6 by 3 returns 2. For division by zero, we use a try...catch block to ensure an error is thrown with the correct message, verifying the method handles errors properly.

If any method fails, the test provides a clear error message, making it easy to pinpoint and resolve issues. Testing methods individually helps catch bugs early, ensuring reliable and maintainable code as the project ? evolves ?.


6. Manage Dependencies Wisely

Dependencies are external pieces of software that your code depends on.

If you're building a web app that sends emails, rather than writing the email-sending functionality from scratch, you might use an external library. In this case, the library is a dependency—your app relies on it to handle the email-sending process.

While dependencies are useful, it's important to avoid over-relying on external libraries or software. Only use dependencies when they simplify your work or provide essential functionality.

Effectively managing dependencies is crucial for clean code. Here are some tips:

  • Limit Dependencies: Only include libraries or modules that are necessary for your project.
  • Keep Versions Updated: Regularly update library versions to minimize security risks.
  • Separate Logic: Write core functions yourself whenever possible. This way, if you need to remove a dependency, your code won’t break.


7. Structure Your Project Effectively

A well-organized project structure is just as crucial as the code itself.

Think of it like organizing your workspace—everything should have its place, making it easy to find. For coding projects, create folders for different parts like components, utils, and services.


?? How to Organize Your Project

Here’s an example of a clean and organized project structure:

myProject
├── src
│   ├── components
│   ├── services
│   ├── utils
└── tests        

Project Structure Breakdown:

  • myProject: Root folder of your project, containing everything related to your app.
  • src (Source): This is where your source code lives—the bulk of your development.
  • components: Reusable UI components like buttons, headers, or forms.
  • services: Functions or files handling specific tasks, such as email-sending logic.
  • utils (Utilities): Helper functions for common tasks like date formatting or input validation.
  • tests: All your testing files go here to keep testing organized as your project grows.

Example structure within components:

components
├── Button.php
├── Header.php
└── Form.php        

Example structure within services:

services
├── emailService.php
├── userService.php
└── productService.php        

Example structure within utils:

utils
├── formatDate.php
├── validateEmail.php
└── generateId.php        

Example structure within tests:

tests
├── emailService.test.php
├── userService.test.php
└── component.test.php        


?? Benefits of a Well-Organized Project:

  • Ease of Navigation: Other developers can easily find the relevant parts of your code.
  • Better Collaboration: Clear structure ensures teammates know where to contribute without conflict.
  • Scalability: As your project grows, a good structure keeps things manageable.
  • Improved Maintenance: Quickly locate and update files, saving time and reducing errors.


8. Avoid Hardcoding Values

"Hardcoding" means, directly embedding/writing data values into your code, such as setting a user ID to 123 instead of using a variable.

Avoid hardcoding to make your code more flexible and reusable. Instead, store values in variables, constants, or configuration files.

Here's an example where hardcoding can lead to issues:

In this example, the numberOfUsers is hardcoded to 100. If you need to change the user limit, you would have to search through the code and update the value every time it appears, which is error-prone and inefficient.


??? Improved Example Using Constants

Let’s refactor the code to use a constant instead:

  1. Using Constants: The MAX_USERS constant is defined at the top. This ensures that if the maximum user limit changes, you only need to update it in one place.
  2. Dynamic Values: The getCurrentUserCount() function retrieves the current user count from a dynamic source, such as a database. This prevents hardcoding and makes the code adaptable to changes in the data source.
  3. Maintainability: By using constants, your code becomes easier to maintain. For example, if the business requirement changes and you need to increase the user limit to 150, you can simply change MAX_USERS from 100 to 150, and it will automatically reflect throughout the application.
  4. Clarity: Descriptive names for constants like MAX_USERS improve code readability, making it clear what the value represents.


?? When to Use Configuration Files

In larger applications, it’s a good idea to use configuration files (like JSON, YAML, or environment variables) to store values that might change across different environments (development, staging, production).

For instance, in a config.json file, you could define the maxUsers value (preferably in camelCase for consistency):

The same rule applies for PHP frameworks that use config.php or .env files.


9. Keep Functions Short and Focused

Long functions are harder to maintain and understand. While there's no strict rule, functions should ideally be no longer than 20-30 lines. If a function is handling multiple tasks or contains too many steps, it's a sign it may be too long.

In such cases, breaking the function down into smaller "helper" functions can make the code more manageable and easier to understand. This keeps each function focused on a single responsibility, improving clarity and maintainability.

long, complex function might look like:

This function handles several tasks:

  • Adds an item to the cart.
  • Calculates the total price.
  • Applies a discount IF a code is provided.
  • Logs the transaction.

Although this function may seem fine initially, it can become cumbersome as additional tasks are added, making it harder to debug and maintain.

Let’s refactor this long function into smaller, single-responsibility functions:

  1. addItemToCart: This function is now dedicated solely to adding an item to the cart, making it simple and clear in purpose.
  2. calculateTotal: This function handles the calculation of the total price for all items in the cart. It’s straightforward to read and understand, and if you need to update how totals are calculated, only this function needs modification.
  3. logTransaction: This function is in charge of logging the transaction details. If you want to change what gets logged (such as adding a timestamp), you can do so here without affecting the rest of the code.
  4. updateCart: The main function now serves as a summary of actions: adding an item, calculating the total, applying discounts, and logging the result. It’s easier to follow and more concise.


??? Key Takeaways for Limiting Function Length:

  1. Focus on One Task: Each function should handle a single responsibility. If a function does too much, break it down.
  2. Use Helper Functions: These are smaller, focused functions that assist the main function. For example, addItemToCart, calculateTotal, and logTransaction are all helper functions.
  3. Descriptive Names: Name functions based on their actions (like addItemToCart) to make the code self-explanatory.


Best Practices for Clean Code

Now that we’ve gone through key tips, let's summarize the core principles behind clean code:

Simplicity: Always aim to keep your code as simple and straightforward as possible. Avoid unnecessary complexity.

Consistency: Maintain uniformity in your code’s style, structure, and conventions. This makes it easier for others (and your future self) to understand.

Clarity: Code should clearly express its intent. If someone else reads it, they should easily understand what it does without needing additional context.

Efficiency: Optimize your code for performance without compromising on readability. Make sure your code runs efficiently, but never at the cost of clarity.

These principles aren't just guidelines—they are the foundation for designing software that grows and adapts over time. Writing clean code is a skill that improves with practice, so always aim to learn and refine your approach.


Conclusion

Writing clean code is like building a solid foundation for a house—it supports the growth and maintenance of your project. Following these practices will help you write code that’s more readable, maintainable, and easier to work on as your project evolves.


Resources

Carbon: Create and share beautiful images of your source code.

Clean Code: A Handbook of Agile Software Craftsmanship

FreePik - Everything you need, from stock images and videos to AI-powered design tools


Thank you for reading.

Abdulrahman Mushref (DevMushref)

要查看或添加评论,请登录

Abdulrahman Mushref的更多文章

社区洞察

其他会员也浏览了