不只程式碼

成為優秀的軟體工程師,不只是在寫「能跑」的程式碼。更重要的是寫出 別人(包含未來的你)能理解、維護、延伸的程式碼。這也關乎清楚溝通、 有思考地貢獻,以及在你參與的生態系中成為好的協作者——不管是開源或 商業閉源環境都一樣。

單向溝通

軟體工程有很大一部分,是在為「沒有你目前脈絡」的人寫東西:之後才加入 的同事、接手你程式碼的維護者,或六個月後已經忘記當初決策原因的你自己。 這類寫作最重要的原則是:目標是記錄並傳達 why,而不只是 whatwhat 常常從程式本身就看得出來;why 則是你花時間踩坑才累積的知識, 最容易被時間沖淡。

工程師之間最常見的溝通方式之一(除了程式碼本身)就是註解。我自己常看到 很多註解其實沒幫助,但它們不一定得這樣!好的註解會補上程式本身無法表達 的事:為什麼要這樣做,而不是它怎麼運作(那是程式本身會呈現的)。好的註解 可以省下數小時的困惑;壞註解則只會增加噪音,甚至誤導。

幾乎都值得寫的註解類型:

README(你有寫吧?)也是其他開發者常見的第一接觸點。一份好的 README 應該 立刻回答四個問題:這是做什麼的?我為什麼要在意?怎麼用?怎麼安裝? 而且順序就照這樣。結構可像漏斗:最上方先放一句話摘要,必要時加視覺化示範, 讓人幾秒內判斷這是否解決他的問題,再逐層加深內容。也建議先展示用法再講安裝—— 多數人會想先看到成果,再決定要不要投入設定成本。

Commit 訊息是另一種常被忽略的「為他人而寫」。很多訊息只寫成「fixed blah」、 「added foo」,某些情境也許夠用,但別忘了 commit 訊息其實是記錄程式碼庫 如何演進的 why 歷史。當某人(包含你自己!)用 git blame 想搞懂一段難懂 變更時,好的 commit 訊息應該能給出答案。

一般來說,commit 內文應回答:

細節量當然要跟複雜度成比例。修一個一行 typo,只要主旨就好;但如果是花數小時 才抓到的微妙 race condition,就值得用數段文字說清楚問題與解法。

對於複雜變更,採用 Problem → Solution → Implications 結構通常很有幫助: 先交代驅動變更的限制或問題,再說明做了哪些改動與關鍵設計決策,最後列出 值得注意的結果(正面與負面)。最後一段尤其重要;真正的工程通常是各方權衡, 把「這是有意識的取捨」寫清楚,能避免後人誤以為你漏看了問題。

LLM 可以_協助寫 commit 訊息。但如果你只是把 diff 丟給它,叫它幫你寫, LLM 通常只看得到 _what,看不到 why。結果往往會變成純描述式訊息 (剛好是我們最不想要的)。如果你本來就用 LLM 協助完成這次改動,那在同一個 對話裡請它寫 commit,通常會好很多,因為先前對話本身就是豐富脈絡來源! 此外(或搭配使用)的一個實用技巧是:明確告訴 LLM 你要的是聚焦在「why」 的 commit 訊息(也可包含上面提到的細節),並且_要求它主動追問缺失脈絡_。 某種程度上,你是在扮演可供代理讀取脈絡的 MCP「工具」。

當改動變得更複雜,記得把 commit 做邏輯切分(git add -p 是你的好夥伴)。 每個 commit 應代表一個可獨立理解、可獨立審查的完整變更。不要把重構和新功能 混在一起,也不要把無關 bug 修正在同一筆提交,否則很難追溯「哪個變更修了哪個 問題」,幾乎一定會拖慢後續審查。做好切分也會讓 git bisect 變得超強,但那是 另一段故事了。

當你開始更認真做技術寫作、也寫得更頻繁時,有一件事很重要:尊重讀者。人一旦 開始寫很容易過度解釋,但你要克制,不然讀者可能乾脆什麼都不看。說清楚「why」, 然後相信讀者有能力在自己的情境推導「how」。

協作

身為工程師,我們工作中確實有很大一部分是在自己鍵盤前寫程式,但也有不小比例 的時間花在與他人溝通。這些時間大致可分成「協作」與「教學/學習」,而在兩者上 刻意投入、持續精進,回報通常都很可觀。

貢獻

不管你是在提交 bug 回報、貢獻小型修正,還是實作大型功能,都值得先記住: 通常使用者數量會比貢獻者多好幾個數量級,而貢獻者又比維護者多一個數量級。 因此,維護者時間幾乎永遠超載。若你希望自己的貢獻能有效被推進,就必須確保 你的內容「訊號高、噪音低」,值得維護者投入時間。

