滴滴曹樂:如何成為技術大牛?

韓楠發表於2022-09-01

圖片


桔妹導讀: 曹樂,清華大學畢業,16年初加入滴滴,帶領團隊建設了滴滴網約車技術體系,現任滴滴網約車技術部負責人。 面對技術團隊同學的成長困惑,曹樂給同學們寫過一封信,他從各個維度去闡明自己的見解與想法,幫助同學們不再侷限於從技術視角去看待問題,而是擁有更廣闊的視野與方法。他圍繞如何成為技術大牛這一話題提出以下一些想法:尋找正規化、刻意練習、及時反饋;垂直打透、橫向遷移、深度覆盤;聰明人要下笨功夫。在此再次分享給大家這封信的內容。


很多同學都有關於工程師該如何成長的問題,大家普遍對如何成長為牛人,如何獲得晉升,如何在繁忙的工作中持續學習充滿了困惑,這其實是每一位同學成長過程中必經之路,在這裡也想跟大家分享一下我的一些心得。

同學們普遍對成長充滿了焦慮感。工作太忙沒時間學習,需求太多太瑣碎感覺自己沒什麼進步,做技術是不是做到35歲以後就沒人要了,等等,都是對成長焦慮的體現。這種焦慮是正常的,所有的渴望,在內心的投射其實都是焦慮。任何一個渴望成長的人,不管處於什麼階段,一線工程師,架構師,還是總監,副總裁,其實內心中都是充滿了焦慮的,無一例外。對於這種焦慮,我們所要做的是接納,而不需要過度擔憂。這種焦慮並不是說,想明白如何成長了就會沒有了,到了某個階段就會沒有了的。成長的腳步和期待一刻不止,內心的焦慮也一刻不會停歇。正是這種焦慮感,驅使你寫程式碼追查問題到星夜,驅使你犧牲休息娛樂的時間和一本本厚厚枯燥的書作伴,驅使你不斷努力向前,不捨晝夜。相反的,如果內心中沒有這種焦慮,反而是值得擔憂的。這可能說明已經習慣呆在自己的舒適區了。在現在這樣一個高速發展的社會,以及我們這樣一個高速發展和變化的行業,失去對成長的渴望和焦慮反而是一個非常危險的訊號。

所謂的程式設計師35歲危機,其實背後的根本原因是,有太多太多人在工作幾年以後,就覺得自己什麼都會了,之後的十幾年工作只不過是頭2-3年的簡單重複而已。在我們這樣一個行業裡,在招聘的時候,如果擺在管理面前的兩個人,一個是初出茅廬或剛工作2-3年,充滿了對成長的渴望;另一個工作十多年了但水平和工作2-3年的人差不多,只是更熟練一些,不過在舒適區已經躺了十年了。如果負責招聘的是你,你會做出什麼樣的選擇?

而另一方面,其實是高階人才在行業內的極度極度稀缺,這在行業內是非常普遍的現象,真正的大牛太稀缺了。在這樣一個行業裡,如果一個人能夠持續成長,能力和工作年限成正比的持續提升,這樣的人,任何時候在行業裡都是被瘋搶,怎麼可能會遇到任何年齡的危機呢?

如何學習,其實是有方法論的,那就是刻意練習。所謂的10000小時成為大牛的理論是片面的,如果只是簡單重複10000小時,是不可能成為大牛的。刻意練習包含了三個步驟。第一,找到你要學習的這個領域體系的正規化(pattern);第二,針對每個正規化刻意的反覆學習和練習;第三,及時反饋。

