優(yōu)越性 vs 一致性

練習(xí)臺球

早年間,我還在一個創(chuàng)業(yè)團(tuán)隊(duì)里的時候,團(tuán)隊(duì)里有一個SAP的老顧問,打臺球?qū)儆讵?dú)孤求敗的那種,自己沒事時會在臺球廳開一張桌子,用左手打右手,基本不是左手一桿收八星,就是右手全清。

正好團(tuán)隊(duì)里那時大家都對臺球很有激情,后來我們每周的體育活動時,大家就去向這位老顧問討教。老顧問也很愛教,給每個人指導(dǎo)動作,怎么站,怎么握桿,怎么推,講的很詳細(xì)。

有一次,我被他好好地指導(dǎo)了一番,感覺自己功力大漲,然后轉(zhuǎn)身就像身邊的小伙伴發(fā)起了挑戰(zhàn)。不過很快我就感覺不對:平時其實(shí)和這位小伙伴水平不相上下,但這次很快就敗下陣來,甚至還沒有被指導(dǎo)之前手感好。

我很是不解,又向老顧問請教,老顧問一聽就樂了,擺出一副智叟的樣子跟我說:“甚矣,汝之不慧!練球不打球,打球不練球。又打又練,敗矣!”

聽到這種解釋,我當(dāng)時也是一臉懵逼。你說這打球不就是練習(xí)嗎,為啥不能跟別人打球的時候順便把技巧練了,這不是一箭雙雕兩全其美的事嗎?

老顧問給我解釋:“你打球的時候是在跟別人比賽,目的是為了贏球;你練球的時候是在訓(xùn)練自己的基本功。訓(xùn)練嘛,一個動作反復(fù)練習(xí),為的是在這個動作不停重復(fù)的過程中,形成自己的肌肉記憶。這完全是兩件關(guān)注點(diǎn)不同的事情,怎么能放在一起做呢?”

聽到這種說法的時候,說實(shí)話,當(dāng)時我是有點(diǎn)小震驚,因?yàn)橹白约撼R?guī)的腦回路就是如何節(jié)省能量嘛,節(jié)省時間嘛,一舉兩得嘛,感覺能在做一件事的時候把自己的能力提升了,心里美美噠。但老顧問這番話,讓我從另一個角度來考慮類似的事情。這種考慮的角度經(jīng)常讓我在用直覺思考的時候,停下來想想,問題到底出在哪。或者說,真的是天上有兩只雕,我就要想盡辦法,找一個好角度拉滿弓,嗖地一箭把兩只雕全部射中嗎?

Solo遺留系統(tǒng)

后來,我有機(jī)會接手一個項(xiàng)目,是為一家國內(nèi)比較大且有歷史的IT制造企業(yè)維護(hù)一套遺留系統(tǒng),不過有趣的是,這個項(xiàng)目需求范圍不是很大,業(yè)務(wù)也相對沒那么復(fù)雜,而且最重要的是,這個項(xiàng)目實(shí)際的開發(fā)人員只有我一個。恰逢當(dāng)時剛來公司,之前又耳濡目染一些重構(gòu)手法和設(shè)計(jì)模式,感覺自己可以大展身手了,想怎么寫怎么寫,把自己之前學(xué)的統(tǒng)統(tǒng)用個遍!

可是真正開始坐下來,拿到那個已經(jīng)十幾歲的代碼庫的時候,我是比較崩潰的,僅僅是數(shù)據(jù)庫的類型就變化過三次,而且配置文件都在留著。整個技術(shù)棧的年代也是停留在它出生的那個時代也沒有更新過。總之就是看哪哪不順眼。

所以當(dāng)時想的是,要不要給丫重構(gòu)了?

可是總不能只憑一張嘴去和客戶講,“噯,你們再加點(diǎn)錢,我給你們把技術(shù)棧換成新點(diǎn)的,因?yàn)槲矣X得那樣很刺激!” 總是要給個有價值的理由先吧。并且后來發(fā)現(xiàn),這個系統(tǒng)在客戶那里并不是核心,甚至只能說是將就著繼續(xù)用,他們也沒什么加錢的意思。所以就只能說服自己將就著寫。

寫著寫著又發(fā)現(xiàn)一個問題,這同一個系統(tǒng)里,對數(shù)據(jù)層的設(shè)計(jì)一共有兩套,并且每一套都不是現(xiàn)在的最佳實(shí)踐。當(dāng)時每次操作數(shù)據(jù)庫時,擺在我面前有三個選擇:選擇第一套,選擇第二套,或者再寫一套現(xiàn)在的最佳實(shí)踐。可是轉(zhuǎn)念又一想,我現(xiàn)在如果再加一種寫法,等到下一個和我一樣的人來維護(hù)這個系統(tǒng)時,也會遇到和我一樣的困境。或者說,至少,我不應(yīng)該再增加一種選擇了。

其實(shí)一樣的道理,遺留系統(tǒng)里不僅是數(shù)據(jù)層,一直到展現(xiàn)層或多或少都有這樣的問題。而正確的重構(gòu)手法是先加測試,在測試保護(hù)下再對其已經(jīng)浮現(xiàn)的模式做手術(shù)。如果每一處都要這樣正確地做事,很有可能在客戶期望的時間內(nèi)無法完成現(xiàn)有功能。所以當(dāng)前,正確的事應(yīng)該是,在完成客戶既定的需求上,盡可能地與現(xiàn)有的風(fēng)格保持一致。這樣等有了資源,再去重構(gòu)的時候也會更容易浮現(xiàn)模式。

關(guān)注點(diǎn)分離

不論在面對遺留系統(tǒng),還是在和團(tuán)隊(duì)一起做項(xiàng)目的時候,每個人在讀到團(tuán)隊(duì)其他人的代碼/設(shè)計(jì)時可能都會面臨這樣的選擇:是保持現(xiàn)有風(fēng)格不變,還是自己使用更好的寫法/框架/模式。在我看來,這兩種做法都不可取,前者使得代碼喪失了優(yōu)越性的可能,后者破壞了一致性。優(yōu)越性的喪失使得代碼質(zhì)量下降,以至于產(chǎn)生一些運(yùn)行時的問題。沒有了一致性,使得代碼變的難以維護(hù),降低了團(tuán)隊(duì)的開發(fā)效率。

那么正確的做法是什么呢?

當(dāng)我們看到一個風(fēng)格,被認(rèn)為是目前的最佳實(shí)踐,然后我們可能直覺地想到把它應(yīng)用到目前正在做的項(xiàng)目中,背后的動機(jī)往往有兩個:一者,這可是社區(qū)的推薦寫法,肯定好;二者,在工作中應(yīng)用了最新的最佳實(shí)踐,可以獲得很多經(jīng)驗(yàn)。而類似前面練習(xí)臺球的例子,這兩種動機(jī)完全對應(yīng)兩個關(guān)注點(diǎn):前者是對于代碼質(zhì)量的提升,后者是對于自身能力的提升。而這兩個關(guān)注點(diǎn)在某些時候是矛盾的:增加了新的行為,使得本來在既有行為下完成任務(wù)的成本大大提升。說白了:當(dāng)我們關(guān)注代碼質(zhì)量時,我們是在想順利完成產(chǎn)品交付,是要贏球;當(dāng)我們關(guān)注自身能力提升時,我們在意的是,使用了最佳實(shí)踐之后,使用者自身有什么新的變化,而不必或者更少地在意練習(xí)后對于團(tuán)隊(duì)要交付的產(chǎn)品的影響。可是現(xiàn)實(shí)情況是,練習(xí)后產(chǎn)生的不一致性,往往提升了后續(xù)維護(hù)的成本。同時,如果這種實(shí)踐只能帶來充分而非必要的好處,團(tuán)隊(duì)也不能獲得太大的收益。

成本與收益

那么剝離掉“練習(xí)”的動機(jī)之后,使用最佳實(shí)踐變成了什么了呢?

我認(rèn)為,使用/更新最佳實(shí)踐可以歸類為提升代碼優(yōu)越性,它本質(zhì)上和修復(fù)缺陷是一類事情。修復(fù)缺陷時,我們的驅(qū)動力是軟件運(yùn)行的實(shí)際結(jié)果與我們的期望不相符,這種差異給了我們提升代碼優(yōu)越性的一個方向。同樣在選擇最佳實(shí)踐時,也一定有一個必要的原因來驅(qū)動我們?nèi)プ鰞?yōu)越性的提升,這個必要原因一定是面向具體問題的,甚至說是可證偽的。基于這樣的考慮,優(yōu)越性提升應(yīng)該對應(yīng)一個明顯的收益。只是在現(xiàn)有的資源下,為了這個優(yōu)越性提升,會有對應(yīng)的成本。

所以事情又變成了經(jīng)濟(jì)問題:我們會根據(jù)成本和收益的結(jié)構(gòu)去選擇,分別在什么時候,在哪部分進(jìn)行優(yōu)越性的提升。

另一方面,我們來考慮一致性:不論是抱著練習(xí)的心態(tài),還是因?yàn)槌杀臼找娴目紤],局部優(yōu)越性的提升的副作用就是不一致性的增加,也就導(dǎo)致后續(xù)維護(hù)成本的增加。直到最終全部舊模式都被改為了最佳實(shí)踐,才恢復(fù)了之前的一致性,即隨著項(xiàng)目中新的實(shí)踐/模式的引入,維護(hù)成本是先提高后下降的。也就是說,作為開發(fā)團(tuán)隊(duì)中的一位協(xié)作者,我們要清楚的知道,局部優(yōu)越性提升的利潤其實(shí)是最小的。

結(jié)論

簡而言之:當(dāng)面對一個新的風(fēng)格被引入時,我們先考慮必要性。如果沒有必須的原因,在考慮一致性的情況下,應(yīng)該保持現(xiàn)狀。其次,如果是有必要原因,我們再考慮兩點(diǎn):一是考慮有沒有成本更低的優(yōu)越性;二是在一的結(jié)論下考慮,既然是必要原因,一定要保證舊模式應(yīng)全部被新的更好的模式替換。最后,如果沒有全局優(yōu)化必須給出合理理由以及后續(xù)優(yōu)化方案。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容