iT邦幫忙

2026 iThome 鐵人賽

DAY 1
0
Software Development

諸神也搖頭的 Legacy Code: 30天 .NET 工程師生存之道系列 第 1

Day 01 -「阿里阿德涅之線」 Legacy Code 不就是很舊的程式碼嗎?

  • 分享至 

  • xImage
  •  

在眾多專案中,總會有一個替公司帶進大筆營收、全年無休高速運轉,卻也讓學長姐避之唯恐不及的系統,每次有人被指派過去,附近的同事都會給一個「節哀」的眼神,然後悄悄退後一步...

主管說得都很簡單:「加一個小功能就好,三天就可以搞定了」於是我們打開專案,看到的第一個 class 就有上萬行,裡面摻著資料庫查詢、業務邏輯、寄信,還有一堆看不出來為什麼會湊在一起的東西,每次要修改都提心吊膽,像玻璃一樣碰錯一下就完蛋了,只要系統停個幾分鐘,損失的不只巨額,還有客戶對系統的信心,所以從程式碼、基礎設施到外部服務,每個環節都得要小心處理。

而這個系列會較大篇幅著重在我們最常去改、也最容易留下後患的「程式碼」開始,談談所謂的 Legacy Code

大多數人聽到 Legacy Code,想到的通常是:

  • 前人留下來的爛東西
  • 十幾年前寫的老系統
  • 沒人敢動的古董程式
  • 文件消失、作者離職

確實,我以前也是這樣理解,反正夠舊、夠醜、又不是我寫的,就叫 Legacy Code。

不過 Michael Feathers 在《Working Effectively with Legacy Code》裡提出了一個他的想法:

對我而言,Legacy Code 就是沒有測試的程式碼。

這代表昨天才推上 production 的功能,只要沒有測試保護,今天就已經是 Legacy Code 了嗎?照這個定義來看的話,是的。

這個定義跟程式碼新不新、醜不醜,甚至是不是前人寫的都沒有直接關係,重點是修改時有沒有可重複的回饋,讓我們知道原本的行為還在,很多系統沒有測試,不一定是工程師偷懶,也不一定是團隊不在乎品質,有時只是因為當時根本沒有測試觀念,或是交付壓力大到沒人停下來在乎這件事情。

剛出社會時,老闆常對我說一句話,到現在還是覺得這句話影響我很深:

當你怕麻煩,麻煩就會找上你。

還是新鮮人的時候,不知道品質對產品的影響到底會怎樣,覺得當下開發順暢舒服、速度又快、老闆也開心,沒什麼不對的,於是開開心心交付,直到兩三個月後再回頭看同一份程式碼,才發現事情已經變得複雜起來了 XD


阿里阿德涅之線 Ariadne’s thread

阿里阿德涅之線意象圖

在古希臘神話中,雅典每隔一段時間,都必須向克里特島進貢七名少年與七名少女。

這些年輕人會被送進一座錯綜複雜的迷宮,成為牛頭人身怪物「米諾陶洛斯」的祭品,於是雅典王子忒修斯自願加入這批人,打算進入迷宮殺死米諾陶洛斯,結束這場殘酷的進貢。

但真正麻煩的不只是打敗怪物,而是迷宮內部錯綜複雜,即使忒修斯成功殺死米諾陶洛斯,也很可能找不到出口,最後也會被困死在裡面。

就這麼好巧不巧,克里特島的公主阿里阿德涅愛上了忒修斯,於是交給他一團線,讓他進入迷宮時將線的一端固定在入口,沿途不斷放線。最後忒修斯成功殺死米諾陶洛斯,再循著線帶著其他雅典青年走出迷宮。

在神話中,我們得知在解決最後大魔王時,仍需要一條保命繩,當系統沒有這條繩子時,工程師自然就會變得保守:

  • 需求要改某個地方,但沒人知道它的邊界在哪裡
  • 怕改了這裡,別的地方會出事
  • 怕看得到的功能正常,看不到的角落卻悄悄壞掉

而因為怕這些事情,最後都可能只好選擇:

加一個 if、繞過原本的設計、commit,然後開始祈禱

最後仍然被困在迷宮...

相信我,這絕對不是能力的問題,這是我們遇到 Legacy Code 時很正常的反應,而「可重複執行的測試」就是那條能帶我們回頭的線,問題在於 Legacy Code 最麻煩的地方正是我們知道需要測試,卻不知道該怎麼開始,因為要把 code 放進能執行測試的環境,往往得先調整依賴或結構,偏偏沒有測試又不敢動,但如果不動問題也不會自己消失。

