淺談活動(dòng)中臺(tái)系統(tǒng)技術(shù)債管理實(shí)踐
在項(xiàng)目研發(fā)過程中,由于時(shí)間、能力等因素往往會(huì)出現(xiàn)設(shè)計(jì)方案沒有做到最好或最優(yōu)、編碼質(zhì)量不夠好等問題,技術(shù)債的出現(xiàn)是不可避免的,并且隨著時(shí)間的推移,技術(shù)債對(duì)系統(tǒng)的影響會(huì)越來越大,同時(shí)使得對(duì)代碼和架構(gòu)設(shè)計(jì)的更改越來越困難,想要進(jìn)一步提升效能必須要對(duì)技術(shù)債進(jìn)行管理,本文通過在活動(dòng)中臺(tái)系統(tǒng)的技術(shù)債實(shí)踐經(jīng)驗(yàn),介紹技術(shù)債的含義、分類和管理。
一、技術(shù)債的含義
1.1 技術(shù)債的含義
關(guān)于技術(shù)債的概念可以追溯到1992年,沃德·坎寧安(Ward Cunningham)首次提出,第一次發(fā)布代碼,就好比借了一筆錢。只要通過不斷重寫來償還債務(wù),小額負(fù)債可以加速開發(fā)。但久未償還債務(wù)會(huì)引發(fā)危險(xiǎn)。復(fù)用馬馬虎虎的代碼,類似于負(fù)債的利息。整個(gè)部門有可能因?yàn)樗缮⒌膶?shí)現(xiàn),不完全的面向?qū)ο蟮脑O(shè)計(jì)或其他諸如此類的負(fù)債而陷入窘境[1]。
《維基百科》中提出,技術(shù)負(fù)債(Technical debt),又稱技術(shù)債,也稱為設(shè)計(jì)負(fù)債(design debt)、代碼負(fù)債(code debt),是程序設(shè)計(jì)及軟件工程中的一個(gè)比喻。指開發(fā)人員為了加速軟件開發(fā),在應(yīng)該采用最佳方案時(shí)進(jìn)行了妥協(xié),改用了短期內(nèi)能加速軟件開發(fā)的方案,從而在未來給自己帶來的額外開發(fā)負(fù)擔(dān)。這種技術(shù)上的選擇,就像一筆債務(wù)一樣,雖然眼前看起來可以得到好處,但必須在未來償還。軟件工程師必須付出額外的時(shí)間和精力持續(xù)修復(fù)之前的妥協(xié)所造成的問題及副作用[3]。
如下圖所示,技術(shù)債在研發(fā)人員的日常工作付出中占據(jù)了一定的比例。
1.2 技術(shù)債的危害
我們可以從效率、質(zhì)量、體驗(yàn)三個(gè)方面來看:
1.2.1 效率
這是最直接的影響,當(dāng)技術(shù)債不斷增加,軟件系統(tǒng)會(huì)變得非常脆弱。這種脆弱主要是由不良的架構(gòu)設(shè)計(jì)或代碼設(shè)計(jì)導(dǎo)致,不管最初是選擇了劃分良好的微服務(wù)架構(gòu),還是單體架構(gòu),技術(shù)債不斷打破設(shè)計(jì)原則,讓原則不復(fù)存在,以至于很難理清系統(tǒng)組件之間的關(guān)系和職責(zé)。當(dāng)修改其中的一部分組件時(shí),其他組件也會(huì)牽連,可能會(huì)陷入惡性循環(huán)。
1.2.2 質(zhì)量
以上圖為例,從研發(fā)持續(xù)交付角度來分析的話,在項(xiàng)目版本迭代前期,業(yè)務(wù)功能較少的情況下,高質(zhì)量要求的項(xiàng)目可能會(huì)比低質(zhì)量要求的項(xiàng)目迭代速度慢一點(diǎn),但是隨著項(xiàng)目逐漸發(fā)展,高質(zhì)量要求的項(xiàng)目對(duì)比低質(zhì)量要求的項(xiàng)目迭代速度顯著提升,技術(shù)債的持續(xù)累積是導(dǎo)致質(zhì)量下降的關(guān)鍵原因,技術(shù)債是無法避免的,因此技術(shù)債的有效管理和消除是我們保障高質(zhì)量軟件的必不可少的方式之一。
1.2.3 體驗(yàn)
軟件產(chǎn)品需要不斷演進(jìn)才能在長時(shí)間后依然還能適應(yīng)市場(chǎng),才能具有較強(qiáng)的生命力。相反,有的軟件在經(jīng)過幾年的開發(fā)之后,隨著技術(shù)債的增加,已經(jīng)變的很難維護(hù),很多時(shí)候只能被推倒重寫,主要是不斷疊加的技術(shù)債導(dǎo)致。技術(shù)債的疊加不斷增加系統(tǒng)的復(fù)雜性,從而開發(fā)的成本逐漸增高,每次迭代都需要解決設(shè)計(jì)不足或技術(shù)所帶來的問題。
二、技術(shù)債是怎么產(chǎn)生的?
技術(shù)債的出現(xiàn)是不可避免的,但是不同的場(chǎng)景下會(huì)產(chǎn)生不同的技術(shù)債,帶來的影響也是不一樣的,如果按照健康角度分類的話,對(duì)于研發(fā)人員允許出現(xiàn)的技術(shù)債可以劃分為健康的一類,對(duì)于研發(fā)人員盡量避免的技術(shù)債則劃分為不健康的一類。我們可以從以下四個(gè)維度進(jìn)行分析。
2.1 沖動(dòng)/有意 - “沒有做更好的設(shè)計(jì)”
研發(fā)團(tuán)隊(duì)雖然識(shí)別到這樣做會(huì)導(dǎo)致技術(shù)債的積累,但是不清楚帶來的后果,沒有去做更好的設(shè)計(jì)方案。比如項(xiàng)目在線上運(yùn)行時(shí),突然出現(xiàn)了一個(gè)線上問題,如果不盡快修復(fù)上線,就會(huì)造成很大的損失,這種情況下,已經(jīng)無法再針對(duì)問題作詳盡的設(shè)計(jì)方案,現(xiàn)在需要以最快的方式修復(fù)上線,這種情況下往往不會(huì)考慮更好的設(shè)計(jì)方案,而是以最快捷的方式解決問題。對(duì)于當(dāng)下的臨時(shí)方案在未來會(huì)帶來什么技術(shù)債,研發(fā)人員并沒有關(guān)注。
2.2 謹(jǐn)慎/有意 - “必須盡快交付”
當(dāng)研發(fā)團(tuán)隊(duì)面臨業(yè)務(wù)壓力時(shí),例如在發(fā)布新產(chǎn)品時(shí)需要快速上線以占領(lǐng)市場(chǎng)時(shí),快速解決問題的重要性常常超越了更好的實(shí)踐。在這種情況下,團(tuán)隊(duì)往往會(huì)選擇快速完成產(chǎn)品交付,然后再處理技術(shù)債務(wù)。團(tuán)隊(duì)清楚這樣做會(huì)帶來技術(shù)債務(wù),也知道逾期還債的具體后果,以至已經(jīng)安排好了未來的改進(jìn)計(jì)劃。這種場(chǎng)景很常見,是已知技術(shù)債的一種主要來源。
2.3 沖動(dòng)/無意 - “不知道怎樣設(shè)計(jì)更好”
這個(gè)維度技術(shù)債務(wù)產(chǎn)生的原因通常是由于人員技能的不足。在實(shí)際研發(fā)中,不可能保證所有人的水平都是一樣的,由于缺乏相關(guān)技能,研發(fā)人員可能不清楚如何編寫更優(yōu)秀和精煉的代碼,不知道如何設(shè)計(jì)更好的架構(gòu)或者給出更佳的解決方案,這種情況下,研發(fā)人員按照自己的理解和設(shè)計(jì)方案進(jìn)行工作,可能會(huì)帶來一部分技術(shù)債。不管怎樣的團(tuán)隊(duì),人員的更替都是避免不了的,可能對(duì)項(xiàng)目不夠熟悉,對(duì)某一塊功能不夠熟悉,短時(shí)間內(nèi)快速理解并給出設(shè)計(jì)方案,可能會(huì)有很大難度,個(gè)人的經(jīng)驗(yàn)不同,認(rèn)知不同,在實(shí)現(xiàn)相同的功能時(shí)選擇的方案也是不同的。
2.4 謹(jǐn)慎/無意 - “現(xiàn)在有更好的方案”
隨著團(tuán)隊(duì)成員的能力提升或者行業(yè)技術(shù)上的演進(jìn),對(duì)于之前認(rèn)為的最佳方案現(xiàn)在看來并不是最好的解決方案。但在當(dāng)時(shí),可能并不知道有更好的做法。這種技術(shù)債確實(shí)也是無法避免的,甚至?xí)?jīng)常遇到,最簡單的是基于當(dāng)下的經(jīng)驗(yàn)甚至業(yè)界最優(yōu)的一些實(shí)踐選擇技術(shù)方案或者技術(shù)框架??赡茉谥白鲞@塊功能的時(shí)候,團(tuán)隊(duì)成員已經(jīng)對(duì)當(dāng)時(shí)的方案達(dá)成了一致,認(rèn)為是最優(yōu)的方案,但是現(xiàn)在突然發(fā)現(xiàn)有更優(yōu)的方案,那么為了項(xiàng)目的長遠(yuǎn)發(fā)展、穩(wěn)定迭代,同樣需要對(duì)項(xiàng)目作最優(yōu)方案的替換。
以上將技術(shù)債務(wù)分為四類。我們通常認(rèn)為,健康的技術(shù)債是右邊的兩個(gè)維度,不健康的技術(shù)債是左邊的兩個(gè)維度?;诖宋覀兛梢苑治黾夹g(shù)債產(chǎn)生的原因并制定相應(yīng)的改進(jìn)措施。
- 對(duì)于沖動(dòng)/有意類型的技術(shù)債,我們可以在日常的研發(fā)過程中擬制嚴(yán)格的規(guī)范,加強(qiáng)流程化的研發(fā)管理,讓我們的研發(fā)人員對(duì)最優(yōu)設(shè)計(jì)達(dá)成習(xí)慣和規(guī)范;
- 對(duì)于謹(jǐn)慎/有意類型的技術(shù)債,我們可以和產(chǎn)品達(dá)成一致,每次面臨這種緊急需求,或者需要快速上線而沒有采取最優(yōu)方案的情況,可以直接記錄,后續(xù)盡快優(yōu)化;
- 對(duì)于沖動(dòng)/無意類型的技術(shù)債,我們可以對(duì)所有的項(xiàng)目成員進(jìn)行能力和認(rèn)知的提升,盡可能讓研發(fā)人員在熟悉功能和項(xiàng)目的情況下進(jìn)行研發(fā),另外可以增加設(shè)計(jì)方案評(píng)審流程和代碼提交評(píng)審流程,有效減少這種類型的技術(shù)債;
- 對(duì)于謹(jǐn)慎/無意類型的技術(shù)債,我們需要在識(shí)別到的時(shí)候第一時(shí)間記錄下技術(shù)債,并且根據(jù)研發(fā)排期合理的安排時(shí)間進(jìn)行修復(fù)。
為了保證產(chǎn)品持續(xù)的競(jìng)爭力,上面幾點(diǎn)只是方法,如果沒有成本上的投入,只能淪為空談。從整個(gè)產(chǎn)品團(tuán)隊(duì),都要提升對(duì)技術(shù)的正確理解,技術(shù)的構(gòu)建并不是一勞永逸的,是需要不斷的成本投入來維護(hù)的。
三、技術(shù)債管理實(shí)踐
3.1 一個(gè)技術(shù)債真實(shí)案例
下面以一個(gè)項(xiàng)目中遇到的真實(shí)技術(shù)債案例來介紹,活動(dòng)中臺(tái)系統(tǒng)是一個(gè)面向用戶的中臺(tái)項(xiàng)目,可能每天都會(huì)產(chǎn)生大量的活動(dòng)數(shù)據(jù),即使進(jìn)行了大量的分表處理,但是動(dòng)輒千萬級(jí)的數(shù)據(jù)仍然給數(shù)據(jù)庫操作帶來了一定的負(fù)擔(dān),所以我們目前沉淀了一套通用的數(shù)據(jù)庫數(shù)據(jù)清理方案,根據(jù)不同類型的表配置不同的清理策略,基本參考維度是數(shù)據(jù)的產(chǎn)生時(shí)間和活動(dòng)狀態(tài),如果一個(gè)已經(jīng)結(jié)束的活動(dòng)且數(shù)據(jù)產(chǎn)生時(shí)間大于半年則直接刪除。這種方案雖然通用,但是在線上發(fā)現(xiàn)了嚴(yán)重的慢SQL問題,即使是通過離線庫操作,仍然會(huì)讓系統(tǒng)存在一定的風(fēng)險(xiǎn),顯然這個(gè)問題需要關(guān)注。
3.2 原來的做法
在原本的做法中,研發(fā)團(tuán)隊(duì)對(duì)于項(xiàng)目產(chǎn)生的技術(shù)債采取的方案是隨機(jī)修復(fù),也就是發(fā)現(xiàn)后會(huì)簡單的記錄下,如果是緊急問題則會(huì)同步項(xiàng)目組盡快上線,如果是非緊急問題,則會(huì)在下次版本迭代涉及該模塊時(shí)進(jìn)行修復(fù),或者在版本gap期間隨機(jī)進(jìn)行修復(fù),缺乏系統(tǒng)性的管理,往往可能會(huì)導(dǎo)致問題的遺漏,并且對(duì)于技術(shù)債的修復(fù)缺乏系統(tǒng)的分析和判斷,雖然在有意識(shí)的修復(fù)技術(shù)債,但是效益容易被忽略,往往看不到真正的價(jià)值。
對(duì)于這個(gè)數(shù)據(jù)清理帶來的慢SQL問題,雖然會(huì)產(chǎn)生慢SQL,但是對(duì)線上業(yè)務(wù)影響較小,所以優(yōu)先級(jí)不高,暫時(shí)擱置,待到項(xiàng)版本有空閑人力再去優(yōu)化,這個(gè)問題由于是技術(shù)側(cè)單純的技術(shù)優(yōu)化,所以沒有納入需求列表,單純的依賴開發(fā)人員人工記憶,等到人力空閑時(shí)再想是否有問題需要優(yōu)化,這個(gè)時(shí)候才想到塵封已久的問題。方案的變動(dòng)需要測(cè)試的介入來回歸功能,這個(gè)時(shí)候開發(fā)人員想要優(yōu)化,可能測(cè)試人力緊張,沒能及時(shí)開發(fā)和測(cè)試,功能的上線又會(huì)擱置。
3.3 新的做法
按照現(xiàn)有方案,我們已經(jīng)形成了一套穩(wěn)定的技術(shù)債機(jī)制,相應(yīng)的按照以下步驟進(jìn)行處理:
3.3.1 識(shí)別技術(shù)債
想要管理技術(shù)債,首先就是要識(shí)別技術(shù)債,技術(shù)的持續(xù)改進(jìn)離不開團(tuán)隊(duì)中每個(gè)人的努力,因此需要每個(gè)成員都積極參與。通常我們?cè)谧R(shí)別技術(shù)債的時(shí)候可以從以下幾個(gè)類別去篩查。
當(dāng)我們發(fā)現(xiàn)這個(gè)數(shù)據(jù)清理問題時(shí),可以直接記錄在技術(shù)債跟蹤列表中,記錄技術(shù)債的所屬項(xiàng)目、問題描述、創(chuàng)建人、處理人、創(chuàng)建時(shí)間、修復(fù)時(shí)間、技術(shù)債狀態(tài)、規(guī)劃版本、備注等屬性,便于技術(shù)債的跟蹤和審視。這種跟蹤表只是一種方式,我們還有各種看板、空間可以用來記錄,項(xiàng)目內(nèi)達(dá)成一致即可。
3.3.2 分析技術(shù)債
記錄技術(shù)債之后,時(shí)常會(huì)遇到的問題是,需要改進(jìn)的地方太多,尤其是對(duì)于遺留系統(tǒng)。怎么辦?分析優(yōu)先級(jí)。我們可以基于價(jià)值/成本矩陣來評(píng)估改進(jìn)任務(wù)的價(jià)值和成本?;谙聢D的價(jià)值-成本矩陣,我們會(huì):
- 優(yōu)先解決高價(jià)值+低成本的技術(shù)債;
- 嘗試將高價(jià)值+高成本的技術(shù)債拆分為高價(jià)值+低成本的技術(shù)債,逐步解決;
- 在沒有高價(jià)值+高/低成本的技術(shù)債時(shí),再來考慮低價(jià)值+低成本的技術(shù)債;
- 最后如果只剩下低價(jià)值+高成本的技術(shù)債,還是先拆分,再解決,或可考慮直接移除。
3.3.3 解決技術(shù)債
分析完技術(shù)債的價(jià)值、成本、優(yōu)先級(jí)、方案,我們可以在版本的gap期間跟隨版本修復(fù)技術(shù)債,如果某部分功能剛好規(guī)劃在版本中,那我們技術(shù)債的修復(fù)剛好由測(cè)試一起回歸,這樣可以做到工作量最小化,如果是高優(yōu)的技術(shù)債,我們就需要盡早安排修復(fù),緊急線上問題更是需要迅速迭代小版本上線。當(dāng)然,修復(fù)完一定要及時(shí)更新技術(shù)債的狀態(tài)。對(duì)于數(shù)據(jù)清理這條技術(shù)債,我們分析后得出結(jié)論:對(duì)于系統(tǒng)穩(wěn)定方面有影響,需要一次性徹底優(yōu)化,價(jià)值較高,優(yōu)先級(jí)較高但是無需緊急修復(fù)上線,所以在下一個(gè)版本人力空閑期間就可以伺機(jī)修復(fù)上線。
這里要注意的是,對(duì)于同一條技術(shù)債,記錄的人、修復(fù)的人可以不是同一人,這里需要技術(shù)債記錄詳細(xì),便于方案的執(zhí)行。數(shù)據(jù)清理這條技術(shù)債我們?cè)陔S后的一段時(shí)間內(nèi)就整改上線,完成了這條技術(shù)債的修復(fù)。
3.3.4 階段審視
在實(shí)行技術(shù)債機(jī)制的管理過程中,建議進(jìn)行階段審視,查漏補(bǔ)缺。我們已經(jīng)詳細(xì)記錄了技術(shù)債的所屬項(xiàng)目、問題描述、創(chuàng)建人、處理人、創(chuàng)建時(shí)間、修復(fù)時(shí)間、技術(shù)債狀態(tài)、規(guī)劃版本、備注等屬性,便于技術(shù)債的跟蹤和審視。可以從多方面審視,一個(gè)是統(tǒng)計(jì)數(shù)據(jù),如下表,可以看出每個(gè)階段的修復(fù)數(shù)量、新增數(shù)量、上線總數(shù)、正在修復(fù)的數(shù)量和待開始的數(shù)量。這也是衡量項(xiàng)目質(zhì)量的影響指標(biāo)之一。
另外一種是趨勢(shì)圖,我們可以從下圖這樣的折線圖明顯看出不同狀態(tài)的技術(shù)債的趨勢(shì),包括不同階段的技術(shù)債新增數(shù)量、修復(fù)數(shù)量、修復(fù)中數(shù)量和技術(shù)債總數(shù)趨勢(shì)變化。
除此之外我們可以觀察團(tuán)隊(duì)成員在修復(fù)技術(shù)債方面的工作量體現(xiàn),比如統(tǒng)計(jì)一年不同季度、不同團(tuán)隊(duì)成員每個(gè)季度對(duì)于技術(shù)債的修復(fù)數(shù)量,都是一些階段審視的方式。
3.4. 技術(shù)債管理機(jī)制
3.4.1 明確管理機(jī)制和責(zé)任分配
團(tuán)隊(duì)在針對(duì)技術(shù)債的治理過程中一定要確定主要責(zé)任人,雖然解決團(tuán)隊(duì)技術(shù)債問題是所有團(tuán)隊(duì)成員的責(zé)任,但是為了管理流程化、合理化、最優(yōu)化,往往需要指定一個(gè)負(fù)責(zé)人專門跟蹤技術(shù)債的管理。除此之外,技術(shù)債的管理機(jī)制要在團(tuán)隊(duì)內(nèi)部達(dá)成高度一致,整個(gè)團(tuán)隊(duì)對(duì)于技術(shù)債問題的認(rèn)知、修復(fù)、管理都是經(jīng)過正式裁決的。
3.4.2 主動(dòng)預(yù)防原則
通常來說,開發(fā)人員能直觀感受到技術(shù)債的壞處,大都愿意去償還技術(shù)債,所以技術(shù)債累積的主要原因是,沒有認(rèn)識(shí)到技術(shù)債累積給業(yè)務(wù)發(fā)展帶來的巨大壞處。這也就意味著,解決技術(shù)債的第一步就是,要意識(shí)到償還技術(shù)債的重要性,從而愿意投入資源去解決。對(duì)主動(dòng)引入的技術(shù)債,要盡量讓管理層和產(chǎn)品團(tuán)隊(duì)了解技術(shù)上的捷徑將會(huì)帶來的長期危害,盡量減少技術(shù)債的引入。
3.4.3 高價(jià)值優(yōu)先原則
需要遵循高價(jià)值優(yōu)先的原則來優(yōu)先修復(fù)技術(shù)債,上面我們已經(jīng)分析過技術(shù)債問題的價(jià)值/成本矩陣,對(duì)于分析結(jié)果,我們?cè)诎姹局薪鉀Q技術(shù)債問題的時(shí)候就要嚴(yán)格按照高價(jià)值優(yōu)先的原則去修復(fù),而不是根據(jù)技術(shù)債發(fā)現(xiàn)的時(shí)間,或者是成本低的技術(shù)債優(yōu)先修復(fù),切忌隨機(jī)修復(fù)技術(shù)債。
四、經(jīng)驗(yàn)總結(jié)
4.1 技術(shù)債是不是越少越好?
當(dāng)然不是!提到技術(shù)債,我們想到的往往是它的壞處,比如難以維護(hù)、難以增加新功能等,但實(shí)際上它也有好處。關(guān)于技術(shù)債的好處,我們可以對(duì)應(yīng)著金融領(lǐng)域的經(jīng)濟(jì)債務(wù)來理解。我們都知道,經(jīng)濟(jì)債務(wù)最明顯的好處在于,可以幫助我們完成很多本來不可能完成的任務(wù),比如貸款買房。相應(yīng)的,技術(shù)債可以在短期內(nèi)幫我們快速完成業(yè)務(wù)開發(fā),滿足用戶需求,就類似房貸的作用。當(dāng)研發(fā)團(tuán)隊(duì)面臨業(yè)務(wù)壓力時(shí),例如在發(fā)布新產(chǎn)品時(shí)需要快速上線以占領(lǐng)市場(chǎng)時(shí),快速解決問題的重要性常常超越了更好的實(shí)踐。在這種情況下,團(tuán)隊(duì)往往會(huì)選擇快速完成產(chǎn)品交付,然后再處理技術(shù)債務(wù)。團(tuán)隊(duì)清楚這樣做會(huì)帶來技術(shù)債務(wù),也知道逾期還債的具體后果,只要有計(jì)劃的進(jìn)行優(yōu)化即可。
4.2 持續(xù)管理技術(shù)債帶來的益處有哪些?
- 提升系統(tǒng)穩(wěn)定性:不斷規(guī)范化的解決更多的技術(shù)債有利于系統(tǒng)更加穩(wěn)定;
- 形成穩(wěn)定機(jī)制:活動(dòng)中臺(tái)系統(tǒng)經(jīng)過長時(shí)間的實(shí)踐,逐漸形成穩(wěn)定的技術(shù)債管理機(jī)制,面對(duì)項(xiàng)目中的技術(shù)債不再頭疼如何跟蹤;
- 提升項(xiàng)目質(zhì)量:隨著技術(shù)債機(jī)制的實(shí)行,項(xiàng)目成員在迭代時(shí)就會(huì)更多的考慮技術(shù)債方面的問題,久而久之項(xiàng)目質(zhì)量也會(huì)有所提升。
4.3 技術(shù)債是否可以作為項(xiàng)目管理的重要指標(biāo)之一?
技術(shù)債已經(jīng)成為很多項(xiàng)目管理的一個(gè)重要指標(biāo),用來衡量項(xiàng)目整體的研發(fā)效能,雖然本文沒有過度涉及技術(shù)債在研發(fā)效能工具方面的體現(xiàn),但是在這個(gè)過程中工具很重要。
五、參考文檔
[1]Ward Cunningham,《WyCash 投資組合管理系統(tǒng)》,ACM SIGPLAN OOPS Messenger4, no.2 (1992)
[2]https://www.productplan.com/glossary/technical-debt/
[3]https://zh.wikipedia.org/wiki/%E6%8A%80%E6%9C%AF%E8%B4%9F%E5%80%BA#cite_note-oopsla92-1
[4]Philippe Kruchten, Rod Nord, and Ipek Ozkaya, 《管理技術(shù)債務(wù):減少軟件開發(fā)中的摩擦》(Addison-Wesley, 2019)