十倍效能提升——Web 基礎(chǔ)研發(fā)體系的建立
1 導(dǎo)讀
web 基礎(chǔ)研發(fā)體系指的是, web 研發(fā)中一線工程師所直接操作的技術(shù)、工具,以及所屬組織架構(gòu)的總和。在過(guò)去提升企業(yè)研發(fā)效能的討論中,圍繞的主題基本都是——”通過(guò)云計(jì)算、云存儲(chǔ)等方式將底層核心技術(shù)封裝成基礎(chǔ)設(shè)施“。而我們?cè)趯?shí)踐中發(fā)現(xiàn),在
- 互聯(lián)網(wǎng)滲入到各行各業(yè),業(yè)務(wù)爆發(fā)
- 企業(yè)競(jìng)爭(zhēng)白熱化,對(duì)速度和品質(zhì)要求越來(lái)越高
- 一線工程師隊(duì)伍越來(lái)越龐大,管理成本增高
這樣的多重背景下,除了底層核心技術(shù)外,一線 web 研發(fā)效能的問(wèn)題也逐漸成為決勝戰(zhàn)場(chǎng)的重要因素。
然而在現(xiàn)實(shí)中我們看到,因?yàn)橐痪€的研發(fā)工作可替換性強(qiáng),所以并沒(méi)有受到足夠的重視,同時(shí)也缺少更統(tǒng)一、更有深度的規(guī)劃和管理。實(shí)際上,將一線工程師所直接接觸到的應(yīng)用框架、測(cè)試、部署、監(jiān)控等領(lǐng)域作為一個(gè)完整的體系來(lái)思考,并打造成一體化的基礎(chǔ)設(shè)施,能為企業(yè)的業(yè)務(wù)研發(fā)帶來(lái)巨大的效能提升。
在《月相》一章中,我們將介紹Web 基礎(chǔ)研發(fā)體系有哪些構(gòu)成部分,并且將深入到關(guān)鍵性的技術(shù)和問(wèn)題中。《潮汐》一章將介紹如何配合這套研發(fā)體系,在組織結(jié)構(gòu)上做出一些調(diào)整,通過(guò)管理手段進(jìn)一步挖掘團(tuán)隊(duì)潛力,打造更高效的組織。
另外,希望這些內(nèi)容也能為一線工程師提供一些職業(yè)規(guī)劃上的引導(dǎo)。
2 月相
我們將要討論的研發(fā)體系,涵蓋了”研發(fā)流程“和”系統(tǒng)“兩個(gè)維度。可以用一張大圖來(lái)描繪:

可以看到,將這些內(nèi)容作為一個(gè)整體,符合目前互聯(lián)網(wǎng)公司”核心技術(shù)“ + ”web 研發(fā)能力“ 的模式,能快速產(chǎn)出應(yīng)用。其中,”用戶“、”權(quán)限“、”流程“可以說(shuō)是絕大部分系統(tǒng)的鐵三角,因此我們也劃入到了基礎(chǔ)研發(fā)體系中。
接下來(lái)看每個(gè)部分。從流程的角度來(lái)說(shuō),提升效能的關(guān)鍵在于”工具化“和”自動(dòng)化“,我們就以這兩點(diǎn)來(lái)切入。
2.1 設(shè)計(jì)
首先是設(shè)計(jì),設(shè)計(jì)與編碼的結(jié)合是目前業(yè)界想象空間最大,但也是最不成熟的領(lǐng)域。對(duì)于自動(dòng)化的實(shí)現(xiàn),目前的嘗試大致可以歸納成兩類:
第一類,與設(shè)計(jì)師約定規(guī)則,按規(guī)則轉(zhuǎn)化設(shè)計(jì)稿。這種方式的關(guān)鍵在于,“既要規(guī)則簡(jiǎn)單易于被設(shè)計(jì)師接受,又要保證視覺(jué)上的關(guān)系能完整轉(zhuǎn)化成程序中的關(guān)系“。我們舉個(gè)例子來(lái)說(shuō)明”視覺(jué)上的關(guān)系“和”常見(jiàn)的程序中的關(guān)系“: 網(wǎng)頁(yè)上這樣一個(gè)場(chǎng)景:

可以很容易地理解為一個(gè) Tab 組件里面嵌著一個(gè)按鈕,他們是”嵌套關(guān)系“,在程序中用 html 可能這樣寫:
<Tabs>
<Tabs.Pane title="tab1">
<Button/>
</Tabs.Pane>
<Tabs.Pane title="tab2" />
</Tab>
但是在現(xiàn)代的設(shè)計(jì)工具中,圖層信息表示的僅僅是視覺(jué)上的前后關(guān)系。

這就出現(xiàn)了一種不匹配,設(shè)計(jì)師可以通過(guò)一萬(wàn)種方式來(lái)表達(dá)同樣的視覺(jué)效果。因此,要保證正確識(shí)別關(guān)系,必須和設(shè)計(jì)師約定只能以某種方式來(lái)創(chuàng)建圖層。但問(wèn)題是這種約定本身對(duì)設(shè)計(jì)師來(lái)說(shuō)沒(méi)有實(shí)際意義,對(duì)他來(lái)說(shuō)只是約束。除了嵌套關(guān)系以外,位置關(guān)系也是同樣的問(wèn)題——目前設(shè)計(jì)工具產(chǎn)出的設(shè)計(jì)稿只是某一種具體尺寸的視覺(jué)效果,而我們實(shí)際產(chǎn)品的尺寸會(huì)因設(shè)備不同而不同的,甚至可以隨著瀏覽器窗口的縮放等功能動(dòng)態(tài)變化:

怎么來(lái)表示這種變化對(duì)設(shè)計(jì)師來(lái)說(shuō)也是額外的約束。樂(lè)觀的是,從技術(shù)角度來(lái)說(shuō),總歸是可實(shí)施的。
第二類嘗試,像游戲一樣做專用的設(shè)計(jì)工具,則從根本上解決了上述問(wèn)題。

