调试一个Wordle错误
创建用于调试的教程尤其具有挑战性。对于我们的新游乐场,我们建立了一个基于Wordle的教程。这就是我们创建的错误...
我有一个忏悔。我对Wordle上瘾了。尤其是现在,它已经过时了,人们也不发帖了。我喜欢它的简短,我可以解决一个词,然后它就消失了。我不觉得沉迷于任何游戏和浪费我的时间有什么不好。这个云调试器教程对我来说是一个巨大的挑战,因为目标是一个Wordle游戏。但是,我已经走在了前面。
作为Lightrun游乐场的一部分,我们最近发布了我们需要一个演示应用程序,让那些刚接触Lightrun的开发者,在一个 "安全的环境 "中练习。我们决定选择Wordle作为我们的演示应用程序,因为它是立即熟悉的,视觉的,而且没有太多互动。如果是Flappy Bird的演示,调试起来可能会很痛苦。在这一点上,我们的关键挑战是创造一个错误,使调试过程足够有趣,但又足够微妙,所以它不会被立即发现。
创造这样的一个bug是出乎意料的挑战。我们不希望有一个跨越多个文件的过于复杂的应用程序。这可能会使调试过程过于困难。另一方面,这个错误需要足够微妙,即使我们直接盯着它也不会注意到它。下面是这个错误。
JavaScript
constguess = []
for (leti = 0; i < game.word.length; ++i) {
if (game.word.includes(guessWord[i])) {
guess.push({ letter:guessWord[i], check:CHECK_TYPES.LETTER_INCLUDED })
} else if (guessWord[i] === game.word[i]) {
guess.push({ letter:guessWord[i], check:CHECK_TYPES.LETTER_MATCHED })
} else {
guess.push({ letter:guessWord[i], check:CHECK_TYPES.LETTER_NOT_INCLUDED })
}
}
你能发现这个问题吗?
为了理解它,我们首先需要理解我们选择的bug的症状。当我谈到bug的时候,人们的脑子里往往会想到崩溃。有时可能是这样,但根据我的经验,最常见的bug是逻辑错误,这些错误的发生是因为生产环境与我们的测试环境有一些微妙的不同。正因为如此,我们挑选了一个逻辑错误,不幸的是,由于简单性的限制,我怀疑这样的错误会进入生产。核心的教训仍然适用。
在这种情况下,这个错误是,Wordle中的字母应该被染成绿色,因为它们在单词中处于正确的位置,但却被染成了黄色。这个逻辑是由我们上面看到的代码实现的。正如你所看到的,我们有三种模式:
CHECK_TYPES.LETTER_INCLUDED- 表示一个字母应该被染成黄色CHECK_TYPES.LETTER_MATCHED- 表示该字母应该被染成绿色CHECK_TYPES.LETTER_NOT_INCLUDED- 表示该字母缺失,应该为灰色。
你现在能发现这个问题吗?
不要向下滚动,以免破坏气氛......
下面是工作代码。
JavaScript
constguess = []
for (leti = 0; i < game.word.length; ++i) {
if (game.word.includes(guessWord[i])) {
guess.push({ letter:guessWord[i], check:CHECK_TYPES.LETTER_MATCHED })
} else if (guessWord[i] === game.word[i]) {
guess.push({ letter:guessWord[i], check:CHECK_TYPES.LETTER_INCLUDED })
} else {
guess.push({ letter:guessWord[i], check:CHECK_TYPES.LETTER_NOT_INCLUDED })
}
}
不同的是,我调换了两行代码。我们需要在CHECK_TYPES.LETTER_MATCHED测试之前测试CHECK_TYPES.LETTER_INCLUDED。测试必须按重要性顺序进行,绿色(完全匹配)应该在黄色(部分匹配)之前。
调试的过程相对简单。我们在下面一行放置了一个快照/断点,在那里我们看到服务器代码层面上的值是不正确的。我认为更 "自然 "的调试方式是在CHECK_TYPES.LETTER_MATCHED行上放置一个断点,一旦我们意识到这个断点从未被击中,我们就会明白哪里出错了。对于我们的游乐场的特殊用例,这不是正确的方法。我们希望人们能看到快照(非断点)被击中。但除此之外,这是一个好的错误。
如果这一点还不清楚,这里有一个很酷的动画,可以直观地解释这个错误。
调试教学
调试是我们在大学里学不到的科目之一。是的,有一些课程涉及它,但不多。你大多被期望自己去学习它(例如,使用专门的实时调试工具)。这在很大程度上说明了为什么会出现这种情况。为调试创造练习是非常困难的,而测试知识就更难了。
我们可以创建一个更精细的演示来调试,但在那里我们过渡到 "理解和解释该代码库 "的世界。这并不是我们的目标。在过去的几年里,我翻阅了很多与调试有关的材料,这似乎是一个普遍的问题,所有的人都在为之奋斗。这是一种耻辱,因为有许多工具、技术和方法,即使是有经验的开发者也会错过。
从这个意义上说,我是一个主张在没有错误的情况下教授调试的人。调试器是我们在有任何bug之前就可以探索和使用的工具,即使是作为一种学习工具。我认为我们需要在调试环境中感到 "舒适",并且应该在没有错误的时候利用它。它不应该是我们在紧急情况下才使用的工具。如果我们经常使用调试器,当我们真正需要它的时候,就会更容易用它来跟踪错误。
这也是我对诸如可观察性工具、日志等工具所持的一种理念。我们不经常使用的肌肉会失去其质量并被削弱。合成问题对于一个简短的教程来说是可以的,但是我们不能每天都使用它们,也很难将它们扩展到一个完整的研讨会或课程中。
最后
你对自己学习调试的方式有什么感觉?是在学院、大学、Bootcamp还是在工作中?
你觉得你对这一主题很了解吗?
您是否向他人传授调试知识?如果是的话,你是怎么教的,使用什么技术?你觉得什么方法最有效?