+1

Fine-grain refactoring deep dive (7) - Comment.

1. Introduction

In computer programming, a comment is a programmer-readable explanation or annotation in the source code of a computer program. They are added with the purpose of making the source code easier for humans to understand, and are generally ignored by compilers and interpreters.

Trong lập trình, comment là lời giải thích hoặc chú thích mà lập trình viên dễ dàng hiểu được trong mã nguồn của chương trình máy tính. Chúng được thêm vào với mục đích làm cho mã nguồn dễ hiểu hơn đối với con người, và thường bị các trình biên dịch và thông dịch bỏ qua.

Chúng ta sẽ kiểm tra lý thuyết trên thông qua Java class sau:

public class Comment {
	//Hello, I'm Logbasex.
	public static void main(String[] args) {}
}

Nếu bạn tiến hành disassemble class này trong trường hợp có comment và không có comment thì bạn sẽ thấy cả hai đều cho ra cùng một kết quả. Từ đấy chúng ta có thể khẳng định rằng việc comment không hề ảnh hưởng đến performance của code.

$ javac Comment.java
$ javap -v Comment.class

Classfile /home/logbasex/IdeaProjects/java-demo/src/Comment.class
  Last modified Mar 7, 2022; size 259 bytes
  MD5 checksum d87a21ec88edb7b9ce782875eaef27d2
  Compiled from "Comment.java"
public class Comment
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#12         // java/lang/Object."<init>":()V
   #2 = Class              #13            // Comment
   #3 = Class              #14            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               main
   #9 = Utf8               ([Ljava/lang/String;)V
  #10 = Utf8               SourceFile
  #11 = Utf8               Comment.java
  #12 = NameAndType        #4:#5          // "<init>":()V
  #13 = Utf8               Comment
  #14 = Utf8               java/lang/Object
{
  public Comment();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 4: 0
}
SourceFile: "Comment.java"

2. Two bits of history

Nghe nói comment ra đời trong một đêm mưa gió, khi một tập tin hello.asm được viết như sau:

          global    _start

          section   .text
_start:   mov       rax, 1             
          mov       rdi, 1                  
          mov       rsi, message            
          mov       rdx, 13                 
          syscall                           
          mov       rax, 60                 
          xor       rdi, rdi                
          syscall                           

          section   .data
message:  db        "Hello, World", 10      

Bạn thường được bảo rằng, comment explain WHY, not HOW, nhưng có vẻ với assembly code thì HOW lại là một điều cần thiết.

; ----------------------------------------------------------------------------------------
; Writes "Hello, World" to the console using only system calls. Runs on 64-bit Linux only.
; To assemble and run:
;
;     nasm -felf64 hello.asm && ld hello.o && ./a.out
; ----------------------------------------------------------------------------------------

          global    _start

          section   .text
_start:   mov       rax, 1                  ; system call for write
          mov       rdi, 1                  ; file handle 1 is stdout
          mov       rsi, message            ; address of string to output
          mov       rdx, 13                 ; number of bytes
          syscall                           ; invoke operating system to do the write
          mov       rax, 60                 ; system call for exit
          xor       rdi, rdi                ; exit code 0
          syscall                           ; invoke operating system to exit

          section   .data
message:  db        "Hello, World", 10      ; note the newline at the end

Bởi vì cú pháp của ngôn ngữ không gần với ngôn ngữ tự nhiên nên là việc xử lý thông tin với bộ não thông thường sẽ gặp delay, đó cũng là lý do dẫn đến sự ra đời của những ngôn ngữ bậc cao sau này.

Bonus một ví dụ comment assembly code bằng high-level code =)) Thật không thể tin được 😂😂😂😂.

Nếu bạn muốn tìm hiểu thêm về lịch sử ra đời của comment thì có thể xem thêm ở đâyđây.

3. Issue

Sau khi có sự xuất hiện ngôn ngữ lập trình bậc cao, chúng ta có thể viết những đoạn code khá mượt mà và trực quan như sau:

private static final int EMPLOYEE_BONUS_PERCENTAGE = 10/100;
	
public void calculateBonus() {
    List<Employee> employees = getAllEmployees();
    for (Employee employee : employees) {
        if (employee.getType() == EmployeeEnum.MANAGER.getType()) {
            employee.setBonus(employee.getWage() * EMPLOYEE_BONUS_PERCENTAGE);
        }
    }
}

Không cần phải là chuyên gia thì bạn cũng dễ dàng nắm được đoạn code này làm cái gì rồi đúng không?