補充小知識:英文 clue 原本是 clew 的另一種拼法,而 clew 早期指的是一團線,後來受到忒修斯循線走出迷宮的故事影響,才發展出「能引導人解開難題的線索」這層意思,套用在 Legacy Code 上簡直再適合不過了。


為什麼要寫這個系列

為什麼程式碼會變成這樣?緣由是什麼?前人寫這什麼爛 Code?害我現在要熬夜加班...

答案我們大概永遠不會知道,原因實在太多了,也沒有這個美國時間一個個去批判,我們能做的,是從現在開始讓系統慢慢變好,先從自己做起,如果進展順利也許還能帶動團隊一起,讓大家的日子都好過一點。

所以在這 30 天,我想分享自己在開發上學到的東西,以及維護遺留系統時累積的經驗,希望大家能帶著手上的 Legacy Code,連同每天上班的心情一起慢慢變好,這樣我們才有餘力活到老學到老嘛!

我是一名 .NET 開發者,平常喜歡研究軟體工程,也很愛讀相關書籍,其中 Michael Feathers 的經典著作《Working Effectively with Legacy Code》對我的工作幫助很大!

因此,這個系列會沿著書中的脈絡與概念往前走,整理其中對我最有價值的觀念,再加入自己的理解與實務經驗,用比較接近工作現場的方式分享。不過再次聲明,本系列講的都是我的理解,有哪裡說錯或出現偏差,請不吝批評,要噴就噴我吧,跟作者沒有關係!

《Working Effectively with Legacy Code》書封
圖片節錄自網路書店

我認為這本書很值得工程師買一本,供奉倒是不必,拿來看比較有用。

至於為什麼要寫這個系列,主要有三個原因。

一、逼自己真正弄懂

看懂一本書和把內容寫給別人看是兩回事,閱讀時覺得自己懂了,真正開始整理才會發現,很多地方只是「看起來懂」。

參加 30 天鐵人賽,是我逼自己重新消化這些內容的方法。

二、提升表達能力

我覺得對優秀的工程師來說,開發能力固然重要,「軟」實力同樣不能少,表達就是其中一項。要怎麼說人話、怎麼組織語言,真的不是一件容易的事,而我也希望透過鐵人賽來練習這方面的能力。

畢竟程式碼裡面沒有「人」,但每個段落都是「人」啊!

三、希望幫到同樣卡住的人

拜讀各位大神的文章時,我得到很大的幫助,這些文章讓我知道,原來有人已經把這些問題想得很清楚,而且願意整理出來。

如果這 30 篇文章,能讓某個正對著 Legacy Code 發呆的工程師知道:

原來不是只能硬改,還有其他方法。

如果大家能從中學到幾個走出迷宮的方法,那這個系列對我來說就有價值了。


先打個預防針

接下來 30 天,我們可能會對自己寫過的程式碼越來越沒有信心:

  • 這段是不是太耦合?
  • 這個 class 是不是做太多事?
  • 我這樣改真的安全嗎?
  • 我是不是重構得太多了

這很正常,知道的越多有時反而越不敢動,但這不是壞事,真正危險的通常不是懷疑,而是毫不懷疑。

就像《駭客任務》裡的紅、藍藥丸,現在關掉文章,明天還是可以照原本的方式工作,短期內不一定會有損失,但如果願意一起走完這 30 天,應該可以學到:

面對 Legacy Code,真正需要的不是勇氣,也不是蠻力,而是一套能讓人安全前進的方法。


30 天,我們要走到哪裡

技術範例會以 C# 和 xUnit 為主,基本上進入實戰篇後每天都會附上程式碼,並陸續整理到 GitHub 供大家做練習,程式碼範例會分成兩個分支:

master: 最原始的 Legacy Code 範例
Refactoring: 修改重構過後的程式碼

文章會盡量用輕鬆一點的語氣來寫,如果有哪裡說得不夠精確,也請大家多多指教。

天數 內容
Day 01 ~ 04 講述 Legacy Code & 單元測試
Day 05 ~ 06 直接進入實戰,體驗一套大多數 Legacy Code 都能套用的萬用起手式
Day 07 ~ 23 在萬用起手式的基礎上,學習不同場景可以採用的做法
Day 24 ~ 29 延伸內容
Day 30 賽後檢討

完整的 文章索引 也會陸續整理,想直接跳著讀的話請多多善用。

就醬!希望這 30 天,我們能一起把工作和生活的節奏找回來 XD

Reference


系列文
諸神也搖頭的 Legacy Code: 30天 .NET 工程師生存之道1
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言