Skip to main content

Write Clean Code!

๐Ÿ˜€ Whyโ€‹

Writing clean code is essential for several reasons: TLDR

  1. ๐Ÿงน Readability and Maintainability: Clean code is easier to read and understand, making it simpler for other developers (or your future self) to maintain, update, or debug the code. This can significantly reduce the time and effort required to make changes or fix issues in the codebase.

  2. ๐Ÿž Reduced Bugs and Errors: Clean code is less prone to bugs and errors. When code is well-organized, with clear naming conventions and logical structure, it becomes easier to identify and rectify potential issues. This leads to more robust and reliable software.

  3. ๐Ÿค Collaboration and Teamwork: When working on a team project, writing clean code becomes crucial for effective collaboration. Clean code enhances communication and understanding between team members, facilitating smoother integration of different modules and components.

  4. ๐Ÿš€ Scalability and Extensibility: Clean code allows for easier scalability and extensibility of the software. When the code is well-structured, adding new features or making modifications becomes less complex and time-consuming.

  5. ๐Ÿ”„ Code Reusability: Clean code often promotes the reusability of code components. Well-organized and modular code can be easily repurposed in different parts of the application or in entirely different projects, saving time and effort in development.

  6. โšก Performance: In some cases, writing clean code can positively impact the performance of the software. Well-optimized and efficient code can lead to faster execution times and reduced resource consumption.

  7. ๐ŸŽ“ Professionalism and Long-Term Success: Writing clean code is a reflection of professionalism and a commitment to quality in software development. It demonstrates a strong understanding of best practices and a dedication to producing high-quality, reliable, and maintainable software, which can contribute to long-term success and customer satisfaction.

[TLDR] Code smellsโ€‹

  1. ๐Ÿ”ง Rigidity. The software is difficult to change. A small change causes a cascade of subsequent changes.
  2. ๐Ÿ˜ฌ Fragility. The software breaks in many places due to a single change.
  3. ๐Ÿ”’ Immobility. You cannot reuse parts of the code in other projects because of involved risks and high effort.
  4. ๐ŸŒ€ Needless Complexity.
  5. ๐Ÿ” Needless Repetition.
  6. ๐Ÿ˜ต Opacity. The code is hard to understand.

๐Ÿ‘“ Readability:โ€‹

Emphasizes the importance of writing code that is easy to read and understand. This involves using descriptive names for variables, functions, and classes, as well as adhering to consistent formatting and style guidelines.

๐Ÿ–‹ Choose descriptive and unambiguous names.โ€‹

Good examples:

#Descriptive variable names
customer_name = "John Doe"
order_quantity = 50

Poor examples:

# Unclear or ambiguous variable names
x = "John Doe" # Unclear what 'x' represents
q = 50 # Unclear what 'q' represents

๐Ÿงฉ Make meaningful distinctions.โ€‹

Good examples:

# Clear and distinct variable names
customer_name = "John Doe"
customer_address = "123 Main Street"
customer_city = "New York"

Poor examples:

# Unclear and indistinct variable names
customer = "John Doe"
address = "123 Main Street"
city = "New York"

๐Ÿ”  Use pronounceable names.โ€‹

Good examples:

# Pronounceable variable names
num_attempts = 3
max_retries = 5
username = "johndoe"
total_amount = 1000.0

Poor examples:

# Unpronounceable variable names
nattmpt = 3 # Difficult to pronounce
mxrt = 5 # Not easily pronounceable
usrn = "johndoe" # Difficult to read aloud
tamt = 1000.0 # Not easily pronounced

๐Ÿ” Use searchable names.โ€‹

Good examples:

# Searchable variable names
customer_list = []
product_inventory = {}
user_input = "..."
total_revenue = 10000

Poor examples:

# Less searchable variable names
lst = []
d = {}
inp = "..."
rev = 10000

๐Ÿงฎ Replace magic numbers with named constants.โ€‹

Good examples:

Widget image() {
const double imageMaxHeight = 100;
const double imageMaxWidth = 100;
const double smallPadding = 10;
const double smallRounding = 10;

return Padding(
padding: const EdgeInsetsDirectional.fromSTEB(smallPadding, smallPadding, smallPadding, 0),
child: ClipRRect(
borderRadius: BorderRadius.circular(smallRounding ),
child: Image.network(
'https://picsum.photos/seed/968/600',
width: imageMaxWidth,
height: imageMaxHeight,
fit: BoxFit.cover,
),
),
);
}

Poor examples:

Widget image() {
return Padding(
padding: const EdgeInsetsDirectional.fromSTEB(10, 10, 10, 0),
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Image.network(
'https://picsum.photos/seed/968/600',
width: 100,
height: 100,
fit: BoxFit.cover,
),
),
);
}

๐Ÿšซ Avoid encodings. Don't append prefixes or type information.โ€‹

Good examples:

# Avoiding encodings in variable names
customer_name = "John Doe"
order_quantity = 50
total_amount = 1000.0

Poor examples:

# Encoded variable names
strCustomerName = "John Doe"
intOrderQuantity = 50
floatTotalAmount = 1000.0