Trong tất cả các nhân viên, tìm ra những ai là quản lý và cấp cho họ khoản bonus tương ứng 10% tiền lương.

Tuy nhiên vấn đề ở đây đó chính là nhiều tháng sau, khi bạn quay lại maintain đoạn code này, bạn không biết tại sao lại có con số 10% cả.

Úi giời dễ, bạn bảo rằng bạn sẽ tìm người đã viết đoạn code này để hỏi, nhưng hồi đó còn chưa có git blame, chỉ có copy rồi patch code qua USB hay cái gì đó tương tự thôi 🤣🤣 .

// ********************************************************************
// * Logger helper                                                    *
// *                                                                  *
// * 2005-03-01 First Version, Anders Abel                            *
// * 2007-08-17 Added Console Output, Anders Abel                     *
// * 2009-12-15 Removed file output, John Doe                         *
// *                                                                  *
// * Usage: Call Logger.Write() with string to be logged.             *
// ********************************************************************
public static class Logger { 

}

Thế thì bạn sẽ hỏi QA, Manager...kiểu gì cũng có người biết. Đồng ý là vấn đề của bạn sẽ được giải quyết nhưng đáng ra bạn sẽ tiết kiệm được thời gian nếu như đoạn code đó có một vài comment chẳng hạn. Nhưng đối với những đoạn tricky/clever code thì sẽ khó có ai giúp bạn hiểu được nếu như người viết đoạn code đó đã ra đi...

{ 
  { 
    while (.. ){ 
      if (..){
          }
      for (.. ){ 
          }
         .... (just putting in the control flow here, imagine another few hundred ifs)
      if(..)   {
            if(..)     {
                   if(..)   {
                ...
                (another few hundred brackets)
                       }
                  }
         } //endif

Thật là mệt mỏi 🥲🥲🥲. image.png

4. Solution

  1. Trong Employee class có một trường type nhưng bạn không biết trường này định nghĩa cái gì, bao gồm những giá trị nào thì hãy dùng javadoc để reference đến enum của nó:
    /**
     * {@link com.logasex.enums.EmployeeEnum}
     */
    @Field(FieldConst.TYPE)
    private String type;
    
  2. Con số 10% được định nghĩa rõ ràng trong Jira ticket, vậy làm sao để comment như một hyper link?
    /**
     * {@link <a href="https://logbasex.atlassian.net/jira/software/c/projects/logbasex/boards/127?modal=detail&selectedIssue=logbasex-2949&assignee=5cf483a4757e4b0f2636c4c0"></a>}
     */
    private static final int EMPLOYEE_BONUS_PERCENTAGE = 10/100;
    
  3. Phương tính tính bonus và wage có sự liên quan chặt chẽ nhưng không gọi trực tiếp đến nhau, vậy thì làm sau để biểu diễn điều đó qua comment? Thật may mắn là javadoc đã support reference method với syntax như sau: image.png
    /**
     * {@link com.logbasex.WageServiceImpl#calculateWage()}
     */
    public void calculateBonus() {}
    

    Với những IDE hiện đại thì bạn có thể chuyển đến bất cứ reference link nào chỉ với một cú nhấp chuột. Thật là tiện lợi phải không?

5. Best practices

Trong trường hợp trên mình đang giả định là chúng ta đã có một đoạn code rõ ràng, dễ hiểu, tuy nhiên trong thực tế nhiều lúc sẽ không đạt được trạng thái lý tưởng đó. Vậy nên chúng ta cần một số kinh nghiệm để viết comment một cách hợp lí, tránh việc comment bừa bãi vừa làm ô nhiễm source code, vừa làm tăng cognitive complexity khiến bạn tốn thời gian không cần thiết cho việc đọc hiểu.

“Every time you write a comment, you should grimace and feel the failure of your ability of expression.” — Robert C. Martin

Good codes have rhythm while mediocre codes have a lot of pauses ... by comments.

Communicate via your codes, not your comments.

Code comment is a smell. If you write code comments as the last option to improve your code, it will force you to improve your self-documenting skills first. That's why it should be considered a smell.

Keep comment up to date. “Code never lies, comments sometimes do.” — Ron Jeffries

Self-documented code over comprehensive comments.

“Don’t comment bad code explaining what is happening, Rewrite it!”

“The only best comment is the comment you found a way not to write.”

Comments should describe the intended outcome of the code in a language-agnostic fashion. It should not restate the code itself.

One should be able to completely re-implement the code in any language, given only the comments. In other words, your intent comments are a living specification!

I don’t comment my code because if it was hard to write, then it should also be hard to read

image.png

image.png,.

References


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.