程序員,拒絕無聊的代碼面試!

要判斷一個人是不是優秀的程序員,不一定非要看他的代碼。


程序員,拒絕無聊的代碼面試!


過去十多年裡,我面試了許多工程師。在那段時間裡,我總結了一系列的方法,可以在不看代碼的情況下快速準確地評價一名開發人員。

而我現在認為,這些方法不僅可行,而且客觀上比代碼面試更好。

什麼是“代碼面試”?

“代碼面試”指所有直接測試候選人的技能,或審查他們編寫的代碼或偽代碼的方法。這些方法包括:

審查代碼片段,或GitHub的個人頁面;

編程測試(Codility等);

編程挑戰,或在個人時間裡自由完成的題目;

現場編程,或結對編程;

在白板上實現算法。

關注我:私信回覆“666”獲取往期Java高級架構資料、源碼、筆記、視頻、Dubbo、Redis、Netty、zookeeper、Spring cloud、分佈式、高併發等架構技術

代碼面試的目的

這些方法的出現絕非偶然,而是為了取代那些更差的面試手段,比如:

腦筋急轉彎:一架波音747中能裝多少個網球?

咬文嚼字:Java中接口和子類的區別是什麼?

白板編程:至少在這些中不是最差的......

發現式測試:“怎樣檢測鏈表中是否存在環?”

我們認為,這一切都是非常愚蠢的面試手段,因為它們無法反映軟件開發者在日常工作中所需的技能。因此,我們在面試過程中,試圖通過代碼面試重現日常的工作。

然而問題在於:這種方法也根本不管用。因為真相是:代碼面試根本不能重現真實的工作。當然,代碼面試能讓候選人展示工作所需的部分技能——但代碼面試的環境和真正的工作環境完全不同。

代碼面試的問題

代碼面試能減少候選人的數量,但也能拒絕真正優秀的候選人,還能對差的候選人做出虛假的判斷。

代碼測試會佔用面試者和候選人雙方大量的時間。如果能產生效果,也許前者還可以接受,但後者會導致很難在買方市場上尋找到好的工程師。

由於隨時更新代碼測試題很困難,結果就導致面試體驗很差。如果候選人對現有的工作滿意,那麼他們根本不會做你的代碼測試題。這些題目也會增加面試的時間,從而延長整個僱傭過程。但這一切都不能增加候選人的數量。

更重要的是,代碼面試並不能很好地模擬真實工作。

