mockgle - mock's love story

Story of a man who falls in love with Google. Sorry, people of the World, but this is in Thai.

Thursday, February 02, 2006

[2] First Date - พบกันครั้งแรก

ก่อนการสัมภาษณ์นั้นคุณฮานนาได้บอกมาว่าให้ผมเตรียม "ท่อนหนึ่งของโปรแกรมที่เคยเขียน" ความยาว 1/2 - 1 หน้ากระดาษ และเตรียมตัวไปอธิบายให้เขาฟังด้วย ว่าทำไมเราถึงเลือกโปรแกรมส่วนนี้มาโชว์ มันทำงานอย่างไร สไตล์การเขียนโปรแกรมของเราเป็นอย่างไร เราคิดว่ามันมีข้อดี/ข้อเสียอย่างไร จะพัฒนาให้มันดีขึ้นได้อย่างไร จะตรวจสอบว่ามันทำงานถูกต้องอย่างไร ฯลฯ Code ที่เตรียมไปนั้นเป็นภาษาอะไรก็ได้ แต่ถ้าจะให้ดีเขาบอกว่าขอเป็น C/C++ หรือ Java

คนที่สัมภาษณ์จะเป็น engineer ตัวจริงจาก Google ดังนั้นคำถามจะเป็นไปในแนว technical เต็มที่ โปรดเตรียมตัว (และเตรียมใจ) ไว้ให้พร้อม การสัมภาษณ์จะกินเวลา 90 นาที โดย 45 นาทีแรกจะดู code (โปรแกรม) ที่เรานำไปโชว์, 45 นาทีหลังจะพูดคุยเรื่องทางเทคนิคต่างๆ

เขาบอกมาว่าให้ใส่ชุดตามสบาย ไม่ต้องเป็นทางการ แต่เพื่อความปลอดภัยไว้ก่อนผมจึงแต่งตัวใส่สูทไปเต็มยศ ระหว่างนั่งรอสัมภาษณ์อยู่ภายใน Career Center ก็ได้ฟังผู้คนที่มาสัมภาษณ์งานคนอื่นนั่งคุยกัน ทุกคนเห็นได้ชัดว่าตื่นเต้น..แต่พยายามทำตัวเหมือนไม่ตื่นเต้น ส่วนผมนั้นจะตื่นเต้นหรือเปล่าผมจำไม่ได้แล้ว (คงตื่นเต้นเกินไปจนจำไม่ได้ หรือไม่ก็ไม่ตื่นเต้นเลยจนกระทั่งไม่ได้สนใจจะจำว่าวันนั้นตื่นเต้นหรือเปล่า... เอ๊ะ ยังไง?)

