前言

「讓 AI 幫忙寫程式碼」的人越來越多了。

我也是這樣的工程師之一,不過在讓 AI 寫程式碼時,我常常會覺得:「應用程式本體的程式碼還好,但程式碼註解和測試程式碼總覺得不太對勁。」

另外,在做程式碼審查時,我也越來越常看到這樣的情況:「大概是把 AI 寫的註解直接採用了吧~」

因此,這篇文章要列出最近在程式碼審查中指出的 9 種「不太理想的程式碼註解」。
(至於不太理想的測試程式碼,我想改天再另外寫一篇)

另外,程式碼範例雖然是用 Ruby 寫的,但概念在其他語言也一樣。
所有範例程式碼都是為了說明而製作的虛構內容。

1. 註解了「看程式碼就知道」的內容

不只是 AI 寫的註解,「看程式碼就知道」的事情本來就不需要寫成註解留下來。

# ❌ BAD(做了什麼看程式碼就知道)

def total_price
  # 單價 x 數量的總和作為總金額回傳
  items.sum { |item| item.unit_price * item.quantity }
end
# ✅ GOOD(不要寫註解!)

def total_price
  items.sum { |item| item.unit_price * item.quantity }
end

如果真的要留註解,也請限定在回答讀者「為什麼要這樣做?」的內容。

# ✅ GOOD

def total_price
  # unit_price 有時會包含小數,
  # 因此轉成 BigDecimal 以避免四捨五入誤差
  items.sum { |item| item.unit_price.to_d * item.quantity }
end

2. 註解的位置(行數)不對

註解基本上要寫在「想要說明的程式碼前一行」。

因此,方法定義前面應該寫的是該方法的概要。
像下面這樣,把方法內某個特定處理寫在方法定義前面,就有點奇怪。

# ❌ BAD(「累了就不做任何事」是 play_guitar 方法的概要??)

# 累了就不做任何事
def play_guitar
  return if tired?

  guitar.play
end

註解要遵守「寫在想要說明的程式碼前一行」這個原則。
所以,下面這樣寫才是正確的。

# ✅ GOOD

def play_guitar
  # 累了就不做任何事
  return if tired?

  guitar.play
end

(另一種解法)如前所述,「看程式碼就知道的資訊」本來就不需要寫成註解留下來!

# ✅ GOOD(看得出來的程式碼就不需要註解!)

def play_guitar
  return if tired?

  guitar.play
end

3. 註解內容只在規格被修改的那一刻才有意義

請看下面這段註解。

# ❌ BAD

def ride_bike(rider)
  # 騎腳踏車時必須戴安全帽
  raise NoHelmetError unless rider.with_helmet?

大概是在某個時間點,對既有程式碼新增了「必須戴安全帽」的檢查。
但是,上面這段註解只在「安全帽從可選變成必須的那一刻」才有意義。

如果每次規格從「A 變成 B」時,都把這種變化一條一條寫進註解裡,程式碼就會變成滿滿都是註解。

這種變更內容應該寫在 commit 訊息或 Pull Request 說明欄,而不是寫成程式碼註解。

除非有特別的理由或目的,否則沒有必要特地把「新規格」寫成註解留下來。

# ✅ GOOD(不需要特地把變更後的規格寫成註解留下來)

def ride_bike(rider)
  raise NoHelmetError unless rider.with_helmet?

4. 太過度關注呼叫方式或被呼叫的地點

例如,如果有一個 cancel_payment 方法,程式碼讀者只要知道「呼叫這個方法就能取消扣款」就夠了。

但有時候會很仔細地註解「這個方法什麼時候、在哪裡、在什麼情況下、為了什麼目的被呼叫」。

# ❌ BAD

# FooController 和 BarController 在...時
# 可能會...,所以在...之前先取消扣款
def cancel_payment

像上面那樣把呼叫方式或被呼叫的地點寫進註解後,當呼叫這個方法的地方增加時,就得一直補充這段註解。

這實在太沒意義了,所以不需要把呼叫方式或被呼叫的地點寫成註解留下來。

# ✅ GOOD(不要把呼叫方式或被呼叫的地點寫成註解)

def cancel_payment

如果真的需要註解,就寫在呼叫這個方法的一側。

class FooController < ApplicationController
  def destroy
    # 因為...的情況下可能會...,所以在...之前先取消扣款
    cancel_payment

    # ...
  end
end

5. 註解和程式碼用語沒有對應上

如果用了程式碼中沒有出現的字詞或術語,讀的人會一瞬間不知道你在講什麼。

# ❌ BAD(咦,「humbucker」是什麼??)

# 如果是 humbucker,就比較不會有雜訊,所以很安心
use(:noise_suppressor) if guitar.pickup == :single_coil

請讓程式碼和註解的用語好好對應起來。

# ✅ GOOD

# 單線圈容易有雜訊,所以用降噪器來抑制雜訊
use(:noise_suppressor) if guitar.pickup == :single_coil

