置頂圖片內的程式碼(Code)並非虛構,是筆者於某 System 內親眼所見;如有雷同,屬於不幸...
圖片中的 WeekDay 如果比著筆者去做,會點樣寫?
負債纍纍的徵兆
當一間公司的軟件開發部門員工流失率高、HR 覺得員工薪金已經係緊貼市價、高層認為自己公司係業內頗有名氣、認為公司工作環境唔錯,但都留唔住員工甚至請唔到人。貴 公司可能已經「負債纍纍」,迫走現役員工!
筆者所提及的「債」並不是由金錢衍生,而是由使用的技術衍生的-技術債務。
什麼是技術債務?
「技術債務」可以由軟件系統設計、開發的缺陷或不足所構成,一般會以 Best Practice 作比較。引致產生技術債務的原因大約有三個因素:
- 公司政䇿
- 開發環境
- 開發人員的質素
由於開發環境以及開發人員的質素十分取決於人,本文往後會集中探討由 公司政䇿 所洐生的技術債務。
一個簡單例子
例如有兩 Team 人要做兩個功能相同的系統 A、B。
Team A Developers 為咗「快」完成 Phase 1,犧牲咗系統中某個代價(i.e. Modularity),到進入下一個 Phase 2 要為系統加入新功能嘅時候,Team A Developers 必先花一部份時間去還因「技術債務」產生咗嘅「利息」,先可以真正開始開發新功能。
Team B Developers 沒有為咗「快」借走系統中的 Modularity,Phase 1 可能比 Team A 用更多時間,但到了 Phase 2,Team B 無需處理 Team A 遇到的「利息」,直接可以開發新功能,所用的時間比 Team A 更少。
如果 Team A 一直只係還「利息」唔還「債」的話,以筆者經驗,以一條四人 Team 黎計,不出 1 個月 Team B 的生產力會遠勝 Team A。
以軟件開發嘅角度去睇,每當 Developer 為系統加入一個新功能時,佢地可以好輕易向系統中的「Scalability、Maintainability、Sustainability、Changeability、Testability⋯⋯」借走某部份的代價換取開發上的速度,當貸款成功被 Senior Developer 批核後,系統就會多了一項新債務-「行外人看不見的技術債務」。
現實上,借貸可以好有效幫助解決實際需要,例如現實中我地會向銀行適度借貸,買樓、買鋪、擴展業務、公司週轉等等⋯⋯ 只要控制得好,適度有為的借貸絕對可取!
同出一轍,在軟件開發上,只要借得有理,定期還債,「技術上的借貸」可以有效幫助 Developers Meet Deadline,讓 Tech Team 能以比較短嘅時間完成一個 Phase,令整個 Project 行得更順暢,減低 Tech 和 Non-Tech Team 的磨擦。
相反,如果無理的借貸、走數避債則會令整個系統步入萬劫不復之地。
利息 利疊利
技術債務與現實中的金錢債務最大的差別就喺「利息」。金錢債務會以時間作為計算利息的因素;技術債務則以系統上 Source Code 的行數作為計算因素,若你在已負債的系統上不斷繼續開發、增加 Source Code 行數,原本可能只需要花 1 小時「償還時間」已經可以還清的技術債務,便因建基於舊有債務的新開發而上升,普遍的升幅會以幾何級數上升,例如 Source Code 行數增加了 30%,估算償還時間可能已經提升一倍,達到 2 小時。
換句話說,同一筆債務,Source Code 每增加一行,「利息」就會增加,如果你沒有清還上一筆債繼續開發,除了利息愈積愈多,利息愈多會有更大的機會產生新嘅技術債務!
久而久之,日後要還清債務將會變得極級困難,走入萬劫不復之地。
過多的技術債務不單只會減低 Developers 的生產力和士氣,甚至會影響公司聲譽及往後發展。
過多技術債務的影響
一個系統如果有過多技術債務會:
-
(1) 減低 Developers 的熱誠,提高流失率
-
(2) 降低公司「技術信貸評級」,更難請到人才
-
(3) 減低員工生產力
-
(4) 難以預測新功能的開發時間
-
(5) 因為 (3)(4) => 無辦法 Meet Deadline
-
(6) 因為 (1)(2) 或 避免 (5) => 不斷惡化,不斷增加技術債務,隨時「資不抵債」
如果系統有過多技術債務,Developer 往後每做一個新開發,就要花精力、時間去「還利息」,亦代表生產力已經下降以致大大提高開發成本,影響公司往後發展。
產生技術債務的主因
-
(1) Developer 本身經驗不足,在不知情的情況下「借咗都唔知」
-
(2) 欠缺 Senior/有經驗者的 Code Review
-
(3) Junior 因為(1),加上 (2)
-
(4) 趕 Deadline,借咗先算
-
(5) 高層唔理甚至唔知
-
(6) 因為 (5) => Developer 可以寫得差(借咗大量技術債)但求過到骨就算 ,因為就算寫得好都無人知!
-
(7) 因為 (6) => 最底層的 Developer 見到個 Project 會伏會爛尾,產生逃亡潮
-
(8) 因為 (7) => 要重新請 Developer,又要趕 Deadline => (1)(2)(3)(4)
普遍要避免一個惡性循環不停 Loop,必須要有一股外來的力量衝破現有惡性循環之間的聯繫。但喺搵到外來力量之前,公司必須改良現有的政䇿,防止重蹈覆轍。
公司政䇿洐生的技債
沒有持續升級 被時代淘汰
社會不斷進步,科技發展一日千里。十多年前一個價值不菲的頂級的伺服器可能比你現今的手提電腦更慢,可見硬件性能不繼提升,同時軟件也必需要作出調整才可以完全發揮硬件,所以軟件開發技術並不是原地踏步卻是不斷在進步。
但很多公司卻在以逸代勞,以「仲用到就得」的想法不斷運行該系統,拒絕或以報天價方式處理現有客戶的新要求。
2015年夏天,我喺朋友 B 和朋友 C 內的 Telegram Group 同佢地講:
岩岩個 Project 由 Java 7 上咗 Java 8,我而家開始見到 Legacy Code 就 Refactor 去 Java 8 Native Stream/Optional API 去做,易寫咗又易睇咗
仲 Cap 低一啲上一手 Java 7 嘅遺照,分享比佢地睇下用新 API 做 Stream 可讀性相差幾遠,
當我好高興分享緊 Java 8 好用咗好多之後,然後我收到朋友 B 一個難聽過粗口嘅 Telegram:
我果邊仲 main 緊 java 1.4
聽到之後好激動,翻查 Wiki 得知 Java 1.4 係 2002 年產物,即係朋友 B 仲 Main 緊十三年前嘅產物,十三年前,我仲係小學生,無記錯仲用緊單核 CPU Pentium 4 512MB RAM。相信當年嘅 Java 大部份以單線程運行,對比而家講緊嘅 High Concurrency System 真係差天共地,莫講話最新 Java 8 嘅 CompletableFuture
無得用,連最基本 java.util.concurrent
Library 都無!
每一年加入去的 Code 都只能用 Java 1.4, Source Code 行數上升亦代表升級就愈困難 ;另外一啲近十年的傳統問題一早已有公認方案解決,卻因為解決方案沒有支持 Java 1.4 而需要自行開發,亦代表花費不必要的人力物力去 「Reinvent the Wheel 」。
相信一個系統每年不斷加新 Code 但從來都唔升級,超過十年的「利疊利」,基本上已經可以判定「資不抵債」,代表要花不成比例的人力物力去維護一個「債台高築」嘅系統,浪費公司資源之餘,更減低開發者的熱誠,提高流失率,可以稱得上係「雙失」。
要升級一個系統當然要付出代價,以朋友 B 的系統為例,如果一個系統可預見使用十年以上,公司都必需堅持代代或隔代升級,無論員工背後有什麼冠冕堂皇的理據,例如「怕孭鑊、有鑊係咪你孭、呢單野唔係我跟開、搵食啫、仲用到就唔好再升佢啦、等埋發叔先升、要停低十五分鐘欣賞中國國旗所以要遲啲升⋯⋯」。否則十年後,呢一個系統已經無想去理、無人想去 Maintain,因為此系統已經資不抵債與時代脫軌,對於一啲與時並進嘅 Developer 黎講,叫佢地 Maintain 呢類技術破產嘅 Project 等同叫佢地今晚打開 LinkedIn 搵地方跳槽!
過舊的技術做新的 Project
好多時 Developer 要起一個新 Project 都被已有的 Comfort Zone 吸引,只會用類近的技術做新 Project,欠缺做基本的 Research 接觸 Comfort Zone 以外的技術 。每當被問到點解新 Project 點解要仲要用呢個技術嘅時候,理據就喺「因為我識」。
新技術的普及並不會是空穴來風,箇中奧妙必然有可取之處。
如果連新技術有乜野可取之處都未知,就急急腳咁開始用舊技術做新 Project。一啲新技術已經被業界測試過安全、高效,可以就咁用兩三句就加入去 Project 嘅功能,倘若你用舊技術寫咗兩三百行都仲未搞得掂仲測試緊,就係你「還債」嘅時候。
缺乏正確使用 Version Control Software (VCS)
筆者估計,2015年依然有一小撮人或公司高層錯誤地以為 Git = GitHub = Open Source
、依然有一部份人認為 VCS 只係適合於 Team Project,Individual Project 根本無需用到 VCS。
根㯫官方的謙虛定義:
git - the stupid content tracker
Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.
Git 係一個免費軟件,不等如用 GitHub 更不等如用 Git 就喺 Open Source。
「Individual Project 根本無需用到 VCS?」呢一個想法係一個極度錯誤的想法!因為 VCS 提供的功能可以非常有效幫助 Rapid Development,所以無論你嘅 Project 喺乜嘢性質,動工之前起一個 VCS Repo 都喺一個 Best Practice。
當年筆者仲係中學生嘅時候未知有 VCS 存在,更未與 Git 邂逅。每當我意識到自己將會大改自己的 Code 嘅時候,為免改爛左返唔到轉頭,我都會事先複製整個 Folder,然後才開始做我的大改動。奶野要返轉頭?成個 Folder 全部取代。
# Init a new Repository
git init
# Commit
git commit -a -m "safe!"
# Reset to the last commit
git reset --hard
邂逅 Git 後,打一句git commit -a -m "safe!"
,我就可以好安心咁做大改動,返轉頭都只需打一句 git reset --hard
就還原到上一次 Commit 狀態。但 Git 的運用本身係一個頗大的課題,遲啲有機會再寫一啲教學去講多啲,㫮因筆者認為作一個 Developer 都必需花少少時間去學、去理解、去提升 Productivity。
如果有公司 Project 因為未識用 Git 從而洐生出「如果用 Git 就不會洐生」的問題,你就係還緊筆者所謂的「技術債務」。
筆者夠膽講句:
Developer 花一個月時間深入學習使用 Git,未來幾年甚至十幾年無論係 Team/Individual Development 你都會輕鬆好多
(範例: 筆者的 Telegram Bot Project,遲啲有時間將佢拆成一個 Module 放上 GitHub)
所以公司理應必需建立完善的 VCS 系統給員工使用,如果以最流行的 Git 為例子,筆者推介有兩個方案
以上兩個方案都可以 Closed Source。
其它經典的技術債務
- Long Method
- God Object
- Tightly Coupled
- 欠缺 Test
- 欠缺 Documentation
- 欠缺 Code Review
- 欠缺 Comment
- 過多 Mutable Variable
- 過多 Duplicate Code
- 可簡化的 Logic
筆者的「借貸」習慣
相信大家都會遇過趕 Project,餘下時間真係唔允許你做 Best Practice 真係要焗住借貸的話,加入一個小小的動作就可以大大咁減低日後還債嘅痛苦 - 留借據 (加入 TODO Task)。
例如當時筆者於 Telegram @HKiPhoneBot Project 內加入的 TODO
//TODO: more broadcast handling can be done
case bMessage: BMessage =>
val channelSubsribers = getSubscriberChatIdInRedis(bMessage.sChannelId)
//TODO: more broadcast handling can be done
bMessage.text match {
case Some(text) =>
messagePublisher ! SendBroadcast(
chatIds = channelSubsribers,
text = renderBroadcastMessage(bMessage)
)
case None =>
// no text then do nothing
}
呢一啲 TODO Task 會被 IDE 讀取並清𥇦地顯示整個 Project 的 TODO List,日後如果新開發涉及 ChannelMessageWorker
都會優先處理這些 TODO Task 然後才開始新開發,避免筆者所提到的「利疊利」。
還債流程
如果你已經發現被技術債務纏繞,你又預見你件系統/產品會不斷使用,假設你嘅系統會不斷加入新功能做 Dev,同時又想清走啲技術債務,筆者有一套流程可以分享比大家參考。
- 任命具能力者,列出現有的技術債務
- 按重要性、影響範圍排先後次序
- 調整開發與維護比例騰出時間
- 實行 Pair Programming 清理技術債務,減低出錯機會並加快進度
善用 IDE 的 Task Management
總結
技術債務喺一把雙面刃,雖可以借佢黎提升攻擊力,但同時都會傷到自己。
其實要好好掌握呢把雙面刃並不需要上乘的心法,其實只要有一個口訣:
借得有理,定期還債
同你嘅戰友分析下當前系統積落嘅技術債務以及其影響,搵個時間坐低傾傾佢,撿一撿個開發 Schedule。
係咪覺得筆者痴人說夢話咁呢?
的確,成日上網見到香港個 IT 市場幾爛,什麼 hknoit,㫮因自己人搞爛自己個市。
好多時 Developer 遇到嘅上司會係行外人/已經脫節嘅人,佢地無能力去分辨好壞,呢一個時候有部份 Developer 會選擇「做到就算」用一啲極度醜陋嘅 Anti-pattern、借落極多技術債務;令到個系統負債纍纍,往後嘅細 Bug 要 Fix 成日,要改少少野又話做唔到。
如果 Developer 以「做到就算」嘅心態生存其實好危險,永遠唔學下公認的 Best Practice,咁除左逗到份糧仲得到啲乜野?下一次,如果你想搵啲好 Offer 面試遇到一個行內人著重 Code Quality,你有無本錢同人爭?
加上做一啲 Main 唔到嘅系統交差,對自己又無得著、對老闆又無得益、仲搞爛埋啲客人對 HKIT 嘅信心。
古語常道:「一次不忠,百次不用」
倘若本地或外地客人對 HKIT 無信心;作為 IT 界嘅其中一人亦會身受其害!
Your employer can't force you to be a good programmer; a lot of times your employer isn't even in a position to judge whether you're good.
If you want to be great, you're responsible for making yourself great. It's a matter of your personal character.
下一次你老闆泰山壓頂係度講:「呢個 Project 十萬火急!一個月內要搞掂所有野!」嘅時候,作為 Developer 嘅你,希望你有勇氣講出呢一句:
無問題!你想我借幾多?