คนสัมภาษณ์ผมคนแรกชื่อคุณบ็อบ อายุน่าจะประมาณ 40 กว่าๆ แล้ว แต่งตัวดี หน้าตายิ้มแย้ม ใจดี หลังจากแนะนำตัว / shake hands กันตามมารยาท (แลกเปลี่ยน SYN# กันเรียบร้อย) แล้วเขาก็พาผมเข้าไปในห้องแคบๆ ห้องหนึ่ง ห้องนั้นดูสว่างและสะอาดเรียบร้อยดี แต่ด้วยความที่มันปิดทึบทุกด้านและไม่มีหน้าต่าง ตลอดจนความตื่นเต้นเล็กน้อย (คราวนี้ยอมรับแล้วว่าตื่นเต้น) ทำให้อดนึกถึงบรรยากาศในห้องสอบสวนอย่างที่เห็นในหนังฆาตรกรรมไม่ได้

คุณบ็อบเริ่มจากการหยิบตัวอย่าง code ที่ผมเตรียมไว้ไปอ่าน; code ที่ผมเตรียมมานั้นเป็นฟังก์ชั่นหนึ่งใน ray tracer ที่เคยเขียนในคลาส Graphics เมื่อเทอมที่ผ่านมา (ภาษา C++) ผมให้เวลาเขาอ่านสักพักหนึ่งก็เริ่มอธิบาย ... ดูเหมือนคุณบ็อบไม่ต้องการคำอธิบายมากก็คงเข้าใจ กระนั้นเขาก็(แกล้ง?)ทำหน้าเหมือนจะไม่เข้าใจ และถามผมใหญ่ว่าทำไมตรงนี้ถึงทำอย่างนั้น ตรงนั้นถึงทำอย่างนี้ คิดว่าคงต้องการลองดูว่าเราเข้าใจในสิ่งที่เราเขียนไปเองดีแค่ไหน และเราอธิบายเหตุผลของ design ของเราได้หรือเปล่า (แน่นอน คำตอบพวกนี้ผมเตรียมมาหมดแล้ว)

ประเด็นหลักที่ผมพยายามอธิบายใน code ผมก็คือ ผมพยายามเขียน code ให้อ่านง่าย ตั้งชื่อตัวแปร/ฟังก์ชันให้สื่อความหมาย และมี debugging mechanism ที่ดี โดยสามารถเปิด/ปิด option การพิมพ์ debuging information สำหรับแต่ละส่วนของรูปภาพได้โดยสะดวกพอสมควร

ท่าทางคุณบ็อบก็จะพอใจในสิ่งที่ผมพูด ... อย่างไรก็ตาม จากการที่ผมโฆษณาซะเหลือเกินว่าโปรแกรมของผมเข้าใจง่าย, debug ง่าย คุณบ็อบก็ยิงคำถาม (ที่ทำให้ผมอึ้งไปราวๆ 1.5 วินาที) มาว่า "คุณแน่ใจได้อย่างไรว่าโปรแกรมของคุณถูก และคุณจะทำให้คนอื่นมั่นใจว่ามันถูกได้อย่างไร?"

ผมจะตอบอย่างไรได้ ในเมื่อคำตอบที่แท้จริงที่ผมมีอยู่ตอนนั้นคือ "ก็ลองๆ มันไปเรื่อยๆ ถ้าภาพที่โปรแกรมสร้างออกมามันดูดี มันก็คงถูก" ... ปัดโถ่เอ๋ย ก็โปรแกรมทางด้าน graphics มันตรวจสอบความถูกต้องกันได้ง่ายๆ ซะที่ไหน มันก็ต้องใช้ตาดูเอาน่ะแหละ

แน่นอน นั่นไม่ใช่คำตอบที่ดี เขาถามกลับมาว่า "ไม่มีวิธีอื่นเหรอที่จะตรวจสอบได้ดีกว่า สะดวกกว่า และทำให้คนอื่นที่จะต้องใช้ฟังก์ชันของคุณสามารถมั่นใจได้มากขึ้น?"

ผมนั่งอึ้งๆ ทำหน้างงๆ หน้าอาจจะซีดเล็กน้อย (ไม่ทราบเหมือนกัน -- ผมไม่เห็นตัวเอง ในนั้นไม่มีกระจก) ในใจก็คิด "เวร.. เค้าต้องการให้เราตอบว่าอะไร?" ยังไม่ทันไรคุณบ็อบก็เฉลยว่า "คุณควรจะเขียน unit test สำหรับทดสอบส่วนย่อยๆ ต่างๆ ของโปรแกรม ... unit test คือโปรแกรมที่รันต่างหากเพื่อทดสอบเพียงบางส่วนของโปรแกรมอื่น และนี่คือสิ่งที่ Google ทำเป็นประจำสำหรับทุกๆ software"

ผมยิ้ม และกล่าวขอบคุณในคำแนะนำของเขา ... ในใจก็คิด "นี่เราเสียแต้มไปแล้วใช่ไหม?"

คุณบ็อบหันมองนาฬิกา ยังเหลือเวลาอีกราวสิบนาที เขาบอกว่าขี้เกียจคุยเรื่อง code แล้ว คุยจบแล้ว ขอคุยเรื่องอื่นบ้างดีกว่า ว่าแล้วก็หยิบกระดาษให้ผมแผ่นหนึ่งแล้วถามว่า...

"สมมติว่ามี array A บรรจุจำนวนเต็มอยู่ n ตัว คุณต้องการสร้าง array B ที่มีขนาด n เช่นเดียวกัน โดยที่ B[i] = ผลคูณของทุกตัวใน A ยกเว้น A[i] คุณจะทำอย่างไร?"

ผมตอบทันทีว่า "ผมสามารถอธิบายวิธีที่มี O(n^2) ได้ในขณะนี้ แต่ผมเชื่อว่ามีวิธีที่ดีกว่านั้น ขอเวลาผมคิดสัก 2 นาทีได้ไหมครับ?"

คุณบ็อบยิ้ม ตอบว่าได้ ไม่มีปัญหา

เวลาผ่านไปสิบวินาทีผมนึกขำ -- ขำว่าทำไมมันง่ายอย่างนี้ ผมบอกคุณบ็อบว่าผมได้ O(n) algorithm แล้ว วิธีที่ผมบอกไปนั้นคือการจับทุกตัวใน A มาคูณกัน เรียกผลคูณว่า K จากนั้นก็ให้ B[i] = K/A[i]

คุณบ็อบไม่รอช้าที่จะอมยิ้ม และถามสวนมาทันที เขาพูดด้วยถ้อยคำนุ่มๆ สุภาพ แต่มีพลังว่า "คุณคิดว่าวิธีการของคุณอาจทำให้เกิดปัญหาอะไรได้บ้างหรือเปล่า?"

ฮ่ะๆๆ พูดอย่างนี้ผมรู้แน่นอนว่านี่ไม่ใช่คำตอบที่เขาต้องการ ผมยิ้ม.. หัวเราะเล็กน้อย แล้วตอบทันทีว่า "ใช่ครับ มีปัญหาเมื่อตัวใดตัวหนึ่งใน A เป็น 0 .. และปัญหา overflow"

คุณบ็อบถามต่อว่า "มีปัญหาอื่นอีกหรือเปล่า?"

ผมนึกไม่ออก

คุณบ็อบเฉลย: "การหารนั้นช้ากว่าการคูณหลายเท่านัก คุณจำเป็นต้องใช้การหารจริงๆ หรือ?"

ถามอย่างนี้แสดงว่าไม่จำเป็น .. ผมตอบทันที (ทั้งที่ยังนึกอะไรไม่ออก) ว่า "ผมคิดว่ามีวิธีที่ดีกว่านี้ ขออีกหนึ่งนาทีแล้วผมจะบอกคุณ" ... ในใจก็คิด "เวร! ตูจะคิดออกไหมฟะ?"

หนึ่งนาทีต่อมาผมนึกขอบคุณวิชา Algorithms ที่เรียนเมื่อปีที่แล้ว และขอบคุณค่ายโอลิมปิกในเมืองไทยที่ทำให้ผมคุ้นเคยกับเทคนิคมาตรฐานเหล่านี้ ผมเขียนเป็นสมการให้คุณบ็อบดู แล้วบอกว่าถ้ายังไม่เคลียร์พอผมจะอธิบาย

**โปรดข้ามย่อหน้านี้ไปหากต้องการลองคิดเอง**
วิธีการนั้นคือ ให้ X[i] = A[0]*...*A[i-1], ให้ Y[i] = A[i+1]*...*A[n-1] (แน่นอน เรานิยามเป็นกรณีพิเศษว่า X[0] = 1 = Y[n-1]) เราสามารถคำนวณ X[i], Y[i] ได้ใน O(n) เพราะเป็นเพียงการหาผลคูณสะสมจากด้านซ้ายและขวาตามลำดับ จากนั้นก็ให้ B[i]=X[i]*Y[i]


คุณบ็อบดูสมการสามวินาทีก็เข้าใจ ผมไม่ต้องอธิบายอะไรเพิ่มเติม แต่ยังไม่วายที่คุณบ็อบจะถามต่อว่า
"แล้วมีวิธีที่เร็วกว่านี้ไหม?"

นั่นแน่! อำกันเห็นๆ .. ผมยิ้มแล้วอธิบายให้เขาฟัง ว่าทำไมโจทย์ข้อนี้จึงแก้ได้ด้วยอัลกอริธึมที่เร็วกว่า O(n) ไม่มีทางได้ ดังนั้นถึงจะมีวิธีที่เร็วกว่านี้ ก็ไม่มีทางที่จะ asymptotically faster

45 นาทีแรกหมดลงแล้ว คุณบ็อบบอกผมว่าจะพาไปหาคนอีกคนนึง ซึ่งจะสัมภาษณ์ผมต่ออีก 45 นาที ผมบ๊ายบายคุณบ็อบ คุณบ็อบไปสัมภาษณ์คนอื่นต่อไป (เห็นได้ชัดว่าโปรแกรมสัมภาษณ์ของ Google นั่นแน่นมาก .. ผมสงสัยว่าคุณบ็อบต้องมานั่งถามคำถามเดิมๆ ฟังคำตอบเดิมๆ อย่างนี้ทั้งวันจะเบื่อไหม) แล้วผมก็เดินไปยังห้องสัมภาษณ์อีกห้องหนึ่ง

คนสัมภาษณ์ผมคนนี้ชื่ออะไรผมจำไม่ได้ หน้าตาเป็นเอเชี่ยนๆ แต่งตัวตามสบายมาก (เสื้อยืด-กางเกงยีนส์) ดูยังหนุ่มๆ อยู่ อายุคงราวๆ 30 ต้นๆ.. ระหว่างแนะนำตัวกันจึงได้ทราบว่าเขาเป็นศิษย์เก่า CMU เพิ่งจบ PhD ไปได้ไม่กี่ปี ตอนนี้ก็ได้ดิบได้ดีทำงานเกี่ยวกับ security (หมายถึง network security, ไม่ใช่ security personnels นะครับ) อยู่ที่ Google สาขา Mountain View ซึ่งเป็นสาขาที่ผมอยากไปทำงาน (เป็นอย่างยิ่ง!)

คุณคนนี้ (เนื่องจากผมลืมชื่อ ดังนั้นจึงขอตั้งนามสมมติให้ว่า "เคน") เป็นศิษย์เก่า จึงดูมีความกันเองสูงมาก ผมคุยกับเขาเหมือนคุยกับเพื่อน (ที่อเมริกาดันไม่มีคำว่ารุ่นพี่ มีแต่คำว่าเพื่อน) คุยไปยิ้มไป/หัวเราะไป บางครั้งก็นั่งนินทาอาจารย์บางคน(ที่เคยสอนผมและเคน)ด้วยซ้ำไป! .. แต่เห็นเล่นๆ อย่างนี้ บทสัมภาษณ์ของเคนนั้นไม่แพ้คุณบ็อบเลย เต็มแน่นไปด้วยเนื้อหา สาระ และความมันส์

เริ่มจากปัญหาแรก เคนยื่นกระดาษให้ผมหนึ่งแผ่น บอกผมว่า..

"ช่วยเขียนฟังก์ชันที่ใช้ทดสอบว่าสตริงสองตัวเป็น anagrams กันหรือไม่ โปรดบอกไอเดียของคุณ แล้วเขียนลงในกระดาษ"

หมายเหตุ: anagrams หมายถึงข้อความที่เกิดจากการสลับตัวอักษรของกันและกัน อย่างเช่น "dog" กับ "god", "panuakdet.." กับ "up.and.take", "i love you!" กับ "o! evil you", "bill gates" กับ "legal bits" เป็นต้น (ตัวอย่างพวกนี้ หามาจาก http://www.anagramgenius.com/server.php)

คำถามนี้พี่มะนาว (อาจารย์ ดร.จิตรทัศน์ ฝักเจริญผล ในปัจจุบัน) เคยนำมาให้ทำตั้งแต่ ม.3 ดังนั้นจึงไม่ใช่เรื่องยากอะไรที่จะคิดคำตอบ ผมตอบเคนไปว่า

**โปรดข้ามย่อหน้านี้ไปหากต้องการลองคิดเอง**
"เพียงแค่หาฮิสโตแกรมของตัวอักษรใน A และใน B ถ้าฮิสโตแกรมเหมือนกันก็คือเป็น anagrams กัน"

เคนบอกว่า "วิธีคุณฟังดูดี แต่ผมอยากเห็นคุณเขียนโปรแกรม" มิน่าเล่า..ถึงได้นำโจทย์ง่ายๆ มาให้ทำ เขาคงต้องการดูว่าเราเขียนโปรแกรมแล้วจะมี bug หรือเปล่า

"ภาษาอะไรดีครับ? ผมถนัด C กับ Java" ผมถาม .. "C ละกัน ผมชอบ C" เคนตอบ

"นั่นแน่! อยากจะดูว่าเราจะงงกับ pointers หรือเปล่าละซี่ เรื่องแบบนี้สบายม็อคอยู่แล้ว" ผมคิด แล้วก็ตั้งหน้าตั้งตาเขียน code บนกระดาษด้วยความระมัดระวัง ไม่นานนักก็ยื่นให้เคนแล้วบอกว่า "เรียบร้อย" ดวงตาของผมพยายามสื่อความหมายว่า "ง่ายจัง ขอยากๆ หน่อย"

เคนถามผมว่า "แน่ใจหรือเปล่าว่าถูก?" ผมตอบแบบรู้ว่าถูกอำ "แน่ใจครับ คำตอบสุดท้าย"

แล้วเคนก็พูดในสิ่งที่ทำให้ผมอึ้ง ... "characters ใน C นั้น signed หรือ unsigned?"

โอ้! นี่เป็นการหน้าแตกครั้งมโหฬาร code ที่ผมเขียนไปนั้นมี bug เนื่องจากผมเผลอลืมไปว่า char ใน C นั้น signed ผมยิ้ม กล่าวยอมรับความผิดแต่โดยดี แล้วแก้ไขโดยการใส่คำว่า unsigned เข้าไปข้างหน้า char ทุกตัว เพียงเท่านั้นก็แก้ปัญหาได้

เพื่ออธิบายให้ผู้อ่านเห็นภาพ ส่วนหนึ่งของ code ที่มีปัญหาคือ
/* s กับ c ต่างเป็น char*, ส่วน f เป็น int[256] */
for (c=s;*c;c++) f[*c]++;

เนื่องจาก *c อาจมีค่าตั้งแต่ -128 ถึง 127 ในขณะที่ f มี index ไล่ตั้งแต่ 0 ถึง 255 จึงเป็นไปได้ (สูงมาก) ว่า code นี้จะก่อให้เกิด segmentation fault

ผมแก้ปัญหาไปแล้วยังไม่วาย เคนยังถามต่อว่า "สมมติว่าระบบที่คุณเขียนโปรแกรมอยู่ ไม่อนุญาตให้มี unsigned char (พูดอีกอย่างหนึ่งคือ char นั้นต้อง signed) คุณจะทำอย่างไร?"

**โปรดข้ามสองย่อหน้านี้ไปหากต้องการลองคิดเอง**
อันนี้ผมใช้ความคิดสักพัก แล้วก็นำ code กลับมาแก้ โดยเปลี่ยนส่วนที่อ้างถึง f[*c] ให้เป็น f[*c>=0?*c:256+*c]

เคนบอกว่าผมทำถูกแล้ว วิธีที่เขาคิดไว้ก็คล้ายๆ กัน ต่างกันนิดเดียวตรงที่เขาจะเปลี่ยน f[*c] ให้เป็น f[*c^-1] (เครื่องหมาย ^ คือการ xor) วิธีนี้สั้นกว่า และอาจจะเร็วกว่านิดหน่อย

ผมนึกว่าเคนจะพอใจกับโจทย์ข้อนี้แล้ว แต่ยังไม่จบแค่นั้น เขาถามต่อว่า "วิธีของคุณมี O(n) ซึ่งนับว่าดีมาก แต่สมมติว่าตัวอักษรแต่ละตัวมีขนาดมากกว่า 8 bits สมมติว่ามันเป็น 32-bit unicode ซึ่งมีตัวอักษรที่เป็นไปได้นับพันล้านแบบ คุณไม่สามารถทำ histogram ได้อีกต่อไป คุณจะทำอย่างไร?"

ผมตอบว่า "งั้นก็อาจหลีกเลี่ยงไม่ได้ที่จะต้องเรียงตัวอักษร การเรียงใช้เวลา O(n log n) หลังจากเรียงเสร็จเราก็เทียบได้ว่า A กับ B เป็น anagrams กันหรือไม่"

เขาถามว่า "เรียงยังไง?"

ผมตอบ: "ใช้ heap sort, merge sort, หรือ quick sort ก็ได้ ... แต่กรณีนี้ใช้ heapsort ดีที่สุด"

เคน: "ทำไมต้อง heap sort?"

ผมอธิบายว่า เพราะ
1) quick sort ใน worst case เป็น O(n^2) และ
2) merge sort ต้องใช้ external memory และ
3) เราสามารถทำ heap sort บน A และ B ไปพร้อมๆ กัน และหากมันไม่ใช่ anagrams กัน ก็เป็นไปได้ที่เราจะพบความจริงข้อนั้นก่อนที่จะต้องเรียงทั้งสตริง ซึ่งอาจช่วยประหยัดเวลาไปได้มาก