6. 日文不自然,讓人看不懂

即使看起來像樣的註解,仔細一讀也常常會覺得「咦?好像不太通順??」

# ❌ BAD

def prepare_for_cancel
  # 取消時會停止草稿訂單的確認與自動續訂,所以對草稿訂單不做任何事
  return if draft?

上面的句子不太清楚到底是「把草稿訂單確定下來,並停止自動續訂」,還是「停止草稿訂單的確定,並且停止自動續訂」。
而且如果是後者,「停止確定」這種說法本身也不太自然。

不要只匆匆看過去就想著「大概沒問題吧」,而是要確認這段話在中文裡是否真的能清楚傳達意思。
如果有不自然的中文,就應該由人負責重新改寫。

# ✅ GOOD

def prepare_for_cancel
  # 草稿訂單在取消時會自動刪除,也不會產生扣款,所以對草稿訂單不做任何事
  return if draft?

7. 因為註解反而使疑慮更深

如果你看到這種註解,會怎麼想呢?

# ❌ BAD 

# 這個類別在畫面上沒有被使用
class Attachment < ApplicationRecord

「如果畫面上沒用到,那是在哪裡用到的?」或是「如果完全沒人用這個類別,那是不是該刪掉?」是不是會冒出這些疑問?(我會)

寫註解時,要想像讀到這段註解的人會產生什麼疑問,並把內容再往前推一步。

# ✅ GOOD

# 雖然畫面上已不再使用,但為了保留過去登錄的資料,
# 仍保留這個模型與資料表
class Attachment < ApplicationRecord

8. 幾乎相同的內容寫在 2 個地方

有時候會看到呼叫端和被呼叫端都寫了幾乎一樣的註解。

# ❌ BAD

class Account
  # 刪除帳號時也會取消扣款
  after_destroy :cancel_payment

  # ...

  # 刪除帳號時也會取消扣款
  def cancel_payment
    # ...
  end
end

通常只要其中一邊有寫就夠了,所以把多餘的註解刪掉吧。

# ✅ GOOD

class Account
  # 刪除帳號時也會取消扣款
  after_destroy :cancel_payment

  # ...

  def cancel_payment
    # ...
  end
end

其實,上面的註解看程式碼就能懂;如果測試程式碼已經把規格寫清楚,那這樣也就足夠了。

# ✅ GOOD(不是在應用程式碼裡寫註解,而是用測試把規格明文化)

class Account
  after_destroy :cancel_payment

  # ...
end

describe '#destroy' do
  example '刪除帳號時也會取消扣款' do
    # ...
  end
end

9. 註解與類別職責或關注點相差太遠

Rails 的模型類別基本上應該是獨立於畫面(view)和控制器的存在。
也因為這樣,模型類別才會更有重用性。

如果在模型裡寫太多「畫面上會怎麼用」、「控制器裡會怎麼用」這類細節,模型和畫面、控制器之間就會看起來像是緊密耦合在一起。

# ❌ BAD(模型裡寫了畫面的事情)

class Guitar < ApplicationRecord
  # 在編輯畫面中會依照...切換顯示內容
  BODY_TYPES = %w(solid flat_top archtop)
end

當然,有些情況下,把畫面或控制器的考量寫進模型,反而會更容易理解程式碼;但除非真的「非這麼做不可」,否則還是不要把畫面或控制器的事情寫進模型裡。

# ✅ GOOD(模型不需要在意畫面或控制器的考量)

class Guitar < ApplicationRecord
  BODY_TYPES = %w(solid flat_top archtop)
end

結語

總之,這篇文章整理了 AI 常見的 9 種「不太理想的程式碼註解」。

讓 AI 寫程式碼時,常常會出現一些「看起來像那麼回事」或「表面上好像沒問題」的註解,散落在各處。

但仔細一讀,會發現很多其實「怪怪的」或「根本不需要註解」。
AI 很容易寫出一堆多餘的註解,所以對 AI 寫的註解,基本上還是先抱持懷疑態度比較好。

不太理想的註解,不只只是噪音,還會讓程式碼更難理解。

對策之一是,把這篇文章餵給 AI,讓它整理成像 CLAUDE.md 這類規則。
這樣應該能降低 AI 寫出奇怪註解的機率。

不過,AI 不一定會 100% 遵守這些規則,而且除了這 9 種以外,還是可能會寫出其他「不太理想的註解」。
所以不要因為訂了規則就過度相信,最後還是一定要由人來做審查。

如果這篇文章能成為你重新檢視自己或 AI 寫的註解的契機,那就太好了!

延伸閱讀

我認為,程式碼註解的基本思考方式,不論是 AI 寫還是人類寫,原則上都不會改變。


原文出處:https://qiita.com/jnchito/items/636c519c0b1d347c79b7


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝6   💬1   ❤️1
258
🥈
boluoji
📝8   💬2   ❤️3
161
🥉
mike
1
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登