思路很簡(jiǎn)單,既然設(shè)計(jì)師能有多種方式來(lái)表達(dá),那么我們從工具角度來(lái)約束,是不是就不會(huì)有問(wèn)題了?雖然同樣有約束,但是對(duì)設(shè)計(jì)師來(lái)說(shuō)負(fù)擔(dān)要小多了,不需要額外記憶,按照工具的指引使用即可。我們甚至還可以提供一些高級(jí)功能防止出現(xiàn)一些人為錯(cuò)誤,以此來(lái)吸引設(shè)計(jì)師。這種方式唯一的缺點(diǎn)是有一次性的學(xué)習(xí)成本。
雖然目前的自動(dòng)化方案,都還只是從“視覺(jué)稿”到“程序靜態(tài)視圖”的自動(dòng)化,并不包括交互邏輯的自動(dòng)化,但已經(jīng)有了巨大的意義。在前端程序員工作的統(tǒng)計(jì)中發(fā)現(xiàn),他們有一半以上的時(shí)間都是在”調(diào)整大小、調(diào)整位置、對(duì)像素、對(duì)色值“,而且越是好的前端,這個(gè)時(shí)間比例越大。因?yàn)閷戇壿嬍强梢酝ㄟ^(guò)提升自身素質(zhì)實(shí)現(xiàn)量級(jí)縮小的,而寫樣式這個(gè)工作本身很難實(shí)現(xiàn)量級(jí)的時(shí)間縮短。
如果在研發(fā)體系中,設(shè)計(jì)稿能自動(dòng)轉(zhuǎn)化成可用的代碼,無(wú)疑對(duì)傳統(tǒng)的 web 頁(yè)面研發(fā)會(huì)有巨大的提升。雖然做專用工具看起來(lái)應(yīng)該是最終的方向,但在目前的現(xiàn)實(shí)環(huán)境中,可能會(huì)因?yàn)榧又卦O(shè)計(jì)師的使用負(fù)擔(dān)而被抵制,所以通過(guò)在原有設(shè)計(jì)工具上做約定的方式來(lái)過(guò)渡可能更合適。在用約定的方案里,怎樣讓約定即不給設(shè)計(jì)師造成太大的負(fù)擔(dān),又能解決上述的規(guī)則轉(zhuǎn)化問(wèn)題,就成了重點(diǎn)。在實(shí)踐中的解法是,通過(guò)工具的高級(jí)能力來(lái)補(bǔ)償設(shè)計(jì)師。這部分細(xì)節(jié)已在《設(shè)計(jì)稿自動(dòng)生成可用頁(yè)面的展望》中詳細(xì)描述過(guò),這里不再贅述。
2.2 研發(fā)、測(cè)試和監(jiān)控
我們將這三個(gè)環(huán)節(jié)合在一起來(lái)討論,是因?yàn)樗麄兇嬖诩夹g(shù)決策上的上下游關(guān)系。過(guò)去在大團(tuán)隊(duì)中規(guī)劃研發(fā)體系,常常會(huì)出現(xiàn)一種現(xiàn)象,就是研發(fā)、測(cè)試、監(jiān)控都是由不同團(tuán)隊(duì)規(guī)劃的,而每個(gè)團(tuán)隊(duì)都想著做平臺(tái)。后來(lái)慢慢發(fā)現(xiàn)這個(gè)思路是有問(wèn)題的,因?yàn)樽銎脚_(tái)必然要考慮到不同端的接入,要花成本將自己的服務(wù)抽象得足夠底層,花成本對(duì)不同的端做適配。而在這三個(gè)環(huán)節(jié)中,研發(fā)中的運(yùn)行時(shí)框架(應(yīng)用框架)是工具化和自動(dòng)化的核心,只要對(duì)運(yùn)行時(shí)框架多進(jìn)行一點(diǎn)點(diǎn)投入,后面測(cè)試、反饋、監(jiān)控的研發(fā)成本就能降到非常低!
舉個(gè)前端的例子。在搭建可視化頁(yè)面搭建平臺(tái)時(shí),我們?cè)O(shè)計(jì)了一個(gè)將“所有組件數(shù)據(jù)都統(tǒng)一到一棵樹”上的方案。

在傳統(tǒng)的 React 中所有組件的 state 和 props 合起來(lái)才能表達(dá)一個(gè)頁(yè)面唯一的狀態(tài),state 和 props 分散在組件中,不易收集。而在這個(gè)設(shè)計(jì)中,全局的 state tree 即表達(dá)了頁(yè)面的一個(gè)狀態(tài),如果將每一次變化后的state tree 都存起來(lái),即可通過(guò)回放來(lái)展現(xiàn)頁(yè)面動(dòng)態(tài)變化的過(guò)程。更進(jìn)一步的是,利用這個(gè)特性,我們?cè)?200 行代碼之內(nèi)就實(shí)現(xiàn)了“錄制即測(cè)試用例”的功能。用戶無(wú)需寫任何晦澀的用例代碼,在調(diào)試自己寫的頁(yè)面時(shí)只要覺(jué)得沒(méi)問(wèn)題,就可以將剛才的調(diào)試過(guò)程保存成一個(gè)用例。

再舉一個(gè)接口層的例子。我們運(yùn)行時(shí)框架的接口采用了 GraphQL ,并且告別了手動(dòng)寫接口的形式,全部利用視圖勾選生成。

這解決了兩個(gè)研發(fā)中常見(jiàn)的問(wèn)題:
- 杜絕了手工約定接口時(shí)可能出現(xiàn)的拼寫等錯(cuò)誤。
- 能自動(dòng)統(tǒng)計(jì)到所有對(duì)某一接口進(jìn)行消費(fèi)的頁(yè)面,一旦接口進(jìn)行調(diào)整,可以自動(dòng)通知到下游,甚至能自動(dòng)生成適配代碼,不影響下游。
這也就極大地減輕了測(cè)試環(huán)節(jié)的壓力。之前的思路基本都是通過(guò)掃描代碼去發(fā)現(xiàn)接口錯(cuò)誤,要消耗大量資源,現(xiàn)在看起來(lái)沒(méi)必要了。
這兩個(gè)例子都是從研發(fā)的角度來(lái)思考所看到的收益,我們?cè)賳为?dú)從測(cè)試與監(jiān)控的角度來(lái)看。
測(cè)試領(lǐng)域有一個(gè)熱點(diǎn),—— UI 自動(dòng)化。目前的 UI 自動(dòng)化有兩種方案,圖片對(duì)比 與 dom 樹對(duì)比。