เคนดูจะพอใจกับคำอธิบาย แต่เขาก็ถามให้แน่ใจว่าผมเข้าใจในสิ่งที่ผมพูดจริงๆ "อธิบายหน่อยว่า heap คืออะไร? ทำไมจึงไม่ต้องใช้เมมโมรี่เพิ่มเติมในการสร้าง? ทำไมวิธีคุณถึงรับประกัน O(n log n)?"

ไม่ใช่เรื่องยากที่จะอธิบาย โดยเฉพาะอย่างยิ่งเมื่อผมได้เรียนวิชา Algorithms มาจากอาจารย์ Blums ทั้งสองท่านเมื่อปีที่แล้ว (คลาสที่ผมเรียนนั้นสอนโดยอาจารย์ที่เป็นพ่อลูกกัน) ในคลาสนั้นเขาให้การบ้านที่ต้องส่งโดย oral presentation (การนำเสนอด้วยปากเปล่า) ทุกสองสัปดาห์

เคนบอกว่าหมดคำถามเรื่องนี้แล้ว มาถามเรื่องที่เขาถนัดบ้าง (คือเรื่อง Networks) แล้วเขาก็ถามคำถามยอดฮิต .. "ขั้นตอนเริ่มต้นของ TCP connection เป็นอย่างไร"

ผมเพิ่งเรียน Networks มาเมื่อเทอมที่แล้ว ตอบไปทันที: "three-way handshakes โดย client เป็นฝ่ายเริ่ม, แล้ว server ก็ตอบ, แล้ว client ก็ตอบอีกทีนึง"

เคนถามต่อว่า "แต่ละรอบที่ส่ง เขาส่งอะไรกันบ้าง?"

คำถามนี้ไม่น่าเชื่อว่าผมจะเกิดอาการ "ลืมกะทันหัน!!" ผมตอบเขาไปตามตรงว่า "โอ้ .. ผมลืมรายละเอียดไปแล้ว จำได้แค่ว่าอันแรกคือ SYN, อันที่สองคือ SYN & ACK แต่จำไม่ได้ว่าอันที่สามคืออะไร"

เคนตอบว่า "ดีมาก ตอบมาเท่านั้นก็พอแล้ว อันที่สามมันก็แค่ ACK" แล้วถามต่อว่าเรารู้จักคำว่า "TCP hijack" หรือไม่ โอกาสที่จะเกิดยากแค่ไหน....

ผมตอบไปตามความรู้ที่เรียนมาจากห้องเรียน ซึ่งคิดว่าตอบถูกหมด ยกเว้นอยู่อย่างหนึ่งคือคำถามที่ว่าเกิดยากแค่ไหน ผมตอบว่าเกิดได้ง่ายถ้าเราใช้ sequence number ที่มีรูปแบบชัดเจน แต่ถ้าใช้ random initial sequence number ก็จะถูกโจมตีได้ยากเพราะ sequence number มี 32 bits แน่ะ มีได้ 4 พันกว่าล้านแบบ การจะเดาถูกนั้นต้องฟลุคจริงๆ

