Need for Speed: A Toptal JavaScript Coding Challenge ย้อนหลัง
เผยแพร่แล้ว: 2022-03-11Toptal เริ่มต้นเว็บแอปท้าทายการเข้ารหัส JavaScript เพื่อดึงดูดผู้คนให้มาที่บูธการประชุมของเรา เมื่อเห็นว่าประสบความสำเร็จเพียงใด เราจึงตัดสินใจสร้างโครงการนำร่องบนเว็บ ซึ่งเปิดให้ทุกคนในชุมชนและเครือข่ายของพวกเขา
ในช่วงเปิดตัว เราได้สนับสนุนให้นักพัฒนาที่มีแรงจูงใจคิดหาวิธีที่สร้างสรรค์เพื่อทำคะแนนให้สูงจากความท้าทายในการเขียนโค้ด JavaScript โดยรวม ปัจจัยความสำเร็จที่สำคัญบางประการของนักแปลอิสระอิสระรายใหญ่คือความสามารถในการคิดนอกกรอบและค้นหาวิธีที่สร้างสรรค์ในการทำงานภายใต้ข้อจำกัดต่างๆ
คำถามท้าทายการเข้ารหัส JavaScript
ถุงมือประกอบด้วยคำถาม JavaScript จำนวนหนึ่ง ซึ่งคล้ายกับคำถามที่อาจใช้เป็นคำถามสัมภาษณ์ ตั้งแต่คำถามท้าทาย JavaScript ขั้นพื้นฐานจริงๆ:
box.double = function double (x) { //return x doubled };
…ถึงคนกลางมากขึ้น:
box.dateRank = function dateRank (x) { // x is a date in 2019 as string (example: "06/30/2019") // return the rank of the day in 2019 (ie, "09/01/2019" translates to 244) };
เราอยากให้ทั้งผู้เริ่มต้นและนักพัฒนาขั้นสูงได้สนุกสนานและเชิญเพื่อนและเพื่อนร่วมงานของพวกเขาให้แข่งขันกับพวกเขาเพื่อให้ได้คะแนนสูงสุด คำถามถูกจัดเรียงตามคะแนน ดังนั้นแม้แต่นักพัฒนารุ่นเยาว์ก็สามารถทำคะแนนได้ ลำดับของคำถามที่มีคะแนนเท่ากันนั้นเป็นแบบสุ่ม ดังนั้นประสบการณ์จึงแตกต่างกันเล็กน้อยทุกครั้ง ในขณะที่คำถามทั้งชุดยังคงเหมือนเดิมตลอดทั้งสัปดาห์
เป้าหมายคือทำงานให้เสร็จให้ได้มากที่สุดภายในเวลาสามนาที ในกรณีที่มีคนพบวิธีที่จะทำงานทั้งหมดให้เสร็จสิ้นในความท้าทายการเข้ารหัส JavaScript จะได้รับรางวัล 10 คะแนนสำหรับแต่ละวินาทีที่เหลือ เราอนุญาตให้พยายามหลายครั้งเพื่อทำภารกิจให้สำเร็จ
สิ่งแรกที่เราคาดไว้จะเกิดขึ้นคือ ผู้คนจะใช้เวลาสักครู่ในการแก้ปัญหาอย่างรวดเร็ว จากนั้นคัดลอกและวางคำตอบลงในเว็บแอปพลิเคชัน
หลังจากเปิดตัวความท้าทายหนึ่งชั่วโมง 40 นาที คนแรกทำตามวิธีนี้และได้รับคะแนนสูงสุด 1445 คะแนนที่แอปพลิเคชันอนุญาต บวกกับคะแนนพิเศษที่เราให้สำหรับทุกวินาทีที่เหลือ
จุดเปลี่ยนในการท้าทายการเข้ารหัส JavaScript
ด้วยวิธีการคัดลอกและวาง ผู้เข้าแข่งขันระดับแนวหน้าจึงไม่ได้อะไรมากไปกว่านี้จากการมุ่งเน้นไปที่การเขียนโค้ดคำตอบด้วยตนเอง แต่พวกเขาหันความสนใจไปที่การเพิ่มความเร็วให้กับทักษะด้านระบบอัตโนมัติ
วิธีที่ง่ายที่สุด ณ จุดนี้คือการเขียน JavaScript บางตัวที่จะแก้ปัญหาแต่ละงานในขณะที่รอการวนซ้ำจนกว่าปุ่มจะพร้อม และคัดลอกและวางลงในคอนโซลของเบราว์เซอร์:
const solutions = { 'double': 'return x*2', 'numberToString': '...', 'square': '...', 'floatToInt': '...', 'isEven': '...', 'squareroot': '...', 'removeFirstFive': '...', // ... 'dateRank': '...', // ... }; const get_submit_button = () => document.querySelector('.task-buttons > .col > .btn'); const solve = () => { const ace_editor = ace.edit(document.querySelector('.ace_editor')) const submission = ace_editor.getValue() for (const key in solutions) { if (submission.includes('box.' + key + ' ')) { ace_editor.insert(solutions[key]) get_submit_button().click() setTimeout(() => { get_submit_button().click() setTimeout(() => { solve() }, 400) }, 900) return } } } solve()
ส่วนนี้อาจเป็นแบบอัตโนมัติโดยใช้เครื่องมืออัตโนมัติทั่วไป เช่น Selenium แต่วิธีที่เร็วกว่าคือการใช้ API โดยอัตโนมัติ โดยส่งโซลูชันไปยังงานต่างๆ:
const request = require('request'); const runTask = (data, entryId, callback) => { const tests = data.nextTask.tests_json; const results = Object.fromEntries( Object.entries(tests).map(([key, value]) => [key, value.result]) ); request.post(`https://speedcoding.toptal.com/webappApi/entry/${entryId}/attemptTask`, { form: { attempt_id: data.attemptId, tests_json: JSON.stringify(results), }, }, (error, res, body) => { if (error) throw error; const next = JSON.parse(body).data if (next.isChallengeEntryFinished) { callback(next) return } runTask(next, entryId, callback) }); } const runEntry = (callback) => { request.post('https://speedcoding.toptal.com/webappApi/entry', { form: { challengeSlug: 'toptal-speedcoding', email: ..., leaderboardName: ..., isConfirmedToBeContacted: ..., dateStop: ... }, }, (error, res, body) => { if (error) throw error; const { data } = JSON.parse(body); const entryId = data.entry.id runTask(data, entryId, callback) }); } runEntry(console.log)
สิ่งหนึ่งที่ควรทราบก็คือ ในเวอร์ชันของความท้าทายในการเข้ารหัสความเร็วนี้ โค้ดได้รับการทดสอบในฝั่งไคลเอ็นต์เท่านั้น ด้วยเหตุนี้ จึงเป็นไปได้ที่จะส่งคำตอบของกรณีทดสอบแทนที่จะส่งรหัส สิ่งนี้ทำให้สามารถเพิ่มประสิทธิภาพและลดเวลามิลลิวินาทีในฝั่งไคลเอ็นต์ได้

เป็นเวลาสามวันคะแนนยังคงเท่าเดิม บางคนกำลังเขียนการเพิ่มประสิทธิภาพแบบไมโครสำหรับโค้ดของพวกเขา และหลายคนกำลังส่งโซลูชันของตนแบบวนซ้ำ โดยหวังว่าเซิร์ฟเวอร์จะมีผู้คนหนาแน่นน้อยลงเพื่อที่พวกเขาจะได้คะแนนนำหน้าสองสามคะแนน เราต้องพบกับความประหลาดใจครั้งใหญ่
ทำลายคะแนนสูงสุดของ JavaScript Coding Challenge
อันดับแรก มาคำนวณเลขกันก่อน: เรามีคะแนนรวม 1445 คะแนนสำหรับการทำภารกิจทั้งหมดให้สำเร็จ และมีเวลา 180 วินาที หากเราให้คะแนน 10 คะแนนต่อวินาทีที่เหลืออยู่ในใบสมัคร คะแนนสูงสุดที่ทำได้ตามทฤษฎีจะเท่ากับ 3245—ในกรณีที่ส่งคำตอบทั้งหมดทันที
หนึ่งในผู้ใช้ของเราได้รับคะแนนมากกว่า 6000 ซึ่งเพิ่มขึ้นอย่างต่อเนื่องเมื่อเวลาผ่านไป
มีคนทำคะแนนได้สูงขนาดนี้ได้อย่างไร?
หลังจากการทบทวนสั้น ๆ เราพบว่าเกิดอะไรขึ้น ผู้เข้าแข่งขันระดับแนวหน้าของเรา นักพัฒนาซอฟต์แวร์ฟูลสแตกมืออาชีพ และ Toptaler ที่มีประสบการณ์การเขียนโปรแกรมเชิงแข่งขันมากกว่า 15 ปี พบช่องโหว่ในการตั้งค่าความท้าทายด้านการเขียนโค้ด เขาเกิดบอทหลายตัว ซึ่งทำให้เซิร์ฟเวอร์ช้าลง ในขณะเดียวกัน เขาสามารถทำงานเดียวกันให้เสร็จ (งานที่ได้รับคะแนนมากที่สุด) ได้หลายครั้งเท่าที่จะทำได้ และกำหนดคะแนนให้กับรายการเดียว โดยเพิ่มคะแนนของรายการนั้นอย่างต่อเนื่อง
สิ่งนี้ไม่ขัดกับกฎ เนื่องจากเราอนุญาตให้ใช้โซลูชันที่สร้างสรรค์ อย่างไรก็ตาม วิธีการเฉพาะที่เขาใช้ทำให้เซิร์ฟเวอร์มีงานยุ่งมาก ทำให้คำขอของเครือข่ายช้าลงสำหรับทุกคน สิ่งแรกที่เราทำคือเพิ่มพลังเซิร์ฟเวอร์ของเรา ซึ่งทำให้เขาเปลี่ยนจาก 56,000 เป็น 70,000 แต้มและอยู่ที่เดิม
ในขณะที่เราไม่ต้องการเข้าไปแทรกแซงในลักษณะที่ผู้คนโต้ตอบกับความท้าทาย ความพยายามเหล่านี้ทำให้เซิร์ฟเวอร์ช้าลงจนถึงระดับที่ความท้าทายนั้นยากต่อการใช้งานสำหรับผู้ใช้รายอื่น ดังนั้นเราจึงตัดสินใจแก้ไขช่องโหว่
การแก้ไขนี้ทำให้คนอื่นๆ เป็นไปไม่ได้ที่จะได้คะแนนเท่ากันในวันสุดท้ายของความท้าทายในการเขียนโค้ด JavaScript ด้วยเหตุนี้ เราจึงตัดสินใจขยายจำนวนรางวัลที่มอบให้กับผู้แข่งขันชั้นนำ เดิมที รางวัลสูงสุด—AirPods หนึ่งคู่—ควรจะตกเป็นของผู้เข้าแข่งขันอันดับต้นๆ เท่านั้น ในที่สุด AirPods ก็มอบให้กับผู้ที่ครองหกอันดับแรก
จุดเริ่มต้นที่ต่ำต้อยและจุดจบที่ดุร้าย: สถิติความท้าทายในการเข้ารหัส JavaScript บางส่วน
แม้แต่ผู้ทำคะแนนสูงสุดของเราก็ยังมีปัญหาในการเริ่มต้น ที่จริงแล้ว ในบรรดาทุกคนที่พยายามห้าครั้งขึ้นไป คะแนนสูงสุดสำหรับความพยายามครั้งแรกของทุกคนคือ 645 และคะแนนมัธยฐานสำหรับความพยายามครั้งแรกในกลุ่มนั้นเพียง 25 คะแนน
ในตอนท้ายของการแข่งขัน เราสามารถเดาได้ว่ากำลังพยายามใช้กลยุทธ์ใดจากจำนวนครั้งที่พยายามทั้งหมด ในขณะที่บางคนมีประสิทธิภาพมากกว่าคนอื่น ๆ ผู้เข้าแข่งขันอันดับต้น ๆ ที่อยู่ห่างไกลก็มีความพยายามสูงสุด
ก้าวไปข้างหน้า
อนาคตจะเป็นอย่างไร?
นี่เป็นเพียงการทำซ้ำความท้าทายการเข้ารหัส JS ครั้งแรกเท่านั้น เราต้องการสร้างความท้าทายในการเขียนโปรแกรม JavaScript อีกมากในอนาคต เรียนรู้บทเรียนจากการรันครั้งก่อน และทำให้น่าตื่นเต้นยิ่งขึ้นไปอีก สิ่งแรกที่เราต้องการทำคือพยายามควบคุมปริมาณเพื่อจำกัดจำนวนการส่ง เรายังต้องการขยายขอบเขตให้มากกว่าความท้าทายในการเขียนโค้ดใน JavaScript ทำให้สามารถใช้งานได้ในภาษาการเขียนโปรแกรมที่หลากหลาย
สุดท้ายนี้ ในขณะที่เรากำลังใช้มาตรการเพื่อทำให้การเข้ารหัส JavaScript มีความปลอดภัยมากขึ้น เราวางแผนที่จะอนุญาตให้ใช้บอทและแนวทางสร้างสรรค์อื่นๆ สำหรับความท้าทายในอนาคตต่อไป
ขอขอบคุณเป็นพิเศษสำหรับ Pavel Vydra, Anton Andriievskyi, Tiago Chilanti และ Matei Copot สำหรับการมีส่วนร่วมในความท้าทายและบทความนี้ และสำหรับ @Zirak สำหรับโครงการโอเพนซอร์ซที่เป็นพื้นฐานของแอปการแข่งขัน ในทำนองเดียวกัน ขอบคุณทุกคนที่เข้าร่วมและดำเนินการแข่งขัน