這兩種方案都有一個(gè)共同的缺點(diǎn),即“無(wú)法正確地識(shí)別變化的類型”。例如現(xiàn)在有個(gè)需求,視圖上的兩個(gè)元素需要調(diào)換一下位置,但邏輯并沒(méi)有變,希望測(cè)試平臺(tái)不報(bào)警。除非人工干預(yù),否則這兩種方案都很難判斷出來(lái),因?yàn)樗麄兪且浴弊詈箐秩窘Y(jié)果“作為判斷依據(jù)的。但是如果我們的測(cè)試是針對(duì)運(yùn)行時(shí)框架來(lái)設(shè)計(jì)的話,就很容易實(shí)現(xiàn)。以上面研發(fā)時(shí)所講的組件樹方案為例,頁(yè)面到底有沒(méi)有邏輯性的變化只和 state tree 有關(guān),因?yàn)轫?yè)面的狀態(tài)是 state tree,而邏輯操作的也是 state tree,所以我們只要認(rèn)為 state tree 沒(méi)變,就可以認(rèn)為頁(yè)面沒(méi)有發(fā)生變化,不用觸發(fā)報(bào)警。
除了能識(shí)別變化外,利用運(yùn)行時(shí)框架的設(shè)計(jì),我們還能實(shí)現(xiàn)更先進(jìn)的功能,例如 B/S 架構(gòu)中還原瀏覽器端出錯(cuò)現(xiàn)場(chǎng)的問(wèn)題。在過(guò)去 debug 時(shí),我們通常都要與測(cè)試交流,按照操作步驟手工還原到現(xiàn)場(chǎng),如果能由程序自動(dòng)化一次性達(dá)到出錯(cuò)現(xiàn)場(chǎng),那無(wú)疑能給 debug 速度帶來(lái)質(zhì)的提升。要實(shí)現(xiàn)這種能力的關(guān)鍵點(diǎn)在于,任何表示頁(yè)面狀態(tài)的數(shù)據(jù),都要能暴露到外部,也能由外部傳入進(jìn)行重置。一旦有一個(gè)決定頁(yè)面狀態(tài)的變量在函數(shù)中,不能取出,不能序列化后傳給服務(wù)端,就無(wú)法做到。毫無(wú)疑問(wèn),這種能力也是需要應(yīng)用框架來(lái)支持的。例子中 state tree 的設(shè)計(jì),有一部分原因就是出于支持這種能力的考慮。
再來(lái)看監(jiān)控領(lǐng)域的熱點(diǎn),“無(wú)埋點(diǎn)”監(jiān)控,和自動(dòng)化測(cè)試有異曲同工之妙。“無(wú)埋點(diǎn)”指的是無(wú)手工在代碼中的埋點(diǎn),通常是使用可視化的技術(shù)來(lái)進(jìn)行“標(biāo)記”。

目前業(yè)界的一些方案中,遇到的問(wèn)題同樣是不能正確地識(shí)別變化。例如當(dāng)頁(yè)面上的元素改變了位置,埋點(diǎn)能不能不受影響?在可視化搭建平臺(tái)這個(gè)項(xiàng)目里,我們同樣是在應(yīng)用框架這個(gè)層面設(shè)計(jì)了解決方案:
我們的頁(yè)面使用一種類似于模板的方式來(lái)嵌套組件,這個(gè)結(jié)構(gòu)我們稱為 component tree,這個(gè)結(jié)構(gòu)是靜態(tài)可分析的,所以可以很容易地實(shí)現(xiàn)可視化。用戶如果想要控制組件使其產(chǎn)生變化,那么必須給組件取個(gè)唯一的名字,在邏輯代碼中使用這個(gè)名字對(duì)它的數(shù)據(jù)進(jìn)行操作來(lái)實(shí)現(xiàn)改變。
有了這個(gè)前提,無(wú)需任何額外的投入,就已經(jīng)實(shí)現(xiàn)了“無(wú)埋點(diǎn)”。因?yàn)椤奥顸c(diǎn)”本身就是對(duì)邏輯功能的統(tǒng)計(jì),所以埋點(diǎn)一定會(huì)埋在有邏輯相關(guān)的組件上,因此一定會(huì)有唯一的名字,那么無(wú)論組件怎么變化,只要沒(méi)有被刪除,我們的埋點(diǎn)信息就不會(huì)受到影響。同時(shí),如果一個(gè)有埋點(diǎn)的組件出現(xiàn)了改名或者刪除,我們還能自動(dòng)提示報(bào)警。而這些功能,同樣是在不到200行的代碼就實(shí)現(xiàn)了。

(埋點(diǎn)取名)
綜上,從測(cè)試和監(jiān)控兩個(gè)角度我們也可以看到,只要運(yùn)行時(shí)框架提供一點(diǎn)點(diǎn)幫助,就能以極小的成本來(lái)實(shí)施。針對(duì)確定的上游研發(fā)框架來(lái)進(jìn)行下游的開(kāi)發(fā),不用再考慮對(duì)各種框架的兼容問(wèn)題,也可以讓下游在能力上走得更遠(yuǎn),實(shí)現(xiàn)更多先進(jìn)的功能。
2.3 框架核心技術(shù)
我們?cè)诰€下交流中發(fā)現(xiàn),很多團(tuán)隊(duì)對(duì)框架的投入只停留在寫小工具和包裝開(kāi)源框架上。因?yàn)榭床磺宸较颍恢廊绾瓮度耄膊恢劳度牒笥卸嗌偈找妫圆桓疑钊搿F鋵?shí)方向和具體應(yīng)該投入哪些技術(shù),都是有跡可循的。這個(gè)蹤跡的源頭我們?cè)?《理想的應(yīng)用框架》中曾提到過(guò)的,就是程序的本質(zhì)——數(shù)據(jù)和邏輯。
2.3.1 數(shù)據(jù)
先具象一點(diǎn)來(lái)說(shuō)數(shù)據(jù)。框架的數(shù)據(jù)就是框架運(yùn)行時(shí)內(nèi)部保存的對(duì)象等數(shù)據(jù)結(jié)構(gòu),只要回答好兩個(gè)問(wèn)題就能展現(xiàn)出強(qiáng)大的威力:
- 數(shù)據(jù)在哪?
- 數(shù)據(jù)的生命周期是怎樣的?
知道數(shù)據(jù)在哪,是管理數(shù)據(jù)的基本條件。應(yīng)用的任何狀態(tài),都可以看做是內(nèi)部數(shù)據(jù)的一種表現(xiàn)。因此只有框架掌握了所有數(shù)據(jù),才有可能實(shí)現(xiàn)例如還原現(xiàn)場(chǎng)之類的功能。這對(duì)我們的研發(fā)有兩點(diǎn)指導(dǎo)意義:
一是在使用已經(jīng)有控制反轉(zhuǎn)和依賴注入的 web 框架時(shí),應(yīng)該完全遵循框架的約定,將服務(wù)等對(duì)象的管理完全由框架。有的框架語(yǔ)法寫起來(lái)比較麻煩,可以通過(guò)命令行或者IDE工具來(lái)自動(dòng)生成。
二是在我們改造或者創(chuàng)造框架時(shí),應(yīng)該把數(shù)據(jù)的統(tǒng)一管理作為最基本的底線,這是上下游實(shí)現(xiàn)自動(dòng)化的基礎(chǔ)。上一節(jié)中所提到的測(cè)試錄制的能力,就是建立在統(tǒng)一數(shù)據(jù)源的基礎(chǔ)上。再舉個(gè)更有意思的例子,過(guò)去的前端的 ajax 請(qǐng)求基本都是獨(dú)立調(diào)用 api,無(wú)中心的模式。這種模式可能會(huì)出現(xiàn)的問(wèn)題是:
請(qǐng)求A發(fā)出后,由于網(wǎng)絡(luò)等問(wèn)題,一直未返回,這時(shí)用戶有重新發(fā)送一次請(qǐng)求 A1。結(jié)果 A1 迅速返回在回調(diào)函數(shù)中提示成功。然后請(qǐng)求 A 超時(shí)返回,在回調(diào)中提示失敗,導(dǎo)致最后用戶看到的是失敗的信息。