เคนยิ้มๆ ไม่ยอมบอกว่าผมตอบผิด (ผมค่อยมารู้ทีหลังว่า จริงๆ แล้วมันเกิดได้ง่ายกว่าที่ผมคิดมาก ด้วยหลักการเดียวกับ birthday paradox -- ขออนุญาตไม่อธิบายรายละเอียด) แล้วมุ่งไปคำถามคลาสสิกข้อต่อไป "TCP ต่างกับ UDP อย่างไร?"

ซึ่งผมตอบได้โดยไม่มีปัญหา ... จากนั้นก็มาถึงคำถามที่ทำให้ผมรู้สึกว่า "ผมดวงดีเสียนี่กระไร!!"

เคนถามว่า "ถ้าจะเขียนโปรแกรมภาษา C ให้เปิด TCP หรือ UDP connections ต้องทำอย่างไรบ้าง? ช่วยอธิบายทั้งกรณีที่เราเป็นฝ่าย client และกรณีที่เราเป็นฝ่าย server"

ผมตอบกลับทันทีว่า "ผมเปิด man page ครับ .. ผมจำหลักการคร่าวๆ และชื่อคำสั่งได้ แต่ผมจำรายละเอียดของคำสั่ง, ลำดับพารามิเตอร์, และวิธีการสะกดชื่อ struct และ constant ต่างๆ ไม่ได้ .. คุณคงเข้าใจว่าของพวกนี้เราเขียนครั้งเดียวสำหรับแต่ละโปรเจก ไม่ได้จำเป็นต้องมาเขียนบ่อยๆ เหมือนคำสั่ง write, read, sendto, recvfrom ซะเมื่อไหร่" ... ผมยิ้ม และทำหน้าเหมือนจะบอกเขาว่า "คำถามของคุณมันไม่ค่อยแฟร์นะจ๊ะ"

เคนแก้ตัวทันทีว่า "เปล่าๆ ผมไม่ได้ต้องการให้คุณเขียน code, ผมแค่ต้องการให้คุณอธิบายวิธีการคร่าวๆ นั่นแหละ เวลาผมเขียน code ผมก็เปิด man page เหมือนกัน ผมเข้าใจคุณ แค่อธิบายเท่าที่คุณพอรู้มาก็พอ"

ฮ่ะๆๆ เสร็จผม.. เคนหารู้ไม่ว่าที่ผมบอกไปว่าผมลืมรายละเอียดต่างๆ ไปแล้วนั้นไม่ได้เป็นความจริงเสียทั้งหมด มันจริงอยู่ที่ว่าผมลืมคำสั่งพวกนั้นไปหมดแล้ว ลืม "หลักการคร่าวๆ" ที่ว่าด้วยซ้ำไป! แต่เมื่อคืนนี้ เมื่อคืนนี้เองที่ผมไปเป็นติวเตอร์ คุณเคทและคุณอัลลี่ (นักเรียนของผม) ถามผมด้วยคำถามแบบเดียวกัน!!! ต่อไปนี้เป็นบทสนทนาที่เกิดขึ้นเมื่อคืนวาน..

เคท: "ม็อค วันนี้เรานั่งอยู่ทั้งวัน ทำอะไรไม่ได้เลยเพราะไม่รู้จะเปิด connection อย่างไร คุณช่วยบอกเราหน่อยได้ไหม?"

ผมอึ้ง! ไม่ใช่อึ้งว่าเขาทำไม่ได้ (เพราะเมื่อปีที่แล้วผมเองก็ทำไม่ค่อยได้) แต่อึ้งว่าเขานั่งอยู่ทั้งวันเพื่อรอการช่วยเหลือ ทำไมเขาจึงไม่พยายามค้นหาคำตอบจากแหล่งอื่นด้วยตนเอง?!?

ผมตอบเคทไปว่า "บอกตรงๆ ผมเองก็ไม่รู้ เพราะเคยเขียนเมื่อนานมาแล้ว แต่ผมรู้ว่าผมจะหาคำตอบได้อย่างไร คุณไม่ลองหาดูเองบ้างหรือ? ลองดูในหนังสือสิ" [ผมโหดไหมครับ?]
เคทบอกว่า "หนังสืออยู่ที่บ้าน"
ผมเลยบอกว่า "งั้นก็ดู man page"
เคทตอบว่า "ไม่รู้จะดูคำสั่งชื่ออะไร"
ผมตอบ: "google ดูสิ"
เคท: "จะ search หาคำว่าอะไรยังไม่รู้เลย"

ผมคิดในใจ "โอ...บัดซบ ใช้ google ยังใช้ไม่เป็น เฮ้อ!..เธอ" [ผมไม่ได้พูดออกไป] แล้วตัดสินใจว่า ถ้าเป็นขนาดนี้ก็คงต้องช่วย google ให้จริงๆ ซะแล้ว [ผมใจดีไหมครับ?]

