相信很多程式設計者都有類似的經驗,當我們在做軟體設計、或者是實際撰寫程式碼時,因為一些理由,我們沒有做出能得到最佳品質的設計、或是寫下有著最佳品質的程式碼。例如,當專案的時程過於緊迫,而在期限內完成工作又是十分重要時,我們就有可能放棄較為彈性、較具可擴充性的架構設計,或是寫出具有壞味道(bad smell)的程式碼。

受限於時程,對設計或程式碼當下的取捨,可能會在日後持續的付出代價。每當你遭遇到現有架構無法因應之際,就必須為當初在架構設計的彈性或擴充性上,所做的犧牲付出代價;每當程式中的壞味道持續影響程式碼的品質時,也必須為當初在程式碼品質上的犧牲付出代價。有些人會用「快,但是髒(quick and dirty)」來描述這種作法。

在1992年的時候,Ward Cunningham首先提出了一個名為「技術債(Technical Debt)」的隱喻(metaphor)來描述以上這種許多人都有的共通類似經驗。這是一個十分有趣的比喻方式。

其實,技術債和財務領域中的債務觀念,有一些可以類比的地方。人們會產生財務上的債務,通常是因為對於立即性資金的需求,也就是說,可以在短期內得到好處。但是,無論是向銀行或是其他個人借貸,總是需要付出代價,也就是利息。你可能會拿借貸而來的資金進行投資,即使需要定期的付出利息,但是因為投資獲利率夠高的關係,使得即使因為借貸而必須付出利息,相較之下仍然划算。

程式開發過程中,為什麼會形成「負債」?
我們在軟體開發上也有類似的情況。我們打算開發一個產品,倘若能夠準時完成產品,將產品推到市場上去,那麼,因為能夠搶佔市場的先機,因而產生足夠多的利潤。在準時提交產品的過程中,可能受限於時間壓力,因而做了一些決策,欠下了技術債,可能是不夠完備的架構設計、也可能是具有壞味道的程式碼。

無論是不夠完備的架構設計,或是具有壞味道的程式碼,都會隨著時間,持續地讓開發團隊付出代價。但是,只要付出的代價是可以接受的(小於得到的好處),那麼,欠下技術債的決策就很有可能是個合理的決策。不過隨著債務積欠愈來愈多,或是固定的債務始終沒有償還,那麼就得付出愈來愈多的利息,或是持續長久的付出利息,最終就可能發生得不償失的情況。

有時候,積欠技術債在所難免,但是怎麼拿捏所需付出的利息、支付利息的期間長短、以及償債的時間點,以使得借貸的決策仍舊得到正面的效益,就成了軟體開發過程中重要的一門學問了。

當然,從最理想的角度來看,程式設計者不應該欠下任何技術債,因為任何的技術債,都意謂著追求短期的好處、而犧牲掉長期的利益。

程式設計者應當要時時刻刻追求完美的品質、理想的表現。但是,有時候,軟體開發產業有其現實的一面。對於有些產品而言,不能如期推出到市場上,即使有再好的品質都無濟於事。這並不是說品質不重要,而是說,在這種情況下,必須權衡時效及品質這兩個因子,在可以接受的品質及如期推出產品之間,找到一個適當的平衡點。

會出現技術債的各種情況
技術債可能發生在設計上,像是設計不夠彈性、不夠有可擴充性、無法因應之後的變動而演化、模組間的耦合力過高、模組內的內聚力過低、模組間的相依性太高、等等。你可能會選擇導致欠下技術債的設計方式,來滿足現實的限制條件。不過,這樣的設計,也很有可能會讓你在之後付出代價。

技術債也可能發生在實作的程式碼中。即使你在設計上沒有負債,但是,當進到程式碼的實作階段時,也有可能基於一些現實的限制條件,使得你採取一些取巧的方式,因而欠下了技術債。

例如,當你察覺了原程式碼中有一段程式碼,可以在接下來的實作中被重複運用,當時你並沒有採取類似重構的方法,把這段程式碼給萃取(extract)出來,而是繞過應該要有的萃取動作,直接使用了複製並貼上(copy and paste)的招數,把現有可以重複使用的程式碼,直接抄過來(或經小幅度修改)使用。一時之間,這樣做當然很快,但是,對程式碼長遠的發展而言,會造成負面的影響。

技術債還有可能發生在程式碼的註解、或是設計及程式碼的說明文件。有些團隊,會為了節省撰寫註解或文件的時間,而減少了為程式碼撰寫註解或撰寫說明文件的數量。這當然可以在短時間內得到好處,因為開發團隊節省了人力和時間。但是就長遠來看,註解和文件有助於程式碼及設計的可讀性,有利於團隊成員間的知識、資訊交流,以及日後系統的維護及修改。倘若註解及文件有不足的情況,開發團隊自然也會漸漸為此付出代價。

忽略測試案例的撰寫、或是僅撰寫不夠充份的測試案例,也是常見的技術債。而在程式中,用TODO式的註解,標註那些你覺得應該要寫,卻還沒寫的程式碼,當然也是一種技術債。

甚至像忽略編譯器所展示的警告訊息,即使程式碼仍可通過編譯,但每一則警告訊息,都像是一個潛在的未爆彈,可能在任何時刻爆炸,進而對你產生傷害。

又好比,明明知道某種程式的寫法可能會造成緩衝區溢位,或是遭受SQL資料隱碼攻擊,但是,為了貪圖一時之快或便利,還是寫下了那樣的程式碼,這同樣也是一種技術債。

會形成技術債的四種主要原因
Martin Fowler大師曾將產生技術債的起因,用兩個象限分為四種:一個象限是區分出蠻幹(reckless)和謹慎(prudent),而另一個象限則是刻意的(deliberate)以及無心的(inadvertent)。這說明了,並不是所有的技術債都是在謹慎理性的評估之下,經刻意安排而做出的決定。最差的情況下,我們可能是不經意、很隨意的就欠下了技術債。

就像一些剛開始從事程式設計的新手一樣,他可能不明白複製並貼上對程式碼可能造成的潛在傷害,他只是憑著直覺,順手就做出了複製並貼上的舉動。在這種情況下,他並不是在明明知道這麼做會在日後付出代價、經過理性的評估及算計之後,仍然決定這麼做。但是,技術債在日後所會造成的傷害並不會因此而減少,甚至可能因為對債務的一無所知,不知應該加以清償、因而讓債務日積月累、利息愈滾愈多。

在四種情況中,最佳的當然是很謹慎的、在刻意的情況下產生技術債。這代表你是在明知山有虎、偏向虎山行的情況下,欠下技術債務。那麼你應當經過一定程序的評估,知道欠債之後可以得到的短期好處是什麼,也預知未來需要付出多少代價。你知道自己是用了什麼換了什麼,而這個交換經計算後是值得的。更重要的是,你可以據以訂立償債的計畫,因為不論欠下什麼樣的債,只要欠的夠長,就會侵蝕掉因為欠債而得到的利益。因此,你必須在情況變得不利之前,即時的清掉這些負債。

認清欠下技術債的意義與償還對策
雖然技術債不完全可以和財務上的負債觀念類比,這個隱喻卻是強而有力,可以隨時提醒。很多時候我們所走的捷徑,都是需要付出代價的,而且,有些時候的確需要走上捷徑,但必須是在經過一定程序的評估之後,而且,必須適時、適度的處理因為走了捷徑而遺留的問題。因為,就如同電影《無間道》裡所說的:「出來跑的,遲早要還」。

 

專欄作者

熱門新聞

Advertisement