Levix

Levix's zone

x
telegram

所有編寫的代碼最終都會變成技術上的持續負擔(技術債務)

Ward Cunningham 最早提出的技術債務這個概念,指的是通過加速軟體開發的進程以獲得短期效率提升,但這樣做的代價是拖慢未來的開發速度。

這很像向銀行貸款。貸款可以讓你比平常更快地完成某件事情。而技術債務,就像你在專案初期的開發過程中獲得的推進力。但是一旦你貸款,你就必須支付利息。對於技術債務而言,這就相當於未來開發速度的放慢。當你歸還了貸款本金,需要支付的利息也會隨之減少。這類似於重構過程中,你投入時間改善程式碼質量,以期加快未來開發的速度。

就如同金融債務一樣,技術債務也可以成為一種有用的工具。有時能夠獲得的短期收益會超過它帶來的長期影響。但是,正如過多的金融債務可能導致破產一樣,過多的技術債務積累可能會使你的產品開發陷入龜速,甚至停滯不前。

如果你有過從零開始創建新應用的經驗,那你一定體驗過那種沒有任何技術債務,專案進展順風順水的愉快感覺。在開發初期,你可以快速迭代出新功能,不用擔心會對現有用戶產生影響,可以全身心投入到新功能的實現上。

但是,隨著應用的不斷成熟和壯大,開發速度不可避免地會逐漸放慢。在一個設計不太完善的產品上,開發速度可能會迅速減緩,而即使產品設計得足夠優雅,但隨著時間的推移,開發速度仍舊會慢慢下降。這是因為你向應用中添加的程式碼越多,開發就會變得越緩慢,因此,我認為所有的程式碼,從本質上來說,都構成了技術債務。

增加新假設導致技術債務增加#

在應用不斷完善的過程中,會逐漸形成一系列基礎性的假設。當你剛開始一個新專案時,由於還沒有任何功能,程式庫中也就不會有任何預設。這使得添加新功能變得非常簡單,就如同功能的直接實現一樣。但是,一旦你的專案有了第一個功能,之後開發的每一步都必須考慮到前面功能對未來開發工作的限制。

以我創建的社區活動平台 Doorkeeper 為例,它幫助組織者吸引參與者並管理註冊。開始時,Doorkeeper 只是為了幫助一個本地網路活動 ——Mobile Monday Tokyo 簡化他們的註冊及簽到流程。當時他們只需要一個簡潔的註冊流程,用戶只能進行活動註冊和取消。

當我們擴展 Doorkeeper 以適應更多組織者的需求時,我們發現許多活動是有固定參與上限的,這是 Mobile Monday 之前沒有考慮過的。要滿足這些新需求,我們決定增加一個限制參與者數量的功能。

我們基於一個假設構建了參與人數有限的活動:人們可以為活動註冊。但我們還需要決定,當某個活動已滿員時,嘗試註冊的人該怎麼處理。最簡單的方法是,當人滿時直接禁止註冊,但我們認為這會給想要參加的人帶來失望,也無法反饋給組織者活動的受歡迎程度。所以,我們引入了候補機制:如某人想註冊已滿的活動,他們會進入候補名單,若有參與者取消,則候補名單上的首位將頂替其位置。

接下來我們添加的功能是活動預付費,如果我們的唯一假設是 “人們可以為活動註冊”,那麼實施起來將非常簡單,但我們還得考慮其他已有的假設。

根據不同的活動,組織者可能允許也可能不允許預付費參與者取消。此外,他們可能想設置一些取消政策,比如根據取消的時間給予不同比例的退款。由於取消預付費註冊涉及到許多特殊情況,而且大多數組織者也不希望讓這一操作過於容易,我們決定不允許參與者自行取消預付費註冊。取而代之的是,參與者需要聯繫組織者,然後由組織者決定如何處理。

另外,因為一場活動的註冊人數有限,我們需要確保只有真正有機會參加的人才能預付費。為此,我們將註冊流程分為兩步:首先輸入註冊詳情,然後進行支付。如果在用戶填寫初始表格和提交之間,活動名額已滿,則該用戶會被添加到候補名單中。

我們還得處理用戶提交了初始表格卻沒有完成支付的情況。為此,我們引入了一個機制,在一定時間後自動取消這些未付款的預訂。

另一個需要考慮的情況是,當有人從候補名單上被轉正。對於需要預付費的活動,我們不能馬上發放票券,須讓用戶返回網站完成支付。

正如你所見,隨著新功能的不斷增加,考慮和解決基於現有假設限制的問題也變得愈加複雜。

功能可能帶來負面價值#

為了讓一個功能對產品有所增益,它需要對用戶確實有用。當一個功能帶來的技術債務超過了它為產品增加的價值,那麼這個功能實際上就具有了負面價值。

本地化就是一個往往會產生負面價值的功能。本地化在最簡單的層面上,就是把你的應用翻譯成多種語言。除了翻譯工作,這一過程還涉及到更多挑戰。就算只考慮最簡單的本地化形式 —— 維護一個包含各種語言特定字串的字典。

作為初步,這意味著你的應用中不能再包含硬編碼的文本,這增加了一層額外的抽象。儘管這一層抽象並不會帶來太多額外工作,但開發人員仍需時刻注意這一點。

你還必須在開發流程中增加翻譯這一步驟。考慮到開發人員可能不是所有支持的語言的母語使用者,他們將不能獨立完成文本部分,而需依賴譯者。這無疑會讓所有未來的開發進程都略顯緩慢。

