早在1992年的時候,Ward Cunningham 就提出了一個「技術債(Technical Debt)」的隱喻,但直到這些年,「技術債」的觀念才被廣泛的討論及運用在開發工作中。

在現實生活中的財務管理中,人們欠下債務,這是因為可以立即滿足一些對資金的需求、支應支出。這通常是為了帶來短期的急效,因為,並不需要真正擁有那麼多的資金,卻又可以運用如此之多。但是,只要是借貸而來的債務,勢必是需要付出代價,這代價就是「利息」。有些時候,你是運用借貸而來的資金於投資之上,即使定期支付的利息會帶來額外的負擔,但若是在權衡所做投資的投資報酬率,高過額外支出的利息負擔時,也能算是划算的決定。

在軟體開發中,我們同樣也時常面臨這種「舉債」的情況,像是產品訂好了完全不能修改的上市時間,但開發的進程落後於預期,此時便可能選擇一些「抄捷徑」的作法來取巧,雖然實作出來的結果,在表面上運作起來沒有什麼兩樣,但骨子裡可能會遺留一些不利於日後繼續開發的因子,甚至是可能會被引爆的未爆彈,就像是擴充性不足的架構,或是具有壞味道、需要日後再重構的程式碼、……等等。

這些便宜行事的做法,就相當於當下需要緊急的資金挹注,只好先借來運用。但所欠下的債務並非毫無代價,一樣是需要付出「利息」的,例如用了「複製、貼上」的手法來處理程式碼,一旦要修改這段程式碼時,就得更花力氣找出究竟那些地方複製了這段程式碼一樣。

虧欠技術債,不一定要還?

即使,技術債是個很好的隱喻,它有利於軟體從業人員想像、類比,還有在開發過程中因為臨時的調度決策,而必須持續負擔代價的觀念,也得以溝通,但是,它和財務上的債務,還是有些許不太能夠類比的地方。

舉例來說,有些技術債不還也沒關係,這是因為它們不會產生什麼額外的負擔,例如幾乎不會被讀到或修改的程式碼。有時候,債務甚至會一筆勾銷,連還都不用還,例如欠債的程式碼片段即將因為改版而被重寫,或是這段程式碼被運用在原型系統、或是即將下市的產品裡。

此外,在軟體開發的技術債領域裡,欠債的人不一定是歸還的人,這一點也和財務領域不相同。

另一方面,著有《Domain-Driven Design》一書的 Eric Evans ,對於處理舊有程式碼(legacy code),也曾提出過一個叫做「戰略設計(Strategic Design)」的觀念。Eric Evans 認為,在一個系統中,根本不可能所有的程式碼都維持夠高的品質,而且,有些情況下,有些程式碼也沒有必要一定非得是高品質。這是個相當務實的觀念,如果我們很現實的來計較在開發過程中每一份生產力的 C/P 值,那麼,維持一些程式碼的完美,需要付出的代價太高,但這些程式碼即使完美對整個系統的效用卻不大時,是否應該讓它們也被一視同仁地被維持高品質?

從這樣的思路出發,你可能會意識到,那些根本不會被閱讀、或是被用到的程式碼,的確可以不需要維持的那樣完美。這麼一來,所有的程式碼對你來說,就不是一視同仁,而是有著不同的權重,有些是兵家必爭之地,必須下重兵駐防;有些地方幾乎沒有敵人覬覦,那麼不需要大費周章。

無論是戰略設計或是技術債的觀念,都在表示有些時候,我們會策略性的決定不將某段程式碼設計到足夠完美或是具備高品質。從戰略設計的觀念來看,有些程式碼可以在撰寫時不那麼完美、具備高品質,我們可以說,在此時選擇了欠下技術債,但事實上,這技術債的危害可能不那麼大,即使持續如此,也不會產生太多的額外負擔。不過,需求會改變、系統也會跟著改變,策略性降低成本而得到的程式碼,其所在位置的重要性也可能隨之改變,到這時候,便是規畫償還債務的時候了。

從現實的角度來看,技術債是不可避免的,成因可能有多種,最主要是時間的壓力,還有戰略設計的成本考量,但有些時候,團隊成員的素質不夠好,以致於欠下技術債而不自知,亦有可能發生。

技術債的類型與處理方式

Martin Fowler 曾將產生技術債的起因,用兩個象限分為四種:一個象限,是區分出蠻幹(reckless)和謹慎(prudent),而另一個象限,則是刻意的(deliberate),以及無心的(inadvertent)。

另一方面,技術債也可依其技術類型而被區分為四類:架構技術債、設計技術債、實作技術債、測試技術債,分別對應了在不同層次、工作領域裡所積欠下來的技術債。

那麼,實務上,要怎麼處理技術債呢?首先,你必須要明白,想要在開發過程中切出一個時間區段,專心的處理技術債,而不繼續的推動開發進度,幾乎是不切實際的事。這種想法就跟想在開發過程中切出一個時間區段,只做重構的工作,而不顧開發一樣。而像重構的想法裡,卻是希望你在開發過程中持續的做重構。而技術債的償還也是一樣,比較好的方式是同時開發,同時權衡可投入償還技術債的能力,接著規畫償還的計畫。因此,可以考慮以一個迭代(iteration)為單位,在一個迭代開始之前,規畫要納入償還的技術債有那些,將它們和這個迭代中要進行的開發合併在一起。

用這個方式來規畫技術債的償還,會改變我們原本只針對需求在評估時程的方式。我們可以說在一個迭代裡的時程規畫是在編列預算,原先我們只考慮到需要支出的預算,而考量到技術債時,我們把利息甚至本金的攤還也編列到預算裡了。透過這種方式,我們可以採用分期攤還債務的想法來處理。事實上,想要一次攤還,原本就是不務實的心態。

此外,團隊應該建立技術債的文件化機制,這包括了應該要有一份技術債的記錄,當你在決定欠下技術債以及在開發過程中找出未被記錄的技術債時,應該將它們記錄下來。或許會有一些其他的欄位,包括它們的戰略意義、影響層級、「利息高低」、應該被償還的優先順序、……等等。在開發的過程中,持續地維持這一份記錄,當技術債被償還時,便可將它們自此份記錄中移除。這麼一來,便可以隨時追蹤、掌握現有系統的技術債概況。

償還技術債的方法

償還技術債可以有三種策略,除了直接償還之外,你也可以選擇「債務轉換」,或是「純支付利息」的方式。

所謂的「債務轉換」,也可以說,是從財務領域借用過來的比喻,對軟體開發來說,就是先花一點力氣,將較高利率的債務轉換成另一種較低利率的債務。例如,沒辦法一次還完某個架構技術債,但可以先花點力氣略為調整架構,讓它所付出的利息變低。而對於那些付利息比還完還划算的技術債,你也可以選擇只支付利息。為什麼會有這種情況?這是因為程式碼是有生命週期的,和財務的債務不同,只要程式碼的生命週期被決定終止,債務就一筆勾銷煙消雲散。倘若一段程式碼在被廢棄前不被重構所造成的成本低於重構它需要付出的代價,那麼還不如選擇不做任何處置。

技術債是軟體開發中的必然元素,面對技術債的正確心態應該是要認知到,技術債總是會存在,而它們也不然總是負面的,運用得當可以獲得合理的投資報配,而更重要的是,技術債不一定要償還,這使得我們有些情況可以策略性的加以運用。

專欄作者

熱門新聞

Advertisement