在写完上一篇文章后不久,一位同事联系我说她找到了问题所在——至少在最直接的层面上,即异常本身。排序代码没有问题,只是异常消息太容易被误读。她说得完全正确,我对此感到非常懊恼。
再次看一下异常消息:
|
|
以及创建该异常的代码:
|
|
在我上一篇文章中,我曾声称:
异常消息暗示在异常发生时,
currentText的值是 “focaldata-01”,而nextText的值是 “mic-01”。
不,并不是这样!它暗示的恰恰相反,即 currentText 的值是 “mic-01”,而 nextText 的值是 “focaldata-01”……换句话说,数据确实是错误的。
唉,即使我不断想着“当我的代码出问题时,几乎总是我的错”,我仍然没能真正退后一步,仔细地双重检查我的逻辑。
但这很奇怪,对吧?因为之前无效的数据(20:15:57)后来神奇地“变成”了有效(20:26:22),对吧?这是我在上一篇文章中声称的。我本应该更仔细地查看日志……在 20:22:58 启动了一个新实例。这个新实例正确加载了数据,因此重新加载已经有效的数据是没问题的。
实际上是什么出了问题?
我在实际修复代码之前就开始写这篇文章,但我现在确信问题出在“部分”重新加载上——向数据库添加一个新的预测集,然后从在其缓存中已有现有数据的存储系统重新加载数据。这应该相对容易测试——
首先,值得修复那条消息。与其谈论“应该出现”什么,不如说清楚实际情况,包括集合中出错的索引:
|
|
接下来,让我们在上传新数据时添加另一层检查:除了从一个干净的状态重新加载两次外,让我们添加一个“前后”重新加载。这方面的代码并不有趣(尽管由于依赖注入的原因,它有些繁琐)。然后只需测试添加一个 ID 为 “aaaa” 的“绝对第一个”预测集……
太好了,我重现了问题!
|
|
之后,花了不太长时间(通过添加更多日志)就找到了问题。一旦找到,修复起来就非常容易。无需过多不必要的细节,我在合并新旧映射时破坏了我的内部“哈希到完整数据”的映射。
|
|
应该是:
|
|
这只有在加载一个包含新预测集的上下文,并且我们之前已经有一个预测集时才会成为问题。
这就是我的选举站点缺乏许多自动化测试(这些可能必须是集成测试而不是单元测试)的不足之处……尽管公平地说,这是少数几次出现这种情况。
可能是时候开始编写更多测试了——尤其是在这种情况下,这是一个在凌晨时分重写的整个上下文存储系统。
结论
那么,学到了一些教训:
- 是的,当我的代码出问题时,几乎总是我的错。即使我盯着它看,并以为我发现了什么真正奇怪的东西。
- 我应该编写更多测试。
- 使异常消息尽可能明确是非常重要的。
- 我应该总是听 Amanda 的话。