築夢角落

致力於用最生活化的例子讓所有人都能懂程式,也喜歡分享動漫、小說心得,以及自己的所見所聞、所思所想。

【思辨】要不要寫註解?先思考過去的工程師為什麼開始寫註解

最後更新時間 : 2022-05-06 | viewed : 1005

 

要不要寫註解似乎是一個頗具爭議的問題,然而這種問法容易導致「要寫」或「不寫」成為唯二可能的選項,每個人都有自己的看法或經驗能支持他們的立場,有些立場比較堅定的人,甚至會指責別人「為什麼都不寫註解」或「為什麼要寫一堆註解」。

要回答這個問題,可以先想想「為什麼程式有註解功能」

 

為什麼程式有註解功能?


在程式的世界裡,沒有任何一個功能是天上掉下來的,如果你不動手打造,就不會有那個功能的存在。

顯然地,註解這個功能也是被人打造出來的,因為編譯器、直譯器、寫程式用的編輯器或IDE,都不是天生就能分辨程式碼跟註解的區別。

但是,為什麼需要註解呢?我認為這和組合語言有關

組合語言和高階語言不同,它的語義很薄弱,程式碼幾乎都靠低階邏輯組成,我們可能要看了10行程式碼之後,才能推敲出這是一個把整數變數遞增的迴圈,這時候如果有註解就能幫大忙了。

相較之下,高階語言的語義就強了很多,看到for就知道是迴圈,看到i++就知道是將整數變數遞增。

 

高階語言還需要註解嗎?


高階語言讓程式碼開始出現語義,並且盡可能貼近人類的自然語言,這讓工程師能用抽象思維去處理更複雜的事情。

既然程式碼的語義已經如此清楚,那還需要再加註解、把顯而易見的事實重述一遍嗎?更別說註解還可能會寫錯?

要回答這個問題,讓我們先想想上面組合語言的例子。

組合語言裡的註解,並不是用來解釋程式碼的邏輯,而是用來表達這段程式碼的意圖

程式語言也是語言,而且組合語言自身就能充份表達邏輯,但是這種低階邏輯本身卻無法表達意圖

即使是高階語言,依然會遇上不能充份表達意圖的情況,這或許就是為什麼每個程式語言都被設計成能寫註解的理由。

 

註解扮演的角色


讓我們回想一下以往看過的偵探劇,即使兇手的手法再高明,偵探還是能將零碎的線索關聯起來,推理出犯案手法、還原案發現場,找出真兇。

問題在於,動機呢

即便已經推理出案發經過,也找出真兇了,但是犯案動機卻不一定能被偵探推理出來,有時必須由兇手自己說明才行。這是因為無論是誰有什麼樣的動機,都能採取相同的犯案手法,所以無法從手法反推出動機

當我們在閱讀別人寫的程式時,就有點像是在扮演一名偵探,整個程式專案就像是案發現場,我們迫切地想知道這些程式碼都在做什麼,但即使我們能推敲出程式本身做了什麼,卻未必能知道兇手(當初寫這段程式的人)的動機。

作為兇手(現在要寫下這段程式的人),如果知道自己的動機無法從程式碼上看出來而且程式碼對自我的描述也已經很完整,那很可能表示你遇到了「意在言外」的情況,寫下註解應該會是個好選擇,不僅能還偵探們一個真相,同時也有助於未來的自己回頭修改時能更加順利。

畢竟從程式碼上看不出動機,那要是忘記當初寫下這段程式的動機,想回頭修改時可能也會碰上麻煩。

 

看個程式例子


雖然高階語言已經能透過語義表達意圖,但有時會有「意在言外」的情況,加上註解能更好地理解程式碼的目的。

比如我寫了一個swap函式:

function swap(a, b) {
    let temp = a;
    a = b;
    b = temp;
 }

它接受a、b兩個參數,功能是將a、b的值互換,這個從函式命名跟程式邏輯很容易就能看出來,自然沒有為swap函式寫註解的必要。

可是從外部呼叫swap函式的程式區段呢?A程式區段呼叫swap的目的,跟B程式區段呼叫swap的目的,可以是完全不同的。

「交換」僅僅是一種表層行為,但交換的理由卻有百百種,不見得每次都能看出來。

 

換言之,swap函式的意圖是交換,但呼叫swap的程式區段有什麼更崇高的意圖卻未必顯而易見。

既然「意」在「言」外,用註解把「意圖」寫在「程式語言」之外,就能幫助任何人(包括未來的自己)更容易看懂程式了。

 

如果硬是為了不寫註解,把swap重新命名成意圖更明確的用語,比如swapForSort(為了排序而交換),那麼當其他程式段呼叫swapForSort的目的不是為了排序時,反而容易誤導人,也讓這個用於「交換」的函式變得很專用,難以通用。

 

如果註解寫錯誤導人怎麼辦?


註解詞不達意,或是程式碼修改了,註解卻沒跟著修改,導致註解是錯的,這種情況應該時不時會發生。

但這不表示要因噎廢食,註解仍然有它存在的意義。

如果是閱讀別人的程式碼,其實只要改變一下閱讀的順序,問題就會減小很多。

一開始先不要管註解,直接閱讀程式碼,從程式碼去推敲整體目的,等到心裡已經有底之後,再去細看註解都寫了什麼

這時候,如果註解寫得好,就對我們有助益,如果註解寫得不好,對我們也沒有影響。

 

寫註解是因為程式碼寫得太爛?


看過有些人主張「寫註解是因為程式碼寫得太爛,寫得好的程式碼不需要註解,因為程式碼本身就是最好的註解」,雖然這種說法有它的合理性,但把這個理念奉為最高準則卻顯然不合理

因為這種主張意味著,程式碼跟註解是運作在同一個層級上,但事實並非如此。程式碼是需要被執行的語言,註解是不該被執行的語言,不論誰的層級高、誰的層級低,終歸不是同一個層級,它們在本質上就有所不同

這正好解釋了「程式修改了,註解卻沒跟著修改,導致註解錯誤」的問題是怎麼發生的。因為在程式碼的思想層級寫註解,會導致註解跟程式碼高度耦合,一旦程式碼修改,註解也不得不跟著修改。

 

所以到底要不要寫註解呢?


這讓我想起一句話:「我們面對的重大問題,永遠不能在產生問題本身的層次上被解決。」這句話似乎是出自愛因斯坦。

我認為寫不寫註解不是一個選擇題,真正的問題應該是什麼事情應該用註解來寫

因為意圖是有分層次的,當程式語言的層次無法表述更崇高的意圖時,就需要靠註解來完整它。如果註解只是把程式碼的語義再描述一遍,那確實沒有太大的意義。

這裡讓我們想像一下寫組合語言的情況。

對人腦來說,低階邏輯很不直覺,過去的工程師用組合語言寫程式,時常寫錯是在所難免,但即使程式碼寫錯了,只要註解寫對,其他工程師明白這段程式碼的真正意圖,就能幫忙修正。

這個時期,註解能表達比程式語言更高階的概念,註解的作用可以不是用來補充說明,而是為了引領工程師寫出正確的邏輯

可以先寫註解,然後才寫程式碼。

所以真正的問題在於,高階語言的出現讓程式碼的表達能力提升了一個層次,但我們寫註解的能力卻沒跟著提昇,還停留在為組合語言(低階邏輯)寫註解的思想層級上

無法用註解表達比高階語言更高階的意象,這種註解才顯得無用跟擾人。

 

總結


其實程式碼寫得好不好要看是相對於什麼人而言,不存在一個絕對的標準。

如果我跟你分析問題的方式很類似,而且我們正處在同一個思考情境裡,我相信沒有註解,我們也能看懂彼此的程式碼。

但是只要我們脫離了特定的情境,或是分析問題的方式改變了,那我們也可能看不懂自己過去寫的程式碼

這時候,註解就能發揮另一層功效,幫助我們回想整件事情的來龍去脈。

 

寫出漂亮的程式碼是一種藝術,寫出漂亮的註解也是一種藝術,兩者都能體現一個人分析問題、表述問題的能力。

當一流的程式碼配上一流的註解,自然會展現超一流的可維護性。

 
我要留言!
 

X
暱稱(選填)
email(選填,僅站長可見。)
留言 To:#