๐Ÿ’ฌ Comments and documentation:โ€‹

Encourage the use of comments and docstrings to explain the purpose of functions, classes, and complex algorithms. The emphasis is on providing clear and concise documentation that helps other developers understand the code quickly.

โœ… Good examplesโ€‹

  1. Function/Method Comments:

    # Calculate the sum of two numbers
    def calculate_sum(a, b):
    return a + b
  2. Explanation of Complex Logic:

    // Perform a binary search on the sorted array
    // Using divide and conquer strategy
  3. Documentation for Classes or Modules:

    /*
    This module handles user authentication
    Includes functions for user login, registration, and password reset.
    */
  4. TODO Comments for Future Work: Make sure that when you leave a TODO comment that the exacts on what is left to do is documented out side like on a issues item on gitlab. // TODO: (task #145) Implement feature to get info xyz faster.

โŒ Bad Examples:โ€‹

  1. Redundant Comments:

    // This function adds two numbers
    function add(a, b) {
    return a + b; // Add a and b
    }
  2. Outdated Comments that Do Not Reflect Code Changes:

    # This function will return the maximum value
    # Updated to return the minimum value for performance reasons
    def find_max_value(arr):
    return min(arr)
  3. Comments that Describe Obvious Code:

    // This is a for loop
    for (int i = 0; i < 10; i++) {
    // do something
    }
  4. Confusing or Misleading Comments: // This code doesn't work, but don't touch it

  5. Excessive Comments that Distract from the Code: // This is the beginning of the main logic for the user authentication system. // Here, we initialize the necessary variables and configure the environment settings. // ... (long, unnecessary comment block)

  6. TODO Comments for Future Work: Make sure when leaving a TODO comment that your task is complete end to end. // TODO: Implement error handling for edge cases. Make sure also that you revert any changes you ment to at the end of a task. // TODO: Revert routing back to home page.

โš™๏ธ Testing and quality assurance:โ€‹

Advocate for writing comprehensive tests to ensure the reliability and quality of the code. This includes writing unit tests, integration tests, and end-to-end tests to verify the functionality of the code and catch any potential issues early in the development process.

// Example of a Java class that implements recommended testing approach
public class MathOperations {
public int add(int a, int b) {
return a + b;
}

public int subtract(int a, int b) {
return a - b;
}
}

// Example of unit tests for the MathOperations class
import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class MathOperationsTest {
@Test
public void testAdd() {
MathOperations math = new MathOperations();
assertEquals(5, math.add(2, 3));
}

@Test
public void testSubtract() {
MathOperations math = new MathOperations();
assertEquals(2, math.subtract(5, 3));
}
}

// Example of integration test to ensure the proper interaction between components
public class IntegrationTest {
// Test the integration of MathOperations with other components
}

// Example of an end-to-end test to verify the overall functionality of the system
public class EndToEndTest {
// Test the complete system including user interactions and data flow
}

๐Ÿš€ Performance and efficiency:โ€‹

Places importance on writing code that is performant and efficient. This involves using appropriate data structures and algorithms, minimizing unnecessary computations, and optimizing code for speed and memory usage.

๐Ÿ› ๏ธ How can I optimize code easily.โ€‹

  1. Use Efficient Data Structures and Algorithms: Choose data structures and algorithms that are well-suited to the specific requirements of your program. Utilizing the right data structure or algorithm can significantly improve the performance of your code.

  2. Minimize Resource Usage: Avoid unnecessary memory allocations and deallocations, and release resources when they are no longer needed. This can prevent memory leaks and improve the overall efficiency of your code.

  3. Reduce Redundant Computations: Store the results of expensive computations or frequently used values to avoid redundant calculations. Caching results can help improve the performance of your code, especially in situations where the same computation is repeated multiple times.

  4. Optimize Loops and Iterations: Reduce the number of iterations wherever possible, and avoid performing heavy computations within loops. Additionally, use optimized looping constructs such as for loops instead of while loops.

  5. Asynchronous Operations: Utilize asynchronous programming to prevent blocking the main thread. This is particularly important for I/O-bound operations and can significantly improve the responsiveness of your application.

  6. Life Hack Write proper unit tests for a section of code you want to optimize. Make sure you have good code coverage. Make sure all edge cases are tested for. Then paste the ineffecient code into an LLM like chat GPT and asked to optimize it. Take the said unstable code and test it with unit tests. If all passes make sure the new logic make sense. When sending out a merge request point out that you used AI-code

// Example of optimizing the performance and efficiency of a web application
// Inefficient code that fetches data from a server on page load
function fetchData() {
// Make an API call to fetch data
// This can potentially slow down the page load time
}

// Optimized code that fetches data asynchronously after the page has loaded
async function fetchDataOptimized() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
// Process the data
} catch (error) {
// Handle errors appropriately
}
}

// Inefficient code that iterates over a large array
function processArray(array) {
for (let i = 0; i < array.length; i++) {
// Perform some processing on each element of the array
}
}

// Optimized code that uses array iteration methods for better performance
function processArrayOptimized(array) {
array.forEach((element) => {
// Perform optimized processing on each element of the array
});
}

