速度的需求:顶级 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 为构成比赛应用程序基础的开源项目。 同样,感谢所有参加并参加比赛的人。