ผมหาคำตอบจาก google แล้วก็อธิบายให้เคทและอัลลี่ฟังถึงวิธีการเปิด connections แบบต่างๆ, structures ต่างๆ ที่ต้องใช้ และ parameters ของฟังก์ชั่นต่างๆ ที่เกี่ยวข้อง -- ความรู้เหล่านี้ผมก็เพิ่งได้เรียนรู้ใหม่ไปพร้อมๆ กับสองคนนั้นเหมือนกัน!

แล้ววันนี้ผมก็ต้องนึกขอบคุณเคทและอัลลี่ ที่ทำให้ผมได้นำคำตอบจาก google ที่ผมเพิ่งค้นหาให้พวกเธอเมื่อคืนวาน มาเป็นคำตอบให้กับ Google ซึ่งถามผมในวันนี้!!! -- อย่างนี้เขาเรียก "อัฐ gooฯ ซื้อขนม gooฯ"

ผมตอบเคนไปด้วยรายละเอียดทุกส่วนทุกตอนที่ผมจำได้ขึ้นใจ (ก็แหม..เพิ่งอ่านมาเมื่อวาน) เคนทำท่าอึ้งๆ แล้วบอกว่า "อ้าว โถ่! คุณก็รู้หมดทุกรายละเอียดนี่หว่า! อย่างนี้ไม่เรียกว่าคร่าวๆ แล้ว!!" ผมคิดว่าเคนคงจะตกใจเหมือนกันที่ผมตอบได้ละเอียดและฉะฉานขนาดนั้น -- ดั่งมี man page อยู่ตรงหน้า (ให้ผมตอบใหม่ตอนนี้ ผมก็ตอบไม่ได้เหมือนวันนั้นแล้ว!)

เคนดูจะ happy ในการสนทนาของเรา ซึ่งก็ทำให้ผม happy และผ่อนคลายไปด้วย เขาถามต่อไปถึงโปรเจกต่างๆ ที่ผมเคยทำมาและเขียนไว้ใน resume และเมื่อเขาเห็นว่าผมเคยทำกิจกรรมในสมาคมนักเรียนไทยฯ เขาก็พูดในสิ่งที่ผมอึ้ง [อีกแล้ว] ว่า "Sawasdi krab" ... เขาบอกว่าเขาพูดไทยได้ "nid noi"

เขาคงเคยมีเพื่อนเป็นคนไทยตอนเรียนอยู่ที่ CMU

เวลาเหลืออีก 5 นาที เขาบอกว่าเขาไม่รู้จะถามอะไรแล้ว เรามีอะไรจะถามเขาไหม

ผมตอบว่า "ผมก็ไม่มีอะไรจะถามเหมือนกัน แค่อยากจะบอกว่า ... blahๆๆๆ [ชื่นชม google และโฆษณาตัวเองต่างๆ นาๆ ว่าตัวเองมีความกระตือรือร้น/อยากทำอะไรใหม่ๆ/ฯลฯ (คำพูดมาตรฐานต่างๆ นานา)]"

และประโยคสุดท้ายของผม: "อ้อ... แค่ต้องการจะให้แน่ใจว่าเราเข้าใจกันถูกต้อง ผมสมัครตำแหน่ง intern (นักศึกษาฝึกงาน) นะครับ ไม่ใช่ full-time (พนักงานประจำ) เพราะผมตั้งใจจะเรียนต่อ PhD"

สิ่งที่ตามมาคือความตกใจของเคน "อ้าว ฮึ้ย ... ตายหละ ผมเข้าใจผิดนะเนี่ยะ ผมนึกว่าคุณสมัคร full-time" แล้วเขาก็ไปเรียกคุณ เคลลี่ ผู้ซึ่งมีหน้าที่จัดการประสานงานมาแจ้งข่าวให้ทราบ คุณเคลลี่ก็ตกใจเหมือนกัน แล้วบอกว่า "โอ โน.. ช่วงนี้เราตั้งใจจะสัมภาษณ์เพื่อรับสมัครแบบ full-time เท่านั้น การสัมภาษณ์เพื่อ internship จะมีขึ้นในเดือน ม.ค. ปีหน้า!"

ผมขอโทษขอโพยเขาใหญ่เลยที่ทำให้เข้าใจผิดตั้งแต่ต้น แต่ก็แอบบอกเขาไป (โดยสุภาพ นิ่มนวล) เหมือนกันว่า "ขอโทษด้วยจริงๆ ครับที่ทำให้เสียเวลาและทำให้เพื่อนคนอื่นเสียโอกาส แต่คุณติดต่อผมมาเองนี่หว่า แล้วก็ไม่ได้ถามผมสักคำว่าจะสมัครตำแหน่งอะไร ผมก็กรอกไปในใบสมัครที่ให้คุณไปในวันนี้แล้วว่าผมต้องการ internship" ... และขอร้องเขาว่า "หวังว่าคุณจะไม่โยนใบสมัครของผมทิ้งนะครับ :)"