大家在過往的工作和學習生活中,或多或少都在實踐著刻意練習。拿面臨高考的中學生舉例子,好的學生通常是把一門功課拆成了很多知識點(尋找pattern),然後針對知識點以及他們的排列組合,有針對性的反覆做各種難度的題(刻意練習),每次做完題都對一下答案看看正確與否,如果錯了就思考,記錄,覆盤(持續及時反饋)。這樣的學習方法就是事半功倍的。而事倍功半的學習方法,就是不分青紅皂白拿起一本習題或卷子就拼命做,我上學的時候身邊不少同學非常勤奮但成績並不好,多半都是這個原因。再舉一個我最近在學打羽毛球的例子,正確的學習方法是把打羽毛球拆解成步法和手上動作,小碎步,米字步,正反手挑球,放網,正手和頭頂高遠球吊球殺球等(尋找pattern),然後針對每一個動作反覆練習(刻意練習),然後請教練或者錄下來看影片糾正自己的動作(及時反饋);而錯誤的學習方法是,上來就盲目找人打比賽,以賽代練,這樣的進步是很慢的,而且錯誤的動作形成習慣以後未來反而很難糾正。

當學習方法不正確的時候,刻苦的學習常常只是看起來很勤奮,並沒有應有的效果。當接觸一個陌生領域的時候,錯誤的學習方法是不帶目的性,上來就找一堆相關的大部頭開始啃。而正確的學習方法應該是快速梳理該領域的知識點,形成框架體系(尋找pattern),這裡有些小竅門可以快速構建起一個領域的知識點體系,例如看一些該領域的綜述性或開創性的文章(看論文,別瞎看網上的文章),或者找本該領域綜述性的教科書看它的目錄(注意,好的教科書的目錄往往就是這個領域的知識框架,內容倒不一定非要看下去)。然後,針對每個知識點,找書裡的相關章節,該領域相關paper裡的相關section深入學習,建立起自己對這個知識點的理解(刻意練習)。最後,再把知識點和現實工作中的情況(自己工作,或其他公司相關的工作)進行對照(及時反饋),從而建立對一個知識點的深度理解,最後融會貫通建立對一個領域的理解。

這樣說可能有點抽象,拿我當年學習分散式儲存的過程為例子,先結合自己的工作內容梳理出需要深入瞭解的知識點(例如,元資訊組織,Meta Server設計和HA,副本組織和管理,Recovery,Rebalance,單機儲存引擎,資料/元資訊流,糾刪碼,一致性,多租戶,儲存介質,網路環境和IDC等等),同時看很多綜述性的材料,梳理分散式儲存的知識點(有網上各種整理的比較好的文章,也有從各種系統實現的paper裡抽出),不斷迭代構建分散式儲存領域的知識點(尋找pattern,這是最難的一個過程);然後針對每一個知識點,找相關材料進行深度學習,例如,對於分散式一致性,需要閱讀CAP理論,Paxos的論文,Raft的論文等等以及周邊的很多材料(刻意練習);然後找各種系統實現的論文或文章,比如GFS,Dynamo,Aurora,OceanBase,Ceph,Spanner等等,看看和對比它們在一致性上是如何考慮和取捨的,當然,最重要的是結合自己工作中的反覆實踐和所學知識點進行比對(及時反饋)。

這三個階段並不是割裂的,而是週而復始的,經常會在刻意練習和及時反饋的學習過程中,發現自己遺漏的知識點,或者發現自己梳理的兩個知識點其實是重合的。透過這種交叉比對,以及在實踐中不斷檢驗的方式建立的知識點是非常可落地的,而不會看了幾篇論文以後就人云亦云。拿分散式儲存的一致性舉例子,如果不是反覆對比、思考和反覆實踐,你不會發現GFS論文裡最難的一段,多個Writer對一個檔案進行append的邏輯,在實踐中根本沒用;你也不會發現看起來優雅而學術的CAP三選二的理論,實踐中壓根不是這麼完美,很多時候只能三選一;你也不會發現Dynamo論文裡的Vector Clock,網上有無數文章搖頭晃腦的解讀,但在Amazon的應用場景裡是個典型的over design,Cassandra在這點就務實很多。

這時候大家可能會有個疑問,工作本身就如此繁忙了,哪裡能抽出足夠多的時間去學習?

