天天看點

Thoughtworks 徐昊:為什麼要成為全流程式員,而非全棧程式員?

作者:美食家滄州3C2

本文由極客時間整理自 Thoughtworks 全球技術政策顧問、中國區 CTO 徐昊在直播中的演講《為什麼要成為全流程式員,而非全棧程式員》。 作者|徐昊 編輯|李辰洋 幾年前,Facebook 聲稱他們隻招聘全棧程式員(Full Stack Developer),要求對大部分技術都要有所涉獵和了解。于是國内也出現了這樣一種風潮,全棧程式員成為大家趨之若鹜的新方向。 然而在微服務、BFF、微前端等一系列技術日趨流行的今天,全棧程式員已不再意味着效率,也讓我們對它所宣傳的效能産生了諸多困惑。那麼我們不禁要問: 為什麼過去幾年大家對于 Full Stack 有着非常多的強調,最近卻講得越來越少了? 如果想達成全棧所承諾的效率提升和人員成長,背後有什麼先決條件? 圍繞着這個先決條件,Full Stack 真的實作了自己的承諾嗎? 甚至應該繼續追問,在今天的環境下成為什麼樣的程式員是更值得關注的?這就是我們今天想展開讨論的一些話題。 全棧工程師的吸引力 我們做項目時肯定會用到技術棧,所謂的技術棧其實是一種類比。比如資料庫會用到 Redis、mongo、SQL 等,中間可能會用 Backend 的一些系統,包括 Java、Spring、Ruby on Rails,前台有 JavaScript、HTML 等。也就是按照分層架構的方式,從前端到後端去排列時,就好像從上到下的一個棧。 全棧程式員就是要求沿着棧的方向,掌握所涉獵的主要技術點。也應該知道,當談論 Full Stack 時,它的重點是按照技術架構,以及技術架構裡所采用的各種元件和技術,讓我們沿着棧的方向都能有所了解。 全棧之是以能夠産生作用,在當時有兩個重要背景。一是代碼集體所有(Collective Code Ownership)。無論前台、背景還是資料庫,當做環境部署時,有關代碼都會放到統一的版本控制當中去。而版本控制的這些東西,所有人都可以直接通路。 我想大家可以很容易聯想到行業裡的一些最佳實踐,比如 Google 的 Monorepo 就是一個大的單一倉庫,而我們會把所有的項目群組件都放到這些倉庫裡。很顯然,在 Monorepo 裡會看到大量 Java、JavaScript 的資料庫的代碼。是以在當時那個狀态下,很多大的網際網路公司都在強調把代碼由小團隊所有轉向集體所有。 而作為全棧工程師,當你調試或使用别人的元件的時候,如果對技術棧所使用的技術都能有所了解,你的效率和工作方法就會得到很大的提升。這是一個出發點。 第二個出發點,或者說第二個讓 Full Stack 變得有吸引力的點,就是行業内所強調的一種端到端的傳遞模式。 所謂端到端的傳遞模式,是跟之前分子產品的傳遞模式相區分的,之前可能是有一幫人寫資料庫,還有一幫人落地背景,前台也是如此。而在端到端的傳遞過程中,既要傳遞資料庫,也要傳遞背景,還要傳遞前台。要想在這樣的工作模式下變得更有效率,就需要對全棧的資訊有更多的了解。 在這種情況下,我們認為在一段時間内,全棧工程師對于整個行業想要的研發效能和業務模式的轉變是能夠适應的。是以在四五年前,全棧工程師的概念就受到了行業内的一些追捧。 現在很少強調全棧 而今天我們很少再去講全棧了,最顯而易見的原因是随着用到的技術越來越多,我們很難對全棧作出明确的定義,比如到底要全到什麼程度才叫全棧呢? 當然,除此之外還有幾個很客觀的因素,首當其沖的就是行業裡引進了以微服務為主的新的架構風格。 在微服務元件進行劃分時,有一個主要特點,就是用 API 分隔了前台和背景。看上去好像跟之前做前背景分離、按元件傳遞沒有什麼差別,但實際上其中的差異性是巨大的。 前背景被 API 分隔後,帶來的結果就是業務能力和 User Journeys 實際上就被 API 隔離開了。而之前,之是以要做端到端的傳遞,是因為我們在業務能力和 User Journeys 上并不做明顯的區分。 大概十幾年前,我們去做系統的時候可能會用 Spring MVC、Map-Works、Ruby on Rails 等,服務端和用戶端之間的契約主要是在頁面流、使用者體驗和使用者流程上産生的。 而在今天,API 已經和使用者體驗、UI 層完全解耦了,我們就會認為被 API 封裝和分隔的這種前背景,可以變成一個獨立被傳遞的元件了。而在過往的時候,它們并不具有獨立傳遞的意義。 比如說一家企業要做微服務,服務封裝了企業内某個核心的業務能力,那麼它是有獨立傳遞的價值和意義的。但在十幾年前,如果背景系統封裝了三五個頁面跳轉的邏輯,以及在頁面跳轉邏輯上所需要的資料,這種獨立傳遞的背景并沒有對應的前台系統,是以也就沒有任何可以被獨立傳遞的意義。 而微服務告訴企業,就算沒有前台,那麼它對于業務能力的更新和改進,放到企業生态中也仍然是有意義的。是以對于獨立傳遞的邊界,就産生了非常大的思路上的轉變。我們今天的系統是有明确傳遞邊界的,它不再是一個從頭到尾需要去傳遞的東西了。 如圖所示,我們從下往上看,背景是 API 層,可以通過把業務能力封裝成服務去通路資料庫。中間是 BFF,通常會在這一層去重組 User Journeys。 就以 BFF 為例,可能會出現中間我有個 API 的用戶端,它會去通路背景的叫 Business capabilities 的 API,借由這些 API 以及由 API 包含的模型,我們可以重組 User Journeys,也就是頁面對應跳轉的流程。 再往前,可能就是一個真正的用戶端,比如 UI 的元件、UI 的互動,以及由 UI 元件和傳遞觸發的用戶端的調用,去調用到 BFF 上通路的這樣一個過程。 在今天這樣一個場景下,我們不禁要問這樣的問題,全棧工程師難道還像之前的概念一樣,跨越用戶端、BFF、Microservice,整個串在一起才叫 Full Stack 嗎?還是說在獨立的傳遞邊界内,隻要掌握了獨立傳遞邊界内的内容,就可以叫做 Full Stack 了? 如果用圖來表示,Full Stack 在我們傳統意義上來講,應該這麼畫(左側黃線)還是這樣畫(右側黃線)? 實際上這也是最近一段時間,行業内不再過分讨論 Full Stack 的一個重要因素,因為我們預設的架構風格和架構的上下文發生了改變。 我們現在傾向于使用比原來更小粒度的範圍,把它變成一個獨立可傳遞的元件。那麼我們可以說,難道隻要在元件内去使用和掌握的這些技術棧歸為了一個,就會被認為是 Full Stack 了嗎? 這就讓 Full Stack 這個概念變得非常尴尬。要麼我不切實際地希望你能掌握從頭到尾所有使用到的技術,或者像之前一樣,隻要把它分散到小的子產品中,就會被認為是 Full Stack。那麼 Full Stack 又與我們之前講的後端開發、前端開發到底有什麼樣的差異和差別呢? 在今天的架構風格和架構環境下,大家不太知道 Full Stack 到底能帶來什麼樣的價值和效用,反而變成了一個非常容易讓人困惑的概念。 可能有人會說 Full Stack 就是一個風潮,一個趨勢,過去就過去了。我覺得我們不能這樣講。我們需要深度反思一下,當年在提倡 Full Stack,或者當 Full Stack 被行業瘋狂采納,甚至很多人預言未來需要的一定是全棧工程師,不再需要單點工程師了,如此種種都表明我們當時充分認識到了 Full Stack 的價值和意義。 是以我們要進一步追問的是:Full Stack 背後的邏輯到底是什麼?圍繞着這個邏輯,在今天的環境下成為什麼樣的程式員才是更有價值的? 全棧的出發點:協同效應 如果我問得再極端一點,Full Stack 這個概念在曆史上真的産生過它所應許的這些效果嗎?我的答案是沒有,甚至是從來都沒有達成過它想要的這些目的和宣稱的好處。 除了剛才講的代碼集體共享和端到端傳遞外,Full Stack 最核心的出發點其實是協同效應,也就是所謂的 1+1>2。比如當兩個全棧工程師在一起工作時,他們産生的效能會大于二。 要知道,全棧工程師追求的,并不是一個全棧工程師比非全棧工程師的效率能高多少。它其實追求的是,一對全棧工程師在一起工作的效率,将會比非全棧工程師的效率高很多倍,因為他們産生了協同效應。 我們強調全棧,并不是指個人在單點上的,而是指他在團隊中發揮的效率和效能,換句話說,全棧工程師可以在團隊中産生和創造出更多的協同效應。 舉個例子。全棧工程師強調開發者需要對整個棧上的内容都要有所了解,一個非常直接的影響就是能看懂系統中的所有代碼。如果出現 Bug 需要調試,不會出現“我不了解,需要等另一個人來幫我做”的情況。而是我可以一直調試下去,直到找到問題的根源所在,甚至完成修改。 這是全棧工程師所發揮的一個重要作用,他掌握了别人知識領域裡的内容,能在工作過程中産生一種協同的效用。 再往深了講,為什麼在軟體開發中需要協同效應呢?我在很多場合都講過這個話題,而且這也是我的談話節目《八叉說》的一個元命題,即軟體工程是一種知識工作。 談及什麼是軟體工程時,我們一般會把它類比成蓋房子,其中有做圖紙的人、有搬磚的人、有放水泥的人,等等。實際上并不是這樣的,在軟體開發過程中真正産生的隻有知識,是以這是一個知識被傳遞、消化和吸收的過程。 我們可以把它想象成客戶,或者是真正花錢購買軟體的人。在他的頭腦中,有一種幫助業務成功的方式和方法,并把這種方法告訴給了 BA 等角色。當 BA 充分了解了客戶的上下文、上下文到底代表什麼樣的含義,就會把這種知識産生成另外一種形式,也就是需求文檔,或者是方案設計加上需求文檔。 産生了方案設計和需求文檔之後,他就需要講給開發者聽。開發者了解吸收了方案文檔中所指定的業務上下文,以及業務上下文中所有的含義,就可以将其轉化成代碼。這個時候,知識就從一個空想的概念轉化成了一種可執行的形态。 最後按照我們傳統的流程,代碼會被放到一名 QA 或測試人員的手裡,驗證客戶最開始提出來的問題是否在他的上下文中得到了唯一的解決。 這就是我想強調的在今天的環境下,我們可以把軟體工程的整個開發看成一個知識生産和傳遞的過程。 知識消費 而知識生産和傳遞的過程是需要協同效應的,這很容易了解。如果開發者完全不懂業務上下文,就不太能了解需求是什麼。如果不能了解需求,那他的代碼大機率也寫不對。是以當我們把軟體開發變成一個知識工作的時候,就非常需要協同效應。 當然這裡有一個更嚴謹的說法,源自管理學領域大師中的大師彼得·格魯克。他說知識工作最大的颠覆是我們價值的産生點變了,知識工作者的價值并不取決于産生,而取決于消費。 舉一個更實際的例子。一個做業務分析的人說自己的需求文檔寫得特别好,有兩百頁,但所有人都看不懂寫的是啥。他可能寫的全部正确,但是因為别人看不懂,消費不了,他就沒有起到有效的知識傳遞的作用,他的價值就是 0。作為一個知識工作者,他的價值需要以消費來度量。 同樣,對于開發者而言,如果寫出來的功能和代碼沒有被消費,那就沒有任何意義。沒有被消費,指的是不能轉化成實際的功能被别人使用,甚至是寫出來的這些功能,其他人不能繼承和調用。 比如說我寫了一個 API 庫,用了一大堆設計模式,最後的代碼非常炫酷,但沒人看得懂。沒有人看得懂,就沒有人會去用,這個架構也就沒有任何意義。 這是非常重要的一點。如果我們把自己看作知識工作者,我們的價值就不由工作決定,而是由消費來決定。對于一個知識工作者而言,關注的應該是消費的價值和消費的效率,而不是産生了多少價值或者産生了多少效率。 很顯然,協同效應将會提升知識消費的效率,這是一個非常簡單的推論。比如說你在一個項目上工作了三年,大家會覺得你的水準提高了,工作效率也非常高。與另一個剛加入公司兩三天的人相比,他的效率可能怎麼都趕不上你。 但并不是你的水準有多高,可能很大一個原因是你對于環境上下文有了更深入的了解,跟團隊其他人的協同效應更高,最終産生的結果和效率也就更高。我們彼此說的話都懂,溝通成本更小,知識在傳遞過程中的失真和損失更小,這本身就會提高知識傳遞的效率和效果。 到這裡我們可以發現,全棧程式員最原始的假設是,當我們在工作棧上了解了所有内容時就會産生協同效應。這個假設本身是沒有錯的。 接下來要繼續追問的是,既然全棧工程師的基本假設和前提是對的,那麼全棧的方式是否真的增加了知識的消費呢?答案是一點點,而且僅僅是在代碼層面上(Sort of,and at code level)。 在代碼層面上,意味着我可以看懂你的代碼,但并不代表我可以完全了解代碼背後所指代的業務上下文和業務邏輯。 我們生活中都有這樣的經驗,比如說一個人的英語很好,但并不代表他能看懂一篇專業領域的英語論文。很可能他能看懂裡面所有的單詞和文法,但是根本讀不懂那篇論文到底在講什麼。 是以當我們去了解全棧上所使用的技術點時,隻能說我們擁有了解最終産出物的能力。但軟體開發真正的過程是圍繞着知識傳遞來展開的,那麼僅僅了解最終産出物,并不代表能了解産出物背後所包含的業務上下文和業務邏輯等知識。這個時候我們可以說,協同效應是不會被大量産生的。 另外也是工作經驗告訴我們,對于技術棧的掌握,并不代表任何含義。哪怕使用的是相同的技術棧,但因為處在不同的業務和領域,兩個開發者也經常是雞同鴨講。是以分享的知識僅僅是按照棧的方向去走的話,其實很難産生必要的協同效應。 那麼什麼樣的協同效應是我們真正需要的呢? 真正的協同效應 無論是什麼樣的開發方式,我們最終要做的事情都是了解真正的問題,得到解決方案,并把解決方案分解成更小的任務,執行,驗證我們的問題是否被解決了。 請注意,我們驗證的不是方案,而是那個真正的問題是否被解決了。如下圖所示,從上到下是知識産生并被傳遞的過程(Konwledge generates and transfer),從後往前是知識被消費了的過程(Konwledge consumption)。 這個時候我們可以把軟體開發過程看成一個圍繞着知識的 Stream,也就是一個知識傳遞和消費的流。那麼我們可以得出這樣一個結論:如果沿着流的方向去共享更多的知識,就會産生更多的協同效應。 知識是沿着流的方向傳遞并最終實施成軟體的,如果我們在流的方向上增加知識的共享和知識的分解,而不是按照棧的方向(不是垂直的方向)去處理,協同效應将會産生得更多、更強。 我想大家可以想到很多具體的技術都符合這個原則。比如說,統一語言的目的就是在流的方向上進行更多的知識分享,讓大家對業務上下文都有相似的了解,然後讓開發人員和業務人員進行更有效的溝通,進而産生更強的協同效應,這是一種簡單且直接的方式。 再舉一個工作中經常碰到的情況。你在某個業務領域做得越多、了解越多的情況下,效率就會變得越高。也就是說有越來越多的業務上下文,某種程度上會讓你成為更好的程式員。 應該有同學會說,你的意思是不是要讓開發人員充分了解業務之後,自己去定業務方向、做産品設計?是不是讓一個人從頭到尾把所有事情都做了? 并不是。我們強調的是共享知識,隻要能提升溝通效率,就會産生對應的協同效應。是以隻要懂和了解别人說什麼,這其實已經足夠了。比如當一個決策出來後,根據業務實施背景,了解背後的原因、推斷就可以了。而不是讓你變成一個專家或者去做解決方案,才能夠産生必要的協同效應。 到這裡,我們很自然就能得出全流程式員所指的是什麼了。Full Stream,就是沿着上下遊去擴充知識和上下文的領域,讓我們能夠了解更多的業務。這是我們現在需要成為的全流工程師,在流的上下文中掌握了更多細節和知識的程式員。 如何成為一個全流工程師? 剩下的問題是,怎麼成為全流工程師?我想很多同學可能會回答說去學習更多的領域知識,能有更多的業務場景。 這的确是我們需要注意的一個方向,但實際上并不僅僅是這樣一些内容。如下圖所示,有這樣幾個方向希望你可以考慮一下。 首先是分析和模組化。我怎麼才能更快地掌握建立在業務和領域上的東西呢?最終的答案,都展現在你對于問題能否進行有效地分析和有效地模組化。别人模組化出來的内容,你能否很快地了解?你能否很快地了解在同一個語言背後,大家到底講的是什麼? 然後是任務分解,也就是所謂的架構。架構就是系統中有多少個元件,以及這些元件是如何互動的。當有一個新的需求,架構實際起到的作用隻有一個,就是指導任務分解。從實作的角度上來講,就是當你拿到需求後,能否還原它背後的架構圖景,了解當初為什麼做出這樣的架構決定。 當然,并不需要你去做一個架構設計,隻需要了解它就可以了,那麼剩下的就是測試和編碼。有了這些東西,該怎麼更好地測試以保證這些内容是完成的呢?該怎麼更好地進行有效編碼呢?這些都是圍繞着編碼解決實際問題、産生解決方案的部分。 當然,後續還有很重要的上線和營運工作。 你可能說公司有專門的 DevOps 部門、産品營運部門。但是如果不了解軟體實際上線的流程,在編碼過程中就很容易做出錯誤的決定。甚至不了解運維的要求,也會産生類似的結果。假設你該埋點的地方沒埋點,那當真正需要運維定位的時候,就會發現資料是缺失的。 但如果沿着這個流的方向,能對知識有更多的了解和體會的話,我們的協同就會更有效率。 以我個人的成長經曆來看,我學得最有用的一門課是如何做業務分析,就是講如何識别業務價值,并把業務價值寫到 User Journey 上。到今天為止,我都認為那是對我職業生涯影響非常重要的一門課,但它跟編碼沒有任何關系。 我想絕大部分程式員在規劃自己的職業生涯時,在編碼和技術上已經投入了非常多的注意力。但是當談到需要打開技術視野,或者希望職業生涯能有更長遠的發展時,我們其實更需要沿着知識傳遞和知識消費的流(Stream)的方向,去增強自身的能力,至少讓自己在整個流的過程中不存在明顯的短闆。 相信做到了這一點,你就會變成和今天完全不一樣的 Engineer!

十年老店,賽前友友圈推薦,全年無休(薇 HMDDYP)