Khi coding là bộ môn nghệ thuật!

Nhân tiện hôm qua có ông anh CTO đẹp trai nhắc đến clean code, lại nhớ đến những anh em đồng nghiệp cũ nhờ mình chia sẻ kỹ năng này, phải nói thật là mình cũng chẳng biết mô tả ra làm sao, và mình cũng không dám nhận là code của mình đã clean hay chưa, nhưng thôi, cứ chia sẻ liều vậy, 😃

Một đoạn code chưa "sạch"

Chúng ta hãy nhìn vào 1 đoạn code ở Github như này:

public String determineTargetUrl(Authentication authentication) {
    String url = "";
    List<String> roles = SecurityUtils.getAuthorities();
    if (isManager(roles)) {
        url = "/manager";
    } else if (isAdmin(roles)) {
        url = "/admin";
    } else if (isUser(roles)) {
        url = "/user";
    }
    return url;
}
private boolean isUser(List<String> roles) {
    if (roles.contains("USER")) {
        return true;
    }
    return false;
}
private boolean isAdmin(List<String> roles) {
    if (roles.contains("ADMIN")) {
        return true;
    }
        return false;
    }
private boolean isManager(List<String> roles) {
    if (roles.contains("MANAGER")) {
        return true;
    }
    return false;
}

Ý của đoạn code này là ứng với từng role thì sẽ có thể vào được các url khác nhau, nhưng chúng ta hãy cùng nhìn xem đoạn code này có vấn đề gì nhé.

  1. Thừa Authentication authentication
  2. Hardcode các url
  3. Trong một hệ thống sẽ có rất nhiều role nên việc sử dụng if else sẽ vị phạm nguyên tắc #OpenClose
  4. Còn gì nữa không nhỉ? anh em để lại comment nhé

Tiến hành clean

Chúng ta đã nhìn thấy 3 vấn đề chính, giờ thì hãy bắt tay vào #cleancode nào.

  1. Bỏ Authentication thừa đi
  2. Định nghĩa enum cho các role
  3. Map các enum với các url trực tiếp vào lớp enum, map qua file hoặc qua database, nhưng để cho đơn giản mình sẽ map trực tiếp vào enum

Giải quyết cả 3 vấn đề chúng ta sẽ có được source code sạch bong kin kít

public String determineTargetUrl() {
    return SecurityUtils.getAuthorities()
        .stream()
        .map(Role::valueOf)
        .sorted()
        .findFirst().get().getTargetURL();
}
public enum Role {

    MANAGER("/manager"),
    ADMIN("/admin"),
    USER("/user");

    @Getter
    String targetURL;

    private Role(String targetURL) {
        this.targetURL = targetURL;
    }
}

Bạn thấy không, số lượng dòng code đã giảm đi đáng kể, code đã gọn gàng và dễ hiểu hơn rất nhiều.

Những yêu cầu kỹ thuật

Clean code giống như là một bộ môn nghệ thuật vậy, thật khó có thước đo thế nào là code đã clean hay chưa nhưng theo mình nó cần thoả mãn được một số yêu cầu:

  • Code nên tuân thủ theo các nguyên tắc S.O.L.D (#SOLID)
  • Code được chia thành các tầng riêng biệt và kết nối với nhau thông qua thừa kế hay #Composite #designpattern
  • Code nên áp dụng các design pattern để cho mềm dẻo và dễ mở rộng về sau này
  • Còn gì nữa không nhỉ? nghĩ ra mình sẽ bổ sung nhé

Tổng kết

Clean code yêu cầu bạn phải code nhiều, trải nghiệm nhiều qua các ngôn ngữ khác nhau, framework khác nhau và điều quan trọng là bạn phải trải qua các dự án thực tế. Bạn cũng cần có được khả năng chịu đựng khi bi người khác nhận xét, góp ý, và quan trọng nhất bạn phải là người mang trong mình tâm thế cầu tiến.

Đã có nhiều anh em ở đây thấy mình và đã cùng mình đi clean code của các dự án, anh em sẽ hiểu là nó không đơn giản chút nào, nên mình sẽ có thêm những bài viết về clean code nữa thông qua việc sửa đổi những đoạn code có trên Github nhé, 🙂

Anh em cũng đừng ngại ngần nếu cần mình tư vấn để clean code hiện tại của anh em nhé, 🙂

Tham khảo

  1. Sách
  2. Ví dụ