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.

Sunday, June 18, 2006

Important Note

This blog contains no confidential information about Google. Everything I wrote here before June 6, 2006, was based on my knowledge and experience prior to working at Google. Since June 6, 2006, as an intern, I have made a confidentiality agreement with Google; therefore, I will not write anything about Google if it has not already been known to the public.

The only reason this blog is in Thai is that I want my family and friends in Thailand to read it. Just for the peace of mind, from now on I will (try to) include a short paragraph in English describing what I am writing about for each blog entry. Trust me, I know the rules and I love Google; I certainly don't want to leak any inside information to Google's competitors ;)

Saturday, February 04, 2006

[5] The Next Step - ก้าวต่อไปของสองเรา

อยู่ระหว่างการเขียน โปรดอ่านตอนเก่าไปก่อนนะครับ
หากต้องการอ่านต่อไวๆ โปรดคอมเมนท์เพื่อให้กำลังใจคนเขียน จะได้รีบเขียนไวๆ ครับผม :)

Friday, February 03, 2006

[4] Long distance - ทางไกล

เสียงโทรศัพท์ของผมดังขึ้นอีกครั้งเมื่อตอนบ่ายๆ ของวันที่ 8 ม.ค. 06 เป็นโทรศัพท์ทางไกลจากเมาเท่นวิว แคลิฟอร์เนีย ใช่แล้ว เขาคือคุณอาร์ทูโร่ที่ผมเฝ้าคอย

คุณอาร์ทูโร่แนะนำตัวว่าเขาเป็นหัวหน้าทีมเอ็นจิเนียร์ฝ่าย Billing & Payment System เรียกได้ว่าเป็นฝ่ายหารายได้มาเลี้ยงบริษัทนั่นเอง สตางค์ทุกดอลล่าร์ทุกเซนต์ที่ Google ได้รับจากค่าโฆษณา [https://www.google.com/adsense/], ค่าขายวิดิโอใน video store [http://video.google.com/], หรือค่าสมาชิก Google Earth Plus/Pro [http://earth.google.com/] นั้นล้วนต้องผ่านระบบที่ทีมของคุณอาร์ทูโร่สร้างขึ้นมา

ว้าว! คิดแล้วคงเป็นทีมที่รวยไม่น้อยเลย

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

แน่นอนผมเลือกโปรเจกล่าสุดที่กำลังทำอยู่ในปัจจุบัน

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

ผมขอไม่กล่าวถึงโปรเจกของผมในที่นี้ (เพราะมันยังไม่เสร็จ) แต่สิ่งที่ผมตอบไปนั้น ผมพยายามอธิบายให้เขาฟังว่าผมได้รับแรงบันดาลใจมาจาก gmail ของ Google นั่นเอง ดูคุณอาร์ทูโร่จะชอบใจเมื่อผมบอกเขาว่าผมใช้ gmail มาราวปีครึ่งแล้ว ผมฟอร์เวอร์ดอีเมลล์ทุกฉบับของผมจากแอดเดรสอื่นเข้า gmail เพราะสามารถจัดการง่าย ค้นหาง่าย และมีพื้นที่มหาศาล ใช้ทั้งชาติก็ไม่หมด (เพราะมันเพิ่มขึ้นเรื่อยๆ -- ถ้ายังไม่พออีกก็ขอ account ใหม่ ฮ่าๆๆๆ)

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

และนั่นก็คือจุดเด่น (feature) หนึ่งใน gmail ที่ผมใช้เป็นแรงบันดาลใจในโปรเจกของผม

คุณอาร์ทูโร่ดูจะชอบใจมาก (ใครๆ [ที่รักบริษัท] ก็คงชอบทั้งนั้นเมื่อเราบอกว่าผลิตภัณฑ์จากบริษัทของเขาเป็นแรงบันดาลใจให้กับเรา) แต่เขาไม่ตกหลุม ปล่อยให้ผมเลีย ...เอ๊ย.. ประจบ ..เอ๊ย.. กล่าวชื่นชม Google อยู่อย่างนี้ตลอด 45 นาทีหรอกครับ ไม่นานนักเขาก็เปลี่ยนเรื่องคุย

หลังจากโม้เรื่องโปรเจกตัวเองมานาน ผมเริ่มคอแห้ง ผมหยิบน้ำเย็นเจี๊ยบที่เตรียมไว้ขึ้นดื่มหนึ่งอึก

โดยไม่รีรอ เขาถามคำถามผมแบบตรงไปตรงมา ... แบบที่ทำให้ผมตั้งตัวแทบไม่ติด และแบบที่ทำให้ผมแทบสำลักน้ำอึกนั้น

"ตลอดชีวิตการเขียนโปรแกรมของคุณ มีบั๊กตัวใดที่น่าสนใจมากที่สุด?"

คำถามนี้หินมาก หินกว่าคำถามใดๆ ที่เคยเจอมาทั้งหมด และเป็นคำถามเดียวที่ผมไม่คาดคิดว่าจะพบเจอ

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

สิ่งที่ผมพูดไปนั้นก็เพียงเพื่อให้มีคำตอบแก้เก้อไปเฉพาะหน้าเสียก่อน ระหว่างที่พูดอยู่นั้นเราก็สามารถใช้สมองอีกส่วนหนึ่งในการคิดค้นหาคำตอบที่แท้จริงได้ เทคนิคการพูดเช่นนี้ภาษาไทยอาจเรียกว่าการ "เตะถ่วง" ภาษาอังกฤษอาจเรียกว่า ... เอ่อ ... bullsh**

เวลาผ่านไปสักพักผมก็ได้คำตอบว่า "ผมคิดว่า 'ความผิดพลาด' ที่น่าสนใจที่สุดที่เคยพบเจอในการเขียนโปรแกรม โดยเฉพาะในโปรเจกที่ผมกล่าวถึงนั้นก็คือความผิดพลาดด้านโครงสร้างและการออกแบบ (design problem) เช่นเมื่อเราเขียนโมดูลหนึ่งไปแล้ว เขียนไปแทบเป็นแทบตาย ทดสอบแล้วถูกต้องทุกอย่าง โมดูลใช้ได้ดีเยี่ยม แต่พอจะเอาไปใช้จริงในโปรแกรมแม่กลับพบว่ารูปแบบการสนทนากับโมดูล (interface) ไม่เป็นไปในแบบที่โปรแกรมแม่ต้องการ ทำให้ต้องเลือกระหว่าง i) แก้ interface และอาจต้องเขียนโมดูลใหม่ หรือ ii) หาทางแก้ไขเฉพาะหน้าในโปรแกรมแม่ (workaround, hacking) ซึ่งเป็นกระบวนการที่เจ็บปวดมาก"

คุณอาร์ทูโร่บอกว่า "คำตอบคุณเยี่ยมมาก ผมเห็นด้วยกับคุณ ผมก็ประสบปัญหาเช่นนั้นบ่อยๆ เหมือนกัน ... แต่...เอ่อ.."

"แต่ในทางเทคนิคมันไม่จัดเป็น 'บั๊ก' ใช่ไหมครับ?" ผมพูดอย่างรู้ทัน .. รู้ทันว่าผมตอบไม่ตรงคำถาม!

"ครับผม" คุณอาร์ทูโร่ตอบ "ผมอยากได้คำตอบที่เป็นบั๊กทางเทคนิค ทางด้านการเขียนโปรแกรม ทางด้าน code ซะมากกว่า คุณพอจะให้ตัวอย่างได้ไหมครับ?"

ผมคิดหนัก และขอเวลาคิดอีก 2 นาที (คราวนี้ขอกันตรงๆ .. ไม่มีการบูลชิ*)

นี่คือสิ่งที่แล่นในความคิดผม "เวรกรรม บ้าเอ๊ย ถามมาได้ อุตส่าห์ตอบเลี่ยงแล้วเชียว โอย คิดไม่ออก คิดไม่ออก เอาอะไรดี? เอ้า ใจเย็นๆ ค่อยๆ คิด คิดดูซิเราเคยเขียน bug อะไรมาบ้าง? .. โอ้โห ร้อยล้านอย่าง เอ้า! ค่อยๆ พิจารณาทีละอย่าง มีอะไรบ้างล่ะ? .....hmmmm.... hmmm....hmm..... [ผ่านไปแล้ว 1 นาที] เฮ้ย! คิดไม่ออกซักอย่าง ทำไมสมองมันปิด มันมึนตึ้บอย่างนี้? เฮ่ออ แย่ละเว้ย แย่ละเว้ย ... ต้องตอบอะไรไปสักอย่างซะแล้ว เวลาจะหมดแล้ว ทำไงดี? ทำไง? ว๊าาาก จ๊ากกกกกกก"

ผมตอบกลับไป "segmentation fault" -- หวังว่าเขาจะเข้าใจว่านั่นคือคำตอบ ไม่ใช่ว่าเป็น error message ที่สมองของผมพิมพ์เข้าไปใส่ stderr หลังจากที่ต้อง dump core เพราะคิดหาคำตอบจน stack corrupted

[ผู้ที่ไม่เข้าใจย่อหน้าที่แล้ว: โปรดดีใจ...คุณปกติแล้ว]

แน่นอนครับ คำตอบเพียงแค่นั้นยังต้องการคำอธิบาย ผมก็จำไม่ค่อยได้แล้วเหมือนกันว่าวันนั้นผมอธิบายไปว่าอย่างไรบ้าง แต่บางประเด็นที่ผมยกขึ้นมาสนับสนุนความน่าสนใจของ segฯ fault ก็อย่างเช่น...
  1. segฯ fault เป็นสิ่งที่พบได้บ่อยที่สุดในการโปรแกรมใน C
  2. segฯ fault เป็นสิ่งที่ยังคงพบได้ แม้จะทดสอบโปรแกรมหลายครั้งแล้วก็ตาม
  3. หลายครั้ง segฯ fault นั้นยากที่จะ reproduce
  4. ไม่ใช่เรื่องง่ายที่จะหาว่าส่วนใดเป็นต้นเหตุของ segฯ fault เพราะแม้จะทราบว่าบรรทัดสุดท้ายก่อน segฯ fault คือบรรทัดไหน แต่ก็ไม่ได้หมายความว่าบรรทัดนั้นเป็น "ผู้ผิด" เสมอไป (แท้จริงแล้วกลับตรงกันข้าม -- บรรทัดนั้นมักไม่ใช่ผู้ผิด)
  5. การหา "ผู้ผิด" ในกรณี segฯ fault นั้นหมายถึงการไล่หาจุดที่อาจเป็นจุดเกิดเหตุทั้งหมดก่อนจะถึงบรรทัดที่ segฯ fault แต่ละจุดนั้นต้องใช้เหตุผลในการอธิบายให้แน่ใจว่าส่วนนี้ถูกต้องหรือไม่ (เช่น pointer นี้เป็น NULL ได้หรือไม่? ได้จัดสรรเมมโมรี่ไว้เพียงพอหรือเปล่า? เหลือที่ให้ null character หลังจบ string หรือยัง? ฯลฯ)
  6. จากประสบการณ์ในการติวเตอร์ เป็นการยากที่จะอธิบายให้โปรแกรมเมอร์มือใหม่เข้าใจ(และเชื่อ)ได้ว่า บรรทัดที่เกิด segฯ fault มักจะไม่ใช่บรรทัดที่ผิดพลาดเสมอไป ผมเคยเกือบต้องทะเลาะกับนักเรียนที่ผมติวมาแล้ว -- เพียงเพราะผมบอกว่า "การที่มันพังตรงนี้ไม่ได้หมายความว่ามันผิดตรงนี้ มันอาจเป็นกรรมเก่า" เขาหาว่าผมเชื่อในไสยศาสตร์

ผมไม่ทราบว่าคุณอาร์ทูโร่คิดกับคำตอบ (ที่สร้างขึ้นแบบ on-the-fly) ของผมอย่างไร -- ผมยังตื่นเต้นจนไม่ทันได้สังเกต แต่เขาบอกว่านั่นเป็นคำตอบที่ดี (แน่นอน เขาต้องพูดเช่นนั้นตามมารยาท) และชวนผมคุยเรื่องที่เป็น technical มากขึ้น

เขาอยากเห็นผมเขียนโปรแกรม ... ผมถามว่าจะเห็นได้อย่างไร เราคุยโทรศัพท์กันอยู่ เขาบอกว่าให้ผมเขียนในกระดาษก็ได้ เขียนเสร็จแล้วค่อยอ่านให้เขาฟัง

เขาบอกว่ามีโจทย์ที่น่าสนใจมาให้ข้อหนึ่ง ไม่ยาก -- เพียงแค่อาจต้องการสมาธิและความสามารถในการแปลงจากไอเดียให้เป็น code

ผมตื่นเต้นยิ่งนักว่าโจทย์นั้นจะเป็นอะไร?

คุณอาร์ทูโร่พูดว่า "สมมติว่ามี array A และ array B ทั้งคู่บรรจุตัวเลขอยู่คนละ n ตัว เรียงแล้วจากน้อยไปหามาก ผมต้องการสร้าง array C ขนาด 2n ที่บรรจุตัวเลขจาก A และ B เรียงตามลำดับจากน้อยไปหามาก ช่วยเขียนฟังก์ชันที่ทำอย่างนั้นให้หน่อย ภาษาอะไรก็ได้"

"นี่ก็คือฟังก์ชั่น merge ใน merge sort นี่ครับ? เป็นอัลกอริธึมมาตรฐาน" ผมเอ่ยถาม .. เพื่อให้แน่ใจว่าเขาต้องการให้ผมเขียนสิ่งนี้จริงๆ

"ใช่ครับ เขียนให้ผมดูหน่อย คุณไปเขียนในกระดาษสัก 5 นาทีก่อนก็ได้" คุณอาร์ทูโร่ตอบ

อ้าว .. ผมบอกไปแล้วนะว่าผมรู้จักสิ่งที่เขาจะให้ผมเขียนแล้ว และ เหอะๆๆๆ วะฮ่าๆๆๆ ถ้าท่านผู้อ่านไม่ได้อ่านข้ามบทคงจะทราบว่าในบทที่แล้วผมเพิ่งจะเขียน merge sort ไปหมาดๆ!! อยากจะบอกว่าไม่เพียงแต่ไอเดียที่ผมยังจำได้ แต่ code ดังกล่าวยังคงตราตรึงอยู่ในสมอง

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

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

คุณอาร์ทูโร่ถามกลับมาคำเดียว "คุณเคยทำแล้วเหรอครับ?"

ผมตอบในใจ: "ป้าดโธ่! เคยทำไม่รู้กี่สิบครั้งแล้ว บอกแล้วไงนี่มันอัลกอฯ มาตรฐาน"

แต่จริงๆ ผมตอบไปว่า: "ก็แน่นอนครับ ต้องเคยทำมาบ้างแล้วในคลาสอัลกอริธึมซึ่งเรียนตอนปีหนึ่ง ตอนนี้ก็เลยยังพอมีไอเดียอยู่ในหัวน่ะครับ"

คุณอาร์ทูโร่ถามต่อไป "เอาหละครับ ดีมาก ผมเชื่อว่าสิ่งที่คุณบอกมามันคือ code แล้ว และผมเชื่อว่ามันถูกต้องครับ คราวนี้คุณช่วยอธิบาย running time ของ code คุณด้วย"

"O(n) ครับ" ผมตอบ และแน่นอน อัลกอริธึมมาตรฐานย่อมมีคำอธิบายมาตรฐาน ผมอธิบายไปว่าทำไมมันถึงเป็น O(n) อย่างที่โฆษณา

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

ผมตอบว่า "อย่างไรเสียมันไม่มีทางดีกว่า O(n) ครับ ยังไงคุณก็ต้องคัดลอกข้อมูลทุกตัวไปไว้ในที่ใหม่ ยกเว้นแต่ว่าคุณจะใช้ linked list แทน array"

คุณอาร์ทูโร่ตอบว่า "ใช่เลย! เราต้องใช้ linked list เอาหละ สมมติว่าทั้ง A และ B เป็น linked list คุณจะแก้ปัญหานี้อย่างไร? ... สมมติว่าเราอนุญาตให้คุณแก้ไขลิสต์ A และ B ได้ จะเก็บคำตอบไว้ใน A หรือ B ก็ได้"

ผมขอเวลาคิดสักพัก เอ.. มันจะเร็วไปกว่า O(n) ได้อย่างไร? ถ้าหากเอาของใน B ไปค่อยๆ ใส่ไว้ใน A ทีละตัว มันก็จะเป็น O(size A * size B) มิแย่กว่าเดิมหรือ? ... อ้อ ไม่ใช่ซะทีเดียว เพราะจำนวนการเขียนข้อมูลนั้นเท่ากับขนาดของ B (ซึ่งเล็กกว่า A มาก) และจำนวนการอ่าน/เปรียบเทียบข้อมูล (ซึ่งเร็วกว่าการเขียนมาก) นั้นในกรณีที่แย่ที่สุดจริงๆ ก็จะราวๆ ขนาด A คูณ ขนาด B ดังนั้นนี่อาจเป็นคำตอบที่ดีก็ได้

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

นี่เป็นอีกหนึ่งฟังก์ชั่นมาตรฐานที่เรียนแล้วเมื่อปี 1 (ไม่ว่าในคลาส 15-111 ซึ่งเป็นจาวา หรือ 15-113 ซึ่งเป็นซี) มีนามว่า "insert_in_order()"

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

คราวนี้ผมเลือกที่จะเขียนด้วยจาวา และมันก็ผ่านไปได้ด้วยดี (แม้จะไม่แคล่วคล่องว่องไวจนน่าสงสัยเท่า merge sort) ในใจผมคิดว่าทำไมผมจึงโชคดีอย่างนี้ เจอแต่โจทย์ที่เคยทำแล้ว (ยกเว้นแต่เรื่อง segฯ fault นั่น)

ผมคาดว่าคุณอาร์ทูโร่คงจะชอบ Java คำถามต่อมานั้นเขาถามผมว่า "คุณถนัด Java ใช่ไหมครับ? ผมขอถามคำถามเกี่ยวกับ OOP ใน Java ซะหน่อย"

และนี่คือคำถาม: "abstract class ต่างกับ interface อย่างไร?"

นี่ก็เป็นคำถามมาตรฐานอีกคำถามหนึ่ง ผมตอบกลับไปตามที่ผมทราบ ความจริงแล้วคำถามนี้เคยมีคนถามอยู่บ่อยๆ จึงไม่ใช่เรื่องยากที่จะอธิบาย (แต่ก็ขอไม่อธิบายในที่นี้เนื่องจากที่นี่ไม่ใช่ java tutorial)

ดูท่าทางคุณอาร์ทูโร่จะพึงพอใจกับคำอธิบาย กระนั้นก็ยังไม่วายถามอีกว่า "เมื่อไหร่จะเลือกใช้ abstract class เมื่อไหร่จะเลือกใช้ interface ล่ะครับ?"

ผมตอบไปว่า "คำถามนี้ในแง่หนึ่งเป็นคำถามเชิงปรัชญา ซึ่งยากที่จะตอบได้สมบูรณ์ แต่หากมองในแง่ของการนำมาใช้งานแล้วละก็ ผมมักจะเลือกใช้ interface ทุกครั้งที่เป็นไปได้เพราะแต่ละคลาสสามารถ implement ได้หลายๆ interface พร้อมๆ กัน ในขณะที่สามารถ extend (เป็น subclass ของ) abstract class ได้เพียงคลาสเดียว แต่ abstract class ก็มีความสามารถที่ interface ไม่มี นั่นคือเราสามารถ implement บาง method ที่ทุก subclass ต้องใช้ร่วมกันได้ทันที" [ฟังแล้วงงไหม? -- ผมก็งง]

คุณอาร์ทูโร่เป็นคนต้องการเห็นอะไรชัดเจน เป็นรูปธรรม จึงเอ่ยว่า "อธิบายได้ดีครับ คราวนี้ช่วยยกตัวอย่างกรณีที่ชัดๆ สักกรณีหนึ่งที่คุณจะเลือกใช้ abstract class แทนที่จะใช้ interface"

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

ผมขอเวลาคิด 1 นาทีเช่นเคย

แล้วผมก็ได้ตัวอย่างนี้มา "สมมติว่ามีสัตว์เลี้ยงอยู่สองชนิดคือหมาและแมว สมมติว่าหมาและแมวเดินท่าเดียวกันแต่ร้องเสียงไม่เหมือนกัน ผมสามารถสร้าง abstract class ชื่อ สัตว์เลี้ยง ขึ้นมาแล้วประกาศ method ร้อง() เป็น abstract เอาไว้ ในขณะที่ผมสามารถ implement method เดิน() ไปได้เลย จากนั้นผมก็สร้างคลาส หมา ให้ extends สัตว์เลี้ยง แล้วเขียน method ร้อง() ว่า {ออกเสียง("โฮ่งๆ");} ส่วนแมวนั้นก็ extends สัตว์เลี้ยงเช่นกันแต่มี method ร้อง() เป็น {ออกเสียง("เมี้ยวๆ");} ในกรณีนี้ผมเขียน method ร้อง() สองครั้ง แต่เีขียน เดิน() แค่ครั้งเดียว"

หมดเวลาพอดี คุณอาร์ทูโร่ก็บอกว่าหมดคำถามพอดี "คุณมีคำถามอะไรหรือเปล่า?" เขาถามทิ้งท้าย

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

คุณอาร์ทูโร่ท่าทางดีใจเล็กน้อยที่ทราบว่าเราเตรียมตัวค้นประวัติเขามาอย่างดี เขาบอกว่า "นั่นคือสิ่งที่ผมทำแล้วสนุก .. เอ่อ ผมหมายความว่า ผมทำงานใน Google ก็สนุก แต่ตอนวันหยุดผมก็ไปหาความสนุกอีกแบบด้วยการปีนเขา ชีวิตผมมีแต่ความสนุก ชีวิตชาว Google ทุกคนก็คงจะเป็นอย่างนั้นเหมือนกัน :)"

"ผมเชื่อเช่นนั้นครับ นั่นคือเหตุผลที่ผมอยากทำงานที่ Google ผมเชื่อว่าการเขียนโปรแกรมนั้นสนุก ยิ่งถ้าเป็นการเขียนให้ Google แล้วละก็ [...บทประจบมาตรฐาน...ความยาว 1 นาทีครึ่ง...]" ผมตอบ

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

ผมเข้าใจว่าขั้นตอนต่อไปคงเป็น "ขอเชิญคุณบินมาสัมภาษณ์รอบต่อไปที่ Mountain View" หรือไม่ก็ "ขอบคุณที่สนใจใน Google แต่เราตัดสินใจรับคนอื่นไปแล้ว โปรดสมัครใหม่ในปีหน้า" ผมหวังว่าจะเป็นแบบแรก

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

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

[3] Waiting - การรอคอย

เวลาผ่านล่วงเลยไปนานจนกระทั่งปิดเทอมเมื่อช่วงกลางเดือนธันวา 05 ในช่วงนั้นผมมัววุ่นกับการสมัครมหาวิทยาลัยต่างๆ (เพื่อหาที่เรียนต่อ PhD) ในขณะเดียวกันก็วางแผนการเที่ยวกับเพื่อนๆ ว่าปีใหม่นี้จะไปเที่ยวไหนกันดี ผลสรุปคือไปเที่ยว San Francisco และเมืองใกล้เคียง (เช่น LA, Lake Tahoe, Yosemite, Las Vegas) [อ่านเรื่องเล่าจากทริปนี้ได้ที่ http://mock.suwannatat.com/journal/sftrip/]

เมือง San Francisco นี้อยู่ใกล้ๆ กับเมือง Mountain View ซึ่งเป็นที่ตั้งของ Google (สำนักงานใหญ่) ผมหวังนิดๆ ว่าจะได้มีโอกาสผ่านไปเห็นสักหน่อยว่าหน้าตาเป็นอย่างไร

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

Google สัญญากับผมว่าจะติดต่อกลับมาในเดือน ม.ค. ผมตั้งตารอเป็นอย่างมาก และแล้วเมื่อ 19 ธ.ค. (ก่อนเวลานัดหมายตั้งครึ่งเดือน) ผมก็ได้รับอีเมลล์จากคุณ เจนนิเฟอร์ บอกว่าอยากจะนัดสัมภาษณ์ผมทางโทรศัพท์เป็นเวลา 45 นาที ในระหว่างวันที่ 4-6 ม.ค. 06 ขอให้ผมตอบกลับไปว่าผมว่างช่วงเวลาไหน

ผมตอบกลับไปว่าว่างทุกวัน-ทุกเวลา อยากโทรมาตอนไหนโทรได้เลย ขอเพียงให้บอกล่วงหน้าสักหน่อยจะได้เตรียมตัวเตรียมใจ คุณเจนนิเฟอร์ตอบว่าจะให้คุณอาร์ทูโร่ (วิศวกรคนหนึ่ง) โทรหาผมวันที่ 6 ม.ค. เวลา 5:30pm (ตามเวลาเมือง Pittsburgh)

ผมตอบตกลงกับวันและเวลาดังกล่าว ความจริงเป็นเรื่องดีเพราะผมจะเที่ยวอยู่ที่แคลิฟอร์เนียจนถึงวันที่ 3 ม.ค. พอกลับมาก็จะมีเวลาพักผ่อน 2 วันก่อนสัมภาษณ์

*** น้องๆ ที่อายุต่ำกว่า 21 ปี (สำหรับอเมริกา) หรือ 18 ปี (สำหรับประเทศไทย) โปรดข้ามย่อหน้านี้ไป ***
คืนวันที่ 2 ม.ค. ผมและเพื่อนๆ เดินทางจาก Los Angeles กลับสู่ San Francisco (เพื่อขึ้นเครื่องบินกลับ Pittsburgh ในวันรุ่งขึ้น) ระหว่างที่พักในโรงแรมพวกเรามองเห็นขวดขวดหนึ่ง ภายในบรรจุของเหลวบางอย่างที่พวกเรายังดื่มกันไม่หมด เพื่อไม่ให้มันหนักกระเป๋าในตอนขากลับเกินไปนักพวกเราจึงตัดสินใจแบ่งๆ กันดื่ม คนละอึกสองอึก ของเหลวยังไม่หมดขวดแต่พวกเราก็หน้าแดง และวิงเวียนศีรษะกันไปคนละเล็กละน้อย (ถึงปานกลาง)

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

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

ไปขับรถดีไหม? -- ไม่ดีแน่! ผิดกฏหมาย และยังอาจทำลายชีวิตตัวเองและคนอื่น

ผมต้องหากิจกรรมที่ต้องใช้สมาธิและความรอบคอบ แต่ผลเสียหายไม่เป็นอันตรายต่อชีวิตและทรัพย์สิน

ผมเปิดคอมพิวเตอร์ เริ่มต้นเขียนอะไรบางอย่างลงไป ผมคิดว่างานเขียนนี้แหละเป็นงานที่ต้องการสมาธิและความรอบคอบ ถ้าไม่เมาผมควรจะเขียนได้ดี แต่ถ้าเมาจริงคงเขียนไม่ได้แน่ เวลาผ่านไปสักพัก (ใหญ่ๆ) ผมได้สิ่งนี้ออกมา (ตัดมาเฉพาะบางส่วน, จัดบรรทัดใหม่เพื่อให้ประหยัดพื้นที่)
int b[MAXCELLS];
void merge(int* a, int l, int m, int r) {
int i1, i2, j;
i1 = l; i2 = m+1; j = l;
while (i1<=m && i2<=r) {
if (a[i1] < a[i2]) b[j++] = a[i1++];
else b[j++] = a[i2++];
}
while (i1<=m) b[j++] = a[i1++];
while (i2<=r) b[j++] = a[i2++];
for (j=l; j<=r; j++) a[j] = b[j];
}

void msort(int* a, int l, int r) {
int m = (l+r)/2;
if (l>=r) return;
msort(a,l,m); msort(a,m+1,r); merge(a,l,m,r);
}
จากการช่วยทดสอบโดยฆนัท (ซึ่งไม่ได้ดื่ม -- ส่วนจะเมาจากอย่างอื่นหรือเปล่าผมไม่ทราบ) พบว่าน่าจะเป็น merge sort ที่ถูกต้องพอสมควร ... ผมสรุปว่าตัวเองไม่เมา ;)

หมายเหตุ: เดิมทีผมตั้งใจจะเขียน quick sort แต่เพื่อนท้วงติงว่าผมเคยเขียนบ่อยแล้ว (เขากล่าวหาว่าผมท่อง code ได้) และเมื่อปาร์ตี้คราวที่แล้วผมก็เพิ่งเขียนไป ... ผมจึงเสนอเขียน merge sort (ซึ่งไม่เคยเขียนมาหลายปีแล้ว -- และแน่นอน ยังไม่เคยเขียนใน C) ในคราวนี้ และคราวหน้าผมจะเขียน heap sort บ้าง (หลังจากนั้นคงเป็น dijkstra's shortest path algorithm)

เช้าตื่นขึ้นมาปวดหัวเล็กน้อย ผมบอกเพื่อนๆ ว่าผมไม่เมา ผมพิสูจน์แล้ว แต่ดันไม่มีใครเชื่อ กลับใส่ร้ายป้ายสีหาว่าผม "เมาแล้วเนอร์ด" บ้าง "เมาแล้ว geek" บ้าง -- ล้วนแต่เป็นข้อกล่าวหาที่ไร้ความยุติธรรมโดยสิ้นเชิง (ผมไม่ได้เมา, ผมไม่ได้ nerd, ผมไม่ได้ geek ... จริงๆ นะ พับผ่า! จะต้องให้ผม implement อีกกี่ algorithms จึงจะเชื่อ?!)

อ้าว.. นอกเรื่องไปนาน ถึงไหนแล้ว? อ้อ! ถึงเมื่อคืนวันที่ 2 ม.ค.

วันที่ 3 ผมเที่ยว San Franฯ ต่ออีกวันแล้วบินกลับถึง Pittsburgh เช้าวันที่ 4 เนื่องจากทราบชื่อของผู้ที่จะโทรมาสัมภาษณ์าผมล่วงหน้า ผมจึงจัดแจงเตรียมตัวโดยการค้นหาประวัติและเว็บส่วนตัวของคุณ อาร์ทูโร่ เครสโป้ ... และแน่นอน อุปกรณ์ที่ผมใช้ค้นหาก็คือ google.com นี่เอง

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

โบราณว่า รู้เขา-รู้เรา รบร้อยครั้งชนะร้อยครา

วันที่ 6 ม.ค. 06 ก่อนเวลานัด 15 นาที ผมปิดห้อง, แปะป้าย "ห้ามรบกวน", ปิด msn, เติมน้ำเย็นเต็มแก้ว (เผื่อคอแห้ง), เตรียมดินสอ ยางลบ กระดาษทด เครื่องคิดเลข, ฯลฯ เรียกได้ว่าเตรียมพร้อมรอการสัมภาษณ์ทางโทรศัพท์ครั้งนี้อย่างเต็มที่

เวลาผ่านไป 15 นาที ได้เวลานัดแล้ว ผมนั่งรออยู่หน้าโทรศัพท์, ผ่านไปครึ่งชั่วโมง เฮ่ย ทำไมยังไม่โทรมาซะที?! ผมไม่รอช้า รีบอีเมลล์ไปหาคุณอาร์ทูโร่และคุณเจนนิเฟอร์ทันที สอบถามว่าเกิดอะไรขึ้น มีปัญหาในการติดต่อกับโทรศัพท์มือถือของผมหรือเปล่า, ผมส่งเบอร์โทรที่บ้าน และเบอร์โทรของพี่อัก (รูมเมทอาวุโสท่านหนึ่ง) ไปให้ เผื่อใช้เป็นเบอร์สำรอง

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

วันนี้วันศุกร์ เขาขอเลื่อนเป็นวันจันทร์ที่ 9 ม.ค. ผมตอบตกลงแต่โดยดี

ผมวางหูโทรศัพท์ ทำหน้าบูดเบี้ยว ในใจก็แอบคิด "หรือว่านี่เขาไปสัมภาษณ์คนอื่นแทนซะแล้ว? หรือว่าจะมีคนอื่นที่เขาสนใจมากกว่าเรา?" -- น่าน! คิดอย่างกับคนขี้หึงซะแล้วเรา :P

"หรือบาปกรรมจะส่งผลทันใจ? ที่ผมซวยในวันนี้เป็นผลจากการที่ผมผิดศีลเมื่อคืนวันที่ 2 หรือเปล่านะ?" ผมคิดในใจ [เปล่าครับ ผมไม่ได้หมายถึงข้อสาม]

ได้แต่หวังว่าคราวหน้าจะไม่ผิดนัดผมอีก ... เรื่องราวที่แท้จริงจะเป็นอย่างไร ต้องติดตามอ่านบทต่อไป

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 อีกครั้ง"

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

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

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

[1] Matching Services - เทศกาลจับคู่

เรื่องนี้มันเริ่มโดยไม่รู้ตัว ในงาน job fair ที่เรียกว่า Technical Opportunities Conference (TOC) เมื่อวันที่ 29 ก.ย. 05 งานนี้บริษัททางด้านเทคโนโลยีต่างๆ ไม่ว่าจะเป็น Google, Microsoft, Yahoo, Amazon, ฯลฯ ต่างก็มาตั้งบูธที่ Carnegie Mellon เพื่อเสาะแสวงหานักศึกษาฝึกงานและพนักงานใหม่ๆ จากมหาวิทยาลัยแห่งนี้

งานนี้ถูกทำให้น่าสนใจยิ่งขึ้นด้วยของที่ระลึกอันแปลกตาที่บริษัทต่างๆ นำมาแจกนักเรียนที่สนใจ ใครก็ตามที่เดินเข้าไปคุยกับคนในบูธของบริษัทไหน ก็มักจะได้ของที่ระลึก (เช่น ปากกา เสื้อยืด ขนม แม่เหล็ก ของเล่น ซอฟท์แวร์ ฯลฯ) จากบริษัทนั้น

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

ผู้คนในงานนี้ท่าทางเอาจริงเอาจังกันมาก ดูหน้าตา ท่าทาง การแต่งกาย การทำผมแล้ว เห็นได้ชัดว่าเตรียมตัวมาดีกันเกือบทุกคน ลักษณะการเข้าไปสนทนากับตัวแทน (representative) ของบริษัทต่างๆ นั้นเห็นได้ชัดว่าเตรียมตัวมาแล้วอย่างดี ทั้งในแง่ของเทคนิคการสนทนา และหลักวิชาที่ได้ร่ำเรียนมา

ก่อนเข้างานพบกล่องกล่องหนึ่ง เขาให้พวกเราหย่อน resume (ใบประวัติย่อ/ใบโฆษณาตัวเอง/ใบโม้) ไว้ในนั้นได้ และบริษัทต่างๆ อาจจะหยิบไปอ่านทีหลัง (ถ้าเขาสนใจจะอ่าน)

งานนี้มีบริษัทมากมาย ผู้คนก็มากมายเช่นเดียวกัน แต่สิ่งที่ผมมีไม่มากมายกลับเป็น "เวลา" เพราะอีกเพียงไม่ถึงชั่วโมงก็ต้องรีบไปเรียน ดังนั้นผมจึงต้องมองหาบริษัทที่[มีของแจก]น่าสนใจและแถวไม่ยาวเกินไปนัก ผมได้ไปคุยกับตัวแทนของ Amazon และ Microsoft แต่น่าเสียดายที่ไม่มีโอกาสได้คุยกับตัวแทนของ Google เพราะใครๆ ก็สนใจ Google แถวจึงยาวจนเกินจะรอ

หลังจากงานนั้นเป็นต้นมา ผมก็คิดว่าคงไม่มีโอกาสได้สมัครงาน Google อีกแล้ว ... ปลอบตัวเองว่าไม่เป็นไร สมัครไปเค้าก็คงไม่รับอยู่ดี :P

จนกระทั่งถึงวันหนึ่ง....

วันที่ 10 ต.ค. 05 ผมได้รับอีเมลล์ฉบับหนึ่งจากคุณ ฮานา คิม มีหัวข้อว่า "Interview w/ Google - Sign up today!" -- ฟังดูเหมือน spam ไหมครับ? ... ใช่แล้ว ผมก็นึกว่ามันเป็น spam เพราะผมไม่เคยติดต่อกับคุณฮานามาก่อนเลย และก็ไม่เคยไปสมัครงานกับ Google ไว้ด้วย เนื้อหาอีเมลล์ก็บอกว่า "เราจะปิดรับลงทะเบียนสัมภาษณ์ภายในเที่ยงคืนวันนี้" .. ผมก็คิดว่า "อะไรหว่า...ส่งผิดคนหรือเปล่า? จะให้ลงทะเบียนยังไงก็ไม่บอก!" แล้วผมก็ไม่ได้ตอบอีเมลล์ฉบับนั้น ปล่อยให้เวลาผ่านไปจนถึงวันรุ่งขึ้น

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

ผมไม่รีรอ รีบโทรกลับไปทันที เขาขอให้ผมส่ง resume และ transcript แบบไม่เป็นทางการไปให้ แล้วนัดสัมภาษณ์วันที่ 14 ต.ค. ผมขอบใจเขาใหญ่เลย ในใจก็นึกว่าแค่ได้พูดคุยกับ engineer ของ Google ก็เป็นเกียรติเกินพอแล้ว

คุณฮานายังบอกข่าวดีอีกว่า คืนวันที่ 13 (วันก่อนวันสัมภาษณ์) นั้น Google จะจัดงานเลี้ยงที่ร้านอาหารที่หรูและแพงแห่งหนึ่ง ขอเชิญเราไปร่วมงานด้วย จะได้พูดคุยแบบกันเองกับเจ้าหน้าที่/วิศวกร ของ Google

โอกาสดีเช่นนี้ผมจะพลาดได้ไง ... ผมศึกษาเส้นทางจาก Google Earth แล้วพิมพ์แผนที่ออกมา เช็ครอบรถเมลล์ แล้วก็เดินทางไปก่อนเวลาเกือบชั่วโมง ... และแล้วเหมือนเคราะห์ซ้ำ กรรมซัด ผมรู้สึกว่ารถเมลล์ที่นั่งมามันเลี้ยวไปผิดทาง ผมรีบลงในทันใด แล้วเดินย้อนกลับไปอีกถนนหนึ่ง ในใจก็คิดว่า "โชคดีนะเนี่ยะที่ลงรถเมลล์ทัน ไม่งั้นหลงชัวร์"

ผมเดินไปเรื่อยๆ .. ในแผนที่บอกว่า 1.1 ไมล์ เอาน่ะ แป๊บเดียวเอง ... เดินไปเรื่อยๆ เอ๊ะ ทำไมมันไม่ถึงซะที? ... เดินไปเรื่อยๆ เอ๊ะ ทำไมถนนมันดูแปลกๆ ไม่เหมือนในแผนที่? ... เดินไปเรื่อยๆ เอ๊ะ ทำไมถนนมันจบตรงนี้? แล้ว เอ๊ะ ทำไม ร้านอาหารที่ว่ามันหายไปไหน?

ไม่นานนัก ผมก็ อ้ออออออ!!!! ที่แท้รถเมลล์แล่นไปถูกทางแล้ว ผมเองที่เดินผิดทาง ... มองแผนที่ มองนาฬิกา และฟังเสียงท้องตัวเองร้อง .. ผมไปงานเลี้ยงไม่ทันแล้ว

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

แต่ด้วยความเห็นใจว่าโปรเจกของนักเรียนสองคนนั้น (ชื่อว่าคุณเคท และคุณอัลลี่) จะต้องส่งในเร็ววัน ผมสมควรจะไปช่วยดูๆ ให้หน่อยว่าเขามีปัญหาอะไรหรือเปล่า

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