服務(wù)一個人的系統(tǒng),和服務(wù)一億人的系統(tǒng),復(fù)雜度有著天壤之別。本文從工程師文化、組織戰(zhàn)略、公司內(nèi)部協(xié)作等角度來分析軟件復(fù)雜度形成的原因,并提出了一些切實可落地的解法。 01 何為研發(fā)效能? 當我們談研發(fā)效能的時候,我們在談些什么?這個議題被拋出來,有人討論,是因為存在問題,問題就在于實際的研發(fā)效率,已經(jīng)遠低于預(yù)期了。企業(yè)初創(chuàng)的時候,一個想法從形成到上線,一個人花兩個小時就完成了,而當企業(yè)發(fā)展到數(shù)千人的時候,類似事情的執(zhí)行,往往需要多個團隊,花費好幾周才能完成。這便造成了鮮明的對比,而這一對比產(chǎn)生的印象,對于沒有深入理解軟件工程的人來說,顯得難以理解,可又往往無計可施。 細心的讀者會留意到,前文我既用了“效能”一詞,也用了“效率”一詞。這是為了做嚴謹?shù)膮^(qū)分,效能往往是用來衡量產(chǎn)品的經(jīng)濟績效,而效率僅僅是指提升業(yè)務(wù)響應(yīng)能力,提高吞吐,降低成本。 這里的定義引用了喬梁的《如何構(gòu)建高效能研發(fā)團隊》課程材料,本文并不討論產(chǎn)品開發(fā)方法,因此后面的關(guān)注都在“效率”上。 本世紀 10 年代,早期的互聯(lián)網(wǎng)從業(yè)者開發(fā)簡易網(wǎng)站的時候,只需要學(xué)會使用 Linux、Apache、MySql、PHP(Perl)即可,這套技術(shù)有一個好記的名字:LAMP。可今天,在一個大型互聯(lián)網(wǎng)公司工作的開發(fā)者,需要理解的技術(shù)棧上升了一個數(shù)量級,例如分布式系統(tǒng)、微服務(wù)、Web 開發(fā)框架、DevOps 流水線、容器等云原生技術(shù)等等。如果僅僅是這些復(fù)雜度還好說,畢竟都是行業(yè)標準的技術(shù),以開發(fā)者的學(xué)習(xí)能力,很快就能掌握。令人生畏的復(fù)雜度在于,大型互聯(lián)網(wǎng)公司都有一套或者多套軟件系統(tǒng),這些軟件系統(tǒng)的規(guī)模往往都在百萬行以上,質(zhì)量有好有壞(壞者居多),而開發(fā)者必須基于這些系統(tǒng)開展工作。這個時候必須承擔(dān)非常高的認知負荷,而修改軟件的時候也會面臨破壞原有功能的巨大風(fēng)險,而風(fēng)險的增高就必然導(dǎo)致速度的降低。 因此研發(fā)效率的大幅降低,其中一個核心因素就是軟件復(fù)雜度的指數(shù)上升。 02 本質(zhì)復(fù)雜度和偶然復(fù)雜度 Fred Brooks 在經(jīng)典著作《人月神話》的「沒有銀彈」一文中對于軟件復(fù)雜度有著精彩的論述,他將軟件復(fù)雜度分為本質(zhì)復(fù)雜度(Essential Complexity)和偶然復(fù)雜度(Accidental Complexity)。這里的本質(zhì)和偶然兩個詞來源于亞里士多德的《形而上學(xué)》,在亞里士多德看來,本質(zhì)屬性是一個物體必然擁有的屬性,偶然屬性是一個物體可以擁有的屬性(也可以不擁有)。例如,一個電商軟件必然會包含交易、商品等業(yè)務(wù)復(fù)雜度,因此我們稱它們?yōu)楸举|(zhì)復(fù)雜度;而同一個電商軟件,可以是基于容器技術(shù)實現(xiàn)(也可以不是),可以是基于 Java 編寫的(也可以不是),因此我們稱由于容器技術(shù)或者Java 技術(shù)而引入的復(fù)雜度,為偶然復(fù)雜度。 Fred Brooks 所描述的軟件本質(zhì)復(fù)雜度,指的就是來自問題域本身的復(fù)雜度,除非縮小問題域的范圍,否則是無法消除本質(zhì)復(fù)雜度的。而偶然復(fù)雜度是由于解決方案帶來的,例如選擇了 Java,選擇了容器,選擇了中臺等等。 此外,我們可以從所謂問題空間(Problem Space)和方案空間(Solution Space)來理解這兩個復(fù)雜度,問題空間就是現(xiàn)實的初始狀態(tài)和期望狀態(tài),以及一系列約束規(guī)則(我們常常稱之為業(yè)務(wù)),方案空間就是工程師設(shè)計實現(xiàn)的,一系列從初始狀態(tài)達到期望狀態(tài)的步驟。缺乏經(jīng)驗的工程師往往在還沒理解清楚問題的情況下就急于寫代碼,這便是缺乏對于問題空間和方案空間的理解,而近年來領(lǐng)域驅(qū)動設(shè)計為那么多工程師所推崇,其核心原因就是它指導(dǎo)了大家去重視問題空間,去直面本質(zhì)復(fù)雜度。Eric Evans 在 2003 年的著作《Domain Driven Design》,其副標題是 “Tackling Complexity in the Heart of Software”,我想這也不是偶然。 《人月神話》寫于 1975 年,距今已經(jīng)有 47 年了,Brooks 認為軟件的本質(zhì)復(fù)雜度是無法得到本質(zhì)上的降低的,同時認為隨著高級編程語言的演進,開發(fā)環(huán)境的發(fā)展演進,偶然復(fù)雜度會得到本質(zhì)的降低。他的論斷前半部分對了,然而后半部分是錯了,我們今天的確有更高級的編程語言,功能更豐富的框架,能力更強大的 IDE,但是大家逐漸發(fā)現(xiàn)學(xué)習(xí)這些工具已經(jīng)成為了一個不小的負擔(dān)。 03 復(fù)雜度的爆炸 軟件只要不消亡,只要有人用,有開發(fā)者維護,那么它的復(fù)雜度幾乎必然是不斷上升的。軟件的生存發(fā)展意味著商業(yè)上的成功,隨著時間的積累,越來越多的人使用它,越來越多的功能被加入進去,它的價值越來越大,給企業(yè)帶去源源不斷的收入。前面我們解釋過,軟件的本質(zhì)復(fù)雜度實際上是問題空間(或者稱之為業(yè)務(wù))帶來的,因此給軟件加入越多的功能,那么它就必然會包含越多的本質(zhì)復(fù)雜度。此外,每解決一個問題,就對應(yīng)了一個方案,而方案的實現(xiàn)必然又引入新的偶然復(fù)雜度,例如為了實現(xiàn)支付,需要實現(xiàn)某種新的協(xié)議,以對接一個三方的支付系統(tǒng)。軟件復(fù)雜度是在商業(yè)上成功的企業(yè)所必須面對的幸福的煩惱。 和Brooks的時代所不同的是,今天的軟件已經(jīng)從深入到人類生活的方方面面。稍有規(guī)模的互聯(lián)網(wǎng)軟件,都服務(wù)著數(shù)百萬、千萬級的用戶。阿里巴巴的雙11在2020年的峰值實現(xiàn)了每秒58.3萬筆的交易;Netflix 在2021年Q4擁有了2.2億的訂閱用戶;而 TikTok 在2021年9月宣布月活數(shù)量超過10億。這些驚人的商業(yè)成功背后,都少不了復(fù)雜的軟件系統(tǒng)。而所有這些復(fù)雜軟件系統(tǒng),都不得不面對巨大的 Scalability 的挑戰(zhàn),服務(wù)一個人的系統(tǒng),和服務(wù)一億人的系統(tǒng),其復(fù)雜度有著天壤之別。 本質(zhì)復(fù)雜度是一個方面,畢竟更多用戶意味著更多的功能特性,但我們無法忽略這里的偶然復(fù)雜度,其中最典型的就是分布式系統(tǒng)引入的偶然復(fù)雜度。為了能夠支撐如此大規(guī)模的用戶量,系統(tǒng)需要能夠管理數(shù)萬機器(調(diào)度系統(tǒng)),需要能否管理好用戶的流量(負載均衡系統(tǒng)),需要能夠管理好不同計算單元之間的通訊(服務(wù)發(fā)現(xiàn),RPC,消息系統(tǒng)),需要能夠保持服務(wù)的穩(wěn)定性(高可用體系)。這里的每一個主題都能延展開用幾本書來描述,而開發(fā)者只有在初步掌握了這些知識后,才能夠設(shè)計實現(xiàn)足夠 Scalable 的系統(tǒng),服務(wù)好大規(guī)模的用戶。 相比于分布式系統(tǒng)引入的復(fù)雜度,團隊的擴張更易帶來偶然復(fù)雜度的急劇增長。成功產(chǎn)品的軟件研發(fā)團隊動輒數(shù)百人,有些已經(jīng)達到了一兩千人的規(guī)模。如果企業(yè)沒有嚴格清晰的人才招聘標準,人員入職后沒有嚴格的技術(shù)規(guī)范培訓(xùn),當所有人以不同的風(fēng)格,不同的長短期目標往代碼倉庫中提交代碼的時候,軟件的復(fù)雜度就會急劇上升。 例如,團隊成員因為個人喜好,在一個全部是 Java 體系的系統(tǒng)中加入了 NodeJS 的組件,當該成員離開團隊后,這個組件對于其他不熟悉 NodeJS 的成員來說,就是純粹多出來的偶然復(fù)雜度; 例如,團隊新人不熟悉系統(tǒng),為了急于上線一個特性,又不想影響到系統(tǒng)的其他部分,就會很自然地在某個地方加一個 flag,然后在所有需要改動的地方加 if 判斷,而不是去調(diào)整系統(tǒng)設(shè)計以適應(yīng)新的問題空間; 例如,同一個領(lǐng)域概念,不同的人在系統(tǒng)不同的模塊中使用了不同的名字,核心內(nèi)涵完全一致,但又加入了差異的屬性,平添了大量理解成本。 類似的復(fù)雜度都不是軟件的本質(zhì)復(fù)雜度,但它們會隨著時間的流逝而積累,給開發(fā)者帶來巨大的認知負擔(dān)。如果軟件存在的時間很長,那除了當前開發(fā)團隊的規(guī)模之外,還得一并考慮歷史上給這個軟件貢獻過代碼的所有人,也難怪當程序員看到“祖?zhèn)鞔a,勿動!”之類調(diào)侃的時候,會會心一笑。 我喜歡學(xué)習(xí)各種能力強大的編程語言,例如具備元編程能力的 Ruby 和 Scala,使用這些能力你可以盡情發(fā)揮自己的興趣和創(chuàng)造力。但是我對在有一定團隊規(guī)模的生產(chǎn)環(huán)境中使用這些編程語言持保留意見,因為除非花很大力氣 Review 和控制代碼風(fēng)格,否則很可能 10 個人寫出來的代碼是 10 種風(fēng)格,這種復(fù)雜度的增長是個災(zāi)難。相反,使用 Java 這種不那么靈活的語言,大家寫代碼的風(fēng)格就比較難不一致。 團隊的擴張還會帶來另外一個問題,在大規(guī)模的團隊中,關(guān)鍵干系人的目標事實上是影響軟件復(fù)雜度的關(guān)鍵因素。我親眼見過許多案例,其方案空間中明明放著簡單的方案,但因為這個原因,當事人不得不選擇復(fù)雜的方案,例如:
更有甚者,為了各種各樣的原因,提出一些完全假設(shè)出來的問題(即,事實上并不存在的本質(zhì)復(fù)雜度),然后拿著軟件系統(tǒng)一陣無謂折騰。最后個人或者某個團隊的目標實現(xiàn)了,但軟件沒有提供任何增量的價值,而復(fù)雜度卻不會因此而停止增長。 ![]() 因此,只要軟件有價值,有用戶,有開發(fā)者維護,那么就不斷會有功能增加,而商業(yè)上獲得成功的軟件必然伴隨著用戶量的增長和研發(fā)團隊的增長,這三個因素會不斷推動軟件復(fù)雜度的增長直至爆炸,研發(fā)效率自然會越來越低。軟件工程要解決的一個核心命題,就是如何控制復(fù)雜度,以讓研發(fā)效率不至于下降的太厲害,這是一場對抗軟件復(fù)雜度的戰(zhàn)爭。 ![]() 04 錯誤的應(yīng)對方式 面對效率地不斷下降,研發(fā)團隊的管理者必須做點什么。不幸的是,很多管理者并不明白效率的降低是由軟件復(fù)雜度的上升造成的,更沒有冷靜地去思考復(fù)雜度蔓延直至爆炸的根因是什么,于是我們看到許多管理者其膚淺的應(yīng)對方式收效甚微,甚至起到了反作用。 最常見的錯誤方式是設(shè)置一個不可更改的 Deadline,用來倒逼研發(fā)團隊交付功能。但無數(shù)經(jīng)驗告訴我們,軟件研發(fā)就是在質(zhì)量、范圍和時間這個三角中求取權(quán)衡。研發(fā)團隊短期可以通過加班,犧牲假期等手段來爭取一些時間(長期加班實際有百害無一利),但如果這個時間限制過于苛刻,那必然就要犧牲需求范圍和軟件質(zhì)量。當需求范圍不可縮減的時候,唯一可以被犧牲的就只有質(zhì)量了,這實際就意味著在很短的時間內(nèi)往系統(tǒng)中傾瀉大量的偶然復(fù)雜度。 另一種做法是用“更先進”的技術(shù)去替換現(xiàn)有系統(tǒng)的技術(shù),例如用 Java 的微服務(wù)體系技術(shù)去替換 PHP Golang 體系的技術(shù);或者用支撐過成功商業(yè)產(chǎn)品的中臺類技術(shù)去替換原來的微服務(wù)體系技術(shù);或者簡單到用云產(chǎn)品去替換自建的開源服務(wù)。這些做法背后的基本邏輯是,“更先進”的技術(shù)在成功的商業(yè)場景中被驗證過,因此可以被直接拿來解決現(xiàn)有的問題。 但在現(xiàn)實情況下,決策者往往忽略了當前的問題是否是“更先進”的技術(shù)可以解決的問題。如果現(xiàn)有的系統(tǒng)服務(wù)的用戶在迅速增長,Scalablity 面臨了嚴重的困境,那么這個答案是肯定的;如果現(xiàn)有的系統(tǒng)的穩(wěn)定性堪憂,經(jīng)常不可用且嚴重影響了用戶體驗,那么這個答案是肯定的。但是,如果現(xiàn)有的軟件系統(tǒng)面臨著研發(fā)效率下降問題,那么“更先進”的技術(shù)不僅幫不了什么忙,還會因為新老技術(shù)的切換給系統(tǒng)增加偶然復(fù)雜度。 05 正確的技術(shù)戰(zhàn)略 前文我解釋了導(dǎo)致復(fù)雜度增長的幾個核心因素,包括業(yè)務(wù)復(fù)雜度的增長,分布式系統(tǒng)規(guī)模的增長,團隊規(guī)模的增長,以及關(guān)鍵干系人目標的因素。這其中,分布式系統(tǒng)引入的偶然復(fù)雜度是最容易被消除的。為了更好得理解這個觀點,我先簡單介紹一下 Wardley Map。 Wardley Map 是一個幫助分析技術(shù)戰(zhàn)略的工具,它以地圖的方式展現(xiàn),地圖中的每個組件可以被理解成一個軟件模塊,縱坐標是價值方向,越往上越靠近用戶價值,橫坐標是進化方向,越往右越靠近成熟商業(yè)產(chǎn)品。 ![]() 例如上圖中,Compute 是計算資源,在今天有許多成熟的云計算公司提供,但它離圖中上下文業(yè)務(wù)的用戶價值非常遠。Virtual Fitting(虛擬試衣)則離用戶價值非常靠近,因為它可以讓用戶更有信心自己是否購買了合適的衣服,但是這個技術(shù)顯然還談不上是成熟產(chǎn)品,只是自己研發(fā)的模塊,遠沒有達到開放商業(yè)化的階段。 設(shè)計研發(fā)一套用來支撐百萬、千萬級用戶的分布式系統(tǒng),是非常有挑戰(zhàn)的事情,而且會給系統(tǒng)引入大量的復(fù)雜度,管理好這些復(fù)雜度本身則又是一項巨大的挑戰(zhàn)。幸運的是,今天的云廠商,包括阿里巴巴,亞馬遜,谷歌和微軟等,在這方面都具有豐富的經(jīng)驗,并且已經(jīng)通過多年的積累,把這些經(jīng)驗通過商業(yè)產(chǎn)品提供給市場。 從 Wardley Map 的方式去分析,我們就會發(fā)現(xiàn),幾乎所有的業(yè)務(wù),其左上角(貼近直接用戶價值,不成熟)都必須是要自己研發(fā)和承擔(dān)復(fù)雜度的,而只要做好正確的軟件架構(gòu),那么就能把右下角的部分(遠離直接用戶價值,有現(xiàn)成商業(yè)產(chǎn)品)提取出來,直接購買。所以在今天,一個合格的架構(gòu)師,除非自己是云廠商,否則絕對不應(yīng)該自己去投入研發(fā)數(shù)據(jù)庫、調(diào)度系統(tǒng)、消息隊列、分布式緩存等軟件。通過購買的方式,研發(fā)團隊完全不用承擔(dān)這些復(fù)雜度,也能輕松地支撐好用戶規(guī)模的增長。 06 微觀層面的復(fù)雜度控制 正確的技術(shù)戰(zhàn)略能夠在宏觀層面幫助系統(tǒng)控制復(fù)雜度,在微觀層面我們需要完全不同的方法。在討論方法之前我想先引用一個來自《Grokking Simplicity》書中的一個簡單例子。(有趣的是,這本書的副標題 “Taming complex software with functional thinking” 也是在表達對抗復(fù)雜度的意圖。) 讓我們來看兩個函數(shù)(JavaScript): function emailsForCustomers(customers, goods, bests) { var emails = []; for(var i = 0; i < customers.length; i ) { var customer = customers[i]; var email = emailForCustomer(customer, goods, bests); emails.push(email); } }
function biggestPurchasePerCustomer(customers) { var purchases = []; for(var i = 0; i < customers.length; i ) { var customer = customers[i]; var purchase = biggestPurchase(customer); purchases.push(purchase); } } 初看起來這兩個函數(shù)沒什么問題,都是準備一個返回值,寫一個循環(huán),根據(jù)具體業(yè)務(wù)邏輯提取需要的數(shù)據(jù),差別只是在于,前一個函數(shù)的業(yè)務(wù)邏輯是獲取客戶的 Email,后一個函數(shù)的業(yè)務(wù)邏輯是獲取客戶下過的最大的單。然而就這么簡單的代碼來說,也是存在可以降低的復(fù)雜度的,理解閱讀這兩個函數(shù),每次都需要去理解 for 循環(huán),這個復(fù)雜度是否可以進一步被降低呢?答案是肯定的。 對于這種到處可見的邏輯,即遍歷集合的每個元素,對其中每個元素做一些處理,返回一個新元素,最后裝成一個新的集合,可以被抽象成一個 map 函數(shù)。在這個例子中,我假設(shè) JavaScript 支持 map 函數(shù),那么上面的代碼可以寫成:
拋開語言語法的因素不談,這段代碼除了這個 map 函數(shù),剩下的就是函數(shù)名了,而函數(shù)名只要是命名得當?shù)模撬鋵嵕褪潜举|(zhì)復(fù)雜度,就是業(yè)務(wù)邏輯。行業(yè)先輩,大家耳熟能詳?shù)?Martin Fowler、Kent Beck、Robert C. Martin,無不在他們的書籍中強調(diào)命名的重要性,都是希望代碼能夠清晰地溝通意圖,而這里最核心的意圖應(yīng)當是與問題域匹配的。 這個例子中的代碼是極其簡單的,所有程序員都能理解,可即便在這些地方還有降低復(fù)雜度的空間。可以想象在數(shù)年日積月累的代碼中,會存在多少復(fù)雜度可被消除。我又想起多年前的一位同事兼長輩的程序員的教誨,他說優(yōu)秀的代碼應(yīng)該是:
事實上要做到第二點已經(jīng)是非常高的要求,這需要軟件工程師精心地設(shè)計,清晰地溝通好需求,思考和遺留系統(tǒng)的融合,還需要壓制住自己使用新技術(shù)(新語言,新的范式)的沖動。而第三點實際上是教會我們認真的寫單元測試。 我不知道大家是否體驗過這種感覺:在需求討論清晰后,我編寫了對應(yīng)的代碼和單元測試,具體是在原來的幾萬行 code base 上加了幾百行,并原來 1000 個左右的單元測試上加入了 3-5 個單元測試,然后我在本地執(zhí)行了一次 mvn clean test,這個過程也就消耗幾分鐘,全部測試都通過了,這時候我非常有信心把代碼提交,而且我知道代碼在生產(chǎn)環(huán)境運行出問題的概率極低。 這種感覺的核心是質(zhì)量反饋,這個反饋時間越短,效率就越高,反饋時間越長,效率就越低。除了控制復(fù)雜度之外,軟件工程師必須明白及時質(zhì)量反饋的重要性,如果一行代碼寫下去,要等好幾個小時,甚至好幾天才知道其質(zhì)量有問題,效率的低下可想而知。所以當我看到當組織自上而下提倡寫單元測試,但大家實踐中的一些怪現(xiàn)象時,常常會感到匪夷所思,這些現(xiàn)象會包括:
07 軟件道德觀 在微觀層面控制軟件復(fù)雜度,認真編寫單元測試以保障代碼編寫的質(zhì)量反饋,對于研發(fā)效率來說是至關(guān)重要的,但同時也是耗時耗力的。而且由于這種投入對商業(yè)的價值需要很長時間才能體現(xiàn)出來,因此容易被研發(fā)主管所忽視。 開發(fā)者都是在生產(chǎn)代碼、文檔、API 服務(wù)等軟件中間產(chǎn)物,這些中間產(chǎn)物被逐漸組裝起來成為產(chǎn)品,產(chǎn)生商業(yè)價值。軟件中間產(chǎn)物的質(zhì)量對于研發(fā)組織的整體效率是至關(guān)重要的,而復(fù)雜度得到很好控制的代碼和系統(tǒng),就是高質(zhì)量的軟件中間產(chǎn)物;良好的軟件研發(fā)道德,或者有時候也會認為這是良好的工程師文化,就是大家形成一種以交付高質(zhì)量軟件中間產(chǎn)物為榮,以交付低質(zhì)量軟件中間產(chǎn)物為恥的共識文化。 軟件研發(fā)的核心職責(zé)之一是關(guān)注軟件復(fù)雜度,通過開放代碼、文檔,Code Review 等方式讓軟件復(fù)雜度的信息透明,并且讓所有在增加/降低復(fù)雜度的行為透明,并且持續(xù)激勵那些消除復(fù)雜度的行為。唯有如此,在微觀層面的控制復(fù)雜度的方法才能得到落實。 08 系統(tǒng)架構(gòu)對復(fù)雜度的影響 介于宏觀的技術(shù)戰(zhàn)略和微觀的工程師文化之間,存在著一塊重要的決策區(qū)域,也對軟件復(fù)雜度有著關(guān)鍵的影響,我稱之為系統(tǒng)架構(gòu)。在面對需求的時候,缺乏經(jīng)驗的工程師會直接想著在自己熟悉的模塊中直接解決,而經(jīng)驗豐富的工程師會先思考一下系統(tǒng)上下文。在《Design Docs at Google》這篇優(yōu)秀的技術(shù)文檔寫作指導(dǎo)中,就重點提到了,設(shè)計文檔應(yīng)當寫清楚系統(tǒng)上下文圖(sysmte-context-diagram),這背后的原因是什么呢? 我近期對一個遺留系統(tǒng)做了一個依賴鏈路的梳理分析,這個系統(tǒng)是負責(zé)生產(chǎn)環(huán)境中各類資源的管理的,包括資源的規(guī)格,版本,依賴關(guān)系等等,梳理完成后,整體的結(jié)構(gòu)嚇了我一跳,這個圖大致是這樣的: ![]() 圖中藍色的部分是控制和執(zhí)行的子系統(tǒng)(System X,Y,Z),例如控制容器的調(diào)度,控制鏡像變更的執(zhí)行等等,是比較清晰的。但是其余部分就不是這樣了(A1, A2, A3, C1, C2, S, E),它們都是在管理一個資源的運行態(tài)版本,包括鏡像的版本,容器的規(guī)格,是否有 GPU,容器的數(shù)量,關(guān)聯(lián)的網(wǎng)絡(luò)資源等等,但卻演進出了七個子系統(tǒng),這實際上是非常高的偶然復(fù)雜度。當一個領(lǐng)域的概念被分散到這么多子系統(tǒng)之后,就會產(chǎn)生一系列問題:
仔細去分析這一復(fù)雜度形成的因素,我發(fā)現(xiàn)這既不是技術(shù)戰(zhàn)略的問題,也不是微觀層面工程師生產(chǎn)低質(zhì)量代碼導(dǎo)致,而是有其他更深層次的問題。其中的最核心的因素是,這些子系統(tǒng)在不同時期是歸屬于不同的團隊的,有的甚至是不同部門的,具體來說,當各個部門各個團隊目標不一致的時候,而這個系統(tǒng)又不幸地被拆到各個團隊,那么就不會有人會對系統(tǒng)整體的復(fù)雜度控制負責(zé)。當有的團隊在負責(zé)把這套系統(tǒng)商業(yè)化對外輸出,有的團隊在負責(zé)把這套系統(tǒng)從虛擬機模式演進到容器模式,有的團隊在負責(zé)資源的成本控制,有的團隊在思考全局高可用架構(gòu),而沒有一個全局的架構(gòu)師從整體控制概念,控制邊界的時候,系統(tǒng)就自然而然地腐化成這樣的一個狀態(tài)了。 當一個問題域沒有系統(tǒng)架構(gòu),或者其系統(tǒng)架構(gòu)是錯誤的時候,你就會發(fā)現(xiàn)不同的人在發(fā)明不同的語言,這就好比相隔幾十公里的兩個村子,常常對同一個概念有不同的用詞或者發(fā)音。日常生活中語言的不精確不是問題,因為日常的溝通是充滿上下文的(表情,氣氛,環(huán)境等),但在計算機的世界,語言的不精確就意味著需要寫代碼翻譯,一旦翻譯錯誤軟件就會執(zhí)行出錯。這也就是為什么領(lǐng)域驅(qū)動設(shè)計那么強調(diào)統(tǒng)一語言,強調(diào)限定上下文。但領(lǐng)域驅(qū)動設(shè)計是方法論,而知道方法并不能取代系統(tǒng)架構(gòu)角色的缺位。 這個復(fù)雜系統(tǒng)是康威定律的絕佳例證,康威定律說:“任何系統(tǒng)設(shè)計的系統(tǒng),其系統(tǒng)結(jié)構(gòu)會復(fù)制組織的溝通結(jié)構(gòu)。”這句話其實還是有些抽象的,更具體的一些闡述是: “康威定律 … 是一個合理的社會學(xué)觀察。… 除非模塊 A 和模塊 B 的設(shè)計及實現(xiàn)者能有效溝通,否則這兩個軟件模塊是無法正確對接的。因此軟件系統(tǒng)的接口結(jié)構(gòu),就必然會和生產(chǎn)軟件系統(tǒng)的社會結(jié)構(gòu)及組織相對應(yīng)。” 康威定律所揭示的事實,就是軟件架構(gòu)在很大程度上是由組織的結(jié)構(gòu)和協(xié)作模式?jīng)Q定的,這實際上已經(jīng)不再是一個軟件技術(shù)問題了,而是一個組織管理問題。因此,解決系統(tǒng)架構(gòu)層面的軟件復(fù)雜度問題,就必須面對組織管理的挑戰(zhàn)。關(guān)鍵問題域是否有唯一的負責(zé)人?當不同的團隊在同一個問題域重復(fù)建設(shè)系統(tǒng)的時候,如何整合團隊?當已有團隊為了自己的生存,不斷夸大其負責(zé)系統(tǒng)的重要性和特殊性,如何識別這種問題?組織如何給予大家充分的安全感,讓工程師愿意為了架構(gòu)的合理性,放棄自己辛苦耕作的系統(tǒng)模塊? 討論管理工作似乎已經(jīng)超出了這篇論述軟件復(fù)雜度的文章的范疇,但很多工程師或者隱隱感覺,或者思來想去最終領(lǐng)悟,這是我們的軟件系統(tǒng)或優(yōu)雅健壯或千瘡百孔的根本因素。 小結(jié) 我曾經(jīng)的大老板郭東白曾在一次 QCon 的演講中討論優(yōu)秀架構(gòu)師的特質(zhì),除了大家都很好理解的有眼光、善于思考、能感召等幾個特質(zhì)外,還特別強調(diào)了“有良知”,他說: 有良知,這是一個架構(gòu)師隨著時間的流逝,沉淀在身上最重要的品質(zhì)。什么是有良知?為人正直,選擇做正確的事情。很多人是非常聰明的,業(yè)務(wù)理解能力強,技術(shù)實踐豐富,但他不一定為公司或為組織做最正確的事情。有良知是非常重要的一個事情,如果架構(gòu)師沒有素質(zhì),他會讓一家公司的損失很慘重。 軟件復(fù)雜度是人的行為引起的,無論是微觀層面的重視質(zhì)量和工程師文化,在系統(tǒng)架構(gòu)層面讓組織結(jié)構(gòu)和溝通符合客觀問題域,還是在技術(shù)戰(zhàn)略層面做符合公司利益的決策,這里都存在客觀無法改變的規(guī)律。如何認識到這些規(guī)律,并基于這些規(guī)律制定決策(可改變可影響),努力為公司創(chuàng)造價值,努力讓每個工程師被尊重,是每個工程師、架構(gòu)師、技術(shù)管理者所應(yīng)當秉承的基本態(tài)度。本文討論軟件復(fù)雜度的初衷,就是盡量去揭示復(fù)雜度背后的客觀規(guī)律,希望幫助大家認清現(xiàn)實,用更務(wù)實的態(tài)度去思考和決策,創(chuàng)造更有價值,也更讓自己滿足的軟件系統(tǒng)。 參考閱讀
|
|