一晃做程式設計師也有十年了,總覺得時間過的很快,彷彿第一次寫程式還是去年的事情。雖然到現在也已經換了三四家公司了,但總有種自己沒有做過什麼的感覺。於是便想把個人的經歷寫下來,留給以後的自己作為個回憶。
大學時代
我原本並沒有想過學計算機。在高中時我搞過化學競賽,2005年考大學時填的志願也和計算機無關,然而機緣巧合,我的分數只能服從專業調劑分配,誤打誤撞進入了計算機專業,屬於沒有任何程式設計基礎的”普通學生“。在大學的時候一直仰望著各種資訊學競賽大神,在被碾壓中渡過了四年本科時光。大一大二的時候對於程式設計是覺得既新奇又畏懼,常常在語法上被困擾半天,又或是為了一個邊界條件而除錯半個小時,演算法也一直是我的短板,只到現在還是會對演算法面試有一種天生的緊張。如果說在本科的大學時光中有什麼事情是我對於寫程式這件事情產生熱愛,那便是大三時選修的一門《基於Visual C++的MFC程式設計》。MFC技術已經作古多年,知道這個名詞的程式設計師估計也都年紀不小。雖然這門課程上學到的知識在後來的工作中並沒有用到,但是第一次寫出在Windows上可以執行的非常簡單的介面程式,那種成就感,比大一大二抄書本除錯出來的遞迴程式要高的多,這門小技術也讓我在大三大四的許多大作業上沾了些光:畢竟助教比起在命令列執行的指令,更喜歡滑鼠點點就可以出來的介面。自此我便在單機圖形介面程式上興趣大增,大四的時候用C#寫WinForm的程式作為軟體工程課的大作業,和大部分其他用Java寫出的介面”劃清界限。
移動應用工程師
學生時代寫程式並不能作為”程式設計師“的經歷,我真正的成為一名程式設計師要從大四開始說起。大四的時候保研結束,有些空閒的時間,想著找一些事情做做。機緣巧合認識了一個大很多屆的師兄,自己開了一個公司做智慧手機應用。那是2009年,現在二分天下的蘋果和安卓的代表手機還是iPhone 2G和HTC G1,系統的版本是iPhone OS 2和Android 1.5. 我進公司實習的第一個應用是把一個在iPhone上的工具類程式移植到Android上。當年的Google還可以訪問,但是Android的程式碼示例也幾乎只有官方的Demo,公司裡也並沒有沒有別的會寫Android程式的程式設計師。正是在這樣一抹黑的情況下,我邁出了移動開發的第一步。當時每天去公司就是把一臺G1連上膝上型電腦,改兩行程式碼後花上半分鐘執行一下,看看效果,不行再改兩行再試。效率非常的低下。功夫不負有心人,做了三個月之後程式終於上線了。雖然反響也並不好,沒有達到iPhone上的營收效果,沒多久就從Market上撤下來了;但不管怎麼說,也是我第一次寫的產品程式碼,我在程式設計師的道路上邁出了第一步。
09年畢業後上了研究生,研究的專案也正好是基於Android的,期間做過Android系統程式的修改,包括修改Java程式碼和底層的C程式碼,現在看來都很簡單粗糙,完全不值一提。但是最寶貴的可能就是讀了大部分Android的框架程式碼,雖然現在已經面目全非,但是在以後的工作中看再大的程式碼庫也不會覺得無力。
研究生期間”不務正業“又輾轉做了幾個公司的intern,當時為了能兼顧實驗室和intern,特意都選擇了可以remote的實習。其中包括兩家在美國的公司。在這兩家公司最大的收穫便是鍛鍊了英語讀寫說的能力,從一開始面試的時候連名詞都聽不明白,到後來可以和老外侃侃而談,在這裡邁出的第一步很關鍵。另一個收穫就是除了Android之外,又接觸了iOS的程式設計(當時還叫iPhone OS),學習了一門叫Objective C的語言,以至於很長一段時間在Java和Objective C之前切換的時候會不自覺的打出括號和點的組合。
整個研究生期間我的技能點幾乎都點在了移動開發上,關注各種安卓蘋果作業系統的新功能,也會藉著職務的便利去玩一些新的機型硬體。加之那幾年移動應用的發展迅速,市場是對於移動應用開發者還有很大的需求,於是自己對自己的定位為一名移動應用開發者,並將至作為自己畢業後找工作的方向。
2012年7月研究生畢業,在年初的時候我開始了找工作,由於實驗室的背景關係好多師兄畢業後都選擇去了國外大公司工作,於是我也在期待著可以步師兄們的後塵。無奈自己的硬實力不夠,沒有能夠通過國外大廠的面試。在國內的找工作也並沒有非常好的進行,大公司並沒有很多移動開發者的職位,待遇比較不錯的職位投遞了簡歷卻並沒有得到回應。在機緣巧合之下,有幾家日本的IT公司來到中國招聘畢業生,我參加了其中一家公司的招聘會並順利的通過了面試,來到了日本東京開始了自己的程式設計師生涯。
我的正式職業生涯的第一家公司(暫且稱之為D社),在當時是一家移動手機遊戲為主體運營業務的公司,在當年憑藉著功能機上的遊戲地位站在日本手遊界的Top2位置。D社雖然其收購了美國的一家公司在舊金山也有分部,並且也連續幾年在海外招聘了一些外國的畢業生程式設計師,但是本質上還是一個比較偏傳統的日式IT公司。
D社對於新加入公司的畢業生程式設計師的培訓不得不說還是做的比較到位,首先對於海外招聘的畢業生,提供了日語的全日制培訓以及之後正式入崗後的日語追加培訓。其次,在正式分配部門之前,有為期兩個月的技能培訓。技能培訓的內容是將公司內的Perl框架簡化後讓大家進行一個類似於填補作業的專案,並全程有老師指導,每階段需要提交程式碼並且答辯。答辯不通過的話需要再等兩天後才可以預約下一次答辯。現在看來過於嚴苛和形式主義,但是在以後的工作中,越來越體會到新人培訓的重要性,因為在之後的公司從沒有過這樣細緻到“手把手”式的培訓。
我自己覺得受益比較深的幾點:
- 對於每一句寫下的程式碼,老師會問為什麼這麼寫,有沒有別的寫法,各種寫法有什麼不同?會細扣到程式碼的順序,變數名的命名,註釋的語法等等。實際上這是非常細緻的程式碼審查(Code Review)流程,大部分新人程式設計師著眼於如何快速的實現功能,有時會不假思索的借鑑來程式碼,而我之後供職的公司並沒有這樣的培訓,大多數的程式碼審查也只是停留在錯誤檢查和效能上。個人覺得在一開始寫程式時養成良好的習慣非常重要,尤其是對於剛脫離校園環境的程式設計師。
- 老師也教會了很多工具的使用,比如vim,git,bash等基本操作,比如用bash完成對Apache log的簡單統計分析等等。這個其實是程式設計師的提高生產效率的方法,在之後的公司中遇到太多的新人進入公司好幾個月還在git提交上遇到各種困難。或者不得不耗費體力做一些簡單指令碼可以解決的問題。比起教會的知識,更重要的收穫是萬事都可以指令碼化的信念,不會因為自己的本職工作不包括寫指令碼而對於指令碼就打退堂鼓。
在D社的培訓結束後加入了一個臨時的崗位,做了三個月的Perl的網站開發,之後又調去了別的部門操刀舊業,維護公司的門戶App,說實話門戶App的技術含量真心不高,就是WebView封裝出來的。期間做了唯一一件有些技術含量的事情是把App內的聊天功能加上了推送功能。在客戶端啟動時,在伺服器端註冊客戶端的推送口令,在客戶端的網頁裡通過api來通知伺服器把訊息放進佇列,伺服器端有定時任務去消化佇列中的訊息。 這其實是一個非常普通的小系統,也比較成熟,對於個人來說主要的作用就是獨立設計並且完成了一個完整的系統,並且在生產環境中實際的執行起來。
在D社的日子沒有持續很長時間,最後在公司的半年被調任到遊戲部門,做了一款基於Unity2D的手遊,雖只有短短的四個月經歷,但是也可成為是個人職業生涯中出品的第一款遊戲,它是一款抄襲了FlappyBird的山寨遊戲,在製作的過程中重溫了一回用C#,順便熟悉了一下Unity2D開發環境。
反思一下自己在D社的1年半,在職場的第一份工作並沒有能夠很好的積累。而只是停留在完成佈置的任務階段,並沒有去主動的學習。
後端程式設計師
在D社待了一年半之後跳槽到了I社,I社是一家在美國以工作搜尋引擎為主體業務的公司,被日本R社收購後在日本開張了辦公室。加入I社的時候辦公室只有二十名不到的程式設計師,等到離職的時候已經超過兩百人,可以說見證了I社在東京辦公室的快速發展時期。
在I社的前三年我一直在SEM組工作,SEM(Search Engine Marketing)組的主要任務是自動的將公司投放在搜尋引擎上的廣告優化。這是一個純後端的組,以前的工作經驗在這裡並沒可以發揮的地方。我的工作內容,從一開始去開發維護一個基於Python的內部工具網站(後來知道老闆看我的簡歷是做App的,誤以為我是前段能手),三個月之後Python工具網站的開發告一段落,開始接觸競價演算法(Java後臺程式)。當時正適逢移動流量開始漸漸追趕並超過個人電腦的流量,針對移動端廣告進行競價調整(Bidding Adjustment)是一個重要的功能。正是在進行這一工作的時候,我有機會去主導從MySQL切換到RabbitMQ的解決方案,解耦合演算法端和API端的緊密聯絡。並且通過和系統工程師的配合,解決了首次部署RabbitMQ中遇到的問題,並設定了警報規則去監視系統的執行健康狀況。在切換的過程中,為了保證無故障的切換,先後採用了試執行(Dry Run)的方式模擬從MySQL切換到RabbitMQ的場景,接著運用了A/B test的工具分出少量流量測試RabbitMQ流程的穩定性,最後達到100%切換後進行程式碼的清理。在這個專案中我學到了很多寶貴的經驗,對於以後進行的一些重構式工程有很重要的方法論上的參照意義。
在SEM組的工作使我從一個入門的初級程式設計師,成長到可以去帶新人的mentor,除了做每個季度組裡的季度目標意外,我也參與到全公司的推進的專案中。比如JDK從1.6升級到1.7,從舊的部署系統遷移到新的部署系統,啟用CI/CD模型等等,在做這些專案的同時,自己接觸到了在平常的開發過程中不會遇到的問題,比如如何解決庫中的class衝突,CI/CD模型適用/不適用的情況等等。
於此同時,自己也不滿足於只是去做分配下來的任務,開始觀察並思索作為工程師的痛點。比如,每次上游的一些庫會莫名其妙的改變一些公有介面,導致下游的專案構建收到影響,結果給下游專案的開發人員帶來了額外的負擔。另一方面,上游庫的開發者要想改變刪除過期的介面讓下游專案遷移到新的介面,又苦於在公司內部喊嗓子得不到有效的回應,下游專案的工程師沒有動力去及時的跟進改變,導致過期介面的刪除遲遲不能進行。在這種情況下,如何可以減少不必要的公有介面修改,同時又能提高必要公共介面修改的曝光性?在研究了公司的構建系統之後,我決定在構建系統上,利用一些開源工具和Java編譯外掛的技術,實現了兩個小功能:1. 在釋出庫的新版本是總是和最後一箇舊版本比較API的修改,如果有任何公有介面的修改或缺失則給出警報。2. 提供編譯期的註解(Annotation),讓程式設計師可以對公有介面(類)設定過期時間,在過期時間到來之時下游的專案如果有引用則會出發構建失敗。這兩個功能我是一前一後做出來並在公司內部發布,但是風評卻是前一個平平偏向負面,後一個得到不少的點贊和使用,但也引起了不少麻煩。然而由於當時急功近利的心裡,並沒有很好的去follow。
I社是我從一名初級程式設計師向著高階程式設計師成長,隨著在公司的時間增長,手頭的工作也很快不能夠滿足自己的興趣,在SEM組待了將近三年之後我的經理建議我換組,在經歷了一番掙扎後我選擇了去一個有前段以及順帶一些移動應用的組,在這裡我又重操了一段做移動端應用的經歷,並且又學習了一些前段方面的知識。
在I社待了3年半的時間,當公司越來越大之後,時常會感到個人的貢獻越來越有限,感覺個人的成長也在逐步的緩慢。在對比了其他同事的晉升道路後,彷彿看到了自己在N年後的場景。但是之前覺得在日本沒有比I社更適合自己的公司了,於是也一直沒有去尋求新的機會。去年隨著幾位前同事的離職,自己也開始認真的考慮換工作的事情。
恰逢也同樣是美國總部的H社在東京開始招全棧程式設計師,雖然同樣是美國公司,但是H社還尚未上市,團隊也較小,所以抱著去施展一番拳腳的想法去面試了H社全棧工程師的職位,並於去年7月加入了H社公司。
全棧程式設計師
加入H社後首先感到的很大的Gap,便是在公司的技術上。在I社,我所碰到的領域都已經有了成熟的解決方案。但是在H社,跟I社所對應的一系列基礎設施建設卻遠遠稱不上完善。這讓我進入公司之後很是懷疑了自己的選擇。在進入公司的前兩個月,我經常會發信給全公司的程式設計師,去探討為什麼我們要這麼做而不是那麼做。並且也提交了很多改進方案,希望可以改成我在I社所接觸到的方案。當然這些都並不是很順利,在H社的老人們給了非常強力的反擊。在拿不出充分證據論證的情況下,我只好選擇了暫時蟄居,先處理好眼下自己手頭的工作。
加入H社後的首個專案是將一個年頭已久的PHP前段+後端網頁改成PHP + Apache Thrift + GraphQL + NodeJS +React的新框架,作為全棧(Full Stack)工程師,我需要從PHP到React頭到尾都做一遍。首先便是讀原來的PHP程式碼,並抽象成Thrift服務。其次便是在NodeJS伺服器端將Thrift服務對映成GraphQL的Schema,並實現GraphQL的Resolver邏輯,然後便是用一個Node應用代替PHP的前段,用React的框架來渲染出一模一樣的網頁。在短短的幾個月內,從一竅不通的React小白,到完成了整個頁面的遷移,自己對於React框架的應用和一些實踐有了自己的理解。GraphQL也是一個對我新鮮的概念,在GraphQL的實踐中,我感到這個框架其實也很適用於我在I社工作的第二個組,甚至可以在腦海中把原來的API用GraphQL一一對應起來。這種相互印證的感覺讓我再次意識到做出換工作的決定並沒有錯誤,否則我的思路會很長時間侷限在I社的框架中。
在加入H社的三個月之後我相通了這樣的道理:一個什麼都做的很完美的公司,或許更不是一個什麼都不完美的公司,因為前者讓人失去了去改進的機會,而後者卻給予了很多這樣的機會。於是,我便在工作中,擠出一部分精力去做一些力所能及的改變。首先便從使用的GraphQL入手,通過除錯發現存在著過度查詢(Over fetching)的情況,某些查詢代價較大的欄位,明明沒有出現在查詢語句中,但是後臺卻仍然將其返回。於是我通過標註(Annotation),在Resolver層面講欄位和Thrift服務的引數進行對映,使得GraphQL被翻譯程式Thrift請求時可以自動的附上請求欄位的列表,在伺服器端根據欄位的列表可以選擇性的返回欄位,達到“減負”的目的。
春節期間利用閒暇時間,把公司的A/B測試系統進行了優化,這個優化也是我剛進入H社時最想改變的一點,然而遭到很多質疑的點,於是我在進公司提出的propse基礎上做了退讓,專注於解決最基本的痛點,加入了基於不同域名實行不同的分配(Bucketing)。在於現行系統並存的情況下一步一步的將功能釋出了出來,在公司內獲得了好評。
下一個十年
從2009年第一次實習經歷算起,一眨眼我已經做了十年的程式設計師。我也過了而立之年,眼看著行業裡自己已經算年齡偏大的從業人員。
縱觀我的程式設計師經歷,從移動應用開發,到後端、前段,以及零星的DevOps和Release Engineering的經驗,我覺的我自己是朝著“全才”的方向發展。然而全才意味著什麼都懂一些,但是又說不上是哪個領域的專家。
近兩年來在各種媒體上看到大齡程式設計師的囧境,時常會思考自己的以後的方向。我時常仍會關注國內程式設計師招崗的要求,發現大多數崗位還是需要領域專家的人才,而不是全才。我也時常會質疑自己,是否太過貪多嚼不爛。然而我最近似乎想通了一點,領域專家vs全才,兩種人在這個行業都是被需要的,只是一般的崗位確實會需要你只會幹某一樣便可以。這並不意味著會的越多就沒有施展的地方,在初期的創業公司,以及新成立的部門,這樣的人才還是很有必要的。既然自己的興趣在於瞭解和挑戰不同的領域,不如索性就將其發展到極致。
下一個十年,我想我任會熱愛程式設計師這個工作,我在現在的崗位上,便朝著填補我技能樹上的空白努力,爭取在下一份工作,可以將自己全部的所學都能夠用上。