其實工作和學習本身,是不應該被割裂的。工作本來就應該是學習的一部分,是學習中的實踐和及時反饋的部分。學習如果脫離工作的實踐,其實是非常低效的。因此每個同學應該對自己工作所在的這個技術和業務領域進行系統性的學習,並在工作中反覆實踐和驗證。不同的領域之間其實是融匯貫通的,當你對一個領域精通並總結出方法論以後,很容易就能上手別的領域。因此花幾年實踐徹底研究透一個領域,對於剛工作幾年的同學來說,是非常重要,甚至是必須的,也只有在一個領域打透之後才談得上跨領域遷移,去擴充自己的知識面。更直接的說,對於一個領域還未完全掌握的同學,深度是最重要的,不用想廣度的事情,等掌握了一個領域之後,再去擴充廣度就變得很容易了。

這裡一個常見的誤區是,學習的內容和工作的領域沒有太多直接的關係。例如,我以前曾經花了非常大的功夫去讀Linux核心的原始碼以及很多相關的大部頭,幾乎花掉了我將近兩年的所有空閒時間,然而在我這些年的工作裡,幾乎是沒有用處的,最多就是有一些“啟發”,ROI實在是太低了,現在也忘得差不多了。更重要的,軟體工程是一門實踐科學 從書本上得到的知識如果沒有在實踐中應用和檢驗,基本上是沒有用處的。舉一個例子,很多優秀的架構師,儘管日常工作中可能反覆在用,但未必說得出開閉原則,里氏替換原則,迪米特法則等等,反過來,對物件導向設計這7大原則出口成章的人,很多其實離真正的架構師還遠得很,有些甚至只是部落格架構師而已。實踐遠遠比看書,看文章重要得多,上文所述的我構建自己分散式儲存知識體系的過程,看起來好像都是看材料,看論文,而實際上80%的收穫都來源於帶著理論的實踐,和從實踐中總結沉澱的理論。因此,徹底搞明白自己工作所在的技術和業務領域,是最務實高效的做法,工作和學習割裂,會導致工作和學習都沒做好。

這時候大家可能會有另一個疑問,感覺日常工作非常瑣碎,學不到什麼東西,怎麼辦?

如果把學習分成從書本中學,和從工作中學這兩種的話,那毫無疑問,工作中的“知識密度”,比起書本的“知識密度”,肯定是要低很多的,因為書本里的知識,那都是人家從他們的工作中抽象總結出來的。這也是為什麼大家普遍覺得日常工作“瑣碎”。然而工作中每個點滴的瑣事與平凡,都是可以抽象總結成為方法論的,更別說工作所在的領域自身的博大精深了。從日常工作中學習的秘訣,就是“行動中思考”。

對於每一個軟體工程師,最重要的兩個能力,是寫程式碼的能力和trouble shooting的能力。並且,要成為優秀的架構師,出色的開發能力和追查問題的能力是一切的基礎。提高寫程式碼的能力的核心,首先在於堅持不斷的寫,但更重要的,在於每天,每週,持續不斷的review自己之前的程式碼;同時,多review牛人寫的程式碼,比如是團隊裡你覺得程式碼寫的比你好的同事,比如社群裡以程式碼漂亮著稱的開原始碼(作為一個C++程式設計師,當年我的榜樣之一是boost庫)。一旦覺得自己之前的程式碼不夠好,就立刻覆盤,立刻重構。更重要的是,多思考自己程式碼和好的程式碼之間不同之處背後的為什麼,通常這就是為什麼這些程式碼更好的背後的秘密。

特別要說明的是,程式碼規範除了知道是什麼外,要格外重視思考每一個程式碼規範背後的為什麼。程式碼規範的每一句話,背後無一例外都是一片江湖上的血淚史。要提高trouble shooting的能力,關鍵在於要深度覆盤自己遇到的每一個問題,包括線上的,包括測試發現的,尋找每一個問題,每一次事故背後的root cause,並且思考後續如何避免同類問題,如何更快的發現同類問題。要對團隊內外遇到的所有問題都要保持好奇心,關注一下週邊的事故、問題背後的root cause。Trouble shooting能力的提高是幾乎無法從書本上得到的,完全來源於對每一個問題的深度思考,以及廣泛積累每一個問題。對於架構師而言,可能未必在一線寫程式碼了,但看團隊中一個架構師是否真正牛逼的一個很重要標準,就是看他是否能夠追查出團隊其他同學查不出來的問題。我見過的一個真正牛的架構師,對於系統中疑難雜症,通常問幾個問題,就能大致猜出是哪裡出的問題,以及可能的原因是什麼,準確程度如同算命,屢試不爽,令人歎為觀止。

