Clean code
  • Overview
    • Introduction
    • Why is clean code so important?
    • What Is Clean Code?
    • How to write clean code?
    • Conventions
  • The key principles of clean code
    • Meaningful Names
    • Functions
    • Classes
    • Comments
    • Error Handling
      • Exception handling best practices
    • Unit Tests
    • Formatting
    • Objects and Data Structures
    • Simple Design Rules
    • Concurrency
    • Code Smells
  • Building Maintainable Software
    • Write Short Units of Code
    • Write Simple Units of Code
    • Write Code Once
    • Keep Unit Interfaces Small
    • Write Clean Code
    • Automate Tests
  • Bonus
    • SOLID Principle
      • SRP - Single Responsibility Principle
      • OCP - Open-Closed Principle
      • LSP - Liskov Substitution Principle
      • ISP - Interface Segregation Principle
      • DIP - Dependency Inversion Principle
    • LoD Principle
    • YAGNI Principle
    • DRY Principle
    • Fail Fast principle
    • Hollywood Principle
    • Library vs Framework
    • Coupling and Cohesion
    • AOP - Aspect-Oriented Programming
      • Building an AOP framework
    • OOP Design Pattern
    • Technical Dept
    • How to learn software Design and Architecture - Roadmap
    • Microservcies
      • Defining the scope of a microservice
      • Step-by-Step: How to Identify Over-Scoped Microservices
      • Benefits of Grouping or Consolidating Microservices
      • A practical step-by-step plan to consolidate microservice
Powered by GitBook
On this page
  • Vertical Openness Between Concepts
  • Use vertical density for tightly related concepts
  • Place dependent functions vertically close
  • Declare variables vertically close to their usage
  • Use horizontal separation and density so that code reads nicely
  • Horizontal Alignment
  • Breaking Indentation
  • Team Rules
  1. The key principles of clean code

Formatting

Code formatting is important.

Vertical Openness Between Concepts

Each blank line is a visual cue that identifies a new and separate concept.

There are blank lines that separate the package declaration, the import(s), and each of the functions.

package com.gpcoder;

import java.io.BufferedReader;

public class Example {

    public static final String FILE_NAME = "user.csv";
    public static final String CSV_SEPARATOR = ",";

    public void method1() {
    }

    public void method2() {
    }

}

Use vertical density for tightly related concepts

Lines of code that are tightly related should appear vertically dense.

The useless comments break the close association of the two instance variables.

/**
    * The class name of the reporter listener
    */
   private String className;
   
   /**
    * The properties of the reporter listener
    */
   private List<Property> properties = new ArrayList<>();

   public void addProperty(Property property) {
       properties.add(property);
   }
private String className;
private List<Property> properties = new ArrayList<>();

public void addProperty(Property property) {
    properties.add(property);
}

Place dependent functions vertically close

If one function calls another, they should be vertically close, and the caller should be above the callee.

public void createUser(UserDto userDto) {
    validateUser(userDto);
    userRepository.saveUser(userDto);
    sendEmailNotification(userDto);
}

public void deleteUser(Long userId) {
    if (isUserInUse(userId)) {
        throw new UserInUseException();
    }
    userRepository.deleteUserById(userId);
}

private void sendEmailNotification(UserDto userDto) {
}

private boolean isUserInUse(Long userId) {
}

private void validateUser(UserDto userDto) {
}

public void createUser(UserDto userDto) {
    validateUser(userDto);
    userRepository.saveUser(userDto);
    sendEmailNotification(userDto);
}

private void validateUser(UserDto userDto) {
}

private void sendEmailNotification(UserDto userDto) {
}

public void deleteUser(Long userId) {
    if (isUserInUse(userId)) {
        throw new UserInUseException();
    }
    userRepository.deleteUserById(userId);
}

private boolean isUserInUse(Long userId) {
}

Declare variables vertically close to their usage

public UserStatisticResponse userStatistics(List<User> users) {
    UserStatisticResponse response = new UserStatisticResponse();
    List<User> admins = new ArrayList<>(); 
    List<User> guests = new ArrayList<>();
    for (User user : users) {
        if (isAdmin(user)) {
            admins.add(user);
        } else {
            guests.add(user);
        }
    }
    response.setAdmins(admins);
    response.setGuests(guests);
    return response;
}
public UserStatisticResponse userStatistics(List<User> users) {
    List<User> admins = new ArrayList<>();
    List<User> guests = new ArrayList<>();
    
    for (User user : users) {
        if (isAdmin(user)) {
            admins.add(user);
        } else {
            guests.add(user);
        }
    }

    UserStatisticResponse response = new UserStatisticResponse();
    response.setAdmins(admins);
    response.setGuests(guests);
    return response;
}

Use horizontal separation and density so that code reads nicely

We use horizontal white space to associate things that are strongly related and disassociate things that are more weakly related.

private void measureLine(String line) { // 1
    lineCount++;
    int lineSize = line.length(); // 2
    totalChars += lineSize;
    lineWidthHistogram.addLine(lineSize, lineCount); // 3
    recordWidestLine(lineSize);
}
  • (1) I didn’t put spaces between the function names and the opening parenthesis. This is because the function and its arguments are closely related. Separating them makes them appear disjoined instead of conjoined.

  • (2) I surrounded the assignment operators with white space to accentuate them. Assignment statements have two distinct and major elements: the left side and the right side

  • (3) I separate arguments within the function call parenthesis to accentuate the comma and show that the arguments are separate.

Horizontal Alignment

public class FitNesseExpediter implements ResponseSender {
     private   Socket           socket;
     private   InputStream      input;
     private   OutputStream     output;
     private   Request          request;
     private   Response         response;
}
public class FitNesseExpediter implements ResponseSender {
    private Socket socket;
    private InputStream input;
    private OutputStream output;
    private Request request;
    private Response response;
}

Breaking Indentation

public class CommentWidget extends TextWidget {

     public static final String REGEXP = "^#[^\r\n]*(?:(?:\r\n)|\n|\r)?";

     public CommentWidget(ParentWidget parent, String text){super(parent, text);}

     public String render() throws Exception {return ""; }

}
public class CommentWidget extends TextWidget {

    public static final String REGEXP = "^#[^\r\n]*(?:(?:\r\n)|\n|\r)?";

    public CommentWidget(ParentWidget parent, String text) {
        super(parent, text);
    }

    public String render() throws Exception {
        return "";
    }
}

Team Rules

Every programmer has his/her own favorite formatting rules, but if he/she works in a team, then the team rules.

A team of developers should agree upon a single formatting style, and then every member of that team should use that style. We want the software to have a consistent style. We don’t want it to appear to have been written by a bunch of disagreeing individuals.

The rules we should follow are coding standards documents:

PreviousUnit TestsNextObjects and Data Structures

Last updated 2 years ago

Many IDEs support coding style checking, the team can define the coding style template and share it to all team members. Refer to development tool.

Google Java Style Guide
Java Code Conventions by Oracle
Checkstyle