例如,一份好的 bug 回報會尊重維護者時間,提供理解與重現問題所需的完整資訊:

如果你發現安全漏洞,不要直接公開。請先私下聯絡維護者,給他們合理時間修補後 再揭露。許多專案會用 SECURITY.md(或類似文件)說明這個流程。

務必先搜尋既有 issue。 你的 bug 或功能需求可能早就有人提過了。比起重開 重複議題,把補充資訊加進既有討論通常更好,也能降低維護者噪音負擔。

如果你能提供最小可重現範例(minimal reproducible example),那幾乎是黃金級資訊。 這能替維護者省下大量時間與心力,而且穩定重現 bug 往往就是修正過程中最困難的一步。 另外,你在隔離問題時投入的功夫,也常會反過來幫助你更理解問題,甚至自己先找到解法。

如果你沒有立刻收到回覆,請記得維護者常是時間有限的志工。等待回覆時,隔幾週 禮貌追問一次可以,但每天 ping 就不太好。同樣地,純粹「me too」留言,或只是 貼一段終端機輸出卻缺乏脈絡的 bug 回報,通常對推動問題進展是負分。

若你想做程式碼貢獻,也要先熟悉專案的貢獻規範。許多專案都有 CONTRIBUTING.md, 請照著做。通常也建議從小處開始:修 typo 或改文件都是很好的第一筆貢獻,能讓你 先熟悉專案流程,而不用一開始就在內容本身來回反覆討論太多輪。

記得確認專案使用的授權條款,因為你提交的程式碼也會落在同一授權下。特別要留意 copyleft(例如 GPL)授權:它要求衍生作品也要開源,若你在工作上接觸此類程式碼, 可能對雇主產生影響。可參考 choosealicense.com

當你決定開 pull request(PR)時,第一步是先把你真正想被接受的改動隔離清楚。 若 PR 同時夾帶很多無關變更,審查者很可能會退回請你先整理。這跟 commit 切分 原則一樣:要切成語意上彼此相關的區塊。

某些情況下,你可能有許多看似分散的改動,但全部都是為了同一個功能不可或缺; 這時開比較大的 PR 也未必不行。不過在這種情境下,commit 衛生特別重要,讓維護者 能選擇以「逐 commit」方式審查。

接著,務必把改動背後的「why」講清楚。不要只描述改了 what,要解釋為什麼 需要這個變更、以及為什麼這是解決問題的好方式。若某些區塊在審查時需要特別留意, 也應主動標註。依 CONTRIBUTING.md 規範與改動性質不同,審查者也可能期待看到 額外資訊,例如你做過的取捨、或如何測試此變更。

我們建議第一優先先回饋給上游專案,而不是直接 fork。Fork(在授權允許下) 較適合用在你想做的貢獻已超出原專案範疇時。若你真的 fork,請務必致謝原專案!

AI 讓你能非常快速地產生看起來「像樣」的程式碼與 PR,但這不代表你可以不理解 自己提交的內容。若你提交了連自己都說不清楚的 AI 產生程式碼,就等於把審查與未來 維護負擔丟給維護者。用 AI 幫你找問題、產生修正或功能都可以,前提是你仍要做完 應盡的查核與打磨,把它整理成真正有價值的貢獻,而不是把這份工作轉嫁給(已經超載的) 維護者。

請記住:對維護者來說,接受一個 PR 代表接受長期責任。貢獻者離開之後,仍是維護者 要持續維護這份程式碼。因此即便你出發點很好,他們也可能拒絕不符合專案方向、引入 他們不想承擔的複雜度,或需求說明不足的改動。身為貢獻者, 要負責把論證做好, 說服大家為何這份貢獻值得相應的維護成本。

收到 PR 回饋時,請記得「你的程式碼不是你本人」!審查者是在讓程式更好,不是 在針對你個人。若你不同意,請用釐清問題的方式討論——你可能學到新東西,對方也可能。

審查

你可能會以為 code review 是資深工程師才做的事,但你通常會比想像中更早被邀請參與, 而你的視角很有價值。新鮮視角常能看見資深開發者忽略的問題;對程式較不熟的人提出 的問題,也常揭露那些其實應該被寫進文件或進一步簡化的隱性假設。

審查也是成長最快的方式之一。你會看到別人如何拆解問題、學到慣用模式與寫法, 並建立「什麼讓程式更可讀」的直覺。除了個人成長,審查還能在上線前攔下 bug、 讓知識在團隊中擴散,並透過協作提升程式品質。它不是官僚流程而已。

好的 code review 是需要長期練習的技能,但以下做法可以讓你更快做得更好:

AI 工具可以抓到部分問題,但不能取代人工審查。它們會漏脈絡、不懂產品需求, 也可能很有自信地給出錯誤建議。拿來做第一輪篩查很值得,但不能取代有思考的人類審查。

