TechBridge 技術共筆部落格

var topics = ['Web前後端', '行動網路', '機器人/物聯網', '數據分析', '產品設計', 'etc.']

記一次軟體工程師面試心得


前言

我自己很喜歡看一些面試的文章,因為可以從裡面學到許多,如果有面試題目的話那就更棒了,可以邊看邊想,測測看自己的實力。這篇文章是我前一陣子面試某間公司的歷程跟一些心得,希望對大家會有幫助。順帶一提,最後是有拿到 offer 的。

我面試的職缺叫做 Software Engineer,軟體工程師,四次面試都是中文的(我原本以為會有英文)。HR 有先跟我聊過,我有說我比較想要做前端,所以有些面試的考題會比較偏前端。但因為這間公司也很注重 CS 的基礎,所以依然會有很多資工本科的問題。(作業系統、資料庫、資料結構與演算法等等)

因為公司不在台灣,所以面試的形式都是採用 Skype 視訊加上某個線上 coding 的網站。現在很多公司的遠端面試都很喜歡採用這種形式,就是出題目給你讓你即時 coding,面試官那邊看得到你打字(就跟 hackpad 或是 Google docs 一樣),也可以直接 compile 看看答案對不對。

一面

一面的面試官是個前端工程師,所以問題會比較偏前端。程式語言的部分我是選擇用 JavaScript 來作答。

第一題

在 Facebook 上面,對於按讚這個功能,通常會有以下幾種描述:

  1. 只有一個人按讚:A likes this
  2. 有兩個人按讚:A and B like this
  3. 有三個人按讚:A, B and C like this
  4. 有四個人以上按讚:A, B and 2 others like this

寫一個 function,會給你一個叫做 names 的陣列,根據 names 輸出結果。

這一題很基本,我覺得主要是想看你會怎麼解決這個問題,以及讓你小試身手一下(怕你太緊張)。我自己的話是直接寫 if…else 去判斷。

另外,記得把一些 edge case 也考慮一下,例如說 names 有可能是空陣列嗎?如果是的話應該輸出什麼?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function like(names) {
var output = " likes this";
if(names.length<=0) return "";
if(names.length===1) {
return names[0] + output;
}
output = " like this";
if(names.length==2) {
return names[0] + " and " + names[1] + output;
}
if(names.length==3) {
return names[0] + ", " + names[1] + " and " + names[2] + output;
}
return names[0] + ", " + names[1] + " and " + names.length-2 + " others" + output;
}

第二題

幫 array 加一個 any 的 function,可以輸入任一 function,如果任何一個元素丟進那 function 裡面的值是 true,就輸出 true,否則就 false。

例如說現在有個 function 叫做:isGreaterThanZero,範例就會是這樣:

1
2
[1, 2, 3, 4, 5].any(isGreaterThanZero); //=> true
[-1, 0].any(isGreaterThanZero); //=> false

這題應該主要是考會不會用 Array.prototype 來新增函式上去,如果會的話,實作的部分則沒有什麼難度。一樣附上我的解答:

1
2
3
4
5
6
7
Array.prototype.any = function(func){
var len = this.length;
for(var i=0; i<len; i++) {
if(func(this[i])) return true;
}
return false;
}

第三題

對於這一行程式碼:var MyObject = new MyClass();可以試著講講看背後做了什麼事嗎?有沒有可能不用 new 但是卻達成一樣的效果?

這一題我答的頗差的,主要是考對 JavaScript prototype 機制的理解程度,想瞭解更多的可以參考:JavaScript 語言核心(15)函式 prototype 特性

第四題

有些很慢的 function,我們想把它 cache 起來,下次執行時就不會那麼慢,例如說:

1
2
3
4
5
6
7
complexFunction('a', 'b'); //=> 10s
complexFunction('a', 'b'); //=> 10s
var ccf = cache(complexFunction);
ccf('a', 'b'); //=> 10s
ccf('a', 'b'); // Instant

寫出一個 cache 的 function,可以把傳進來的 function 加上 cache 功能

這一題其實考的點滿多的,第一個是考你會不會回傳一個 function(雖然這也滿基本的啦),第二個是考你知不知道怎麼做 deep equal。

因為他範例給的是兩個字串,所以乍看之下好像不是很難,但再追問下去,就會知道應該要寫出一個能夠 cache 所有參數的版本,意思就是如果參數是 Object 的話也應該能做 cache。所以就要紀錄參數跟輸出的組合,去查一下有沒有已經算過的參數,有的話就直接輸出結果。

