面試心得–Appier沛星互動科技 - 關於| BetterLog

文章推薦指數: 80 %
投票人數:10人

面試心得–Appier沛星互動科技. 2019-03-20. 由於大一的室友在Appier工作,剛好趁著就業博覽會期間讓他幫我內推,順便賺個推薦獎金,也幸運地得到了面試機會。

面試雜記/面試心得–Appier沛星互動科技面試心得–Appier沛星互動科技2019-03-20由於大一的室友在Appier工作,剛好趁著就業博覽會期間讓他幫我內推,順便賺個推薦獎金,也幸運地得到了面試機會。

公司地點位於101大樓附近的華南銀行大樓,是台北的市中心,生活機能極佳;大樓的門禁非常先進而且嚴謹,要先到發卡機填寫資料,接著拿起話筒與要拜訪的公司通話,確認無誤後才會拿到拿到一片塑膠磁扣,大樓閘門及電梯上下樓都需要掃描磁扣,到了6樓的Appier公司大門後還有最後一層門禁,需要用對講機與員工聯絡後才能踏入公司大門。

職缺介紹請見官方職缺連結—SoftwareEngineer,FrontendDevelopment,Appier沛星互動科技。

第一輪面試過程(On-site面試)本次面試是由2位TechLeaderCT及CJ負責,分別是對外產品及內部產品的前端技術主管,並且直接表明此次面試只會有2題TechnicalTests,一題purecss,一題javascript。

自我介紹首先還是讓我進行自我介紹來開場,雖然我自認為用心地介紹著自己的經歷,但兩位面試官似乎沒有什麼回饋,只有提問「你覺得過去的經歷中遇過最困難的是?」,等我回答地差不多時,面試官有點突兀地說,由於時間關係,要直接進行TechnicalTest了。

TechnicalTest第一題:CSSCJ給出的題目是他自己工作中實際遇到的Card實作問題,題目已經準備在jsbin了:

JSBin Iamcontent Iamoverlay Showmore .card{ height:200px; width:200px; background:#efefef; border-radius:3px; } .content{} .overlay{} .more{}CJ僅提供了html結構、class命名以及Card容器的基本樣式,並且demo最終要我實作的效果:Showmore按鈕置於card底部滑鼠移至Showmore按鈕時,Overlay會由下方以動畫滑動至上方,並且覆蓋住Content條件限制是,不允許對Overlay設定background相關的屬性(實作參考解答附於文末)第二題:Javascript由CT出題,題目同樣準備在jsbin:functionrun(promiseFactories,concurrency){ returnnewPromise(resolve=>{ //implementit }); } functiondelay(data,delay){ return()=>newPromise(resolve=>setTimeout(()=>{ console.log('resolves',data);//Debug resolve(data); },delay*1000)) } run([ delay('a',1), delay('b',2), delay('c',4), delay('d',2), delay('e',3), delay('f',2), delay('g',1) ],3).then(console.log); //printsa(pause1s)b(pause1s)d(pause1s)c(pause1s)efg(inthesametime) //thenprints['a','b','c','d','e','f','g'] //Visualization:https://docs.google.com/drawings/d/1R1z2-3jDTK2muutdSsze1W1_nF8SGHZBAZhBRzeRjtw/edit?usp=sharingpromiseFactories是一個function陣列,其中每個function都會回傳一個promise,並且回傳的promise會在經過指定的秒數後resolve,此題解答的目標是實作run這個function,使其回傳的promiseresolve時得到promiseFactories的所有執行結果,此執行結果必須是一個陣列,並且保留promiseFactories元素之間的順序。

題目乍看之下很冗長且難懂,但其實只要把他想像成實作Promise.all()這個method即可,唯一不同之處在於,Promise.all()接受的參數是promise陣列,而本題的run()接受的參數則是function陣列。

原先預定還會有變化題,是要考量到run()的第二個參數concurrency,例如本題設定為3,即同時間只能有3個Promise在等待resolve,概念與threadpool類似,面試官還有特別準備視覺化圖片供參考(如下圖),但是由於時間不夠,這題就直接跳過了。

(實作參考解答附於文末) Promise.allwithconcurrency TechnicalTest小結實作過程中可以隨時說明自己的想法,與面試官交流解答思路,也可以查詢任何網路文件,面試官在整個過程中也都會十分和善地提供各種提示。

例如我對CSS動畫其實非常不熟,當場各種查詢MDN和Stackoverflow,然後才在面試官的引導下逐步實作出來;第二題解答的過程中因為太緊張而犯了一些Typo,面試官也會直接指出。

HR面談這關是HR跟我安排二面,並說明後續如果能有三面及四面的話面試官將會是誰。

二面會有CTO及EngineeringVP;三面是PM;最後階段的四面則由CEO進行面試。

第二輪面試過程(On-site面試)這大概是我自介過最多次的一天,先是CTO,接著EngineerVP,最後HR考量到我要南北奔波,當天想直接幫我塞一個TeamLead面試,不過TeamLead不在,便由TeamMember代替。

CTO兼Co-Founder講話節奏很跳躍的交大學長,非常認真而且用心地閱讀我的履歷,基本上看到或聽到你介紹某個關鍵字時,就會抓著當下的討論拋出很艱澀的大哉問,例如我介紹Scribo時,就被問到「你的MongoDB怎麼做textsearch?」「MongoDB每個document有32MB上限,如果你的文章超過32MB要怎麼辦?」表面上彼此是在亂聊,但其實跟如此Geek的人聊天時內心是很暢快的!此外,CTO是穿著藍白拖鞋和襪子進來會議室的,我一直投入在技術的討論上,直到他把腳盤上來沙發時,我才注意到原來他在公司裡是穿拖鞋XDEngineerVPEngineerVP是一位講中文有點口音的新加坡人,並且為了Appier全家移民台灣。

這關主要是針對人格特質和團隊合作進行面試,講到一半時還要求與我用英文交談。

本以為他是屬於管理相關的主管,應該不會問技術題,不過還是被問到「你對PWA了解多少?」FinTechTeamMembersHR與CTO及EngineerVP討論過後,當下就挑出了適合我的Team,不過TeamLead不在,因此這關由一位負責DataScience及另一位負責Backend的TeamMember進行面試。

原則上針對此團隊負責的專案討論,不過也有被問到一些不易回答的問題,像是「前端開發上最近遇過什麼難題,能否用白話解釋到我們backend或PM都能聽得懂?」第三輪面試過程(視訊面試)前一輪已經和TeamMember聊過了,此次基本上只是和TeamLead見個面閒聊一下,一樣我先自介,接著就補問一些上一輪面試沒問到的問題,於是就這樣順順地度過這關了。

第四輪面試過程(On-site面試)最後一輪面試是由CEO及COO擔任面試官,一如以往自我介紹後,以下是仍有印象的對話:CEO:為什麼會想來Appier? 我:(自由發揮)COO:你認為你最大的優點及缺點是什麼? 我:(按照自己的套路回應)我:這個職位可能面對的最大困難是? COO:會參與客戶溝通,還有把AI為人詬病的blackbox運算過程視覺化,讓客戶能夠理解我:為什麼會面試這麼多次? CEO&COO:精兵策略。

LarryPage在公司500人的時候仍然是親自面試呢!面試結果及時程2019/03/09內推投履歷2019/03/12朋友送出Referral2019/03/14確認3/20面試2019/03/20第一輪面試(TechLead*2),確認3/25第二輪面試2019/03/25第二輪面試(CTO,EngineerVP,TeamMember*2)2019/03/26確認第三輪及第四輪面試時間2019/03/29第三輪視訊面試(TeamLead)2019/03/31第四輪面試(CEO,COO)2019/04/01HR電話確認期望薪資2019/04/03電話核薪 本薪:(>60)k/mth×14mth/y=(>84)w/y(>60)k/mth\times14mth/y=(>84)w/y(>60)k/mth×14mth/y=(>84)w/y 股票選擇權:依照入職後3個月時的貢獻及當時公司的估值計算佔股比例2019/04/06接受offer2019/04/15報到2020/04/08預告離職2020/05/15離職附錄:第一輪面試題目參考解答第一題參考解答解答重點:html的部分有調整div的順序實作overlay上滑動畫由於不能對overlay設定background,此題的解題巧思在於替content設定height變化的動畫,總共利用兩個不同功用的動畫來完成視覺上的覆蓋效果 JSBin ShowmoreIamcontent Iamoverlay .card{ height:200px; width:200px; background:#efefef; border-radius:3px; position:relative;overflow:hidden;} .content{ width:100%;height:180px;transition:height1sease-in-out;overflow:hidden;} .overlay{ position:absolute;top:100%;height:calc(100%-20px);width:100%;} .more{ position:absolute;bottom:0px;width:100%;height:20px;} .more:hover~.overlay{transition:transform1s;transform:translateY(-200px);}.more:hover~.content{height:0px;}第二題參考解答解答重點:使用forEach來iterate每一個promiseFactory由於每個promiseresolve的時間點受到給定的delay秒數控制,必須善用index值來保持執行結果的順序利用counter及promiseFactories陣列長度來判斷終止條件functionrun(promiseFactories,concurrency){ returnnewPromise(resolve=>{ letresults=newArray(promiseFactories.length);letcounter=0;promiseFactories.forEach((pf,idx)=>{pf().then(result=>{results[idx]=result;counter++;if(counter===promiseFactories.length){resolve(results);}});});}); } functiondelay(data,delay){ return()=>newPromise(resolve=>setTimeout(()=>{ console.log('resolves',data);//Debug resolve(data); },delay*1000)) } run([ delay('a',1), delay('b',2), delay('c',4), delay('d',2), delay('e',3), delay('f',2), delay('g',1) ],3).then(console.log); //printsa(pause1s)b(pause1s)d(pause1s)c(pause1s)efg(inthesametime) //thenprints['a','b','c','d','e','f','g'] //Visualization:https://docs.google.com/drawings/d/1R1z2-3jDTK2muutdSsze1W1_nF8SGHZBAZhBRzeRjtw/edit?usp=sharing面試過後在家把變化題給實作出來,主要是利用遞迴函式來達成:functionrun(promiseFactories,concurrency){ returnnewPromise(resolve=>{ letresults=newArray(promiseFactories.length);letresolvedCounter=0;letidxNext=0;letrunNextPf=(idxToStore)=>{if(idxNext>=promiseFactories.length){return}letpf=promiseFactories[idxNext];idxNext++;pf().then(result=>{resolvedCounter++;results[idxToStore]=result;runNextPf(idxNext);if(resolvedCounter===promiseFactories.length){resolve(results);}});}promiseFactories.slice(0,concurrency).forEach((_,idx)=>{runNextPf(idx);});}); } functiondelay(data,delay){ return()=>newPromise(resolve=>setTimeout(()=>{ console.log('resolves',data);//Debug resolve(data); },delay*1000)) } run([ delay('a',1), delay('b',2), delay('c',4), delay('d',2), delay('e',3), delay('f',2), delay('g',1) ],3).then(console.log); //printsa(pause1s)b(pause1s)d(pause1s)c(pause1s)efg(inthesametime) //thenprints['a','b','c','d','e','f','g'] //Visualization:https://docs.google.com/drawings/d/1R1z2-3jDTK2muutdSsze1W1_nF8SGHZBAZhBRzeRjtw/edit?usp=sharing


請為這篇文章評分?