如果本地化能夠產生巨大價值,那麼這點額外工作不成問題。但我常常看到一些應用進行馬虎的本地化,希望通過此吸引其他國家的用戶。但這並非有效的工作方式。除非你願意全力以赴地進行本地化和在支持的語言區域市場推廣,否則本地化不會帶來真正的價值。這樣一來,你最終會有一個功能,它帶來的技術債務超過了它本身的價值。

程式碼本身並不自帶價值#

作為開發人員,我們容易陷入這樣的錯覺 —— 認為編寫程式碼即是創造價值。然而,軟體的價值在於它對用戶的實用性,而非我們程式碼的質量。即便編寫得不完美但實現了有用功能的程式碼,比起完成無用任務的漂亮程式碼來說,其價值要大得多。

由於這個原因,我們需要確保自己的開發工作聚焦於有價值的功能。雖然傳統的開發過程中總假設有一個全能的產品主人,他們似乎能準確判斷各項功能的價值,但實際情況往往並非如此。

希望你已經和其他利益相關者合作,並深刻理解到你手頭工作的價值。但如果你並不這麼認為,那麼就應該提出質疑,試圖去探究他們為何認為這個功能有價值,以及是否有任何驗證工作被執行過。

確保我們實施的功能具有價值,這樣我們就減少了它們帶來的技術債務成為不可承受之重的可能性。

一旦添加功能,它大概會永久存在#

之所以我們需要對那些未能帶來足夠價值的功能保持高度警惕,部分原因在於一旦功能被加入,它通常就會永久地留存。

即便事後明顯看出該功能未能如我們預期那樣表現出色,常見的做法是不採取任何行動。這在一定程度上是由於沉沒成本的誤判,經常有種希望:即使功能目前未被使用,將來可能會有用武之地。

然而,不採取行動也有合理之處。移除一個功能也需要付出成本,不僅包括清除功能所需的開發工作,也可能會引起客戶的不滿。因此,一旦某個功能被加入到產品中,它幾乎總是會存在。

要避免技術債務,最好不要編寫程式碼#

避免技術債務的最可靠方法就是一開始就不寫程式碼。作為開發人員,我們最初的直覺是通過編寫程式碼來解決問題,但這並不總是最佳策略。很多時候,我們需要克制這種直覺。

舉個我自己的例子,我經營的一個招聘網站,幫助國際開發者在日本找到工作。起初我只是隨機發布我看到的職位資訊,但隨著聽到越來越多的成功案例,我認為公司會願意為這項服務付費。與此同時,我希望能在申請被發送給公司之前,對其進行一些基本的垃圾廣告篩查。

為了實現這一點,我開始使用 Ruby on Rails 構建一個篩選系統。然而,開發大約一天之後,我發現創造一個比讓候選人發送電子郵件表現更好的系統相當複雜。我需要複製電子郵件所具有的所有功能:附件、候選人與公司之間的通信等。更嚴峻的是,我需要保證系統的穩定運行,監控日誌等。

然而,我真正需要的只是在郵件發送至公司之前,有辦法對其進行適度地審核。因此,我沒有繼續走下去,而是選擇了使用 Google 應用中的組功能為每個公司設立一個郵件列表。儘管這不是最好的技術方案,但我創建的價值並非僅在於技術本身。相反,我更應該把時間用於幫助公司和候選人之間建立聯繫。

在現有的框架內工作來實現新功能#

當我們增加新功能時,一個減少技術債務的方法是在現有的假設或條件約束內完成工作,而非增添新的假設。以我們在 Doorkeeper 中的實踐為例來說明。

活動組織者可以給參與者發送資訊。我們建議組織者利用此功能向參與者發送活動提醒。但有些組織者從來不發送這種提醒,或許是因為他們忘記了,或者實在太忙。同時,還有一些組織者會發送定制化的提醒,其中包括活動當天的具體說明。

要作為新特性的我們的目標是確保每個參與者總是能收到提醒,而不依賴於組織者手動發送消息。

增加自動提醒的功能似乎最簡單的方法便是活動前一天自動向參與者發送電子郵件。這種實現方式很簡單,但沒能很好地考慮到那些需要發送臨時指令的組織者的情況。如果組織者還要發送額外的消息作為補充提醒,那麼參與者就會因為同一件事收到多封郵件,這會帶來不太理想的體驗。要應對這個問題,我們可以允許組織者自定義提醒內容。

考慮到自定義提醒的功能需求,我們意識到提醒和消息本質上是沒有太大區別的。如果我們能自動安排一條消息在指定時間發送,那麼組織者就能夠修改這條消息,甚至完全停用該功能。

當時我們並沒有安排消息在特定時間發送出去的功能。不過,允許組織者安排消息發送時間在更廣的應用場景中同樣也是一個很有用的特性。更為重要的是,把提醒保留為普通消息,這樣我們就能為組織者展示通常的相關報告,比如多少人打開和點擊了消息。

通過在已有的特性之上構建,而不是創造一個全新的獨立功能,我們找到了更好的解決方案。它不僅提供了更優的用戶體驗,而且產生了更少的技術債務。

概要回顧#

所以來快速回顧一下,由於在產品中增加更多程式碼會導致開發速度變慢,我們應該把所有程式碼看作是一種技術債務。為了確保開發不至於逐步停滯,我們需要確保我們編寫的程式碼能創造出更多的價值而非債務。

作為開發人員,我們應該成為產品的守護者,從不成熟的功能設計中保護它。我知道這不容易做到,但我們通過確保自己創造的產品有價值,而不僅僅是源源不斷地產出程式碼,可以帶來更大的好處。

原文鏈接:https://www.tokyodev.com/articles/all-code-is-technical-debt

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。