這題我覺得要做到完美的話其實也挺難的,可以再優化的點應該很多。

我最後完成的不完美的版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
function cache(func) {
var cached = [];
function deepEqual(obj1, obj2) {
var obj1Type = typeof obj1;
var obj2Type = typeof obj2;
if(obj1Type !== obj2Type) {
return false;
}
// same type
if(obj1Type!=='object') {
return obj1===obj2;
}
// object
for(var key in obj1){
if(!obj2[key]){
return false;
}
// have the same key
if(!deepEqual(obj1[key], obj2[key])){
return false;
}
}
return true;
}
return function(){
var isCached = false;
var cacheResult = null;
for(var i=0; i<cached.length; i++){
if( deepEqual(cached[i].arguments, arguments) ) {
isCached = true;
cacheResult = cached[i].result;
break;
}
}
if(isCached) {
return cacheResult;
} else {
var result = func.apply(null, arguments);
cached.push({
arguments: arguments,
result: result
})
return result;
}
}
}

第五題

用 CSS 實現一個很簡單的網格系統,假設一行有 12 格好了,請問像是col-4這種 class 的 CSS 應該怎麼寫?

因為我 CSS 原本就比較弱,所以還滿怕碰到 CSS 問題,也沒有自己實作過網格系統。所以這一題我就答說:display: inline-block; width: 25%

後來就被提示說,概念差不多,可是實作上會碰到一些問題,因為預設會有 margin,所以四個雖然看起來會排滿,但其實會排成兩行。要再加上一些修正才行。

一面差不多就到這邊結束了,問的都是一些基本的 JavaScript 跟 CSS 的題目,我覺得沒有特別困難的。所以我自己覺得一面的表現算是還不錯啦。

二面

考的問題都是一些比較偏資工本科系的問題了,問題大致如下:

  1. tcp 連線時有三次握手,那關閉時候的流程是什麼(考你四次揮手的流程)
  2. 有寫過 linux 上的程式嗎(應該是考你有沒有寫過系統程式)
  3. thread 跟 process 的差別(經典考題)
  4. mysql 的 index 有哪些,差在哪?(考對資料庫的熟悉程度)
  5. hashmap 怎麼實現(考資料結構)
  6. virtual memory 在幹嘛(考作業系統)
  7. 資料庫欄位 TEXT 跟 VARCHAR 差異(考資料庫)

可以看到考題還滿廣的,網路、系統程式、作業系統、資料庫、資料結構全部都有問到。這邊是我的弱項,所以都答得滿差的…

三面

原本以為二面完就掰掰了,但我自己猜測因為我一面的表現還不錯,綜合起來還是進到了第三面。結果第三面考的依舊是我不太在行的部分。

第三面我有印象的題目只有一題而已,考完之後上網查了一下發現也是滿經典的題目。

假設現在有很多 url 的資料,每筆一行,請找出重複次數最多的前 k 個,並講一下時間複雜度是多少?

其實就是一個純粹考資料結構加演算法的題目,看你要用哪些組合來處理這個問題。但光是知道還不夠,也要能夠把時間複雜度一併講出來才行。我記得我最後給出的解法應該是維護一個有 k 個元素的陣列,然後用 map 來存 url 的出現次數,邊讀資料邊更新出現次數,然後也更新那 k 個元素的陣列,找到最後就是答案了。但這個解法我的時間複雜度也沒有回答得很好,有些地方不太清楚時間複雜度是多少。

對這類型的題目有興趣的話,可參考:十道海量数据处理面试题与十个方法大总结

四面

最後一面依舊是問了很多技術,這一輪面試被問的問題最多,而且也有針對我以前做過的東西去問。我覺得廣度跟深度都有顧及到。

第一題

先小試身手,寫一個 reverse 的 function,反轉字串

1
2
3
4
5
6
7
8
function reverse(s) {
var output = "";
var len = s.length;
for(var i=len-1; i>=0; i--){
output+=s[i];
}
return output;
}

第二題

寫一個 function:

1
2
3
var main = [1,2,3,4,5,6];
var sub = [3,5];
removeSubArray(main, sub) -> [1,2,4,6]

這一題比較特別的點是要直接改變傳進來的 array 而不是 return 新的