教學與學習

工程師不寫程式的時間,很多都在提問或回答問題(有時兩者同時發生),可能是 協作時、與同儕討論時,或在學習新事物時。會問好問題是一項關鍵能力,能讓你 更會向各種人學習,而不只依賴「很會教的人」。Julia Evans 有兩篇很棒的文章: 「How to ask good questions」與 「How to get useful answers to your questions」, 很值得一讀。

其中幾個特別實用的建議:

請記得:設計良好的問題會讓整個社群受益。它能把隱性假設浮上檯面,而這些通常 也是其他人需要理解的內容。

這些原則用在和 LLM 溝通時同樣成立!

AI 使用禮儀

隨著 LLM 與 AI 在軟體工程中的使用越來越普遍,相關的社交與職場規範仍在快速演變。 我們已在代理式程式開發講座談過許多戰術層面的注意點, 但還有一些較「軟性」的使用面向也值得討論。

第一點是:當 AI 對你的工作有實質貢獻時,要揭露。這不是羞恥問題,而是誠實、 設定正確預期,以及確保成果獲得相應程度的審查。也建議進一步說明你是在哪些_部分_ 使用 AI——「這整份都是 vibe code」和「我自己寫了備份工具,只用 LLM 幫前端排版」 之間有明顯差異。舉例來說,我們也有用 LLM 協助撰寫部分講義內容,包含校稿、腦力激盪, 以及程式片段與練習題的初稿生成。

你也需要遵守所屬團隊或專案的規範。有些團隊對 AI 使用政策更嚴格(例如基於合規、 資料駐留等原因),你不會希望不小心踩線。公開透明地說明你的 AI 使用方式,能避免 代價高昂的失誤。

如果你是想在工作中順便學習,要記得:若把全部或大部分工作都交給 AI,可能會 本末倒置。你最後學到的常是怎麼下提示(也許再加一點審查 AI 輸出),而不是任務 本身。尤其在學習階段,重點往往是過程不是終點,所以用 AI「快速拿到答案」反而 是反目標。

相關議題也常出現在面試或其他評量情境。這些情境通常是要評估_你_ 的能力, 不是 LLM 的能力。現在越來越多公司允許你在面試中使用 LLM 與其他 AI 輔助工具, 前提是你願意讓面試方觀察你的操作過程(也就是他們同時在評估你使用這些工具的能力), 但這仍屬少數。若你不確定某項任務是否可用 AI,請先問清楚!

幾乎不用多說:若評量規則明確寫了不能用外部工具、不能用 LLM 等,就不該使用。 想偷偷用而不被發現,最後一定 會反噬你。

練習

  1. 瀏覽一個知名專案的原始碼(例如 Rediscurl)。找出講座中提到的註解類型範例: 有用的 TODO、外部文件參考、「為何不」註解(說明刻意避開的作法), 或踩坑後留下的經驗。思考:若這則註解不存在,會少掉什麼關鍵資訊?

  2. 挑一個你有興趣的開源專案,查看近期 commit 歷史(git log)。 找一筆訊息寫得好的 commit(有解釋 why),再找一筆只描述 what 的弱訊息。對後者查看 diff(git show <hash>),嘗試用 Problem → Solution → Implications 結構重寫更好的 commit 訊息。 體會看看:事後補回必要脈絡需要多少額外成本!

  3. 比較三個 GitHub 上超過 1000 stars 專案的 README。它們都一樣好用嗎? 找出那些對你而言比較像噪音的內容,當作你未來撰寫 README 的反面教材。

  4. 在你有使用的專案中找一個 open issue(若有可先看 good first issuehelp wanted 標籤)。依照本講座標準評估它:這份 issue 是否有尊重 維護者時間、並提供除錯所需完整資訊?還是你預期維護者得來回追問很多輪, 才能找到核心問題?

  5. 回想你在日常軟體中遇過的 bug(或從 issue tracker 找一個),練習建立 最小可重現範例:把與 bug 無關的元素一層層拿掉,直到剩下最小且仍可重現 問題的案例。並寫下你移除了哪些部分、為什麼移除。

  6. 在你熟悉的專案中找一個已合併、且有實質審查留言(不只是「LGTM」)的 pull request,完整讀過審查內容。所有留言都一樣有幫助嗎?如果你是 PR 作者, 你會如何感受這整段回饋體驗?

  7. 到 Stack Overflow 找一個你熟悉技術領域中高票回答的問題,再找一個被關閉 或大量負評的問題。對照本講座建議比較兩者:你是否能預測哪種提問會得到 較高品質的回答?


編輯此頁面

本內容採用 CC BY-NC-SA 授權。