這一篇的契機,其實是很久之前曾在社群媒體看到一張佛系技術債的圖,當時就在代辦事項裡留個紀錄,不過一直都被其他題目插隊 (代表我很 agile,更重要的先寫,精簡 ── 或最大化未完成工作量之技藝 ── 是不可或缺的),但年代久遠,我已經忘記那張圖上有那些文字了,印象中是不看、不找、不改,程式自然會變好的樣子,稱為佛系技術債。
事隔多日,會把這題目再拿出來,是前陣子回母校聽了一場有趣的演講,主講人是《Software Architecture in Practice》、《Designing Software Architectures: A Practical Approach》等知名著作的作者 Rick Kazman,題目是《Finding and fixing Design Debt》,內容主要介紹如何自動化偵測六種設計上的壞味道 (個人覺得還是比較偏 code level 的設計壞味道,無法找出 high level 的 conceptual design 問題)。
演講提到一個重要的觀念,設計債或技術債要能自動化被偵測出來,時時做才會願意修,就好像很多專案會在 CI 上跑 CPD/PMD 或 SonarQube 等靜態分析檢測,提醒團隊整體 code base 的品質如何。這是偏知難行易的情況,知道債在哪就容易改。
提問時間,有一位應該是有在業界待過的男生問道:「我有能力說服我的主管給資源修技術債,但我要如何說服同儕修技術債?特別是他不覺得這段程式有問題?」,業界情況百百種,也會有另一種是團隊知道有技術債,但無奈沒有資源 (或是工程師自己拿下班後的時間)。這是知易行難的情況,其實有點 sense 的開發人員,大概都知道哪裡有技術債...
先不管是知難行易或是知易行難,是否有想過為什麼借用「債」這個詞?一般的生活中,錢不夠,但需要車,於是跟銀行貸款買車 (租車其實也是一種方式,但不夠酷),然後每個月還利息跟本金。車能幫助產生新的價值,所以即便要還利息還是件值得的事。也就是說,我們會為了某個未來可能有助益的目標 (買車),願意欠債去提前去完成,而這個助益的價值高於利息。
但在軟體開發中呢?利息是什麼?在演講中有提到幾個:開發效率降低、產生的 bugs 數變多、開發體驗變差可能導致人員離職等等。一般生活中的利息是錢,白紙黑字很清楚,但上述的幾點卻很難量化。所以很難判斷助益的價值是否高於利息...
自己的觀察是技術債都是選擇來的,只是這個選擇有幾種可能:
無知的選擇。這裡的無知是中性詞,並不是在罵人。軟體開發的領域,技術一直在革新,沒有人是無所不知的,即便是資深的的工程師也會有盲點,只是資歷較淺的工程師通常比較容易做出無知的選擇,因為不知道有更好的設計。這個階段,比較是知難行易,有工具自動化的偵測確實能幫助團隊移除技術債,或是透過 code review,讓資深的工程師有機會介紹更好的設計來避免留下技術債。
當下的選擇。根據當下已知的需求,在眾人討論後做出的合適選擇,但可能隨著時間,業務規模變大或方向轉換,當時的選擇成為了現在的阻礙,這種情況蠻常發生的,但通常是利息開始變重,團隊才會有明顯的感知,能靠自動化的工具時時提醒團隊絕對是好事。
無奈的選擇。之所以無奈,就是團隊知道這樣不好,但可能為了時程,為了快速搶佔市場或是測試市場,團隊只好選擇一個較快但是不好的設計。這是刻意留下的技術債,所以需要一個清單管理這些刻意留下的技術債,日後要安排時間還,但有多少公司確實還債呢?在難以量化的利息前,決策者能否很好地判斷:要欠新的債去追求更大的目標,還是停下腳步來還債?於是,通常是到利息痛到受不了時才決定要還債 (或是工程師自己受不了,用下班的時間還債)。
這裡分享一個故事,大家覺得這是哪一種選擇:
一個小 app,是針對某個知名客戶做的新嘗試,由於不知道之後會有多少客戶會使用,加上要用的客戶很急,於是當時決定以最快速最簡單的方式,要在數天內就交付給客戶,承接的工程師想:至少套個簡單的 MVC 吧?但由於時間會拉長,最後就寫成一團能動的泥球。而這個 app 後來越來越多客戶使用,工程師只好用下班之餘的時間慢慢修改...
事實上,技術債是還活著的公司才需要考慮跟煩惱的,如果產品失敗,公司倒閉了,技術債就不用煩惱了,當然也會有人說:「就是因為技術債才拖垮產品的。」這句話可能是對的,但由於難以量化技術債帶來的影響,沒有充分的證據來證明這句話。因此,我不會說永遠不要欠技術債,畢竟無奈的選擇很常出現。
但是,即便要貸款,也有多種選擇,可以全額貸款,也可以部分額度貸款,技術債也是一樣,排除無知的選擇和當下的選擇,在做出無奈的選擇時,個人的建議是不要 all in,和決策者討論一個平衡點,讓之後還債時能比較輕鬆一點。
特別是某些技術決策一旦決定了,後面要再修改就非常痛苦。像是資料庫的選擇,一開始可能沒有大量的資料,沒有特別的感覺,當資料越來越多,不同資料庫可能遇到的狀況不同,但都會慢慢開始浮現,這時不只程式要轉換很麻煩,光是資料要轉換就是一件苦差事。所以,最起碼,存取資料庫一定要保留抽象層 (參閱《閒談軟體設計:Repository》)。
另外,便是避免 vendor lock-in,通常技術廠商會提供不少開發上的糖衣,讓使用該廠商的技術時,省去不少工夫或時間,一開始開發效率會很好,但系統流量開始增加後,和資料庫一樣,也是會有奇怪的問題冒出來,此時,如果已經被廠商鎖死時,轉換也是相當痛苦。解決辦法還是一樣,至少留下抽象層隔離 (參閱《閒談軟體設計:友善的距離》)。
也就是說,不管要欠什麼樣的技術債,切記,抽象層花不了太多的時間 (不是零,也不見得很少),卻可以讓之後要還債時,容易一點。