รหัสการเขียนเป็นเพียงส่วนหนึ่งของกระบวนการสัมภาษณ์
การแก้ปัญหาเชิงตรรกะจริง ๆ แล้วเป็นเพียงส่วนหนึ่งของงานเขียนโค้ด
ผู้สัมภาษณ์ต้องการแน่ใจว่า:
คุณสามารถเขียนรหัส ผู้สมัครหลายคนที่มีประสบการณ์ด้านภาษาสิบปีไม่สามารถเขียนรหัสใด ๆ เลยและการทดสอบนี้มีวัตถุประสงค์เพื่อปฏิเสธผู้สมัครเหล่านั้น
คุณคิดถึงปัญหาก่อนที่จะเขียนโค้ด หลายคนจะข้ามไปที่คีย์บอร์ดเขียนโค้ดหลายสิบบรรทัดแล้วพบว่าพวกเขาเข้าใจผิดปัญหาเดิมเพราะพวกเขาไม่ได้คิดถึงเรื่องนี้
คุณสามารถปรับตัวเองเมื่อเขียนรหัส สมมติว่าคุณพบวิธีแก้ปัญหา แต่เมื่อคุณเริ่มใช้มันปรากฏว่าความคิดแรกของคุณไม่ใช่สิ่งที่ดีที่สุด คุณสามารถเปลี่ยนไปใช้โค้ดที่ดีกว่าได้อย่างรวดเร็วและท้ายที่สุดจะทำการเปลี่ยนรหัสที่คุณเขียนใหม่ในที่สุด
นี่ก็หมายความว่าการสัมภาษณ์ดังกล่าวควรมีการโต้ตอบมากกว่านี้ แทนที่จะพิมพ์ด้วยมือเดียวซื้อชุดแฮนด์ฟรีหรือโทรผ่าน Skype และใช้ชุดหูฟัง พิมพ์ตามที่คุณพิมพ์ในที่ทำงานในขณะที่แสดงความคิดเห็นและอธิบายสิ่งที่คุณทำ: มันจะกลายเป็นอึดอัดน้อยกว่ามาก
คุณเขียนโปรแกรมจับคู่เสร็จแล้วหรือยัง ถ้าใช่สถานการณ์การสัมภาษณ์คล้ายกันมากยกเว้นว่าผู้สัมภาษณ์อาจไม่ให้ความเห็นของเขาและคุณไม่ขอให้เขาสลับคีย์บอร์ดกับคุณเมื่อคุณทำเสร็จแล้ว
นี่คือตัวอย่างของปัญหาทางคณิตศาสตร์ล้วนๆและวิธีที่แสดงให้เห็นถึงทักษะที่ไม่ใช่ทางคณิตศาสตร์ของนักพัฒนาซอฟต์แวร์
ตัวอย่างที่ 1: การฝึกการเข้ารหัสอย่างง่าย
คุณต้องใช้เครื่องคำนวณหมายเลขฟีโบนักชีใน JavaScript คุณควรจะสามารถเปลี่ยนดัชนี ลำดับ Fibonacci เป็นไปตามกฎเหล่านี้:
- ตัวเลขสองตัวแรกของลำดับคือ 0 และ 1
- แต่ละหมายเลขที่ตามมาคือผลรวมของสองหมายเลขก่อนหน้า
ตัวอย่าง: F 0 = 0, F 1 = 1, F 2 = 1, F 3 = 2, F 10 = 55
คุณมีสามนาที
ที่นี่ผู้สัมภาษณ์ต้องการให้คุณคิดให้เร็วที่สุดค้นหาวิธีแก้ปัญหาและนำไปใช้อย่างรวดเร็ว แบบฝึกหัดดังกล่าวไม่เกี่ยวข้องกับสิ่งที่นักพัฒนาที่แท้จริงทำและใกล้เคียงกับสิ่งที่คุณสามารถพบได้มากที่สุดเมื่อทำการศึกษาระดับ CS แต่ผู้สัมภาษณ์ชอบสิ่งเหล่านี้ นอกจากนี้ข้อ จำกัด ด้านเวลาทำให้เป็นไปไม่ได้ที่จะทำการทดสอบอัตโนมัติดังนั้นผู้สัมภาษณ์อาจไม่คาดหวังสิ่งนี้จากคุณ
“ คำอธิบายของอัลกอริทึมทำให้ฉันคิดถึงการเรียกซ้ำ กฎข้อที่สองนำไปสู่ฟังก์ชันเวียนเกิดดังต่อไปนี้”
var fibonacci = function (n) {
return fibonacci(n - 2) + fibonacci(n - 1);
};
console.log(fibonacci(10));
“ ในการยุติการสอบถามซ้ำเราจะเพิ่มเคสพิเศษโดยแทนที่ส่วนของfibonacci
ฟังก์ชัน”
switch (n) {
case 0: return 0;
case 1: return 1;
default: return fibonacci(n - 2) + fibonacci(n - 1);
}
“ทำ.”
ข้อสรุป
ดังที่ฉันได้กล่าวไปแล้วว่าการฝึกดังกล่าวไม่เกี่ยวข้องกับงานที่แท้จริงของผู้พัฒนา มันทำให้ไม่มีความหมาย? ไม่จริงเพราะอย่างน้อยก็แสดงให้เห็นว่าคน:
สามารถคิดเกี่ยวกับปัญหาได้ ผู้สมัครบางคนจะสูญเสียโดยสิ้นเชิงและอยู่ภายใต้ความเครียดจะใช้เวลามากกว่าเวลาที่จัดสรรไว้เพียงเพื่อคิดหาวิธีที่เป็นไปได้ในการแก้ไขปัญหา
รู้ว่าการเรียกซ้ำหรือสามารถหลีกเลี่ยงการเรียกซ้ำผ่านลูปธรรมดา หลังจากนั้นผู้สัมภาษณ์อาจถามว่ามีวิธีการใช้ / ไม่ใช้การเรียกซ้ำหรือไม่และมีข้อดี / ข้อเสียของการเรียกซ้ำ
รู้พื้นฐานของภาษาการเขียนโปรแกรม มันไม่สำคัญว่าคนที่ใช้switch
ประโยคคำสั่งเงื่อนไขหรือพจนานุกรม : ขึ้นอยู่กับพื้นหลังผู้สมัครที่แตกต่างกันจะเลือกเครื่องมือต่าง ๆ เพื่อให้ได้สิ่งเดียวกัน
มุ่งเน้นไปที่ปัญหาโดยไม่ต้องนำสิ่งต่าง ๆ เช่นการทดสอบหน่วยการขยายขีดความสามารถหรือประสิทธิภาพ จากนั้นผู้สัมภาษณ์อาจถามว่าทำไมการแสดงที่ชาญฉลาดฟังก์ชั่นด้านบนนั้นแย่มากโดยคาดหวังว่าผู้สมัครจะอธิบายสิ่งที่ควรทำเพื่อให้การแสดงอยู่ในระดับที่สมเหตุสมผล
ตัวอย่างที่ 2: คำถามที่ยุ่งยาก
คุณต้องใช้เครื่องคำนวณหมายเลขฟีโบนักชีใน JavaScript มันควรจะเร็วที่สุด คุณควรจะสามารถเปลี่ยนดัชนีได้ตั้งแต่ 0 ถึง 100 ลำดับ Fibonacci เป็นไปตามกฎเหล่านั้น:
- ตัวเลขสองตัวแรกของลำดับคือ 0 และ 1
- แต่ละหมายเลขที่ตามมาคือผลรวมของสองหมายเลขก่อนหน้า
ตัวอย่าง: F 0 = 0, F 1 = 1, F 2 = 1, F 3 = 2, F 10 = 55
คุณมีสามนาที
ตอนนี้เรามีข้อ จำกัด ที่น่าสนใจซึ่งแสดงให้เห็นว่าผู้สัมภาษณ์ไม่สนใจจริง ๆ ว่าความสามารถของผู้สมัครในการแก้ปัญหา แต่เป็นเรื่องของความสามารถในการคาดเดาว่าวิธีใดจะเร็วกว่าวิธีอื่น
คำถามที่ซับซ้อนเหล่านั้นมักจะเชิญคำตอบที่ซับซ้อน ที่นี่มีข้อ จำกัด ด้านเวลาไม่มีวิธีที่จะทำให้เกิดการใช้งานหลายแบบเปรียบเทียบกับพวกเขาโพรไฟล์ที่เร็วที่สุดและมาพร้อมกับทางออกที่ดีที่สุด
แต่จะทำอย่างไรกับ:
“ ให้ฉัน Google "หมายเลขฟีโบนักชีครั้งแรก" ... นี่ดูมีแนวโน้ม ด้วยนิพจน์ทั่วไปแบบเรียบง่าย (ซึ่งจะเป็นแบบโอเพ่น) เราสามารถสร้างรายการค่าที่คั่นด้วยเครื่องหมายจุลภาค "
sed -e "s;\([0-9]*\) \([0-9]*\);'\2',;g" fbncc10.txt | tr '\n' ' '
“ ในที่สุดตัวโปรแกรมเอง”
var map = ['0', '1', '1', '2', '3', '5', '8', '13', '21', '34', '55', '89', '144', '233', '377', '610', '987', '1597', '2584', '4181', '6765', '10946', '17711', '28657', '46368', '75025', '121393', '196418', '317811', '514229', '832040', '1346269', '2178309', '3524578', '5702887', '9227465', '14930352', '24157817', '39088169', '63245986', '102334155', '165580141', '267914296', '433494437', '701408733', '1134903170', '1836311903', '2971215073', '4807526976', '7778742049', '12586269025', '20365011074', '32951280099', '53316291173', '86267571272', '139583862445', '225851433717', '365435296162', '591286729879', '956722026041', '1548008755920', '2504730781961', '4052739537881', '6557470319842', '10610209857723', '17167680177565', '27777890035288', '44945570212853', '72723460248141', '117669030460994', '190392490709135', '308061521170129', '498454011879264', '806515533049393', '1304969544928657', '2111485077978050', '3416454622906707', '5527939700884757', '8944394323791464', '14472334024676221', '23416728348467685', '37889062373143906', '61305790721611591', '99194853094755497', '160500643816367088', '259695496911122585', '420196140727489673', '679891637638612258', '1100087778366101931', '1779979416004714189', '2880067194370816120', '4660046610375530309', '7540113804746346429', '12200160415121876738', '19740274219868223167', '31940434634990099905', '51680708854858323072', '83621143489848422977', '135301852344706746049', '218922995834555169026', '354224848179261915075'];
var fibonacci = function (n) {
return map[n];
};
console.log(fibonacci(10));
ข้อสรุป
คำถามหากินเชิญคำตอบที่ซับซ้อน อย่ากล้าหาญและอย่าเริ่มทำการเปรียบเทียบและทำโปรไฟล์เมื่อคุณมีเวลาเพียงสามนาที คิดหาวิธีที่ชาญฉลาดในการแก้ปัญหาขณะใช้ประสบการณ์ของคุณ ประสบการณ์ของฉันให้คำแนะนำแก่ฉันว่าการใช้แผนที่อาจเร็วกว่าการคำนวณตัวเลข อาจผิด แต่ความพยายามครั้งนี้คาดว่าจะได้รับตามเวลาที่กำหนด
การรู้เครื่องมือของคุณช่วยได้และเป็นส่วนสำคัญของทักษะนักพัฒนา: โดยไม่ต้องรู้คำพูดฉันจะใช้ Googling ที่จัดสรรไว้เป็นเวลาสามนาทีสำหรับรายการที่คั่นด้วยเครื่องหมายจุลภาคหรือจะเริ่มเขียนโปรแกรมแยกวิเคราะห์ซึ่งจะสร้างอาร์เรย์ที่ฉันต้องการ
โปรดจำไว้ว่านักพัฒนาที่ดีไม่ใช่ผู้ที่เริ่มการเขียนโค้ดทันที แต่ใครจะรู้วิธีหลีกเลี่ยงการเข้ารหัสเมื่อมีโอกาสที่ดีกว่า ผู้สัมภาษณ์บางคนจะไม่ลังเลที่จะมอบหมายงานให้คุณซึ่งดูเหมือนว่าจะเข้ารหัส แต่ก็ไม่ต้องการรหัสเลย
ตัวอย่างที่ 3: การพัฒนาแอปพลิเคชันให้สมบูรณ์
คุณต้องใช้ลำดับ Fibonacci ใน JavaScript ความยาวของลำดับถูกกำหนดระหว่างการดำเนินการของโปรแกรม ลำดับตามกฎเหล่านี้:
- ตัวเลขสองตัวแรกของลำดับคือ 0 และ 1
- แต่ละหมายเลขที่ตามมาคือผลรวมของสองหมายเลขก่อนหน้า
ตัวอย่าง: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
แอปพลิเคชันควรถูกนำเสนอเป็นเว็บเพจช่วยให้ผู้ใช้สามารถระบุความยาวของลำดับผ่านฟิลด์อินพุต
คุณมีหนึ่งชั่วโมง
เริ่มกันเลย.
“ ลำดับตัวอย่างมีประโยชน์มากเพราะจะทำให้ฉันมีการทดสอบหน่วยจำนวนมากเพื่อให้แน่ใจว่าการใช้งานของฉันไม่ผิดอย่างสมบูรณ์ โดยทั่วไปแล้วฉันใช้ Mocha สำหรับ node.js หรือ QUnit สำหรับ JavaScript ฝั่งไคลเอ็นต์ แต่ที่นี่เพื่อความเรียบง่ายฉันจะใช้ฟังก์ชันทดสอบมากมาย”
“ ฉันเริ่มต้นด้วยการสร้างindex.htm
และfib.js
ไฟล์ จากนั้นฉันก็เติมเต็มindex.htm
ด้วยมินิมัลลิสต์และไม่ใช่รหัสที่สอดคล้องกับ W3C (เราสามารถกลับไปที่นี่ในภายหลังหากคุณสนใจทักษะ HTML ของฉันด้วย)
<label>Length</label> <input id="length" value="15" />
<input id="compute" type="button" value="Compute" />
<div id="result" style="font-weight:bold;"></div>
<div id="tests"></div>
<script src="fib.js"></script>
“ ตอนนี้เรามาเขียนโค้ดที่จะเรียกใช้ฟังก์ชันตัวสร้างฟีโบนักชีและแสดงผลลัพธ์”
fibonacci = (function () {
var compute,
init;
compute = function (length) {
// TODO: Implement Fibonacci sequence.
return [1, 2, 3];
};
init = function () {
var button = document.getElementById('compute');
button.addEventListener('onclick', function () {
var length = parseInt(document.getElementById('length').value, 10),
result;
console.log(
'Computing Fibonacci sequence of length ' + length + '.'
);
result = compute(length);
document.getElementById('result').innerText = result.join(', ');
});
};
return {
compute: compute,
init: init
};
}());
“ ถึงเวลาที่ต้องรันโค้ดเป็นครั้งแรกและ ... มันไม่ทำงาน ไม่มีอะไรเกิดขึ้น. ทำไม?"
“ ตกลงฉันลืมfibonacci.init();
ตอนท้าย ฉันเพิ่มและยังคงไม่มีอะไรเกิดขึ้นในขณะที่อย่างน้อยก็ควรแสดงข้อความในคอนโซล เดี๋ยวก่อนใช่มันไม่ใช่onclick
แต่click
; ฉันใช้ JQuery บ่อยครั้งที่ฉันเริ่มลืมชื่อเหตุการณ์ใน JavaScript ธรรมดา”
“ มาเพิ่มการทดสอบกันเถอะ”
ensureAreEqual = function (expected, actual) {
var testResultsContainer = document.getElementById('tests');
testResultsContainer.innerText += (expected.equals(actual) ?
'.' :
('Actual [' + actual.join(', ') + '] is different from ' +
'expected [' + expected.join(', ') + '].'));
};
test = function () {
ensureAreEqual([0], compute(1));
};
“ การเปรียบเทียบอาร์เรย์อาจยุ่งยากดังนั้นฉันเพิ่งคัดลอก Array.prototype.equals
โค้ดจากคำตอบนี้”
“ ตอนนี้เราเรียกใช้แอปพลิเคชันก็จะปรากฏขึ้น:”
จริง [1, 2, 3] แตกต่างจากที่คาดไว้ [0]
“ การทดสอบล้มเหลวซึ่งคาดว่าจะสูงเนื่องจากการใช้งานจริง ( return [1, 2, 3];
) ของลำดับ Fibonacci ถึงเวลาเปลี่ยนแล้ว”
“ จากคำแถลงเดิมลำดับ Fibonacci เริ่มต้นด้วย[0, 1]
ดังนั้นcompute
กลายเป็น:”
compute = function (length) {
var fib = [0];
return fib;
};
“ สิ่งนี้ทำให้เป็นไปได้ที่จะผ่านการทดสอบครั้งแรกและตอนนี้เราสามารถเขียนบทที่สองของเราได้”
ensureAreEqual([0, 1], compute(2));
“ มันล้มเหลวเราจึงกลับไปcompute
และแก้ไข”
compute = function (length) {
var fib = [0, 1];
return length === 1 ? [0] : fib;
};
“ ตอนนี้การทดสอบทั้งสองผ่านไปได้แล้วและถึงเวลาที่จะต้องย้ายไปสู่คดีที่ไม่ได้เปรียบ”
compute = function (length) {
var fib = [0, 1],
i,
next,
current = 1,
previous = 0;
for (i = 2; i < length; i += 1) {
next = current + previous;
previous = current;
current = next;
fib.push(next);
}
return length === 1 ? [0] : fib;
};
“ การทดสอบทั้งสามผ่านแล้วยกเว้นว่าผลลัพธ์จะไม่เหมาะกับความยาวที่มากขึ้นเช่น 100 เพื่อให้ได้ผลลัพธ์ที่ถูกต้องเราควรใช้ไลบรารี่ที่มีความแม่นยำตามอำเภอใจ นอกจากนี้ยังมีสิ่งที่ต้องปรับปรุง ตัวอย่างเช่นการตั้งชื่อการประชุมบางครั้งก็แย่เกินไป (คือfib
อะไร) รหัส JavaScript ที่เกี่ยวข้องกับ HTML ควรไปที่วัตถุอื่นเช่นเดียวกับรหัสทดสอบ นอกจากนี้ฉันยังไม่ได้ทดสอบcompute(0)
และยังไม่ได้ตรวจสอบอินพุต "
ข้อสรุป
โดยการเดินผ่านตัวอย่างคุณอาจเห็นปฏิสัมพันธ์ที่คาดหวังในระหว่างการสัมภาษณ์ ไม่ใช่ทุกอย่างราบรื่น (ฉันทำผิดพลาดหลายครั้งในตอนแรกซึ่งนำฉันไปสู่สถานการณ์ที่น่าอับอายที่ไม่มีอะไรเกิดขึ้นเมื่อฉันเรียกใช้แอปพลิเคชัน) และวิธีการดั้งเดิมนั้นอ่อนแอถ้าเราต้องรองรับความยาวต่อเนื่องจำนวนมาก เพื่อแสดงว่า:
- ฉันสามารถจัดการกับปัญหาต่าง ๆ
- ฉันใช้การพัฒนาแบบทดสอบขับเคลื่อนลำดับ Fibonacci เป็นโอกาสที่ดีสำหรับสิ่งนี้
- ฉันคัดลอกโค้ดวางเมื่อแหล่งที่มาเชื่อถือได้และเขียนตั้งแต่เริ่มต้นดูเหมือนว่าจะซับซ้อนและมีข้อผิดพลาดเกิดขึ้นได้ยาก
- ฉันไม่พึ่งพาห้องสมุดมากเช่น JQuery
- ฉันเลือกขอบเขตที่เหมาะสม: เนื่องจากผู้สัมภาษณ์ต้องการตรวจสอบทักษะ JavaScript ของฉันฉันจะไม่เสียเวลาเขียน HTML ที่สมบูรณ์และสะอาด: การไม่ใช้เวลาที่นี่ทำให้สามารถใช้เวลาในการเขียนหน่วยทดสอบได้มากขึ้น
- ฉันรู้ว่าต้องทำอะไรให้เสร็จและบอกว่าฉันทำไปแล้วในขณะที่จำไว้ว่าสิ่งต่าง ๆ ไม่สมบูรณ์แบบ (
compute(0)
ซึ่งจะล้มเหลว แต่ไม่สำคัญสำหรับการสาธิต)
นี่คือสิ่งที่ผู้สัมภาษณ์ควรคาดหวังจากคุณ