當(dāng)引入 saga 之后,所有異步的操作都統(tǒng)一收歸到通信管道中,就能進(jìn)行跨請(qǐng)求的管理了。單個(gè)異步請(qǐng)求的取消、多個(gè)異步請(qǐng)求到底是獨(dú)立、還是競(jìng)爭(zhēng)、還是只保持最后一個(gè),就都能很容易地實(shí)現(xiàn)了。基于中心化的請(qǐng)求管理,還能進(jìn)行可視化:


(kuker)
繼續(xù)講到第二個(gè)問(wèn)題,數(shù)據(jù)的生命周期是怎樣的?生命周期通常是由外部事件來(lái)觸發(fā),或者自己運(yùn)行到某一階段自動(dòng)觸發(fā)的。對(duì)深度開(kāi)發(fā)來(lái)說(shuō),有兩個(gè)基礎(chǔ)能力必須由框架來(lái)提供。即框架要支持:
- 手動(dòng)驅(qū)動(dòng)生命周期
- 內(nèi)部數(shù)據(jù)的復(fù)制和置換
手動(dòng)驅(qū)動(dòng)生命周期對(duì)自動(dòng)化測(cè)試之類的功能來(lái)說(shuō)很重要,特別是在做一些基礎(chǔ)性的測(cè)試時(shí),有了這個(gè)能力就不用再完全模擬外部的觸發(fā)條件。而內(nèi)部數(shù)據(jù)的復(fù)制和置換則能為錄制、還原現(xiàn)場(chǎng)、協(xié)同等高級(jí)功能提供基礎(chǔ)。我們現(xiàn)在就在嘗試基于這種能力,實(shí)現(xiàn)“用戶可以將自己的出錯(cuò)場(chǎng)景一鍵發(fā)送給開(kāi)發(fā)人員來(lái)復(fù)現(xiàn)”的功能。值得注意的是,有的語(yǔ)言中復(fù)制對(duì)象是非常昂貴的操作,這時(shí)可能就需要考慮,是否使用 immutable 的數(shù)據(jù)格式會(huì)更好?還是依靠一些約定和標(biāo)記提供自身提供廉價(jià)的復(fù)制能力?限于篇幅,在此就不再展開(kāi)。對(duì)框架中的數(shù)據(jù)問(wèn)題感興趣的讀者可以去搜索 Single Source of Truth 和 Shared Mutable State 之類的話題,業(yè)界已經(jīng)有非常多的精彩討論。
2.3.2 邏輯
聊完數(shù)據(jù),終于來(lái)到最有意思的邏輯部分。框架從某種意義上來(lái)說(shuō),就是提供了一種邏輯表達(dá)的方式。要在邏輯表達(dá)上提升效能,有兩個(gè)發(fā)展階段:
- 提供一些模式或技術(shù)。讓用戶寫出低耦合、易重用、易擴(kuò)展的代碼。在寫代碼時(shí)提高效能。例如 MVC、IOC 等等。
- 針對(duì)不同場(chǎng)景設(shè)計(jì)更合理的 DSL,能實(shí)現(xiàn)代碼、圖等表達(dá)方式的互相轉(zhuǎn)換。在研發(fā)的整條鏈路上實(shí)現(xiàn)自動(dòng)化。
我們看到大部分的框架都處于第一個(gè)階段,不管是服務(wù)器端的 MVC 還是前端的 MVVM 。但也有少量第二階段的嘗試。例如 Flow Based Programming,試圖完全用數(shù)據(jù)流向的角度來(lái)詮釋業(yè)務(wù)中的邏輯。它的代碼可以天然被分析成圖,甚至能在運(yùn)行時(shí)進(jìn)行觀察:

(noflo)
還有《理想的應(yīng)用框架》中提到的基于事件來(lái)表示業(yè)務(wù)邏輯,也是一種 DSL。但這些嘗試離最終的目標(biāo)仍然有差距,最終理想的狀態(tài)應(yīng)該是能實(shí)現(xiàn)業(yè)務(wù)流程圖、時(shí)序圖、決策樹等業(yè)務(wù)領(lǐng)域常用的表達(dá)方式與代碼的互轉(zhuǎn)。雖然有差距,而且看起來(lái)要走的路還很長(zhǎng),但是針對(duì)一些已經(jīng)比較穩(wěn)定的場(chǎng)景,已經(jīng)有一些好的經(jīng)驗(yàn)。CMS 框架 Drupal 就是一個(gè)很好的例子。它定義好了數(shù)據(jù)發(fā)布的整個(gè)流程和相應(yīng)的鉤子系統(tǒng),讓開(kāi)發(fā)者用模塊的方式在鉤子里去修改或者增加自己的功能。曾經(jīng)一度實(shí)現(xiàn)了一個(gè)非常繁榮的社區(qū)。更值得肯定的是,社區(qū)中很多模塊都是可視化的,最終用戶不需要寫任何代碼,按照模塊的可視化指引就能完成相應(yīng)的功能。這實(shí)際上就等同于 DSL 與代碼的互轉(zhuǎn)了。
不管哪一個(gè)階段的關(guān)鍵技術(shù),都離不開(kāi)分析語(yǔ)義的能力。直白一點(diǎn)來(lái)說(shuō),就是“知道哪段代碼是干什么”的能力。
在第一階段的框架中,最影響效能的因素并不是”要寫代碼的多少“,而是寫按框架概念寫出來(lái)的代碼是否易于理解、易于維護(hù)。這一點(diǎn)在越是大型、越是多人參與的項(xiàng)目中,越是明顯。而代碼的“語(yǔ)義”是否清晰在某種程度上直接決定了我們是否能通過(guò)技術(shù)手段來(lái)提升可維護(hù)性。例如,在使用依賴注入的系統(tǒng)中,如果所有代碼的注入聲明都清晰地表明了注入的到底是什么的話,那我們就很容通過(guò)語(yǔ)言層面的支持或者簡(jiǎn)單字符串匹配得到依賴關(guān)系圖。反之,如果注入的信息模糊,既可能是函數(shù)也可能是 model,沒(méi)有任何明顯約束的話,那就可能得通過(guò)語(yǔ)法樹,找到注入的入口才能分析出來(lái),這樣實(shí)現(xiàn)的成本就成倍增加了。