Google的研究發現,優秀的團隊都擁有一項特質,叫做“心理安全”(https://rework.withgoogle.com/blog/five-keys-to-a-successful-google-team/)。只有當團隊的所有人都願意承擔風險、願意身處弱勢時,團隊才能達到最佳狀態。

這跟代碼面試完全不一樣。候選人通常會感到焦躁、感到壓力,擔心一個小錯誤就會丟失這份工作。因此你沒辦法獲得候選人的最佳狀態。

更糟糕的是,這些題目會刷掉那些沒有太多自由時間的候選人。通過這些題目只會讓你篩選出那些有空閒時間的人。因此你的候選人會更年輕、更沒有經驗。你還會錯過一些其他人,如未婚父母或需要照顧家中病人的人。

有更好的辦法嗎?

雖說忠言逆耳,但是你必須去和你的候選人談話。你需要去了解他們,需要和他們對話。也許這很難,但從整體來看這種方法更容易。

作為面試官你必須提高技術力。

面試技巧:前提條件

代碼面試是空中樓閣,看起來很美好,唯一的缺點是無法篩選出好的候選人。你需要思考什麼樣的技術力和品質對你的團隊最有價值,而代碼面試只不過是你偷懶的藉口而已。

招聘很難,想做好招聘可能需要掌握一系列的技巧。但是,有些技巧可以立即提升你的面試水平:

事先規定你需要的候選人的特徵,該規定需要做到具體、詳細;

詢問候選人一系列固定的問題;

在面試之後、徵求他人意見之前,記下所有面試的反饋;

練習,練習,再練習。

不需要代碼的方法

不需要寫代碼就能衡量候選人的方法可能有一萬種。我常用的三個主要方法可以覆蓋許多不同的技能。在面試過程中,我們會談論候選人的經驗,要求他們做一些代碼審查,並與別人合作設計一個系統。

下面我會詳細解釋這個過程。

我試圖通過這些方法找到真正能夠勝任技術工作的候選人,並且他們必須能在單純的編程技能之外給團隊帶來價值。通常在一次面試中我能在大約一個小時內覆蓋所有三個部分。我有信心這些信息能讓我找到好的候選人。

深入挖掘他們的經驗

許多團隊已經這樣做了。他們會在面試一開始花幾分鐘,詢問候選人之前的工作,他們對工作的態度,等等。大多時候這就像隨意談話一樣。

但這是不對的。

記住這是面試。你需要儘可能地理解他們構建系統時使用的技術。

為了做好這一點,你需要在面試開始之前仔細閱讀他們的簡歷。這不是開玩笑,在面試開始之前至少花上10分鐘仔細閱讀(不是略讀)簡歷,如果花30分鐘時間則最好。要從簡歷中儘可能多瞭解些他們之前的項目,Google一下看看能否找到他們項目的公開信息。面試時挖掘背景信息所花的時間越少,就越能獲得好的效果。

在面試中,要求候選人談談他最近最感興趣的項目。要練習主動的傾聽,要學會參與。假裝你是他團隊中的一員,或者假裝你們是在做架構審查。你要努力瞭解他們構建的東西以及構建的方法。這樣做的好處和壞處是什麼?要讓候選人知道,不知道答案無所謂,但重要的是能勾起你的好奇心。

下面是我認為能獲得好的答案的問題:

你在項目中的職責是什麼?這個問題本身並不是決定性的。即使在項目中承擔的職責很小,他們也可能很適合你們的團隊。你的候選人也許正是因為沒能獲得重要的職責而在尋找新的機會。因此,知道他們過去的職責會很有幫助。

你從他人那裡獲得了什麼幫助?無法感受他人的幫助是個極其危險的信號。即使是個人項目,也一定需要別人的幫忙。你肯定不想要一個以自我為中心的同事。

給我介紹下那個功能的工作原理。解釋下數據的來源和去向、存儲方式以及這一切能帶給最終用戶的好處。這個問題的答案足以吸引你的好奇心。

這個項目中最糟糕的技術債務是什麼?好的工程師必須理解他們做出決定時需要付出的代價。問完這個問題,可以繼續詢問他們怎樣改正這些問題,或者尚未改正的理由。

有沒有出過生產環境下的bug或服務中斷?測試下他們是否理解bug的原因,以及團隊解決bug的方法。他們是否提前預期到了bug?下次怎樣才能避免同樣的問題發生?

這一部分面試能讓你直接瞭解候選人的經驗。做好這一部分還能讓你瞭解他們如何感謝別人或責備別人。你將會了解到他們如何在兩難的工程問題上做出抉擇,他們會與你分享最近的教訓,他們與別人溝通技術的能力應該也很明顯。

如果他們選擇了不太適合的項目,可以考慮談論其他項目。所謂不太適合的意思是項目不夠複雜或他們記不清的情況。

注意,這一步要避免詢問類似於“告訴我你解決過的最難的bug”之類的問題。要求別人回憶系統的某一部分的具體原理會帶來大量的虛假負面判斷。人們不可能擁有他們修復的bug相關的一切知識,這種問題會給面試過程帶來很大壓力。

讓他們審查你們的代碼

這項活動一半是代碼審查一半是角色扮演。你可以藉此篩選出那些能夠提升團隊整體代碼質量並促進辦公室氛圍的人。

下面是代碼審查過程中需要關注的一些方面:

他們怎樣與代碼的“作者”交流?交流是否有用?是否高效?是否友善?

他們會著重哪些問題?是否能明確表達出他們的疑問?他們是否會立即指出哪些無關緊要的問題?

他們是否善於閱讀自己不熟悉的代碼?

這個方法需要提前準備很多東西。你需要找到或編寫一段代碼供候選人審查。你還需要為你希望候選人找出的問題創建一個優先級列表。不要讓面試管當場出題,一定要事先準備好。

在選擇需要審查的代碼時,不要選擇產品代碼。你的候選人沒有你所擁有的背景知識,這樣做實際上是將候選人與你的同事比較,而不是與其他候選人比較。

努力降低代碼示例中的複雜度。面試的時候,候選人沒有太多時間閱讀代碼,而且很可能他們並沒有想到會做代碼審查。熱身就要花很長時間。

在代碼中加入一兩個真實的bug,但不要強調找bug。一般來說,代碼審查並不是個好的找bug方法,特別是審查者從來沒有見過代碼的情況下。能自證的bug(如給需要數組的函數傳遞字符串)最好。在你的優先級列表中,bug的優先級應該是最低的,bug應該是給極其優秀的人的加分項。

最後,代碼應該做一些實際的事情。如果你的公司很出名,那可以選擇你的產品簡化版本。但如果你需要花大量時間為候選人提供背景信息的話還是算了。

最好的選擇要麼是虛構的代碼(也許可以選擇本文竭力避免的代碼面試中用到的代碼),要麼是開源代碼中的一個拉取請求。

一旦決定了要審查的代碼,你應該期待候選人找出下面這些東西:

過於糟糕的拉取請求的描述或提交信息;

能用但無法自洽的代碼;

過於複雜的代碼(需要重構的代碼);

混亂的變量或方法名;

過度設計的代碼(即實際上永遠不會用到的功能)。

如果代碼中沒有足夠的問題,就多加一些。

這裡有個潛在的問題,我還沒有確定的答案。這個問題是:你是否應該提前將代碼發給候選人?

如果你這樣做,就又給那些有空閒時間的人以巨大的優勢。如果不這樣做,就要面臨增加面試壓力的風險。

我傾向於後者。好的面試官可以減輕壓力,方法之一就是讓面試者提前知道他們將做代碼審查,你也可以在審查開始之前介紹你的期望。

共同設計系統

作為面試官,你最重要的任務之一就是判斷候選人是否能完成要求他們完成的技術工作。好的評價方法應當儘可能避免虛假的正面和負面判斷,同時在更廣泛的技術水平範圍內區分候選人。

即使是新手也應當能針對問題取得一些進展。最高級的候選人應當能快速找出他們無法立即解決的問題。

這種方法我從大學時代就開始使用,後來在業界用了二十多年。這種方法非常有效。

這種方法是什麼?

協同設計系統的意思是與你的候選人共同設計一個工具、平臺或項目。不需要寫代碼或偽代碼,只需要討論系統的設計思路和做出的取捨,還要提出這些取捨可能帶來的問題,以及解決問題的方案。

這種方法之所以有效,是因為新手工程師和高級工程師之間的主要區別就是他們能預見到的問題的數量。憑藉經驗可以造就更強壯的系統設計,也能隨時解決新問題。

怎樣使用這種方法?

首先你的團隊需要選擇一個希望候選人“構建”的項目(所有候選人應當使用同一個項目。長時間這樣做,面試官就能做出更好的評價),自己做一次練習並計時。面試時要讓候選人知道系統設計大概要花多少時間,並告訴他們不可能完成所有設計。他們應當提前瞭解預期的產出。

花上幾分鐘解釋基本的需求。如果需求無法用幾句話解釋清楚,那可能不是個好項目。例如,你的項目可以是構建一個與某個著名的社交媒體平臺相似的東西,比如你無需解釋Instragram的工作原理。

事先提供一切你認為價值不大的東西。然後詢問候選人他們希望首先構建的部分。然後繼續討論新功能,直到時間用完。

如果候選人很容易就完成了這一切,那麼可以提高複雜度。如果他們表現得很困難,就降低複雜度。

項目的難度可變,這樣就能深入瞭解候選人的技能水平。就像是對候選人水平做二分查找一樣!

選一個項目

這項活動的關鍵就是需求必須易於理解。如果你公司的產品很出名,可以利用它做為起點。否則,選一個知名的網站(如Facebook)。項目應當與候選人入職後要做的工作相關。拿我們來說,我們有兩個項目,一個用於後端招聘,一個用於前端招聘。

後端項目的主要關注點是流行社交網絡的底層系統。前端項目會提供一些簡化了的產品功能截圖,並詢問候選人如何構建(組件怎麼定義、組件間交互用什麼方法等)。

示例:構建Facebook

首先,我們會介紹任務。告訴候選人我們要構建一個類似於Facebook的網站。我們假設現在這個網站包含了用戶、認證和一些其他功能。

此時,我會詢問候選人怎樣才能構建最小功能的Facebook。我們喜歡這個問題,因為這個問題能看出候選人怎樣考慮產品上的需求,也可以給之後的決策和取捨的討論提供基礎。

此時,我會使用白板記錄下他們的想法。這樣能使我參與其中,保證我之後能理解他們的設計。如果我理解錯了,他們會立即注意到並糾正。

候選人可能會告訴我,最小功能集合包含好友、狀態更新、新聞源,以及點讚的功能。問問他們挑選這個功能列表時的原則。是否漏掉了什麼明顯的功能?是否包含了不必要的功能?他們的思考過程比功能列表本身更重要。然後,問問他們打算先做哪個。假設候選人決定先做“好友”功能。

候選人會有不同的想法。一些候選人可能會提出不可行工作的方案,但不應該剝奪他們的機會。最優秀的候選人應該能很快就完成這個階段。

我們假設候選人告訴我,他要建一個表來保存好友關係。這個表應該包含好友關係的發起人和接收者。

然後繼續挖掘。在Facebook中的好友關係是雙向的。怎樣才能在數據庫中表示?這種表示方法對系統設計有什麼影響?

選擇之一就是不需要做任何特別處理。查找給定用戶的好友時用兩列同時查找。另一個選擇是在好友數據庫中保存兩份數據,每個數據表示一個方向。如果這樣做,那麼刪除好友時要同時刪掉兩條數據。討論兩者的取捨。

下個話題可能是如何處理好友請求。他們可能會選擇在“好友”一欄添加一個“接受”按鈕。他們可能會建立新的表保存好友請求。接下來可以討論黑名單和垃圾請求等話題。

此時好友的話題基本上說完了,可以繼續討論下一個功能。隨著新的功能不斷加入系統,討論各個功能之間的交互是件很有意思的事情。

假如候選人無話可說也沒關係!你可以提出一種解決方案,問問他們的想法。這種方案的優缺點是什麼?要是他們還是不理解,可以試著討論其他的功能。

這項活動中我最喜歡的地方就是它很有意思。如果面試官表現很好,候選人也積極參與,那麼最終整個面試過程可能不怎麼像面試,而更像是一次與同事間就新項目進行的談話。

而這正是候選人即將擔任的角色。完美。

什麼時候應該用代碼面試?

儘管我很不喜歡代碼面試,但有時候也有用:

確定入門級程序員是否能夠編程;

如果你的公司強制進行結對編程,那麼在面試中進行結對編程可以當做是以後工作的預演;

一個角色需要許多特定的編程技能,而你沒有太多時間去教他們,當你在兩個高級職位名稱之間猶豫不定時尤為如此;

從代碼面試到無代碼面試的轉變過程中不要突然轉變,給自己一段轉變的時間,可以幫你建立無代碼面試的技能。

最後,如果團隊的面試技能欠缺,就需要利用代碼面試。代碼面試的效果不太好,而且也有許多缺點。但是,它非常容易實施。即使是沒有經驗的面試官也可以很好地處理代碼面試。

如果你正是這樣的人,那麼培養自己的面試能力應該是最優先的——僱傭錯誤的人是最昂貴的錯誤。

結論

只要一點點練習,你的團隊就能在這種無代碼面試中做得很好。他們能在較短的時間內做出更好的僱傭決策,而且面試也能招來更多的候選人。

我希望這篇文章對你有幫助。如果有問題,請在評論區留言。希望你能在下一次面試中幹掉代碼面試!

關注我:私信回覆“666”獲取往期Java高級架構資料、源碼、筆記、視頻、Dubbo、Redis、Netty、zookeeper、Spring cloud、分佈式、高併發等架構技術


分享到:


相關文章: