開(kāi)發(fā)者寫(xiě)好了某個(gè)功能的代碼,想知道這個(gè)功能是不是實(shí)現(xiàn)了,代碼還需不需要再改,這就是一種反饋。在軟件開(kāi)發(fā)中,尤其是聯(lián)調(diào)時(shí),縮短反饋弧有助于及時(shí)發(fā)現(xiàn)問(wèn)題、采取對(duì)策,提高開(kāi)發(fā)效率。那么什么樣的反饋弧才算短?如何看待縮短反饋弧的投入產(chǎn)出比?本文分享阿里巴巴研究員南門(mén)對(duì)軟件開(kāi)發(fā)中反饋弧的相關(guān)思考和看法。
一 為什么縮短反饋弧是關(guān)鍵
都說(shuō)“沒(méi)有度量就沒(méi)改進(jìn)”。但這句話(huà)還不完整。度量對(duì)于改進(jìn)的作用是給反饋,但單單有度量還不夠,還要度量得足夠頻繁、度量得足夠快,這樣才能更有效的進(jìn)行改進(jìn)。縮短反饋弧(feedback loop)的價(jià)值在生活中有很多例子:
減肥。如果每天稱(chēng)體重,就有助于減肥、有助于控制體重。吃多了,看著體重一天天上去,心里就有壓力了,就會(huì)控制。如果不是每天稱(chēng)體重,就容易放縱自己,一發(fā)而不可收拾。每天稱(chēng)體重,和每半年稱(chēng)一次體重,對(duì)減(gai)肥(jin)的作用是完全不一樣的。
吃飯,如果吃太快,就容易吃太多。原因也是反饋弧太長(zhǎng)。人的飽腹感是有delay的,從肚子已經(jīng)吃飽了,到大腦感受到飽腹感,有一個(gè)delay。在這個(gè)delay這段時(shí)間里,如果繼續(xù)吃,就會(huì)吃多了。
育兒,是反饋弧的另一個(gè)很好的例子。家里有小孩的人,都對(duì)育兒很焦慮。因?yàn)椋翰恢垃F(xiàn)在做的這些事情,對(duì)小孩將來(lái)的上學(xué)、就業(yè)會(huì)產(chǎn)生什么影響。在育兒這件事情上面,反饋弧的長(zhǎng)度是論年記的。
工作中也有很多例子:
線(xiàn)上變更,我們強(qiáng)調(diào)“可監(jiān)控”。做了一個(gè)變更,如果能馬上得到高質(zhì)量的反饋(高質(zhì)量的反饋 = 監(jiān)控覆蓋率高、噪音低、閾值設(shè)定合理),就非常有助于判斷我做的這個(gè)變更是好的還是不好的。資損核對(duì),從T+1,到T+H,到TM,也是反饋弧不斷縮短的過(guò)程。反饋弧縮短是非常有助于及時(shí)發(fā)現(xiàn)問(wèn)題、及時(shí)采取對(duì)策的。
系統(tǒng)設(shè)計(jì)分析的評(píng)估遺漏,仍然是反饋的問(wèn)題。我的這個(gè)系分,對(duì)不對(duì),有沒(méi)有遺漏。我系分的時(shí)候做了一個(gè)判斷:這個(gè)鏈路可以復(fù)用。那么這個(gè)判斷對(duì)不對(duì)?有沒(méi)有遺漏、判斷對(duì)不對(duì),這些都是反饋。
我們平時(shí)說(shuō) “業(yè)務(wù)試錯(cuò)”,也是反饋。“試錯(cuò)”的意思就是:試一下,看看錯(cuò)不錯(cuò),如果錯(cuò)了就掉頭,如果對(duì)了就可以繼續(xù)投入。“快速試錯(cuò)”就是業(yè)務(wù)效果的反饋弧要縮短。沒(méi)有“快速試錯(cuò)”能力,就是反饋弧長(zhǎng),就不好。我們要有快速試錯(cuò)能力。
晉升,也是很痛苦。因?yàn)闀x升的反饋弧也很長(zhǎng)。辛辛苦苦干兩三年,還要準(zhǔn)備晉升述職,也不知道最后評(píng)委會(huì)怎么評(píng)價(jià)。為了解決這個(gè)問(wèn)題,如果能在過(guò)程中增加了一些非正式的述職,提供反饋,效果就很好。
二 怎么算反饋弧短?
反饋弧短不短,有兩個(gè)方面:
反饋的前置等待時(shí)間。理想狀態(tài)是:反饋不需要等,任何時(shí)候想要反饋都可以。
反饋本身的耗時(shí)。理想狀態(tài)是:反饋本身的耗時(shí)很短,結(jié)果立等可取。
打個(gè)比方,二三十年前,那時(shí)候量血壓(量血壓就是一種反饋)是要去醫(yī)院量的,只有等早上醫(yī)院開(kāi)門(mén)了、掛個(gè)號(hào)、排隊(duì)等,輪到你了醫(yī)生給你量血壓。所以不是任何時(shí)候想量血壓就能量血壓的,量血壓的前置等待時(shí)間很長(zhǎng)。但量血壓這個(gè)事情本身,耗時(shí)很短,一分鐘就知道結(jié)果了。后來(lái),有了家用血壓計(jì),量血壓就不用等了,也不需要求助于醫(yī)生,自己在家里任何時(shí)候都可以量,可以每天早中晚量三次,甚至可以每小時(shí)都量一下。有了家用血壓計(jì),雖然量血壓這個(gè)反饋動(dòng)作本身的耗時(shí)并沒(méi)有縮短很多,但提高了頻次,任何時(shí)候想要反饋就可以給反饋,前置等待時(shí)間縮短到幾乎為零。這個(gè)變化就大大的有助于病人控制自己的血壓。類(lèi)似的,控制血糖也是類(lèi)似的道理。以前要知道血糖是要去醫(yī)院驗(yàn)血的,現(xiàn)在有一些新技術(shù),可以讓病人自己就可以測(cè)量血糖,手指尖夾一下就可以了。這個(gè)變化就大大的有助于控制自己的血糖。
軟件開(kāi)發(fā)活動(dòng)中的反饋也是類(lèi)似的。我是一個(gè)開(kāi)發(fā),我改了一行代碼,我想知道這行代碼有沒(méi)有問(wèn)題。這就是給我反饋。我是一個(gè)開(kāi)發(fā),我寫(xiě)了大半天代碼,把某個(gè)功能需要的代碼寫(xiě)好了,我現(xiàn)在想知道這個(gè)功能是不是能work了、我的代碼還要不要再改。這也是反饋。今天,在有些團(tuán)隊(duì),一個(gè)開(kāi)發(fā)要得到這些反饋,反饋弧還很長(zhǎng),長(zhǎng)在兩個(gè)方面:1)要等,不是任何時(shí)候想要反饋都可以。2)反饋本身的耗時(shí)長(zhǎng)、成本高,結(jié)果也不是立等可取的。反饋弧一長(zhǎng),開(kāi)發(fā)效率就降低了。在一些團(tuán)隊(duì)里,反饋弧長(zhǎng),在他們的開(kāi)發(fā)聯(lián)調(diào)中的體現(xiàn)就是:
反饋不是隨時(shí)隨地的,要等。因?yàn)椴皇请S時(shí)隨地都可以發(fā)起一筆的。也不是每個(gè)人都知道怎么發(fā)起一筆的,只有特定的同學(xué)才知道怎么發(fā)起一筆。
反饋不是立等可取的。就算發(fā)起了一筆交易,還要找一個(gè)個(gè)域的同學(xué)check數(shù)據(jù)。同時(shí),反饋的質(zhì)量也不高,反饋不consistent,因?yàn)閏heck是人做的,不同人的做的check不一樣。
持續(xù)集成就是要縮短反饋弧。我們平時(shí)一直在做各種事情,比如改代碼、數(shù)據(jù)庫(kù)加字段、修改DRM值、數(shù)據(jù)庫(kù)里插入數(shù)據(jù)。持續(xù)集成就是每件事情做了以后、每個(gè)動(dòng)作發(fā)生以后,都要盡可能快的給我反饋,告訴我各種場(chǎng)景是不是通的、代碼是不是work。“持續(xù)”了,反饋要隨時(shí)隨地都可以給。自動(dòng)化是縮短反饋弧的必要條件(但不是充要條件,因?yàn)樽詣?dòng)化了以后,還有覆蓋率、充分性、有效性等要素)。如果還有人工步驟,就不肯能做到反饋弧很短,因?yàn)槿耸遣豢赡茈S時(shí)隨地都available的,人的動(dòng)作也是很慢的。
三 縮短反饋弧的成本和投入產(chǎn)出比
要縮短反饋弧、建設(shè)持續(xù)集成,的確是需要投入成本的。要花人花時(shí)間去寫(xiě)自動(dòng)化、去維護(hù)整個(gè)基建、去維護(hù)持續(xù)集成的良好運(yùn)行。但是,在縮短反饋弧上投入的成本,是能從其他地方收回來(lái)的。很多人只看到了建設(shè)持續(xù)集成需要的投入,但是他們沒(méi)有算另一筆賬:這個(gè)做好了,能節(jié)省多少時(shí)間。
例如,對(duì)每個(gè)項(xiàng)目來(lái)說(shuō),把每個(gè)聯(lián)(ji)調(diào)(cheng)用例和check都自動(dòng)化了,這個(gè)前期投入,在項(xiàng)目進(jìn)行的過(guò)程中會(huì)收到回報(bào)。比如,人肉做一次check,算上找人的功夫,加起來(lái)每次人肉check可能要15分鐘。而把這個(gè)check自動(dòng)化,需要2小時(shí)的工作量(包括自動(dòng)化、以及后面的維護(hù))。那么,如果整個(gè)項(xiàng)目過(guò)程中要做的check次數(shù)超過(guò)8次,這個(gè)自動(dòng)化就是一筆劃算的買(mǎi)賣(mài)。事實(shí)上,一個(gè)check在一個(gè)項(xiàng)目里面何止跑8次。現(xiàn)在,可能一個(gè)check在一個(gè)項(xiàng)目里面只跑幾次,但這是因?yàn)閷?shí)在沒(méi)法再多跑了,因?yàn)槊看蝐heck都非常累。但如果自動(dòng)化了,check就可以跑很多次很多次。我們是希望check跑很多次很多次的。因?yàn)椋何覀兿M覀內(nèi)魏螘r(shí)候改了代碼,都能隨時(shí)隨地的得到反饋。
另外,隨時(shí)隨地跑一下check、隨時(shí)隨地的得到反饋,還有一個(gè)很大的好處,就是:能使得排查問(wèn)題變得很方便。九十年代的時(shí)候,IDE還沒(méi)有今天這么好,比如那時(shí)候在Turbo C 2.0里面寫(xiě)代碼,當(dāng)時(shí)很多程序員的習(xí)慣是每寫(xiě)幾分鐘代碼就編譯一下。因?yàn)楫?dāng)時(shí)的IDE比較“簡(jiǎn)陋”,不像今天的IDE,哪個(gè)地方如果有typo,比如變量名打錯(cuò)了、關(guān)鍵字打錯(cuò)了,都會(huì)馬上有波浪線(xiàn)提示。當(dāng)時(shí)的IDE是沒(méi)有這種提示的。如果寫(xiě)了半個(gè)小時(shí)、一個(gè)小時(shí)的代碼,寫(xiě)了幾百行,然后再編譯,如果編譯有問(wèn)題,排查起來(lái)就比較辛苦(雖然編譯錯(cuò)誤會(huì)告訴我哪行錯(cuò)了,但是真正的問(wèn)題根源未必就在報(bào)錯(cuò)的那一行)。所以,當(dāng)時(shí)大家每寫(xiě)幾分鐘代碼就編譯一下,一旦有錯(cuò)就知道了,問(wèn)題就出在剛才那幾分鐘寫(xiě)的代碼里面。這就是為什么縮短反饋弧能讓排查問(wèn)題變得更方便。
投入在建設(shè)持續(xù)集成上的成本,不能孤立的看。如果只從單個(gè)開(kāi)發(fā)同學(xué)的視角看,我的投入產(chǎn)出比未必很高,也許在某些情況下,用原來(lái)的方式反而對(duì)個(gè)人更方便。但在很多情況下,個(gè)體受益,往往會(huì)導(dǎo)致群體受損,進(jìn)而導(dǎo)致每個(gè)個(gè)體都受損。個(gè)體做一些小的付出,會(huì)導(dǎo)致整個(gè)群體受益,進(jìn)而讓每個(gè)個(gè)體受益。
這樣的例子在生活中也很多。如果每個(gè)人開(kāi)車(chē)都不遵守秩序,都亂變道、亂加塞,那么整體的道路秩序就會(huì)很混亂,進(jìn)而導(dǎo)致整個(gè)高速上面的車(chē)速都降下來(lái),進(jìn)而導(dǎo)致每個(gè)人都更晚回家。疫情防控也是這個(gè)道理。局部的一些隔離措施對(duì)個(gè)體來(lái)說(shuō)是一個(gè)付出。但這些個(gè)體的付出,換來(lái)的是群體的受益,我們整個(gè)社會(huì)的疫情防控就做好了,整個(gè)社會(huì)的經(jīng)濟(jì)恢復(fù)了,進(jìn)而讓每個(gè)個(gè)體都受益。