# 作者簡介:
vczh,本名陳梓瀚,因知乎的個人信息介紹上寫有“專業造輪子”,所以江湖人稱“輪子哥”。 vczh大學時代就在微軟實習,畢業後即加入微軟。一開始是在微軟上海,後來進入北京的微軟亞洲研究院。現已移居美國西雅圖,在Office組做工程師。
以前常有人問我,要怎麼樣才可以去微軟。其實我從來沒有想過這個問題,所以那時候的答案自然就是微軟的廣告(程式設計好,數學好,態度好)了。 09 年大四那會兒,剛好碰上了美帝的次貸危機,令我們這些想去美帝的公司被剝削的這群人倍感艱辛。所幸後來還是過五關斬六將,最後在實習結束後成功留了下來。這其中的因果,顯然不是面試的那幾天所能夠決定的,因此還得從 hello world 講起。
# 中學
我有幸從初二開始就學習程式設計。那時世界已經處於一個現代化的程度了,操作系統都有虛擬內存,有圖形界面,有因特網,開發軟體還有集成開發環境可用,跟一些老前輩所描述的編譯一個程序還要換幾次磁盤的日子已經完全不一樣了。
那時正值購買電腦半年,處於看見什麼東西都感到十分好奇的時候,再加上父親那個時候不太同意我玩遊戲,所以我就在想什麼時候也自己做幾個遊戲,就可以光明正大地玩了。所以在聽到汕頭華僑中學開 Visual Basic 5.0 的課的時候,我感到比較興奮。但是其興奮程度比起初一為了上第一堂電腦課興奮過度,騎自行車超速以至於流了一大堆血沒了幾顆牙的那一天,已經可以忽略了。
那時還是 21 世紀的第一年,正處於上網費用巨貴無比、Google 還剛起來沒多久基本沒人知道的時候,學習程式設計要比現在困難很多。當時想尋找什麼知識,因特網基本上是沒什麼期待的,所以我就有了一個沒事去書店的愛好。
沒多久我就找到一本《Visual Studio高級圖形程式設計教學》了。這本書我很喜歡,插畫十分漂亮,還是用 Visual Basic 程式繪製的,更是愛不釋手。可惜內容過於高深,所以後來就有了初三的時候自學學會初步的立體解析幾何,以及高三上課不聽講僅憑自己看數學分析後來還被我看明白了的故事。
中間因為試圖使用程式來繪製許多複雜的圖形和對影像進行各種複雜的變換,於是每當寫程式之前都要在紙上推導長長的公式。如果程式的運行結果不對了,根本無從調試,只好重新推導,藉以希望可以發現公式的幾個 bug 來解釋為什麼會出現錯誤。
從此以後我對符號運算就十分拿手。而且做數學物理作業也好,為了程式推導公式也好,需要計算的東西太多懶得到處尋找廢紙,從而便獲得了心算複雜過程的本領(可惜現在已經喪失了)。這順帶也為我帶來了一個好處,就是高考數學選擇題在發捲後不准動筆的 10 分鐘內就被我全部心算出答案,而且全對了。
圖形程式設計做久了,就想起了當初的理想,於是就搞遊戲去了。那會兒看到了成都金點工作小組開發的《聖劍英雄傳》,點燃了我開發 RPG 的熱情。在經歷了幾次失敗之後,我終於在高二的正月初一那一天完成了《天地傳》的所有編碼工作,沒多久就上傳到了 GameRes 的網站上。
這是我第一個行數過萬的程式。為了順利完成它,我悟到了很多道理,包括為什麼要面向對象,為什麼要劃分模組減少互相依賴。這也成為我後來開發自繪圖式介面和腳本引擎的機會。後來我試著用 OpenGL 做 3D 遊戲,但由於很難找到有共同愛好的美工跟我一起做,便作罷了。但這讓我獲得了很多時間,可以投入在圖形介面和腳本引擎之中去。
後來我就萌發了解釋高階語言的想法。這是我整個程式設計史上的第一個轉捩點。那時候我資料結構只會用鍊錶,而且編譯原理也好,設計模式也好,都沒聽過。那時候去解釋高階語言自然是比較困難的。因此我經過很多天的苦思冥想自己想出了一個如今稱之為一遍編譯(也就是很爛)的方法來把一個簡單的高級語言重新處理成一個簡單的指令集語言,就跟彙編長得差不多。
那時候已經高三了,所以其實也沒多少時間可以投入在程式設計上面,因此做出來的第一個原型是一個簡化後的 Pascal 的解釋器,用 Delphi 開發的。現在想起來,裡面肯定有巨多記憶體洩漏和效能問題,但當時根本不知道這些東西是什麼。在高中畢業之後的三個月無所事事的日子裡,我就重新把這個東西設計了一遍,得到了一個幾十頁的計劃。由於後來沒來得及做完,就印出來帶去了華南理工大學。
# 大學
後來我陸陸續續寫了很多腳本引擎。大一的時候做的 Jove 是第一個我覺得還能見到人的腳本引擎。第二個就是大二失敗了一整年吸取了很多教訓之後,於大三開發出的動態語言,名字叫 Free(可以在我的部落格 http://www.cppblog.com/vczh 找到)。最近正在打算將其更新到 3.0 來配合一個正在開發中的顯示卡加速的 GUI 類別庫 GacUI。接下來就是去微軟上海的 WCFTools 組實習的那一段時間裡面,利用每天晚上的時間完成的一門純函數式語言叫 KernelFP,這後來成為了我的畢業設計。
在提交了畢業設計之後,我又在畢業前的幾個月時間裡完成了 CMinus。這不是編譯原理課程設計上的那個簡單到沒法再簡單的 CMinus,而是一個完整的 C 語言編譯器(其中函數指標的語法被我改掉了,但仍然支援)。其編譯結果是保存到記憶體中的一段X86 二進位程式碼,可以將函數的起始位址強制轉換成函數指標直接在C 程式中使用,這是因為我在產生指令的時候遵守了Visual C 中的一些在MSDN 裡描述得很清楚的約定。
畢業後我又雄心勃勃地做了 NativeX,是一個帶有泛型以及 concept mapping 的 C 語言。前幾個月我又試著山寨 C#,但無奈 C# 實在太複雜,所以轉而去做 GacUI。圖形介面(GUI)類別庫我也寫了不少。繼高中的時候為 RPG 而開發的兩個控制項類別庫之後,在上大學的過程中使用 OpenGL 開發的兩次 GUI 類別庫均告失敗。後來也封裝了一次 Windows 的 API(Vczh GUI),試圖讓其易用性接近 VCL 或 WinForm。
畢業後我又嘗試發了若干次基於渲染的 GUI,換了幾次架構,一直到現在正在開發的 GacUI 才感覺走上了正軌。我在這個過程中得到的一個結論是:Windows Presentation Foundation 的設計實在是太完美了……在做這些東西之餘,我還開發了三次三維物體的軟體渲染程序,前兩個是在畢業前做的,最後一個是一年前因為一下子不知道要如何利用業餘時間來充實生活而開發出來的,目的是用於打發時間。
在這裡我想可以回答一個月前不能好好回答師弟師妹們的一個問題了。如何能夠在微軟找到工作?因為我把我上面做的這些東西都寫進履歷了。同時如果你們到了大四才來問這個,就已經太遲了…
# 值得一提的是,我從大三開始指導一名基礎幾乎是零的、比我低兩個年級的軟體學院的一位學生學習程式設計。為了讓對方在接受我為期3 年的訓練之後有紮實的C 基礎、熟練的單元測試編寫水平以及能夠靠直覺給出一些不算太差的設計,我回顧了許多關於C 的內容,特別是給指針的幾堂課備課了好幾天,每一天都要出一份作業。在這個過程中我深刻的感覺到,如果要快速提高自己的編程水平的話,你必須總是去做一些你做得出來,但是難度大到只要再難一點點你就做不出來的事情。再這麼堅持好些年之後,一定會進入高手的行列。
因此我在安排作業的過程中,有意地推遲了關於指針的內容。首先讓對方接受變數和分支循環,然後要養成一個好的風格(譬如說不能老是用一個字母給變數命名之類),然後學會操作數組,接下來才是關於沒有強制類型轉換的指針的一些操作,並且在一個月之內做出一個帶有單元測試的字串類別。指針的重點是要對方深刻的理解,「指標本身就是一個指向位置的數字」這麼一個概念。為此我特別設計(但沒有實現)了一門只帶有一個全局無限長數組的彙編語言來講述指針背後一些複雜的概念。之後就是一些關於物件導向的知識、設計模式的知識、還有跟腳本引擎有關的一些東西。
該學生的畢業設計是一個簡單的動態語言的腳本引擎,並且該腳本引擎的實現正確地運行了我在上面模仿 Linq 的一個列表處理函數庫。這個實作閉包一層套一層,到處都在為一個物件添加刪除函數,創建各種延遲執行的迭代器,很是能夠考驗一個腳本引擎的實作。對方畢業後被網易招去了,在待遇上給了一些人文關懷。
自己的程式設計歷程不僅包括自己在業餘時間內所做的這些程序,也包括在微軟實習和工作的過程。高中的時候就聽說了華南理工大學有微軟俱樂部的事情,再加上自己對微軟也持有一定的嚮往,因此在入學之後,除了學院的學生會以外,我就一直在密切關注著微軟俱樂部的招新,並且忽略其它所有社團。不過說實話在學生會和微軟俱樂部的工作也純屬打醬油,沒幹過什麼正事兒。
大二的時候微軟搜尋科技中心(STC)來微軟俱樂部收履歷的時候,我在路上碰到了陳健老師,也就是之前提到的班主任,就跟她說了這個事情。後來由於對方說我年紀太小而作罷,因為其它人全部都是研究生。到了大三的時候,陳健老師就跟我提到她可以找老同學幫我投微軟的實習履歷,因此我於 2008 年 3 月接到了微軟上海的電話面試。電話面試有兩次,第一次對方是一位 HR,第二次則是軟體工程師。在第二次電話面試的過程中,我們聊了上面提到的 Free,也針對一些資料結構和框架設計的問題進行了熱情洋溢的討論。沒過幾天,我就收到了面試通知,前往上海閔行區的紫竹數位資訊港面試。那是我人生中第一次的面試。
# 實習
微軟的面試安排精確到秒,這跟某些公司比起來人性化許多,不會動輒浪費別人數小時的時間。實習的面試一共有三輪,對話全部使用英語,儘管裡面只有一個是外國人。我還依稀記得被那個年輕的老外面試的時候由於過於緊張,而導致一道簡單的問題沒有給出最優解的事情。不過他們最後還是讓我進入微軟位於上海的一個 WCF Tools 小組實習。
這個小組有一位讓我十分尊敬的軟體開發主管葛子昂先生。葛先生是一位熱愛敏捷並且經常投身於實踐中的人。他在我長達 4.5 個月的實習過程中,教給了我很多軟體工程上的東西,而其中最重要的、讓我受益匪淺的則是關於單元測試的內容。
除此之外,我還體驗了快速迭代、Scrum 會議、結對程式設計以及基於原始碼版本管理系統(我們使用的是 TFS)進行多人協作開發的流程。在經歷了為TechEd 大會修改PetShop 製作WCF的Demo、為Visual Studio 2010 的WCF 開發工具修bug 和開發一個具有高度可擴展性的配置文件編輯器之後,我於2008 年12 月結束了在微軟的實習。經過了這次實習,我對原始碼的掌控能力也得到了提高,並且直接體現在我利用業餘時間開發的專案的程式碼品質上。
# 轉正
在實習結束之前,我獲得了一次面試全職員工(FTE)的機會。當時形勢十分嚴峻。 2008 年美國的次貸危機於 10 月正式影響微軟上海,公司在那一段時間決定減少全職員工的招募數量。而我是 11 月進行轉正的面試,結果這件事令我十分緊張。後來葛先生表示他的個人建議是希望我畢業後留下來繼續工作,讓我吃了一顆定心丸。
實習生轉全職員工的面試一共有五輪。其中令我印象非常深刻的是有一輪的面試官問了我很多非常複雜的問題,最後還考了我一道關於線索二叉樹在線更新的問題,不過我已經記不清楚具體是什麼內容了。我只記得我花了很長時間終於想到了一個正確的演算法之後,時間就結束了,根本來不及在白板上寫程式碼。後來我終於通過了面試,少數的幾個名額裡面終於被我拿走了一個。不過聽說幾個月後限制開始放寬,沒有我面試的時候那麼困難了。
在實習和麵試的過程中,我覺得華南理工大學軟體學院開設的許多課程其實都是十分有用的,特別是關於資料結構、設計模式和軟體測驗的內容。這些都是在工作中十分有用的知識,也需要在未來的工作中持續累積這些東西的經驗。只不過因為學院學生人數眾多,而一個新的學院總是免不了缺乏一些師資力量,所以我有很多同學都表示很難體會到課本中所提到內容的作用。想必如今應該比我們那幾年要改善許多了。
# Microsoft SQL Server
# 面試結束到獲得 offer 中間隔了幾十天,最後HR的通知在除夕的那一天終於到來了。之後的半年時間我就在學校裡面繼續做自己的事情,偶爾參加幾個活動介紹經驗等等,還有就是跟一些人出去遊玩。畢業後動身前往上海微軟。中間發生了一些事情,因為名額變動的問題,我雖然拿的是WCF Tools的offer,但是最後卻被安排到SQL Server組,在此之前我並沒有收到通知。由於我比較不喜歡資料庫,對SQL Server了解很淺,所以我做了一年半的SQL Server Management Studio(也就是傳說中的「介面」)的開發。在這段期間我跟同事們傳播了一些關於單元測試、介面開發、設計模式、Linq和語法分析器的知識。
這一年半的經驗讓我成長了許多,主要是比起實習,正式工作的時候總是免不了經常要跟別的團隊、公司、民族、國家和物種進行熱情洋溢的廣泛交流,而且還佔用了不少的時間。有些時候還要坐飛機前往美帝,感受社會主義的優越性。正式軟體的介面部分十分複雜,不僅要在作業系統的DPI 變動以及在地化(大部分內容是把介面上的文字翻譯成別的語言)的過程中介面的版面需要自動調整,以便不讓一些文字或者按鈕只顯示一半,還要照顧各式各樣的殘疾人(特別是失去視力的人群),並且對於某些自繪的複雜內容還要提供一些運行時的接口,使得自動測試團隊可以完成他們的工作。
#這個經驗讓我感受到了發展嚴謹的介面是多麼不容易。另一個感受是關於需求變更的。設計模式的存在就是為了抵禦需求變更,這個真理我直到工作之後才能明白。你必須把一個軟體的架構設計得如此之好,才能在需求大規模變更之後,還能在整體上讓你的程式碼是漂亮的、易於修改的、高效能的、而且是安全的。每一次改動都不能是打補丁,你總是需要重構來使得你的程式碼在任何一刻都在整體上是好的。為了達到這個目標,就需要熟練並使用設計模式來開發專案。
微軟的跟別的公司比起來罕有一個好處就是他會給你很多時間,讓你慢慢把軟體做好。而這個好的定義,當然是以功能和可維護性為重點。倘若一段程式碼以非常精妙的方法來高速完成一個任務,但是卻複雜到哪怕寫遍了註釋也不能讓後續維護的人看懂的話,那這段程式碼是沒有實用價值的。一段好的程式碼,不在於它的設計有多麼巧妙,不在於它的演算法有多麼高深,而在於它可以被幾千個人同時開發10 年,並且在持續添加功能的過程中,不會因為過於混亂而導致出現了重寫的需要。
# 後來我因為一些原因申請了到微軟亞洲研究院(MSRA)的人事調動。 2011年1月份我在獲得了經理的批准之後,從上海前往北京參加研究院的面試。這次面試仍然有五輪。這次面試很難,其中一個面試官因為在我的履歷上發現了很多跟編譯器有關的東西之後,決定讓我實作一個 strncpy 函數,要求是 CPU 對記憶體的存取次數要最少。這包含了許多諸如頻寬、對齊和二進位位元組位移操作等各種問題。方法本身就已經很繁瑣,再加上紙上寫程式總是免不了要犯錯誤,所以我還是沒有時間把整個程式寫完。另一個面試官老外在年輕的時候也做過一些編譯器的事情,讓我出乎意料的是他在面試的過程中沒有跟我出題目,反而就編譯器的各種算法和問題聊了整整一個小時,基本上我會的知識全部都因為要回答問題而說了出來。之後我跟這個人產生了深厚的友誼。
不久之後我就獲得了調動的批准。在做了一些包括給上海的SQL Server團隊建立單元測試標準之類的收尾工作之後,我於2011年的4月份前往北京,正式成為微軟亞洲研究院的一員,做一些跟分散式系統相關的研究。
# Microsoft Research Asia
在研究院的這幾年,其實除了增長了一些技術上的見識,和學會瞭如何成為一個老油條以外,技術上主要的成長仍然來自自己開發的 項目。研究院的結構是非常適合我這種喜歡把玩複雜(但不一定是新)技術程式設計師的。而且我在研究院的直屬老闆還是鄒欣,讓我深刻的明白了一位好的領導是多麼的重要。
已經寫了四年半了。寫 GacUI 的初衷是,想為自己的語言做 IDE,但只有 C 寫parser才寫的爽,之前又試驗過 C# 寫 UI,C 寫智能提示演算法的專案。
後來我乾脆就想,要是整個都能用 C 寫多好。但 C 的 GUI 函式庫對 MVVM 的支援都是垃圾,於是就有了 GacUI。但是做一個 GUI 庫工作量實在有點大,我又追求要有好的開發體驗,因此就做了這麼久。今年應該可以出 1.0 了…
# 透過開發 GacUI,不僅理順了之前那麼多年做的 7 個天國的 GUI 庫的經驗教訓,還學會瞭如何最小代價開發跨平台的客戶端程式。其實寫一個跨平台的程式一點都不難,不知道為什麼網路上有那麼多人搞的雞飛狗跳。 GacUI 帶給我的另一個好處是,基本上全部複習了一遍設計模式的內容,而且由於體積龐大,我還弄了一個專門在不同git repo 之間實現偏序依賴的小工具——用來把一整個repo 下的C 程式碼打包成兩個文件,以便於其它repo直接使用。本來想試試 submodule 的,無奈 submodule 只能實現樹狀依賴,實在太爛。
GacUI 最後也複習了之前學過的編譯原理的內容。因為 GacUI 在編譯 XML 的過程中,實際上是把所有的東西都翻譯成了一個腳本引擎的字節碼,最後要么直接運行這個腳本,要么把腳本翻譯成 C (正在開發)。因此為了實現這一點,寫一個編譯器在所難免,而且編譯出來的東西還要能跟C 那邊的類相互溝通,從而又復習了一遍COM 的內容(儘管我並沒有使用它,我只是嘗試做了一個一樣的東西)。
等 C 生成搞定之後,我就要繼續寫去年就開始的 GacJS了,把 GacUI 搬上瀏覽器,全方位運行我的 IDE。適合使用 C 的那些領域真是博大精深啊。
# 出國
# 我不得不說,當初由於不喜歡資料庫所以跳槽到了研究院,結果研究院看我是從 SQL Server來的,弄了很多資料庫的東西給我做。後來我找了老闆說能不能弄點別的啊?老闆問我那你想做什麼,我說要弄點編譯器的東西試試看?於是老闆後來安排我給另一幫研究院,替他們做一個分散式圖資料庫的 query language。不過這種東西本來就是超簡單的,很快弄完之後,我又變成做資料庫的了。於是這讓我明白了一個道理,多半研究院是沒有我喜歡的東西的了。
於是又過了一些年,由於我對北京(主要)和研究院(次要)的不慢逐漸增加,於是我趕緊弄了個老婆之後,就觸過了。其實跟普通的面試是一樣的:
1.找到你想要去的群組
#2.聯絡他的老闆,把履歷給他
3.看他是否因為經濟危機或收購案件什麼的,正在裁員或無法招人
4.然後面試
5.拿offer(這是肯定的)
6.辦簽證
這個過程讓我不由得感嘆,美帝的面試官就是沒有見過世面啊。競爭壓力太小了,搞出來的題目都超級容易,得讓他們來中國呆一呆,面一面,不然美帝遲早藥丸。不過我覺得另一個方面是,我給 Office 做跨平台 GUI 的那個組看了一下我做的 GacUI,估計他們覺得還不錯吧,就隨便麵了一下我,這也是有可能的。
這裡不得不提到微軟照顧員工真是無微不至,不僅幫我提供優質的搬家服務,在我到了美帝之後還給我安排了一位大媽,負責幫我融入現代社會。還說如果我覺得自己屌不需要這些東西,就給我兩萬刀。這些就算在谷歌,也只有被公司強行安排到美帝(而不是員工自己想出國)的那些人才有。最重要的是,微軟員工買 BMW 還能打折,真開心。
雖然牛逼的人在中國和美帝拿的工資並沒有太大差距,但是撇去美帝的IT地區跟北上廣相似的房價以外,美帝除了汽車和電器的其他東西貴得一逼啊,總體來講幸福感還是下降了。不過幸好中國IT發達地區空氣污染太嚴重,不僅抵銷了這個缺點,反而讓我覺得窮一點過得更爽了。於是自從翻了牆,每天就過著再也沒空把玩電子產品的日子,有空就開車,沒空就上班,爽的不行。
果然站在風口豬都會飛啊。明明其它行業的工資中國比美帝低那麼多,但是程式設計師居然只有1-3 倍的差距。果然中國還是需要大量的、專門訓練來添補社會主義發展過程中的缺口的、專業的程式設計師的。
# Microsoft Office
這次跳槽剛好遇到了微軟要開除諾基亞的人,搞到大部分的組都凍結名額了,只有財大氣粗的Office能招人,因此我也就只能來Office了。原本我的目標是想給Edge弄JS引擎,或是去VS組搞搞編譯器什麼的,無奈他們都太窮了,只好作罷。
在Office的工作讓我大開眼界,算是體驗了一把一萬個人寫了三十年的、一個repo的snapshot就有幾百G代碼的軟體是怎麼弄出來的。由於機器實在太貴,所以平常修改程式碼的時候,只能在本機編譯,因此我們基於msbuild弄出來的這套CI,還包含瞭如果需要連結的lib/dll的程式碼在硬碟裡面沒有的話,就去伺服器找目前checkpoint的編譯好的緩存,下載下來編譯的功能。因此偶爾build farm掛掉的那幾天,由於網路連線斷了,本機編譯也沒辦法弄。
# 尾聲
回顧自己的程式設計之路,學生時期大概就是從一開始寫遊戲,到寫遊戲引擎,到專門搞遊戲引擎需要的圖形、GUI 庫和腳本引擎,最終由於精力的關係生下了GUI 庫和編譯器。我從一開始設計腳本引擎的時候就很注意腳本如何暫停的問題——其實基本就是源自於遊戲的需要——於是人肉做了 coroutine 的各種奇怪的實現方式。到了最後終於學習到了正統的方法,於是本來可以很簡單的完成的問題,由於後來需求就是複雜了那麼一丁點(說白了就是要讓腳本也可以customize(或者說hack)coroutine 相關的類型系統的一部分內容),導致了需要用無限複雜的方法來實現coroutine。人類為什麼要互相傷害?
到了工作,基本上就是
1.本來衝著去弄Visual Studio 的,而且學生時期還不喜歡SQL,結果工作的時候由於經濟危機的關係給我弄到SQL 去了,工作的內容包含了學習專業的資料庫知識和拖控件。
2.但我做了幾年還是覺得不喜歡SQL,就跳槽到了MSRA,結果MSRA 拼命讓我搞資料庫的東西。也不想本來我就是不喜歡弄這個才走的…##
#3.後來我想好吧,反正編譯器沒搞了,那我還是拖控制吧。於是我就告訴Office的人說,你看我做 GacUI 多屌不屌! Office 的人說,屌!於是把我招了進來,專門負責組裡面不是 GUI 的那部分。
4.過了半年老闆開始安排工作了,我想了個辦法表達了一下我還是喜歡弄別的東西。於是終於做了老本行——給Office的程式設計師開發內部的編譯器了。
總算最後還是做了喜歡的工作。
以上是傳奇程式設計師知乎輪子哥,看完我跪了的詳細內容。更多資訊請關注PHP中文網其他相關文章!