速度的需求:頂級 JavaScript 編碼挑戰回顧展
已發表: 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 分。 我們允許多次嘗試來完成挑戰。
我們預計會發生的第一件事是人們會花一些時間從容不迫地解決問題,然後將答案複製並粘貼到 Web 應用程序中。
在發起挑戰一小時四十分鐘後,第一人按照這種方法獲得了應用程序允許的最高 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 編碼挑戰賽的最高分
首先,讓我們快速計算一下:完成所有任務總共獲得 1445 分,並有 180 秒的時間限制。 如果我們在申請中每秒獎勵 10 分,那麼在立即提交所有答案的情況下,理論上可達到的最高分數將是 3245。
我們的一位用戶得分超過 6000,並且隨著時間的推移不斷增長。
怎麼會有人拿到這麼高的分數?
經過簡短的審查,我們發現了正在發生的事情。 我們的頂級選手,專業的全棧開發人員和擁有超過 15 年競爭編程經驗的 Toptaler,在編碼挑戰的設置中發現了一個漏洞。 他產生了多個機器人,這降低了服務器的速度; 同時,他可以盡可能多地完成相同的任務(得分最高的任務)並將其分數分配給單個條目,並不斷增加該條目的分數。
這並不違反規則,因為我們允許創造性的解決方案; 但是,他使用的特定方法導致服務器相當繁忙,導致其他人的網絡請求變慢。 我們做的第一件事就是增加我們的服務器功率,這只是讓他從56,000點到70,000點並保持在第一位。
雖然我們不想干預人們與挑戰互動的方式,但這些嘗試會減慢服務器速度,以至於其他用戶難以使用挑戰,因此我們決定修復漏洞。
該修復使其他人無法在 JavaScript 編碼挑戰的最後一天獲得相同的分數。 正因為如此,我們決定擴大授予頂級參賽者的獎項數量。 最初,最高獎——一對 AirPods——應該只授予一位頂級選手。 最終,獲得前六名的人獲得了 AirPods。
卑微的開始和兇猛的結束:一些 JavaScript 編碼挑戰統計
即使是我們得分最高的人也有一些困難。 事實上,在所有嘗試過 5 次或以上的人中,任何人第一次嘗試的最高得分為 645,而該組第一次嘗試的中位數僅為 25 分。
到比賽結束時,人們可以從嘗試的總數中猜出正在嘗試的策略。 雖然有些人比其他人更有效率,但遙遙領先的選手的嘗試次數最多。
向前進
未來該何去何從?
這只是第一次 JS 編碼挑戰迭代。 我們希望在未來做更多的 JavaScript 編程挑戰,從以前的運行中吸取教訓,讓它變得更加精彩。 我們要做的第一件事是實施嘗試限制以限制提交的數量。 我們還希望超越 JavaScript 中的編碼挑戰,使其可用於各種編程語言。
最後,雖然我們正在採取措施使 JavaScript 編碼挑戰更加安全,但我們計劃繼續允許使用機器人和其他創造性方法來應對未來的挑戰。
特別感謝 Pavel Vydra、Anton Andriievskyi、Tiago Chilanti 和 Matei Copot 對挑戰賽和本文的貢獻,並感謝 @Zirak 為構成比賽應用程序基礎的開源項目。 同樣,感謝所有參加並參加比賽的人。