(Rekit Studio 依賴分析圖)
相比于依賴分析,更重要的是“調(diào)用關(guān)系分析”,它對(duì)于幫助理解流程,特別是排查問(wèn)題特別有用。舉個(gè)簡(jiǎn)單的例子,在數(shù)據(jù)驅(qū)動(dòng)的前端框架中,因?yàn)橐晥D完全是數(shù)據(jù)的展現(xiàn),發(fā)現(xiàn)視圖不對(duì)了,如果能動(dòng)態(tài)展示出修改了數(shù)據(jù)的業(yè)務(wù)堆棧(不是函數(shù)堆棧),就非常有用。不需要再一步一步斷點(diǎn)。

當(dāng)然實(shí)現(xiàn)起來(lái)也更難。難點(diǎn)有兩個(gè):一是依賴分析一般是運(yùn)行前的,是靜態(tài)的,而調(diào)用關(guān)系一般是運(yùn)行時(shí)的,是動(dòng)態(tài)的;二是依賴通常是聲明出來(lái),容易讀出來(lái),而調(diào)用通常是在主動(dòng)式的語(yǔ)句中,會(huì)遇到條件判斷、循環(huán)、甚至通過(guò)變量在不同函數(shù)、類作用域中傳遞,比較難分析。這種難,其實(shí)也就是語(yǔ)義不清。在框架的設(shè)計(jì)或者我們自己的改造中,可以通過(guò)三點(diǎn)來(lái)盡量提供明確的語(yǔ)義:
- 盡量轉(zhuǎn)主動(dòng)為被動(dòng)
- 盡量片段化
- 消除用戶代碼中的副作用和對(duì)外部作用域中變量的依賴
前兩點(diǎn)很好理解,被動(dòng)聲明式的代碼結(jié)構(gòu)更容易被分析。雖然在實(shí)踐的時(shí)候需要大量經(jīng)驗(yàn),來(lái)保障設(shè)計(jì)出來(lái)的聲明格式即能覆蓋所有場(chǎng)景又要容易編寫,但是它帶來(lái)的收益也是最可觀的。GraphQL 就是一個(gè)最好的例子,在服務(wù)器端用聲明的結(jié)構(gòu)將數(shù)據(jù)結(jié)構(gòu)和關(guān)系表達(dá)出來(lái),在客戶端用聲明的結(jié)構(gòu)將要獲取的數(shù)據(jù)結(jié)構(gòu)表達(dá)出來(lái),后端就可以使用統(tǒng)一的引擎來(lái)生成調(diào)用,省去的大量寫接口的時(shí)間。第二點(diǎn),盡量片段化是指我們?cè)谝龑?dǎo)用戶寫代碼的時(shí)候,應(yīng)該把生命周期等等概念拆得盡可能小,使語(yǔ)義更細(xì)致。寫起來(lái)繁瑣的問(wèn)題可以通過(guò)工具或者語(yǔ)法糖去解決。
第三點(diǎn)最重要,消除副作用指的是任何時(shí)候運(yùn)行用戶的代碼片段應(yīng)該都不會(huì)對(duì)外部環(huán)境產(chǎn)生影響。而消除對(duì)外部作用域中變量的依賴指的是對(duì)要用的數(shù)據(jù)、服務(wù)盡量都用參數(shù)的形式傳入。這樣做的好處有兩個(gè),對(duì)于一些復(fù)雜的,難以分析的調(diào)用的關(guān)系,可以將要觀測(cè)的對(duì)象包裝一下再傳入,這樣就能動(dòng)態(tài)得到調(diào)用關(guān)系。在整體運(yùn)行前,因?yàn)闊o(wú)副作用,也可以很容易地通過(guò)試運(yùn)行這些片段來(lái)得到一些信息。雖然現(xiàn)在的語(yǔ)法樹工具已經(jīng)比較流行,但真的要完全通過(guò)語(yǔ)法分析來(lái)得到足夠的語(yǔ)義仍然有很大的工作量。而上述的這三點(diǎn),可以看做是快速、廉價(jià)的實(shí)現(xiàn)方式,并且實(shí)踐中效果非常不錯(cuò)。
綜合
最后值得一提的是,上面所講到的數(shù)據(jù)和邏輯中的原則與技術(shù)并不是相互獨(dú)立的。在《前端服務(wù)化——頁(yè)面搭建工具的死與生》和《通天塔之石——企業(yè)級(jí)前端組件庫(kù)方案》這兩篇文章中看到,我們所使用的很多技術(shù),其實(shí)是混合支撐著數(shù)據(jù)修改追溯、組件屬性可視化等功能。他們中間有的也有著依賴關(guān)系。但相比于“數(shù)據(jù)和邏輯”這兩個(gè)源頭,這些并不重要。只要掌握了這兩個(gè)源頭面對(duì)的問(wèn)題,其他都是能推導(dǎo)出來(lái)的。
對(duì)開(kāi)源框架如何使用也是同樣的道理。對(duì)于嚴(yán)肅的企業(yè)生產(chǎn)來(lái)說(shuō),應(yīng)該找到業(yè)務(wù)所面臨場(chǎng)景的源頭,吸收解決問(wèn)題的先進(jìn)的想法,但自己實(shí)現(xiàn),就像編程語(yǔ)言各自實(shí)現(xiàn)語(yǔ)言特性一樣。而不應(yīng)該只是停留在包裝開(kāi)源框架這個(gè)層次。開(kāi)源框架為了適應(yīng)盡量廣的場(chǎng)景,有更大的群眾基礎(chǔ),給出的一定是普適性的方案,這種普適性在業(yè)務(wù)發(fā)展到一定程度,有了足夠多的獨(dú)特性之后就會(huì)變成巨大的包袱反噬研發(fā)效能。等到了這個(gè)時(shí)候再考慮自己研發(fā),其遷移、適配、研發(fā)成本以及帶來(lái)的風(fēng)險(xiǎn)可能會(huì)變得非常大。而我們從前文看到,掌握了框架研發(fā)的幾個(gè)核心,從小的場(chǎng)景就開(kāi)始投入,成本并不高。最重要的是長(zhǎng)久積累形成體系后,所帶來(lái)的“流程上自動(dòng)化“、”降低下游實(shí)現(xiàn)成本”等能力能持續(xù)地幫助企業(yè)提升研發(fā)效能。
2.3 通用子系統(tǒng)與核心接口
從流程的角度來(lái)看,提升效能的主要是靠自動(dòng)化。而從系統(tǒng)的角度來(lái)說(shuō),則主要是靠能力的復(fù)用。”用戶“、”流程“、”權(quán)限“幾乎是任何業(yè)務(wù)系統(tǒng)中都存在的,因此將這三者也納入到了基礎(chǔ)研發(fā)體系的范圍。在這里我們并不打算深入到每個(gè)系統(tǒng)所面臨的具體問(wèn)題中,只講兩點(diǎn):
一、產(chǎn)品化或者子系統(tǒng)化,不要過(guò)早平臺(tái)化,對(duì)將來(lái)系統(tǒng)整體打包有益。過(guò)去的互聯(lián)網(wǎng)公司習(xí)慣將這些公用系統(tǒng)平臺(tái)化,各個(gè)業(yè)務(wù)系統(tǒng)來(lái)接入。但這幾年互聯(lián)網(wǎng)業(yè)務(wù)進(jìn)入的都是新領(lǐng)域,面臨的市場(chǎng)、用戶常常是需要隔離的。這個(gè)時(shí)候系統(tǒng)整體復(fù)制的能力就變得非常重要,所以一開(kāi)始就將這三者以子系統(tǒng)或者子產(chǎn)品的方式來(lái)對(duì)待,能為之后的發(fā)展提供更多的靈活性。
二、三者不是并列關(guān)系,不用糾結(jié)于能力解耦,制定核心系統(tǒng)接入規(guī)范才是最重要的。權(quán)限系統(tǒng)無(wú)論是 RBAC 還是 DAC 都離不開(kāi)用戶系統(tǒng)的支持。流程則是既依賴于權(quán)限也依賴于用戶。如果把運(yùn)行時(shí)框架看做是主板,這三者應(yīng)該是主板上的補(bǔ)充部分,一起為核心系統(tǒng)的接入提供針腳。同樣是為了系統(tǒng)整體打包的能力,應(yīng)該盡早制定核心系統(tǒng)接入的規(guī)范。
3 潮汐
在《月相》一章我們探討了 web 基礎(chǔ)研發(fā)體系的構(gòu)成及部分重難點(diǎn)。相比于具體技術(shù)本身,這套方案對(duì)組織成長(zhǎng)和重塑的意義更大。在這一章中我們會(huì)先從大團(tuán)隊(duì)中兩個(gè)有啟發(fā)性的問(wèn)題出發(fā),逐步深入到如何打造一個(gè)更高效的研發(fā)組織方案中。雖然問(wèn)題出現(xiàn)是在大團(tuán)隊(duì)的,但對(duì)小團(tuán)隊(duì)仍有兩點(diǎn)借鑒意義:
- 小團(tuán)隊(duì)隨著業(yè)務(wù)發(fā)展會(huì)長(zhǎng)成大團(tuán)隊(duì),也可能碰到一樣的問(wèn)題。
- 問(wèn)題本身萌芽于成長(zhǎng)過(guò)程之中,予以正確的指導(dǎo)能更加節(jié)約人力,助力公司發(fā)展。
3.1 平臺(tái)林立
首先注意,我們討論的仍是 web 層的問(wèn)題。這個(gè)現(xiàn)象在有多個(gè)不同業(yè)務(wù)的大公司中最常見(jiàn)。出現(xiàn)這種現(xiàn)象的原因有兩個(gè),一是公司到了萬(wàn)人規(guī)模,實(shí)際上就相當(dāng)于上百個(gè)百人規(guī)模的小公司,必然想法很多,出現(xiàn)重復(fù)的自然也多。
另一個(gè)更重要是,在 web 這個(gè)領(lǐng)域,特別是前端,基礎(chǔ)設(shè)施變化太快。
無(wú)論是瀏覽器底層所支持的 api,還是 javascript 語(yǔ)言本身變化都非常快。底層一變化,研發(fā)的各個(gè)環(huán)節(jié)必然出現(xiàn)基于新技術(shù)的空缺,很多框架和平臺(tái)就是隨著這些空缺出現(xiàn)的。現(xiàn)象本身存在即合理,但如果有更好的統(tǒng)一管理,是能從如下兩個(gè)方面提取出巨大的效能的。
一、如果將研發(fā)流程中的各個(gè)環(huán)節(jié)中獨(dú)立的平臺(tái)統(tǒng)一,可以極大地加速業(yè)務(wù)開(kāi)發(fā)。直接決定業(yè)務(wù)發(fā)展速度的是進(jìn)行業(yè)務(wù)開(kāi)發(fā)的工程師。他們最希望的就是只有一個(gè)平臺(tái)將研發(fā)的所有流程都搞定,并且盡量自動(dòng)化。平臺(tái)一多,對(duì)業(yè)務(wù)開(kāi)發(fā)工程師來(lái)說(shuō),學(xué)習(xí)、溝通、協(xié)作的成本就會(huì)陡增。這個(gè)成本有多大?在我們通過(guò)線下了解發(fā)現(xiàn),這個(gè)成本很多時(shí)候甚至?xí)^(guò)業(yè)務(wù)開(kāi)發(fā)本身。
二、加大對(duì)趨勢(shì)和方向的研究,預(yù)防無(wú)序的框架和平臺(tái)的投入,這樣能盡量防止走偏和無(wú)效勞動(dòng),也是一種提升。越是大的團(tuán)隊(duì),這一點(diǎn)越明顯。“基礎(chǔ)設(shè)施變化”這樣一個(gè)滾滾巨輪這些年壓碎了多少框架和平臺(tái),其中很多產(chǎn)生的效益都不足以覆蓋其研發(fā)成本。更壞的是,出于個(gè)人利益等原因,有的平臺(tái)過(guò)時(shí)了也不肯下線,阻擋了整個(gè)團(tuán)隊(duì)隨基礎(chǔ)設(shè)施一起進(jìn)步的機(jī)遇,消耗的是更多的未來(lái)的人力。
我們?cè)凇对孪唷分刑岢龅难邪l(fā)體系就是實(shí)現(xiàn)這兩個(gè)提升的具體手段。
首先,有一個(gè)完整的體系來(lái)將研發(fā)流程當(dāng)成一個(gè)整體對(duì)待,并且通過(guò)統(tǒng)一的平臺(tái)來(lái)實(shí)現(xiàn),能更好地實(shí)現(xiàn)流程的自動(dòng)化。降低一線工程師溝通、學(xué)習(xí)成本。
其次,對(duì)運(yùn)行時(shí)框架的投入,本身就包含著對(duì)趨勢(shì)和新技術(shù)的研究,可以緩解被基礎(chǔ)設(shè)施帶著跑的問(wèn)題。并且我們看到運(yùn)行時(shí)框架研究到了一定程度,能夠極大的減少后續(xù)測(cè)試、監(jiān)控實(shí)現(xiàn)的成本,也降低了基礎(chǔ)設(shè)施變化所產(chǎn)生的多米諾效應(yīng)。這里對(duì)管理帶來(lái)的反思是,我們應(yīng)該謹(jǐn)慎“平臺(tái)化”的思考。特別是下游環(huán)節(jié),因?yàn)椤捌脚_(tái)化”的思維,必然要考慮對(duì)各種不同的端進(jìn)行適配,必然要制定各種規(guī)范,這些都是人力成本。如《月相》中所示,上游理清楚并且統(tǒng)一后,下游是能有針對(duì)性地、很低成本地實(shí)現(xiàn)的,根本不需要“平臺(tái)級(jí)”的成本投入。當(dāng)然,在這里所說(shuō)的只是減少技術(shù)上的投入,環(huán)節(jié)本身還是非常重要的。
平臺(tái)林立從某一方面來(lái)說(shuō)也表示著團(tuán)隊(duì)內(nèi)部有著大量的無(wú)序的力量,這種力量在團(tuán)隊(duì)出現(xiàn)不同環(huán)節(jié)的分工時(shí)就產(chǎn)生了,盡早地建立研發(fā)體系就能盡早地將這些力量用起來(lái),創(chuàng)造真正的價(jià)值。
3.2 資源池
很多大公司的 web 研發(fā)團(tuán)隊(duì)都被當(dāng)成資源池來(lái)用,哪個(gè)業(yè)務(wù)需要就投入到哪里。現(xiàn)象的直接原因有兩個(gè):一是從管理的角度來(lái)說(shuō),web 層的研發(fā)工作相對(duì)來(lái)說(shuō)可替換性強(qiáng),具備形成資源池的可能。二是 web 研發(fā)處于業(yè)務(wù)決策鏈底層,人員相對(duì)來(lái)說(shuō)最緊張,因此通過(guò)資源池的方式能動(dòng)態(tài)地支持業(yè)務(wù)開(kāi)發(fā),是最簡(jiǎn)單的解決方案。但這個(gè)方案其實(shí)是相當(dāng)?shù)托У摹N覀儚膶?duì)工程師個(gè)人的關(guān)注來(lái)切入這個(gè)話題。
首先從主觀的角度出發(fā),一個(gè)有激情,對(duì)職業(yè)未來(lái)充滿憧憬的工程師與苦大仇深的工程師在效率上是有成倍差別的。除了其本身的性格外,造就這兩種態(tài)度有很大一部分是職業(yè)上升渠道的問(wèn)題。首先,和任何能被當(dāng)成資源池來(lái)用的工作一樣,因?yàn)榭商鎿Q性強(qiáng),所以不容易被重視。其次,目前的上升渠道不夠。web 研發(fā)工程師的上升渠道要么是縱向的,當(dāng)業(yè)務(wù)發(fā)展得足夠好,重要性提高,成為系統(tǒng)負(fù)責(zé)人。要么是橫向的,隨著團(tuán)隊(duì)擴(kuò)大,管理需要,成為管理者。這兩者一個(gè)基于業(yè)務(wù)一個(gè)基于人力,和技術(shù)相關(guān)不大。所以有才華的工程師自然會(huì)想要造框架、造平臺(tái),努力成為公司技術(shù)中重要的一部分。但沒(méi)有正確的引導(dǎo),就會(huì)成為上面所說(shuō)”無(wú)序的力量“,發(fā)展得不對(duì)反而會(huì)變成公司的消耗。而當(dāng)他發(fā)現(xiàn)自己付出的努力得不到回報(bào)的時(shí),就有可能變成苦大仇深的工程師。
最終影響的不只是工程師自身,公司也會(huì)要在管理成本上為其買單。我們?cè)谂c一些資深 hr 交流時(shí),他們進(jìn)一步說(shuō)明了這個(gè)問(wèn)題。在公司工作了四、五年的員工,是已經(jīng)融入了公司,理解公司文化也了解公司問(wèn)題的人,算是中流砥柱。如果得不到好的上升,可能會(huì)有兩種情況:其中有想法有行動(dòng)力的,多半會(huì)選擇離開(kāi)。既會(huì)對(duì)組織穩(wěn)定性會(huì)造成影響,也會(huì)讓公司付出的培養(yǎng)成本付諸東流,對(duì)公司來(lái)說(shuō)可算是很大的損失;另一種更不好的則是既不離開(kāi),也不像以前一樣努力。他們?cè)趫F(tuán)隊(duì)內(nèi)有一定的話語(yǔ)權(quán),卻喪失了進(jìn)去的激情,不再發(fā)揮積極的作用。當(dāng)公司需要快速擴(kuò)張、快速發(fā)生變革的時(shí)候,他們就會(huì)成為隱性的管理成本。
而解決方案,其實(shí)很簡(jiǎn)單。大公司內(nèi)部通常都有”框架組“、”平臺(tái)組“類似的部門,但基本都停留在”可用“階段就完成任務(wù)了。這遠(yuǎn)遠(yuǎn)不夠,如果將建立 web 基礎(chǔ)研發(fā)體系作為目標(biāo),以產(chǎn)品化為衡量標(biāo)準(zhǔn),加強(qiáng)重視和投入。 web 工程師的上升渠道就會(huì)得以擴(kuò)張,公司內(nèi)無(wú)序的力量就會(huì)進(jìn)入到正確的領(lǐng)域。創(chuàng)造的價(jià)值又能進(jìn)一步為研發(fā)提供能量,形成一個(gè)正循環(huán),逐步緩解人力緊張的態(tài)勢(shì),資源池現(xiàn)象也就自然會(huì)消失。這很像我們身體受傷時(shí),外部腫脹只是炎癥的表現(xiàn),消炎了,腫脹自然也就好了。重點(diǎn)是找到關(guān)鍵進(jìn)行消炎,而不是圍著外部現(xiàn)象思考。

