這是一篇綜合類技術選型指南,試圖為你提供一份比較通用的技術選型思維框架。當你需要進行技術選型時,可以參照它來設計自己的決策樹。這其中你需要考慮的主要維度包括目標產品、目標使用者、目標團隊和技術本身,下面我將分別細述,並在此基礎上介紹一些反模式。
維度
目標產品
這是最重要的維度。產品本身的特徵將影響技術選型時的很多因素。
短生命週期產品和長生命週期產品
短生命週期的產品通常要求快速起步:門檻低、書寫自由、不強制遵循任何最佳實踐。當它的使命結束時,程式碼會被直接拋棄。所以,對於這類產品,“快糙猛”的技術是較好的選擇,當然,能做到“快精猛”更佳。
而長生命週期的產品則會強烈要求可維護性,因為它們在很長時間內都是不可報廢的。甚至對於一些生命線產品,連重寫都會要求在重寫期間線上系統平穩過渡,一點點遷移到新技術。
這種要求對團隊的工程化能力是個極端的考驗。如果沒有相應的工程能力,其代價甚至會高於用新技術重新寫一個功能相同的系統。
探索型的產品和守成型的產品
探索型產品往往也是短週期產品,但是同時也有自己的特點。它要求快速,但往往同時會要求高質量。探索型的產品如果證明了可行性,那麼過渡到長生命週期的可能性很大。
這就要求它最好是一個微核心系統,提前留出一些擴充套件的空間。當然,設計微核心系統對架構師的能力具有相當的考驗,如果沒有一個優秀的架構師,建議還是不要刻意做任何預留,優先保障系統的簡單性。
除此之外,探索型產品的技術棧必須支援可靠的、自動化的重構。因為探索型產品的迭代速度很快,如果完全靠人工去新增功能並手動重構,那麼一旦出現 BUG,將給此產品的使用者體驗帶來嚴重的負面影響。
所以,除非由於人才儲備等原因而被迫做出折中,否則探索型產品的技術棧一定要快速而嚴謹。
當然,“大力出奇跡”定律也是成立的。也就是說,如果你有決心也有力量在將來對這個探索型產品進行徹底的重寫,那麼採用快糙猛的技術快速把它搭建起來,也未嘗不可。如果你的業務確實能如預期般爆發,那麼只要把重點放在系統延展性等方面即可;但是如果不能如預期般爆發,可能就會導致維護成本在中期開始飆升,在競爭中處於劣勢。這是一種“不成功便成仁”的策略。據我所知某獨角獸企業就是在業務起來之後通過鉅額投入來償還技術債的。但這對於 CTO 的技術直覺是一項極大的考驗,不要輕易效仿。
而對守成型產品的選型則會側重於與現有技術棧的相似程度和無縫整合能力。如果整合時需要藉助很多技巧,那麼可能你就是在給自己挖坑。
在引入新技術的過程中,要儘可能符合現有的開發流程、基礎設施和開發習慣。當然,如果現有的這些已經嚴重過時,那麼應該找新老技術的專家,共同幫你設計一個路線圖,讓你可以平穩地引入新技術,這份投資絕對值得。如果老技術已經有新版本,則應該優先考慮升級它。不要幻想換個技術棧就能解決一切問題,事實上,它帶來的問題往往會更多。
邊緣產品和生命線產品
在人員的學習能力和意願允許的前提下,邊緣產品是最佳的試驗場,適合探索各種候選技術,試驗各種激進方案,積累經驗教訓。其影響範圍可控,即使失控也不會帶來太大的損失。當然,即使探索,也應該有計劃地探索,不要每個邊緣產品都採用不同的技術方案,那樣會給人才供應帶來巨大的挑戰。
而生命線產品則應該穩妥優先,採用保守方案。所以應該優先採用團隊內部積累了一定經驗或具有穩定的強力外援的技術。
所有的生命線產品幾乎必然是長週期產品,所以其可維護性同樣是重中之重。
產品維度總結
在目標產品維度上,低價值產品優先考慮門檻低的技術,但是高價值產品應該儘早進行投資性技術積累,優先考慮天花板高的技術,這樣才不至於在若干年之後被迫重寫。如果工程化能力不足,這種重寫往往會成為災難。
目標使用者
使用者的特點對於技術選型具有顯著的影響,甚至可能會導致產品不可用。
瀏覽器版本
在前端領域,瀏覽器版本是永遠的痛,但這是需要權衡的。高版本瀏覽器甚至是單一的低版本瀏覽器會顯著節省開發成本,但是可能會損失一些使用者。該怎麼解決呢?當然不能拍腦袋決定。
如果你們已經有同領域的線上系統,那麼應該統計這些線上系統的訪問情況,得出一個最準確的、針對目標客戶群的統計,然後分析一下不同版本的瀏覽器有多大價值,有沒有可能通過非技術手段讓使用者使用你們的目標瀏覽器。即使沒有線上系統,也可以隨機對目標使用者群發一些調查問卷,確定他們的實際使用情況,以及安裝新版瀏覽器的可能性。
下下之策是查一下百度公佈的全網瀏覽器資料,然後說“我們要支援某某瀏覽器,它還有 10% 市場佔有率呢!”,這是懶。
使用者頻寬
同樣是前端領域,檔案的下載體積可能會被一些人當做亮點進行宣傳,但是你要清楚,現在已經是 4G 時代了,更不用說很多企業內部應用都是千兆頻寬。就算能比候選技術小 100k,在 4G 頻寬下(假設現實頻寬是 2MB/s)也就是 100 毫秒,有誰能感覺到這部分差異? 這就是一個明顯的“誤導讀者”的例子。
可訪問性
在產品的使用者群體中,不但有健康人,還有色盲以及盲人等殘疾人。特別是對於面向消費者的產品,儘可能的考慮這些人的需求不但能體現出產品的“人文關懷”,而且也在一定程度上擴大客戶群。比如蘋果和微軟等大公司都把可訪問性放在了核心位置。如果你決定要實現可訪問性,那麼就應該把它作為一項需求,納入到選型時要考慮的因素中。
之所以要把它納入到技術選型過程中,是因為新增可訪問性支援的代價比較高,而很多第三方庫並沒有提供這方面的支援。所以應該提早考慮。
國際化
與可訪問性相似,國際化也是一個後期新增代價比較高,但很多候選技術卻沒有提供支援的特性。
如果你的產品在預期生命週期的相當一段時間內需要供多語言使用者使用,那麼,在初期選型時,就要把候選技術的國際化能力和質量納入你的主要考量。
訪問頻度
使用者的訪問頻度對前後端的技術選型都有很大影響。
比如說一個一年只用一次的功能,考慮其效能很可能是沒有必要的,在一小時內跑完和在一分鐘內跑完往往沒有顯著的價值差異。但是這兩種技術方案卻可能有著硬碟佔用、程式設計複雜性、運維複雜性等方面的成本差異。你需要考慮:那種能在一分鐘內跑完的技術是否能給你帶來足夠的價值。
對於前端來說,頻繁訪問的、面向消費者的應用通常會要求更高的流暢度,那麼在技術選型時,就要選擇流暢度更高的技術。但是這個流暢度一定要設計一個模擬的場景,親自驗證一下,甚至做一些灰度釋出在現實場景下進行驗證,而不要只看其官網宣稱的流暢度。比如阿里的閒魚團隊就對 Flutter 技術進行了長時間的灰度驗證,最終替換成了完全使用 Flutter 的版本,堪稱對新技術進行選型的模範。
使用者維度總結
要特別小心,不要根據錯誤的、片面的資訊作出決策。很多第三方的技術選型指南背後都有著它們自己的場景,但大多數都不會給你寫清楚,有的甚至複雜到想給你寫清楚都做不到。甚至有些選型指南還有著強烈的主觀立場,為了證明自己的預設立場甚至不惜造假。所以,你要先清點出你們的產品最應該重視的那些指標,然後拿這些指標對候選技術進行可行性測試,甚至為此專門開啟一些 SPIKE 專案,而不要迷信第三方選型指南。
目標團隊
目標團隊的因素確實很重要,但並不像你認為的那麼重要。除非你的人才供應真的有問題(難道不應該先反思一下是不是錢給少了?),否則應該優先考慮提升團隊能力,而不是削足適履。
技術背景
目標團隊的技術背景對新技術的選型確實很重要,但是沒必要去精確匹配。
比如 Java 團隊要做前端,選擇 GWT 看似很好,但 GWT 也有自己的問題,幾乎完全無法利用前端生態。他們更好的選擇可能是 Angular:從語言上,TypeScript 跟 Java 有諸多相似之處;從架構模式上,對 MVC 的理解稍微往前推一步就是 Angular 的 MVVM 模式;從特性上,依賴注入不要太熟悉;從生態上,你可以自由決定是否使用前端生態,取長補短。
同樣,前端團隊如果打算自己寫 BFF,也不一定非要在 Node 生態下打轉。你完全可以使用 Java 世界的 Reactor 或者 WebFlux 進行響應式程式設計。這樣可以和後端的其它 Java 體系更好地進行整合,並減少運維的複雜度。
團隊規模
團隊規模可能是團隊維度中對技術選型影響最大的因素。
四位開發人員以下的小規模團隊,如果大家都很專業,那麼其溝通成本就很低,在技術選型上可以更傾向於選擇靈活的技術,因為較高的人員能力和較低的溝通成本,可以讓靈活的框架更好地發揮其作用,最終更加高效、高質量的推出產品。這種場景通常出現在由牛人組成的創業團隊中。
如果開發人員經驗不足或者做事不夠專業,就需要更強的約束,特別是對於職場新鮮人,在早期養成好的開發習慣是非常重要的。而開發習慣中最重要的一點就是:約束 —— 知道不該做什麼。這時候,偏向自由的技術可能會一時爽,但最終會構築一個玻璃天花板,導致遲遲無法突破到下一個層次。
如果團隊規模過大,那麼首要的選擇是用 DDD 等巨集觀技術把問題域細分,使其可以被小規模團隊承接。如果暫時還做不到,就要考慮建設完善的基礎設施和交付紀律,來為團隊協作提供自動化保障。如果這些都做不到,就應該選擇強約束性的具體技術,讓大家避免犯錯,或者儘早發現錯誤。在爭取到時間之後,再逐漸深入化解根本性原因。
組織架構
康威定律深刻地影響著很多方面,技術選型也不例外。特別是做巨集觀技術選型時,必須考慮它在最終技術架構中的位置,以及與團隊溝通結構的匹配程度。即使是一項很先進的技術,假如它與體系中的其它技術棧不匹配,也可能導致翻車。
當選擇多個第三方庫的時候更要加倍小心,因為它們開發時互相不知道彼此的存在,特別是對於一些較新的技術,可能都沒人把它們搭配使用過。
除了開發架構之外,還要考慮更廣泛的運維架構。假如你們引入了 DevOps,可能這個問題會得到一定程度的緩解。假如沒有,那就要充分考慮上下游環節的人員能力和配套設施是否完備。比如如果運維部門缺乏 NodeJS 運維技能,就不要盲目引入基於 NodeJS 的後端,一定要拿到他們“我能”的承諾之後再開始。
除非你是個前後端 + DevOps 全棧,否則就需要儘早對組織架構方面的因素進行驗證並排除風險。也就是說,在一個可控的演習環境中,用一個小型案例,完整地走一遍開發、上線、發新版的流程。在這個過程中,一些顯著的風險將會暴露出來,要評估其影響,來決定如何選型。
人員流動性
人員流動帶來的損失比大多數人所認為的要大得多。人員流動會帶走知識和文化。企業要避免損失,就要把這些知識和文化儘可能記錄在程式碼中。
當然,這並不意味著應該要求大量寫註釋,而應該使用那些能留存知識的技術,比如型別系統和規範化命名。型別系統和規範化命名可以半強制性地要求開發人員把原本只存在於自己腦子裡的知識記錄到程式碼中。如果更有追求一點,可以再嘗試普及單元測試。這樣,當他離開的時候,即使沒有文件,這些知識也仍然能留存下來。從效果上說,程式碼往往比文件和註釋更好。
而文化的留存則更加困難,事實上,程式碼中的奇葩註釋往往留存的是負面文化。應該在程式碼中留存的文化,是嚴謹、專業的工作態度。雖然自由也是文化的一部分,甚至在管理領域是非常值得嚮往的文化,但在工程領域,它往往是一種負面文化,因為軟體開發領域並沒有公認的法律甚至道德。你可以想象一下管理領域中沒有約束的自由會導致怎樣的後果。
所以,要想應對人員流動的風險,除非你有信心留存知識與文化,否則就應該在技術選型時,傾向於選擇更加嚴謹的、隱式資訊更少的技術。
團隊維度總結
鞋子好不好,只有腳知道。錯誤的選型,也只能由團隊自身來承受。阿波羅神廟上鐫刻著一句警世名言——瞭解你自己。所以,請先客觀認識自己的團隊,然後再據此進行選型,千萬不要懶於思考,盲從潮流。
技術本身
對技術本身的考量,主要是代入其它維度之後,看其匹配程度。
技術本身在選型中可能反而是最不重要的一個維度。這些年的歷史早已證明:優秀的技術未必能流行起來;很多技術的流行,也並非是由於其優秀。
明確的定位
一項優秀的技術,應該有其明確的定位和發展路線。這些定位能清楚地表明自己要做什麼、不做什麼。而其發展路線應該至少有一年以上的提前規劃,而且在定位上要能與其前輩做出有效區隔,而不是亦步亦趨,沒有自己的特長。
程式碼質量
雖然流行的未必優秀,優秀的也未必流行,但技術選型不是趕時髦。所以,在條件允許的情況下,還是應該儘可能選擇優秀的技術。程式碼質量高的技術,將來技術本身由於維護成本飆升而被放棄的可能性也較小。
衡量程式碼質量的標準有很多,其中最常用、也比較有效的是單元測試的覆蓋率。而那些從一開始就具有比較完備的單元測試的程式碼庫,往往優於後補測試的程式碼庫。因為這證明的是開發組的工程化能力和意識,而這些是該技術長期可維護性的根本保障。當然,除非該技術特別複雜或應用場景的容錯性特別小,否則也不必苛求超過 90% 的覆蓋率。
維護團隊
維護團隊的規模和能力,對於一項技術在長跑中的表現非常重要。在歷史上如流星般劃過的技術數不勝數,但最終能長期留下來的卻不多。維護一項技術的成本遠高於建立它,所以如果沒有一個健康、可持續的商業模式,一個像 Linus 那樣的志願者,以及一個願意出錢的超級大金主,那麼它在未來的競爭中落敗只是遲早的事。除非這項技術的需求集足夠小而穩定,否則這些因素缺一不可。
社群
社群的質量,決定著這項技術長遠的未來,一些草根型技術的隱患就在於此。如果社群人員的素質過低,喜歡無原則的站隊,而不能理性的對該技術提出尖銳的意見甚至批評,那麼這個社群遲早會衰落。這類社群有一個顯著地特徵就是喜歡宣揚它“包治百病”,也就是說它適合一切場景,而不會先問你一些問題再決定是否要推薦給你。另一個特徵就是喜歡通過刻意選取某些標準來做出片面的對比,這種行為在學術界屬於學術造假行為,但在我們工業界卻被習以為常,這不能不說是我們的悲哀。
好的社群應該是一個君子社群。他們會自覺遵守共同的、理性的行為規範。會把精力放在對技術本身做貢獻,而不是通過詭辯、群毆等手段來攻擊競爭技術。社群的主要領導者會對社群的不良行為提出批評、做出約束,甚至為社群成員的不良行為道歉,而不是放任不管。
技術維度總結
不要把技術看得太重。對所有的主觀性宣傳文章,留一些心眼,多問一句——那缺點呢?將來決定你們是否會掉在坑裡的,就是它的缺點。
對於那些會如實告訴你缺點的宣傳文章,請高看一眼,因為作者是真的希望對你們團隊的未來負責。
對於功利社群,請務必小心;對於君子社群,請自覺維護。
反模式
有一些技術選型策略可能會導致災難性的失敗,這些選型中存在一些共同的反模式,比如:
輿論驅動選型
人云亦云,盲目聽信外人或者某些佈道師的主觀性言論,這就是輿論驅動選型。它往往會帶來災難。
做任何決策時,如果要藉助參考資料,請記住:最重要的不是它告訴了你什麼,而是它對你隱瞞了什麼,這些隱瞞的資訊最終會置你於險境。
特別是當該資料的作者對某項技術具有顯著的傾向性時,請深入想想,他向你推薦的每一項優點是否真的“對你”有價值,以及它背後的代價是什麼。比如,推崇“自由”的技術往往不夠“嚴謹”,如果你的產品需要嚴謹,那麼請把“自由”看做減分項而不是加分項。比如,推崇“體積小”的技術在現在動輒幾T硬碟、幾M頻寬的環境下,到底對你來說有多大價值?它是不是因為沒有其它的優點了才把這種細枝末節亮出來吸引你?
即使是調查報告之類的客觀參考資料,也需要了解其背景。比如一份只發給程式設計師的調查報告,可能會發現 Chrome 的使用率超過了 99%,但顯然它對你的面向普通使用者的產品毫無價值,只會給你帶來風險。同時,要注意很多調查報告的設計是有主觀傾向性的,甚至題目的排列順序都會給最終結果帶來 10% 以上的偏差。所以,一定要仔細分析其中立性、客觀性以及調查物件在你的目標場景下的代表性。
單一指標驅動選型
根據任何一個單一指標進行選型都會給你帶來災難,更何況很多指標並不適合作為選型的依據。
有些指標很容易操縱,比如 GitHub 倉庫上的 Star 就是很容易操縱的,在淘寶網上還有專門購買 GitHub Star 的服務,而 GitHub 的年度報告中也已經不再把 Star 作為主要指標使用。即使是那些不容易造假的指標,比如 commit 數量,其實也不適合作為主要指標使用,它可能意味著作者具有良好的工程習慣和足夠勤奮,但也可能意味著程式碼庫質量堪憂,因此不斷推出補丁。
當然,有一些客觀指標還是比較適合作為主要指標來使用的,但也不要盲目相信數字。比如單元測試中覆蓋率較高的專案,確實通常質量比較好,但是我也見過一些只有呼叫卻沒有斷言的測試,那些測試的覆蓋率也會很高,但卻是假的。所以,如果要評估其質量,最好還是親自開啟看一看。
即使你選出了一些主要指標,並且確信它們沒有造假,也仍然不能簡單地把它們加起來或加權平均來得出一個數字進行比較。你要綜合評估這些指標對你的目標產品、目標使用者、目標團隊的價值。如果技術選型只是個數字遊戲,那還要你幹嘛?
話語權驅動選型
這幾乎是最糟的選型,但卻屢見不鮮。技術棧的更迭往往會帶來話語權的變化,而這將給公司帶來災難。
對於高階技術決策者,需要有戰略定力,應該以一種規範的、用事實說話的方式來控制技術選型的副作用。我曾見過一幫程式設計師“偷襲珍珠港”導致架構師被迫辭職的慘劇,我當時的意見是:這是 CTO 的鍋。團隊由於選擇技術棧而產生了話語權之爭,說明制度設計和文化建設出了大問題,這隻能由 CTO 背鍋。
所以,如果你是個技術決策者,那麼應該儘早站出來,發揮你的職權和非職權影響力,抑制這些負面文化,而不是任由其發展,最終破壞公司的總體技術路線,甚至技術氛圍。
粉絲驅動選型
對於生命線產品,最糟糕的選型莫過於粉絲驅動選型了,這次可沒有“幾乎”。對於技術人員來講,最重要的特質是客觀冷靜,這樣才能配得上“專業”二字。而拜大神,當作玩笑尚可,如果讓它影響到你的決策,那麼你就應該趁早隱退了,免得將來被迫引咎辭職。
雖然也曾被人稱作“大神”,但我一般會提出反對,至少不作正面回應。我已工作二十多年,太清楚業界百態了。實際上,很少有人真的配得上大神的稱號,舉世可能只有 Anders Hejlsberg、Bob 大叔、Martin Fowler、Jeff Dean 等少數幾位。不過我相信如果你當面叫他們大神,他們也會反感的。
就算是對於這些舉世公認的大神,也不應該成為你技術選型的依據,頂多是相信他們會珍惜名譽、不會粗製濫造而已,因為即使是精品也仍然有著明確的適用範圍,超出這個範圍它也可能會成為毒藥。
當然,對於邊緣產品,進行粉絲驅動選型也未嘗不可,甚至可能更好。只是得記住,要做就請做好,別給你的偶像丟臉,更不要做好之後就覺得公司一定要把它應用於生命線產品中。
決策樹
如果我在這篇文章的最後部分給你一棵決策樹,你會不會很高興?
很抱歉,寫這一章的目的,就是為了告訴你:我不會給你任何決策樹。請根據我提供的思維框架,自行設計適合你們自己的決策樹,及時更新它,並且不要盲目相信量化的評估結果。
文/ThoughtWorks汪志成
更多精彩洞見,請關注微信公眾號:ThoughtWorks洞見