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

當然,要打造一款作品,僅有上面的兩點能力是不夠的,作品裡很重要的一點是對業務、技術趨勢的判斷。
希望作為程式員的大夥,都能有機會打造一款世界級的作品,去為技術圈的發展做出貢獻。
由于目前IT技術更新速度還是很快的,程式員這個行當是特别需要學習能力的。我一直認為,隻有對程式員這個職業真正的充滿興趣,保持自驅,才有可能在這個職業上做好,否則的話是很容易淘汰的。
作者簡介:
畢玄,2007年加入阿裡,十多年來主要從事在軟體基礎設施領域,先後負責阿裡的服務架構、Hbase、Sigma、異地多活等重大的基礎技術産品和整體架構改造。