คุณเคลลี่ยิ้มตอบ แล้วบอกว่า "เราจะเก็บมันไว้แน่นอน รวมทั้งผลการสัมภาษณ์วันนี้ด้วย เราจะแจ้งให้คุณทราบภายในหนึ่งสัปดาห์"

ผมขอบคุณเคนและคุณเคลลี่ แล้วเดินกลับบ้านมาด้วยความประทับใจ วันนี้ไม่ว่าผลการสัมภาษณ์จะเป็นอย่างไร เขาจะโยนใบสมัครของผมทิ้งหรือไม่ก็ไม่สำคัญ แค่ได้คุยกับ engineers ของ Google ถึงสองคนอย่างดุเด็ดเผ็ดมันก็ถือว่าเป็นเกียรติเกินพอแล้ว และประสบการณ์การสัมภาษณ์งานครั้งแรกในชีวิตของผมครั้งนี้ก็คงยากที่จะลืมเลือน (กระนั้นผมก็ยังกลัวว่าจะลืม จึงมาเขียนบันทึกฉบับนี้เก็บไว้เตือนความจำ แหะๆ)

ห้าวันถัดมา (เร็วกว่าที่สัญญาไว้) คุณเคลลี่อีเมลล์มาบอกว่า "เนื่องจากคุณไม่ได้ต้องการสมัคร full-time เราจะติดต่อคุณอีกทีในเดือนมกราคม แล้วเราค่อยคุยกัน ขอให้โชคดี"

อีเมลล์มันฟังดูแปลกๆ ดูไม่ออกว่าดีหรือร้าย ผมจึงเมลล์กลับไป (ภายใน 4 นาที) เพื่อถามให้แน่ใจว่า "ขอบคุณครับที่ติดต่อกลับมา ถ้าคุณไม่รังเกียจ ช่วยบอกหน่อยได้ไหมว่าการสัมภาษณ์ครั้งที่ผ่านมานั้นเป็นไปด้วยดีหรือไม่? แต่ไม่ว่าจะเป็นอย่างไรผมหวังเป็นอย่างยิ่งว่าจะได้มีโอกาสคุยกับ Google อีกครั้ง"

หกนาทีถัดมา คุณเคลลี่ตอบมาสั้นๆ ว่า "มันผ่านไปด้วยดี ม็อค, ไม่งั้นดิฉันคงไม่สัญญาว่าจะให้คนของเราติดต่อคุณอีกครั้งในเดือนมกราฯ :)"

อีเมลล์ฉบับนั้นทำให้ผมนอนยิ้มได้ทั้งคืน ความรู้สึกเหมือนมีผู้หญิงมาให้ความหวัง (เอ๊ะ ก็จริง!) ขอเพียงแต่ว่านี่คงจะไม่ใช่เพียงหวังลมๆ แล้งๆ... คงไม่ใช่ "เพียงสัญญาปากเปล่า เพียงแค่ลมปากเป่า" อย่างที่เคยพบเจอ (เอ๊ะ!!! ผมกำลังพูดถึงเรื่องอะไร?) -- เอาหละน่า.. จะปากเปล่าได้อย่างไร ผมมีอีเมลล์เป็นหลักฐาน!

เรื่องราวจะเป็นอย่างไรต่อไป โปรดติดตามชม

7 Comments:

  • At 8:35 PM, Blogger keaw said…

    This comment has been removed by a blog administrator.

     
  • At 10:36 PM, Blogger keaw said…

    เฮอะๆ สงสัยถ้าเป็นเราสัมภาษณ์ เราคงตกแฮะ

    อ้อ หา anagrams จาก 32-bit unicode เราคงทำ bucket sort ดีกว่า O(n) ป่ะ

     
  • At 1:45 AM, Blogger mock said…

    ทำไงครับ? ได้ดีกว่า O(n) ด้วยเหรอครับ?

     
  • At 5:33 AM, Blogger keaw said…

    เปล่าๆ โทษทีเขียนไม่ดี

    anagrams จาก 32-bit unicode เราคงทำ bucket sort O(n) ดีกว่าหรือเปล่า

     
  • At 3:29 PM, Blogger mock said…

    Don't we need 4294967296 buckets?

     
  • At 8:53 PM, Blogger keaw said…

    ไม่นิ ต้องการ 256 แต่ทำ4ชั้นแค่นั้น

    เหมือนกับทำ bucket sort string แหละ

     
  • At 8:19 PM, Anonymous Anonymous said…

    mockgle.blogspot.com is very informative. The article is very professionally written. I enjoy reading mockgle.blogspot.com every day.
    instant cash loan
    payday loans

     

Post a Comment

<< Home