建立體系還能帶來(lái)的好處是,通過(guò)提升 web 研發(fā)的效率,降低業(yè)務(wù)研發(fā)所需的人數(shù),能幫助大公司重新回到小步快跑的節(jié)奏。張小龍有一篇演講《警惕KPI和復(fù)雜流程》,講到了小團(tuán)隊(duì)的重要性,隨著互聯(lián)網(wǎng)公司的競(jìng)爭(zhēng)越來(lái)越激烈,這種重要性會(huì)變得越來(lái)越高。我們從一些互聯(lián)網(wǎng)的新巨頭上,其實(shí)已經(jīng)看見(jiàn)了“核心技術(shù)+基礎(chǔ)web研發(fā)能力”來(lái)快速出產(chǎn)品,占領(lǐng)市場(chǎng)的趨勢(shì)。對(duì)小公司來(lái)說(shuō),統(tǒng)一的 web 基礎(chǔ)研發(fā)體系,是幫助實(shí)現(xiàn)超車的重要一環(huán)。對(duì)大公司來(lái)說(shuō),則是進(jìn)一步挖掘效能,防止掉隊(duì)的必修課了。
4 后記
這篇文章筆者前后重寫了三次,因?yàn)槊鎸?duì) web 一線工程師這樣一個(gè)龐大的群體,效能提升已經(jīng)不僅僅是技術(shù)或管理某一方面的事情,而是要綜合各個(gè)方面來(lái)尋求個(gè)人和公司發(fā)展的共贏。 web 一線研發(fā)是很多工程師進(jìn)入這個(gè)領(lǐng)域最開(kāi)始做的事情,但是筆者看到了很多有才華的人困在了低效、重復(fù)的工作里面,努力了也因?yàn)榉较虿粚?duì)而徒勞。這對(duì)個(gè)人和公司都是損失。在技術(shù)上找到方向,在管理上予以支持,多方發(fā)力,其實(shí)能提升的效能遠(yuǎn)超十倍。當(dāng)然,一篇文章不足以實(shí)現(xiàn)任何改變,這篇文章最主要的目還是拋磚引玉,也希望對(duì)這個(gè)方向有想法,志同道合的朋友聯(lián)系我,一起交流,一起推動(dòng)。
郵箱: ariesate@outlook.com。
5 答讀者問(wèn)
問(wèn):研發(fā)體系的統(tǒng)一規(guī)劃不是破壞了競(jìng)爭(zhēng)和創(chuàng)新嗎?
答:統(tǒng)一規(guī)劃并不是指不要競(jìng)爭(zhēng),不要?jiǎng)?chuàng)新。而是防止開(kāi)倒車的情況出現(xiàn),是給競(jìng)爭(zhēng)和創(chuàng)新指定一個(gè)方向。例如我們?cè)谖闹欣砬迳舷掠侮P(guān)系,目的是指導(dǎo)研發(fā)力量應(yīng)該往哪里投入,在投入的過(guò)程中仍然可以采取競(jìng)爭(zhēng)的形式。
問(wèn):框架研發(fā)提升效能的趨勢(shì)?
答:分兩個(gè)方向。一是框架本身,會(huì)朝著“增強(qiáng)對(duì)用戶代碼的理解和控制力”這個(gè)方向前進(jìn)。用戶按框架寫的代碼,能不能通過(guò)工具分析出具體的語(yǔ)義?人工的低級(jí)錯(cuò)誤能不能自動(dòng)檢測(cè)出來(lái)并自動(dòng)修正?能不能轉(zhuǎn)化成某種人類習(xí)慣的表達(dá)方式,比如圖?當(dāng)控制力達(dá)到一定程度后,這些能力都實(shí)現(xiàn)后,再往下應(yīng)該就是代碼的自動(dòng)生成。
另一個(gè)值得一提的是框架能力與業(yè)務(wù)特有屬性會(huì)一起沉淀到 IDE 上,會(huì)出現(xiàn)面向?qū)S锌蚣艿?IDE,面向單個(gè)具體工程的 IDE。分析圖,自動(dòng)掃描工具都由 IDE 作為載體,就像很多游戲的專用編輯器一樣。只有沉淀到 IDE 上才是最便捷、最有針對(duì)性的。對(duì)這個(gè)方向感興趣的讀者可以跟我郵件討論,目前我們已經(jīng)有一些初步的想法。
問(wèn):文章中講到的問(wèn)題都是大公司的,對(duì)小團(tuán)隊(duì)來(lái)說(shuō),什么時(shí)候應(yīng)該開(kāi)始建立自己的基礎(chǔ)研發(fā)體系?
答:研發(fā)體系的建立可以分為規(guī)劃和實(shí)施兩個(gè)階段。規(guī)劃的話,從一開(kāi)始就應(yīng)該有所規(guī)劃。在前期人力不夠的情況下,不用強(qiáng)行追求打造自己的框架和工具,可以用開(kāi)源的。但應(yīng)該始終把開(kāi)源的東西拿到自己的體系中,清楚地知道它在自己體系中的角色,也清晰地知道自己用了它的什么特性,未來(lái)還需要補(bǔ)充什么。什么時(shí)候開(kāi)始實(shí)施其實(shí)有一個(gè)象征性的標(biāo)準(zhǔn),也是我們前面在無(wú)序的力量中提到的——出現(xiàn)了不同環(huán)節(jié)的分工時(shí)。有的團(tuán)隊(duì)業(yè)務(wù)擴(kuò)張?zhí)欤肆σ恢辈粔颍敲唇ㄗh按五分之一到三分之一的比例來(lái)抽出人力打造基礎(chǔ)設(shè)施。磨刀不誤砍柴工,何況投資得到的回報(bào)是電鋸呢。
浙公網(wǎng)安備 33010602011771號(hào)