阿里妹導(dǎo)讀:在阿里,我們習(xí)慣尊稱畢玄老師為“畢大師”。他2007年加入阿里,一手打造了HSF,十多年來更見證、參與了阿里在基礎(chǔ)技術(shù)上的演進與發(fā)展:如淘寶在2007-2009年的分布式應(yīng)用架構(gòu)升級、2013-2016年的阿里電商異地多活架構(gòu)升級等。但很少有人知道,他大學(xué)讀的是生物專業(yè)。
左手代碼右手詩,亦是生活亦是癡。今天,畢玄老師將為你講述十多年開發(fā)經(jīng)歷的收獲與感悟,希望能對你有所啟發(fā)。
畢玄
本文轉(zhuǎn)自畢玄老師個人公眾號:hellojavacases
(不常更新,一更就是經(jīng)典)
從業(yè)余程序員到職業(yè)程序員
程序員剛?cè)胄袝r,我覺得最重要的是把自己培養(yǎng)成職業(yè)的程序員,我的程序員起步比同齡人都晚了很多,更不用說現(xiàn)在的年輕人了,我大學(xué)讀的是生物專業(yè),在上大學(xué)前基本算是完全沒接觸過計算機,軍訓(xùn)的時候因為很無聊,我和室友每天跑去學(xué)校的機房玩,我現(xiàn)在還印象很深刻,我第一次走進機房的時候,別人問,你是要玩windows,還是dos,我那是完全的一抹黑,后來就只記得在機房一堆人都是在練習(xí)盲打,軍訓(xùn)完,盲打倒是練的差不多了,對計算機就這么產(chǎn)生了濃厚的興趣,大一的時候都是玩組裝機,搗鼓了一些,對計算機的硬件有了那么一些了解。
到大二后,買了一些書開始學(xué)習(xí)當(dāng)時最火的網(wǎng)頁三劍客,學(xué)會了手寫HTML、PS的基本玩法之類的,課余、暑假也能開始給人做做網(wǎng)站什么的(ps: 那個時候做網(wǎng)站真的好賺錢),可能那樣過了個一年左右,做靜態(tài)的網(wǎng)頁就不好賺錢了,也不好找實習(xí)工作,于是就開始學(xué)asp,寫些簡單的CRUD,做做留言板、論壇這些動態(tài)程序,應(yīng)該算是在這個階段接觸編程了。
畢業(yè)后加入了深圳的一家做政府行業(yè)軟件的公司,一個非常靠譜和給我空間的Leader,使得自己在那幾年有了不錯的成長,終于成了一個職業(yè)的程序員,通常來說,業(yè)余或半職業(yè)的程序員,多數(shù)是1個人,或者很小的一個團隊一起開發(fā),使得在開發(fā)流程、協(xié)作工具(例如jira、cvs/svn/git等)、測試上通常會有很大的欠缺,而職業(yè)的程序員在這方面則會專業(yè)很多,另外,通常,職業(yè)的程序員做的系統(tǒng)都要運行較長的時間,所以在可維護性上會特別注意,這點我是在加入阿里后理解更深的,一個運行10年的系統(tǒng),和一個寫來玩玩的系統(tǒng)顯然是有非常大差別的。
這塊自己感覺也很難講清楚,只能說模模糊糊有個這樣的概念,通常在有興趣的基礎(chǔ)上,從業(yè)余程序員跨越到成為職業(yè)程序員我覺得不會太難。
編程能力的成長
作為程序員,最重要的能力始終是編程能力,就我自己的感受而言,我覺得編程能力的成長主要有這么幾個部分。
編程能力初級:會用
編程,首先都是從學(xué)習(xí)編程語言的基本知識學(xué)起的,不論是什么編程語言,有很多共同的基本知識,例如怎么寫第一個Hello World、if/while/for、變量等,因此我比較建議在剛剛開始學(xué)一門編程語言的時候,還是就看看編程語言自己的一些文檔就好,而不要上來就去看一些高階的書,我當(dāng)年學(xué)Java的時候上來就看Think in Java、Effective Java之類的,真心好難懂。
除了看文檔以外,編程是個超級實踐的活,所以一定要多寫代碼,只有這樣才能真正熟練起來,這也是為什么我還是覺得在面試的時候讓面試者手寫代碼是很重要的,這個過程是非常容易判斷寫代碼的熟悉程度的,很多人會說由于寫代碼都是高度依賴IDE的,導(dǎo)致手寫很難,但我絕對相信寫代碼寫了很多的人,手寫一段不是太復(fù)雜的可運行的代碼是不難的,即使像我這種三年多沒寫過代碼的人,讓我現(xiàn)在手寫一段不太復(fù)雜的可運行的Java程序,還是沒問題的,前面N年的寫代碼生涯使得很多東西已經(jīng)深入骨髓了。
我覺得編程能力初級這個階段對于大部分程序員來說都不會是問題,勤學(xué)苦練,是這個階段的核心。
編程能力中級:會查和避免問題
除了初級要掌握的會熟練的使用編程語言去解決問題外,中級我覺得首先是提升查問題的能力。
在寫代碼的過程中,出問題是非常正常的,怎么去有效且高效的排查問題,是程序員群體中通常能感受到的大家在編程能力上最大的差距,解決問題能力強的基本很容易在程序員群體里得到很高的認(rèn)可,在查問題的能力上,首先要掌握的是一些基本的調(diào)試技巧,好用的調(diào)試工具,就像在Java里JDK自帶的jstat、jmap、jinfo,不在JDK里的mat、gperf、btrace等,工欲善其事必先利其器,在查問題上是非常典型的,有些時候大家在查問題時的能力差距,有可能僅僅是因為別人比你多知道一個工具而已,除了調(diào)試技巧和工具外,查問題的更高境界會和編程能力的高級階段有非常大的關(guān)系,就是懂原理,一個懂原理的程序員在查問題的水平上是有明顯差距的,我想很多的同學(xué)應(yīng)該能感受到,有些時候查出問題的原因僅僅是因為有效的工具,知其然不知其所以然,我給很多阿里的同學(xué)培訓(xùn)過Java排查問題的方法,在這個培訓(xùn)里,我經(jīng)常也會講到查問題的能力的培養(yǎng)最主要的也是熟練,多嘗試給自己寫一些會出問題的程序,多積極的看別人是怎么查問題的,多積極的去參與排查問題,很多最后查問題能力強的人多數(shù)僅僅是因為“無他,但手熟爾”。
就像我自己,排查問題能力的提升主要是在2009年和2010年,那兩年作為淘寶消防隊(處理各種問題和故障的虛擬團隊)的成員處理了很多的故障和問題,當(dāng)時消防隊還有阿里最公認(rèn)的技術(shù)大神多隆,向他學(xué)習(xí)到了很多排查問題的技巧,和他比,我排查問題的能力就是初級的那種,我印象最深刻的是有一次我們一起查一個應(yīng)用cpu us高的問題,我們兩定位到是一段代碼在某種輸入?yún)?shù)的時候會造成cpu us高的原因后,我能想到的繼續(xù)查的方法是去生產(chǎn)環(huán)境抓輸入?yún)?shù),然后再用參數(shù)來本地debug看是什么原因,但多隆在看了一會那段代碼后,給了我一個輸入?yún)?shù),我拿這個參數(shù)一運行,果然cpu us很高,哎,而且這種case不是一次兩次,所以我經(jīng)常和別人說,我是需要有問題場景才能排查出問題的,但多隆是完全有可能直接看代碼就能看出問題的,這是本質(zhì)的差距。
除了查問題外,更厲害的程序員是在寫代碼的過程就會很好的去避免問題,大家最容易理解的就是在寫代碼時處理各種異常情況,但這里通常也是程序員們很大的差距的地方,寫一段正向邏輯的代碼,大部分情況下即使有差距,也不會太大,但在怎么很好的處理這個過程中有可能出現(xiàn)的異常上,這個時候的功力差距會非常明顯,很多時候一段代碼里處理異常邏輯的部分都會超過正常邏輯的代碼量,我經(jīng)常說,一個優(yōu)秀程序員和普通程序員的差距,很多時候壓根就不需要看什么滿天飛的架構(gòu)圖,而只用show一小段的代碼就可以,舉一個小case大家感受下,當(dāng)年有一個嚴(yán)重故障,最后查出的原因是輸入的參數(shù)里有一個是數(shù)組,把這個數(shù)組里的值作為參數(shù)去查數(shù)據(jù)庫,結(jié)果前面輸入了一個很大的數(shù)組,導(dǎo)致從數(shù)據(jù)庫查了大量的數(shù)據(jù),內(nèi)存溢出了,很多程序員現(xiàn)在看都會明白對入?yún)?、出參的保護check,但類似這樣的case在我自己排查問題的經(jīng)歷了真的碰到了好多。
在中級這個階段,我會推薦大家盡可能的多刻意的去培養(yǎng)下自己這兩個方面的能力,成為一個能寫出高質(zhì)量代碼、有效排查問題的優(yōu)秀程序員。
編程能力高級:懂高級API和原理
就我自己的經(jīng)歷而言,我是在寫了多年的Java代碼后,才開始真正更細致的學(xué)習(xí)和掌握J(rèn)ava的一些更高級的API,我相信多數(shù)Java程序員也是如此,我算是從2003年開始用Java寫商業(yè)系統(tǒng)的代碼,但直到在2007年加入淘寶后,才開始非常認(rèn)真的學(xué)習(xí)Java的IO通信、并發(fā)這些部分的API,盡管以前也學(xué)過也寫過一些這樣的代碼,但完全就是皮毛,當(dāng)然,這些通常來說有很大部分的原因會是工作的相關(guān)性,多數(shù)的寫業(yè)務(wù)系統(tǒng)的程序員可能基本就不需要用到這些,所以導(dǎo)致會很難懂這些相對高級一些的API,但這些API對真正的理解一門編程語言我覺得至關(guān)重要,在之前的程序員成長路線的文章里我也講到了這個部分,在沒有場景的情況下,只能靠自己去創(chuàng)造場景來學(xué)習(xí)好,我覺得只要有足夠的興趣,這個問題還是不大的,畢竟現(xiàn)在有各種開源,這些是可以非常好的幫助自己創(chuàng)造機會學(xué)習(xí)的,例如學(xué)Java NIO,可以自己基于NIO包一個框架,然后對比Netty,看看哪些寫的是不如Netty的,這樣會非常有助于真正的理解。
在學(xué)習(xí)高級API的過程中,以及排查問題的過程中,我自己越來越明白懂編程語言的運行原理是非常重要的,因此我到了后面的階段開始學(xué)習(xí)Java的編譯機制、內(nèi)存管理、線程機制等,對于我這種非科班出身的而言,學(xué)這些會因為缺乏基礎(chǔ)更難很多,但這些更原理性的東西學(xué)會了后,對自己的編程能力會有質(zhì)的提升,包括以后學(xué)習(xí)其他編程語言的能力,學(xué)這些原理最好的方法我覺得是先看看一些講相關(guān)知識的書,然后去翻看源碼,這樣才能真正的更好的掌握,最后是在以后寫代碼的過程中、查問題的過程中多結(jié)合掌握的原理,才能做到即使在N年后也不會忘。
在編程能力的成長上,我覺得沒什么捷徑,非常贊同1萬小時理論,在中級、高級階段如果有人指點或和優(yōu)秀的程序員們共事,會好非常多,不過我覺得這個和讀書也有點像,到了一定階段后(例如高中),天分會成為最重要的分水嶺,不過就和大部分行業(yè)一樣,大部分的情況下都還沒到拼天分的時候,只需要拼勤奮就好。
系統(tǒng)設(shè)計能力的成長
除了少數(shù)程序員會進入專深的領(lǐng)域,例如Linux Kernel、JVM,其他多數(shù)的程序員除了編程能力的成長外,也會越來越需要在系統(tǒng)設(shè)計能力上成長。
通常一個編程能力不錯的程序員,在一定階段后就會開始承擔(dān)一個模塊的工作,進而承擔(dān)一個子系統(tǒng)、系統(tǒng)、跨多領(lǐng)域的更大系統(tǒng)等。
我自己在工作的第三年開始承擔(dān)一個流程引擎的設(shè)計和實現(xiàn)工作,算是一個不算小的系統(tǒng),并且也是當(dāng)時那個項目里的核心部分,那個階段學(xué)會了一些系統(tǒng)設(shè)計的基本知識,例如需要想清楚整個系統(tǒng)的目標(biāo)、模塊的劃分和職責(zé)、關(guān)鍵的對象設(shè)計等,而不是上來就開始寫代碼,但那個時候由于我是一個人寫整個系統(tǒng),所以其實對設(shè)計的感覺并還沒有那么強力的感覺。
在那之后的幾年也負(fù)責(zé)過一些系統(tǒng),但總體感覺好像在系統(tǒng)設(shè)計上的成長沒那么多,直到在阿里的經(jīng)歷,才敢上自己在系統(tǒng)設(shè)計上有了越來越多的體會(References里有一篇我在系統(tǒng)設(shè)計上犯過的14個錯,可以看到我走的一堆的彎路),在阿里有一次做分享,講到我在系統(tǒng)設(shè)計能力方面的成長,主要是因為三段經(jīng)歷,負(fù)責(zé)專業(yè)領(lǐng)域系統(tǒng)的設(shè)計 -> 負(fù)責(zé)跨專業(yè)領(lǐng)域的專業(yè)系統(tǒng)的設(shè)計 -> 負(fù)責(zé)阿里電商系統(tǒng)架構(gòu)級改造的設(shè)計。
第一段經(jīng)歷,是我負(fù)責(zé)HSF,HSF是一個從0開始打造的系統(tǒng),它主要是作為支撐服務(wù)化的框架,是個非常專業(yè)領(lǐng)域的系統(tǒng),放在整個淘寶電商的大系統(tǒng)來看,其實它就是一個很小的子系統(tǒng),這段經(jīng)歷里讓我最深刻的有三點:
1). 要設(shè)計好這種非常專業(yè)領(lǐng)域的系統(tǒng),專業(yè)的知識深度是非常重要的,我在最早設(shè)計HSF的幾個框的時候,是沒有設(shè)計好服務(wù)消費者/提供者要怎么和現(xiàn)有框架結(jié)合的,在設(shè)計負(fù)載均衡這個部分也反復(fù)了幾次,這個主要是因為自己當(dāng)時對這個領(lǐng)域掌握不深的原因造成的;
2). 太技術(shù)化,在HSF的階段,出于情懷,在有一個版本里投入了非常大的精力去引進OSGi以及去做動態(tài)化,這個后來事實證明是個非常非常錯誤的決定,從這個點我才真正明白在設(shè)計系統(tǒng)時一定要想清楚目標(biāo),而目標(biāo)很重要的是和公司發(fā)展階段結(jié)合;
3). 可持續(xù)性,作為一個要在生產(chǎn)環(huán)境持續(xù)運行很多年的系統(tǒng)而言,怎么樣讓其在未來更可持續(xù)的發(fā)展,這個對設(shè)計階段來說至關(guān)重要,這里最low的例子是最早設(shè)計HSF協(xié)議的時候,協(xié)議頭里竟然沒有版本號,導(dǎo)致后來升級都特別復(fù)雜,最典型的例子是HSF在早期缺乏了缺乏了服務(wù)Tracing這方面的設(shè)計,導(dǎo)致后面發(fā)現(xiàn)了這個地方非常重要后,全部落地花了長達幾年的時間,又例如HSF早期缺乏Filter Chain的設(shè)計,導(dǎo)致很多擴展、定制化做起來非常不方便。
第二段經(jīng)歷,是做T4,T4是基于LXC的阿里的容器,它和HSF的不同是,它其實是一個跨多領(lǐng)域的系統(tǒng),包括了單機上的容器引擎,容器管理系統(tǒng),容器管理系統(tǒng)對外提供API,其他系統(tǒng)或用戶通過這個來管理容器,這個系統(tǒng)發(fā)展過程也是各種犯錯,犯錯的主要原因也是因為領(lǐng)域掌握不深,在做T4的日子里,學(xué)會到的最重要的是怎么去設(shè)計這種跨多個專業(yè)領(lǐng)域的系統(tǒng),怎么更好的劃分模塊的職責(zé),設(shè)計交互邏輯,這段經(jīng)歷對我自己更為重要的意義是我有了做更大一些系統(tǒng)的架構(gòu)的信心。
第三段經(jīng)歷,是做阿里電商的異地多活,這對我來說是真正的去做一個巨大系統(tǒng)的架構(gòu)師,盡管我以前做HSF的時候參與了淘寶電商2.0-3.0的重大技術(shù)改造,但參與和自己主導(dǎo)是有很大區(qū)別的,這個架構(gòu)改造涉及到了阿里電商眾多不同專業(yè)領(lǐng)域的技術(shù)團隊,在這個階段,我學(xué)會的最主要的:
1). 子系統(tǒng)職責(zé)劃分,在這種超大的技術(shù)方案中,很容易出現(xiàn)某些部分的職責(zé)重疊和沖突,這個時候怎么去劃分子系統(tǒng),就非常重要了,作為大架構(gòu)師,這個時候要從團隊的職責(zé)、團隊的可持續(xù)性上去選擇團隊;
2). 大架構(gòu)師最主要的職責(zé)是控制系統(tǒng)風(fēng)險,對于這種超大系統(tǒng),一定是多個專業(yè)領(lǐng)域的架構(gòu)師和大架構(gòu)師共同設(shè)計,怎么確保在執(zhí)行的過程中對于系統(tǒng)而言最重要的風(fēng)險能夠被控制住,這是我真正的理解什么叫系統(tǒng)設(shè)計文檔里設(shè)計原則的部分,設(shè)計原則我自己覺得就是用來確保各個子系統(tǒng)在設(shè)計時都會遵循和考慮的,一定不能是虛的東西,例如在異地多活架構(gòu)里,最重要的是如何控制數(shù)據(jù)風(fēng)險,這個需要在原則里寫上,最基本的原則是可接受系統(tǒng)不可用,但也要保障數(shù)據(jù)一致,而我看過更多的系統(tǒng)設(shè)計里設(shè)計原則只是寫寫的,或者千篇一律的,設(shè)計原則切實的體現(xiàn)了架構(gòu)師對目標(biāo)的理解(例如當(dāng)時異地多活這個其實開始只是個概念,但做到什么程度才叫做到異地多活,這是需要解讀的,也要確保在技術(shù)層面的設(shè)計上是達到了目標(biāo)的),技術(shù)方案層面上的選擇原則,并確保在細節(jié)的設(shè)計方案里有對于設(shè)計原則的承接以及執(zhí)行;
3). 考慮問題的全面性,像異地多活這種大架構(gòu)改造,涉及業(yè)務(wù)層面、各種基礎(chǔ)技術(shù)層面、基礎(chǔ)設(shè)施層面,對于執(zhí)行節(jié)奏的決定要綜合考慮人力投入、機器成本、基礎(chǔ)設(shè)施布局訴求、穩(wěn)定性控制等,這會比只是做一個小的系統(tǒng)的設(shè)計復(fù)雜非常多。
系統(tǒng)設(shè)計能力的成長,我自己覺得最重要的一是先在一兩個技術(shù)領(lǐng)域做到專業(yè),然后盡量擴大自己的知識廣度,例如除了自己的代碼部分外,還應(yīng)該知道具體是怎么部署的,部署到哪去了,部署的環(huán)境具體是怎么樣的,和整個系統(tǒng)的關(guān)系是什么樣的,像我自己,是在加入基礎(chǔ)設(shè)施團隊后才更加明白有些時候軟件上做的一個決策,會導(dǎo)致基礎(chǔ)設(shè)施上巨大的硬件、網(wǎng)絡(luò)或機房的投入,但其實有可能只需要在軟件上做些調(diào)整就可以避免,做做研發(fā)、做做運維可能是比較好的把知識廣度擴大的方法,第二點是練習(xí)自己做tradeoff的能力,這個比較難,做tradeoff這事需要綜合各種因素做選擇,但這也是所有的架構(gòu)師最關(guān)鍵的,可以回頭反思下自己在做各種系統(tǒng)設(shè)計時做出的tradeoff是什么,這個最好是親身經(jīng)歷,聽一些有經(jīng)驗的架構(gòu)師分享他們選擇背后的邏輯也會很有幫助,尤其是如果恰好你也在同樣的挑戰(zhàn)階段,光聽最終的架構(gòu)結(jié)果其實大多數(shù)時候幫助有限。
技術(shù)Leader我覺得最好是能在架構(gòu)師的基礎(chǔ)上,后續(xù)注重成長的方面還是有挺大差別,就不在這篇里寫了,后面再專門來寫一篇。
程序員金字塔
我認(rèn)為程序員的價值關(guān)鍵體現(xiàn)在作品上,被打上作品標(biāo)簽是一種很大的榮幸,作品影響程度的大小我覺得決定了金字塔的層次,所以我會這么去理解程序員的金字塔。
當(dāng)然,要打造一款作品,僅有上面的兩點能力是不夠的,作品里很重要的一點是對業(yè)務(wù)、技術(shù)趨勢的判斷,希望作為程序員的大伙,都能有機會打造一款世界級的作品,去為技術(shù)圈的發(fā)展做出貢獻。
由于目前IT技術(shù)更新速度還是很快的,程序員這個行當(dāng)是特別需要學(xué)習(xí)能力的,我一直認(rèn)為,只有對程序員這個職業(yè)真正的充滿興趣,保持自驅(qū),才有可能在這個職業(yè)上做好,否則的話是很容易淘汰的。
阿里技術(shù)重磅發(fā)布!年度精選集開放下載
《數(shù)字經(jīng)濟下的算法力量:阿里算法年度精選集》電子書,精選數(shù)十篇年度算法頂級干貨,合計300 頁,為你呈現(xiàn)阿里最新的算法實踐案例。