1
2
3
4
5
6
7
8
9
10
11
12
function removeSubArray(main, sub) {
for(var i=0; i<main.length; i++){
var temp = sub.indexOf(main[i]);
//remove
if(temp>=0) {
sub.splice(temp, 1);
main.splice(i, 1);
i--;
}
}
}

第三題

寫一個 copy 的 function,複製傳進來的 object

這一題雖然看似簡單但其實陷阱很多,例如說:如果碰到循環引用的 case 怎麼辦?
例如說

1
2
3
4
5
var a = {
test: {
}
};
a.test = a;

有些 library 提供的 deep clone 函式,碰到這個 case 一樣也會掛掉。但在面試的時候這個 case 我依舊解不掉,需要再花點時間想想。

第四題

寫一個 closure(什麼樣子的都可以)

這一題還滿簡單的啦,只要你知道什麼是 closure 應該都寫得出來。

1
2
3
4
5
6
var increment = function(){
var times = 0;
return function(){
return ++times;
}
}

第五題

問我之前做過的 Android 熱更新怎麼做的,問很多技術細節。

第六題

問我之前做的搶紅包活動是怎麼設計的?這邊的實作在我之前寫過的文章:資料庫的好夥伴:Redis裡面有提到過。

那個活動的需求是:

  1. 中午 12 點開放使用者進入網站,並且回答一題問題
  2. 回答完後會看到自己的排名(依答題時間排序),照名次獲得獎品
  3. 只有前 300 名有獎品,之後都沒有

評估過後我決定引入 Redis 來減輕資料庫的負擔。面試官問的問題是:有沒有辦法寫成:300 名以後連答題頁面都看不到,直接擋在外面。這邊我想很久之後還是沒有想到一個比較好的解法,就只想到把 Database lock 起來,但這樣又會造成很多性能的損耗。最後我有問面試官這題應該怎麼解,他說他也還沒有想法,只是問問看有沒有可能而已XD

第七題

講一下 session 跟 cookie 的差別,還有 session 存在哪裡、如果有兩台機器怎麼管理 session?

剛好這一塊我之前有弄懂過,所以回答的還滿完整的。在之前公司也有碰過兩台機器要共用 session 的情況,我先給了他一個 AWS EC2 上面的 sticky session 的解法,他不太滿意。再來給了用 Redis 統一儲存 cache 再搭配 Redis Replication 來做 HA 的解法,他就很滿意的說:「嗯,這樣可以」

第八題

問資料庫的index的概念,為什麼要有 index?index 應該怎麼建?

因為資料庫跟後端那邊我沒有很熟,所以這題也是回答得亂七八糟的。

結論

其實這樣四次面試下來,每一次都問技術也是還滿累的,但每次面試也都是可以檢驗自己技術能力的好時刻。你會越面試越知道自己哪一個部分不足,例如說我就是對於資工本科系的那些必修比較不熟,所以之後就應該往這個方向加強。

還有,很多時候我都喜歡自己默默思考,思考出一個自己覺得可行的解法以後才跟面試官講。可是我後來發現這樣做不太好,因為你不說話,他也不說話,整個面試過程就會有很多空白,兩個都不講話。所以可以的話,應該要邊想邊講話我認為是比較好的。例如說:「我剛剛提出的解法是 O(n^2),我現在在想說有沒有可能把複雜度壓到 O(n log n),我目前的方向大概是朝…去思考」

儘管最後沒有答出來,有把想法講出來,總比只給一句:「我不知道」來得好。

面試的時候,其實我也都是抱著一種學習的心態。因為知道自己的實力真的不強,所以也希望能從面試官那邊得到一些建議。很多題目我在答不出來之後都會問他們說能不能提供一些方向,因為我真的很想知道答案(不過有些不一定會給就是了)。

大致上就是這樣囉,希望這篇心得對大家之後的面試有幫助。

關於作者:
@huli 野生工程師,相信分享與交流能讓世界變得更美好

喜歡我們的文章嗎?歡迎分享按讚給予我們支持和鼓勵!



TechBridge Weekly 技術週刊編輯團隊

TechBridge Weekly 技術週刊團隊是一群對用技術改變世界懷抱熱情的團隊。本技術共筆部落格初期專注於Web前後端、行動網路、機器人/物聯網、資料科學與產品設計等技術分享。This is TechBridge Weekly Team Tech Blog, which focus on web, mobile, robot, IoT, Data Science technology sharing.

關於我們 / 技術日報 / 技術週刊 / 粉絲專頁 / 訂閱RSS

Comments