最佳工程实践:如何修复错误?
我想通过一系列文章来介绍一些基本的工程实践,首先是最重要的一点:如何修复错误?
首先,为什么我认为修复 bug 是最重要的事?
因为 bug 总是会发生。只要你写代码,就必然会写出 bug。
但这根本不是问题。我们坚持的可重复软件开发流程
正是基于这个理念:人都会犯错。 不久前我写过一篇文章专门讨论这个问题:不应该责怪开发者,而应该责怪项目本身。
重要的是:你如何应对你和其他人造成的漏洞?你如何防止它们将来再次发生?你又是如何知道这些漏洞存在的?
发现虫子
在真正修复问题之前,你需要先找出错误行为。
这可能很棘手。请考虑以下两种情况:
- 由于出现错误,所有用户都无法登录帐户。
- 一位用户偶尔会在本地计算机上遇到您的应用程序的异常行为。
哪一个更容易被发现?我想你猜对了:第一个。
有些虫子比其他虫子更容易看到。
影响漏洞被发现的因素有很多:
- 有多少用户受到这个漏洞的影响?如果数量足够多,肯定会有人举报。利用用户作为监控服务是否合理?这是另一个我们本文不予讨论的问题。
- 代码在哪里执行?在您自己的服务器上执行要容易得多,这样可以创建一个监控服务,捕获大多数意外情况并发出警报。有时您可能无法访问自己开发的产品。例如,当产品交付给使用其自身基础设施的企业客户时。此外,在您自己的服务器上创建一个固定环境也容易得多,这样任何第三方实体都无法干扰您的项目。
- 重现这些 bug 有多难?有些 bug 很容易重现。点击此链接,输入此文本,然后按回车键即可。有些 bug 则非常棘手!你需要搭建一个特殊的环境,安装一些特定的软件,执行一些奇怪的操作,然后(如果运气好的话)才能重现该 bug。需要注意的是,有些 bug 根本无法重现。它们完全可以忽略。
当然,也有一些工具可以帮助你发现漏洞,并在漏洞发生时发出警报。
- Sentry可以帮助您追踪代码中的错误。它支持几乎所有编程语言,并提供免费的自托管版本。此外,它还允许您直接收集用户的口头反馈。
- Prometheus是最流行的监控工具之一。可通过以下方式
docker-compose up快速启动: - 此外,还有付费服务,例如,,,
NewRelic以及其他许多服务。WombatDataDog
生活小妙招:你可以先从最简单的设置开始,Sentry它就能满足你的大部分需求。之后你可以根据需要添加更多服务和工具。
报告错误
一旦发现漏洞,就需要提交报告。这看起来很简单,对吧?实际上,虽然看似简单,但这绝对是整个流程中最关键的一步。要提交一份有效的漏洞报告,你需要提供大量信息。你的问题描述必须完整地讲述一个完整的故事:
- 你为什么觉得这是个bug?也许这是个特性呢……
- 您认为应该如何处理?没有明确预期行为的 bug 可能很难修复,而且可能会演变成功能请求,而功能请求应该用不同的方式解决。
- 这个漏洞为什么重要?你必须证明它应该立即修复。因为有些漏洞无关紧要,可以暂时忽略。
- 如何重现问题?这部分应包含所有与问题相关的技术信息。使用了哪些版本?使用了哪个浏览器/操作系统?应用了哪些配置?有时甚至可以创建一个单独的代码仓库来专门展示问题的重现步骤。
- 查找有关问题的更多信息,例如日志、堆栈跟踪、屏幕截图、监控报告、所需输入数据、相关错误和功能等。所有链接都必须包含在提交内容中。否则,随着时间的推移,将很难解决这个问题。
小技巧:截图和GIF 动画对于带有用户界面的系统来说简直太棒了!尽量多用它们。但是,千万不要用截图来截取堆栈跟踪和调试输出中的文本信息,因为其他开发者无法复制这些信息。
现在,我们来看两个在同一个项目中创建的不同 bug 示例。第一个示例严格遵循版本、回溯和范围要求,这是一个优秀的 bug 报告。
第二个错误报告是我提交的。这是一个糟糕的错误报告范例。
它几乎违反了我们之前制定的所有规则。这是匆忙之举——为了不忘记这张工单,我刚和一位用户通完电话。请不要这样做。
以下是一些您可以在项目中使用的真实错误报告模板:
github-issue-templates仓库中还收集了各种不同的错误报告模板。您可以随意使用其中任何一个来改进您的开发流程!
重现错误
现在,你需要重现这个错误。不仅要手动操作,还要编写代码。记住——你的目标是不要再次出现同样的错误。这怎么可能呢?
你需要编写一个会失败的回归测试
。 可以是单元测试,也可以是端到端测试,这并不重要。关键是要编写一个会失败的测试,以便暴露你正在尝试解决的 bug。
小技巧:有时候,你可能需要向分支提交一段有问题的代码,这样就能触发持续集成(CI)构建。构建完成后,这段代码会被保存到你的项目中。这样,你的同事就能找到这个问题了。你的下一次提交就必须解决这个问题。
哪些工具可以帮助你重现复杂的错误?嗯,有好几种:
- 调试器在任何情况下都是你最好的朋友。
- 查找并发错误很困难,有时甚至更难重现。在这种情况下,您可以退而求其次,使用静态分析来静态地查找错误。
- 有时你可能需要调整你的基础设施,这时基础设施即代码就派上用场了。
请记住,有些错误无法在合理的时间内重现。
您可以看看我为 [此处应填写具体产品名称] 创建的一些回归测试wemake-python-styleguide。以下是我们常用的测试结构示例:
code_that_breaks = '''
def current_session(
telegram_id: int,
for_update: bool = True,
) -> TelegramSession:
...
'''
def test_regression112(default_options):
"""
There was a conflict between pyflakes and our plugin.
We were fighting for ``parent`` property.
Now we use a custom prefix.
See: https://github.com/wemake-services/wemake-python-styleguide/issues/112
</span><span class="sh">"""</span>
<span class="bp">...</span>
<span class="c1"># It was failing on this line:
# AttributeError: 'ExceptHandler' object has no attribute 'depth'
flakes = PyFlakesChecker(module)
<span class="k">assert</span> <span class="n">flakes</span><span class="p">.</span><span class="n">root</span>
修复漏洞
现在,当我们发现、报告并重现了错误之后,我们必须真正修复它。
接下来就是修改代码库以消除意外行为的部分了。其实这应该不难!
修复代码并提交后,CI 构建必须通过。如果通过,则表示 bug 已修复。但是,还有一件事要做。
等等,什么?
是的,还有一件事大多数开发人员往往忽略:编写项目回顾报告。有些 bug 很容易解决,不需要这一步,但有些 bug 会耗费我们大量的时间和金钱,我们应该格外重视。项目回顾报告是用非技术语言描述发生的事情,你可以把它展示给你的管理层(以及他们能够理解的人)。那么,项目回顾报告应该包含哪些内容呢?
- 为什么会出现这个错误?请提供一份非技术性的摘要,概述导致此问题的所有操作。并且必须包含指向原始错误报告的链接。
- 我们采取了哪些措施来修复这个漏洞?再次强调,请尽量简洁,不要深入技术细节。只需确保您的提交与此文档关联即可。
- 它对我们的产品/用户/客户产生了什么影响?这需要计算或进行合理的推测。
- 时间线是怎样的?还记得你保存所有日志/监控等链接的时间吗?整理一下时间线会很有帮助。这个bug困扰了我们多久?它是什么时候解决的?
这就是为什么需要进行缺陷分析:它能向未来的团队讲述这个缺陷背后的故事。维护一份持续更新的重要缺陷列表将极大地改进项目的文档。和往常一样,这里提供一些不同的缺陷分析模板链接。
后记
这就是高技能工程师修复漏洞的方式。具体实现可能有所不同,但原则始终不变:发现问题、报告问题、重现问题、修复问题、记录问题。
希望这篇文章能帮助你的项目发展。如果你想了解我目前正在开发哪些开发者工具,请订阅我的 GitHub账号。
文章来源:https://dev.to/wemake-services/best-engineering-practices-how-to-fix-a-bug-58g5