對於一個架構師,除了更加優秀的程式碼能力和trouble shooting能力外,需要構建相對完整的當前技術領域的知識體系,需要有體系化的思維能力,需要對技術所服務的業務有非常深入的瞭解。體系化的思維能力,來源於兩個方面。一方面是在日常工作中,對每一個介面設計,每一個邏輯,每一個模組、子系統的拆分和組織方式,每一個需求的技術方案,每一個系統的頂層設計,都要反覆思考和推敲,不斷地覆盤。另一方面,需要大量廣泛地學習行業內相似系統的架構設計,這其實就是開天眼,只是技術相對來說,行業內的交流更加頻繁。淘寶、美團、百度、Google、Facebook、Amazon等各個公司介紹系統架構的論文和PPT鋪天蓋地,需要帶著問題持續學習。 除了技術領域本身外,架構師需要非常瞭解業務上是如何使用我們的系統的,否則非常容易over design,陷入技術的自嗨中,這也是為什麼我說Amazon Dynamo論文裡講的Vector Clock是個over design的原因。

另一方面,很多時候技術上繞不過去的坎,可能非常複雜的實現,往往只需要上層業務稍微變通一下,就完全可以繞過去,這也是為什麼我說GFS論文裡,多個Writer同時Append同一個檔案是個根本沒用的設計(實際上Google內部也把這個功能去掉了)。只有真正知道上層業務是如何使用系統的,才可能真正做好架構。深入瞭解業務並不難,對於每個同學,只要對於每一個接到的需求,對於每一個需求評審中的需求,對於周邊同學或團隊要做的需求,都深入思考為什麼業務要提出這個需求,這個需求解決了業務的什麼問題,有沒有更好的方案。遇到不明白的多和周邊同學、產品、運營同學請教。最怕的是自己把自己限定為純粹的研發,接到需求就無腦做,這等於放棄了主動思考。衡量一個人是不是好的架構師,也有一個方法。對於一個需求,如果他給出了好幾個可行的方案,說這些方案也可以,那些方案也可以,往往說明他在架構師的路上還沒有完全入門。架構師的難點不在於給出方案,而在於找到唯一的那一個最簡單優雅的方案。

總結起來看,行動中思考,就是始終保持好奇,不斷從工作中發現問題,不斷帶著問題回到工作中去;不斷思考,不斷在工作中驗證思考;不斷從工作中總結抽象,不斷對工作進行復盤,持續不斷把工作內容和全領域的知識交叉驗證,反覆實踐的過程。

在工作所在的技術和業務領域中刻意練習,加上行動中思考,就是成為技術大牛的秘訣。

看起來方法也不復雜,為什麼大牛還是非常稀少?

儘管我們通篇都在講方法,但其實在成為技術大牛的路上,方法反而是沒那麼重要的。真正困難的,在於數年,數十年如一日的堅持。太多人遇到挫折,遇到瓶頸,就覺得手頭的事情太乏味枯燥,就想要換一個方向,換一個領域,去學新的技術,新的東西。而真正能夠成為大牛的,必須是能夠青燈古佛,熬得住突破瓶頸前長時間的寂寞的,必須是肯下笨功夫的聰明人。因此,和堅持相比,方法其實並沒有那麼重要。


本文作者


來自 “ 滴滴技術 ”, 原文作者:曹樂;原文連結:https://mp.weixin.qq.com/s/blazNWi-z2mAT9U-c6VdPw,如有侵權,請聯絡管理員刪除。

相關文章