๐Ÿ›ก๏ธ Error handling and robustness:โ€‹

Emphasizes the importance of handling errors gracefully and designing code that is robust and resilient. This involves implementing appropriate error-handling mechanisms, validating inputs, and providing meaningful error messages to users. Good Example:

// Good Example
public class FileHandler {
public void readFromFile(String fileName) {
try {
// Read from file
} catch (FileNotFoundException e) {
// Handle file not found error
System.err.println("File not found: " + fileName);
} catch (IOException e) {
// Handle other IO errors
System.err.println("Error reading from file: " + e.getMessage());
} finally {
// Close the file or release any resources
}
}
}

Bad Example:

// Bad Example
public class FileHandler {
public void readFromFile(String fileName) {
try {
// Read from file
} catch (Exception e) {
// Do nothing or print a generic error message
System.err.println("An error occurred while reading the file.");
}
}
}

๐Ÿ”’ Security:โ€‹

Emphasize writing code that is secure and resistant to common security vulnerabilities. This includes following best practices for handling sensitive data, preventing injection attacks, and implementing proper authentication and authorization mechanisms.

๐Ÿ“ˆ Scalability:โ€‹

Focuse on writing code that is scalable and maintainable over time. This involves designing modular and reusable components, minimizing dependencies, and following best practices for refactoring and code organization.

๐Ÿšฅ Lintsโ€‹

Code linting is the process of analyzing source code to identify potential errors, bugs, stylistic inconsistencies, and suspicious constructs. It checks for compliance with coding standards, best practices, and syntax rules specific to the programming language being used.

  1. ๐ŸŒŸ Ensures consistent coding style and readability.
  2. ๐Ÿ› Identifies errors and bugs early in the development process.
  3. ๐Ÿ“ Enforces best practices and coding standards.
  4. ๐Ÿ›ก๏ธ Mitigates security vulnerabilities and code smells.
  5. ๐Ÿ† Improves code quality and maintainability.
  6. ๐Ÿ‘ฅ Facilitates effective collaboration among team members.
  7. ๐Ÿค– Automates certain aspects of code reviews, saving time and effort.

๐ŸŽ›๏ธ Functions rules

  1. ๐Ÿ”ง Small.
  2. ๐Ÿ› ๏ธ Do one thing.
  3. ๐Ÿ“ Use descriptive names.
  4. ๐Ÿงฉ Prefer fewer arguments.
  5. ๐Ÿ™… Have no side effects.
  6. ๐Ÿšฉ Don't use flag arguments. Split method into several independent methods that can be called from the client without the flag.
# Example of a function that follows the specified rules

# Small, does one thing, and has a descriptive name
def calculate_total_price(items):
# Calculate the total price of items in a shopping cart
total_price = 0
for item in items:
total_price += item['price']
return total_price

# Function with fewer arguments and no side effects
def apply_discount(price, discount_percentage):
# Apply a discount to the price
discounted_price = price - (price * discount_percentage / 100)
return discounted_price

# Example of splitting a method without using flag arguments
class OrderProcessor:
def process_order(self, order_items):
# Process the order and perform necessary actions
self.validate_order_items(order_items)
self.update_inventory(order_items)
self.charge_customer(order_items)

def validate_order_items(self, order_items):
# Validate the items in the order
pass

def update_inventory(self, order_items):
# Update the inventory based on the order
pass

def charge_customer(self, order_items):
# Charge the customer for the order
pass

๐Ÿ—๏ธ Source code structureโ€‹

  1. ๐Ÿงฑ Separate concepts vertically.
  2. ๐ŸŒ Related code should appear vertically dense.
  3. ๐Ÿ”ค Declare variables close to their usage.
  4. ๐Ÿค Dependent functions should be close.
  5. ๐Ÿค Similar functions should be close.
  6. ๐Ÿ“ Place functions in the downward direction.
  7. ๐Ÿ“ Keep lines short.
  8. โ†”๏ธ Don't use horizontal alignment.
  9. ๐ŸŒŒ Use white space to associate related things and disassociate weakly related.
  10. โ›” Don't break indentation.
# Separate concepts vertically
shopping_cart = []
inventory = []

# Related code appearing vertically dense
def add_item_to_cart(item):
shopping_cart.append(item)

def remove_item_from_cart(item):
if item in shopping_cart:
shopping_cart.remove(item)

# Declare variables close to their usage
def process_order():
total_price = calculate_total_price(shopping_cart)
apply_discount(total_price)

# Dependent functions are close
def calculate_total_price(items):
total_price = 0
for item in items:
total_price += item['price']
return total_price

def apply_discount(price):
# Apply discount to the price
pass

# Similar functions are close
def validate_order():
pass

def update_inventory():
pass

# Place functions in the downward direction
def main():
process_order()
validate_order()
update_inventory()

# Keep lines short and avoid horizontal alignment
long_variable_name = 20
short_name = 5

# Use white space to associate related things and disassociate weakly related
def check_inventory(item):
if item in inventory:
return True
return False