报bug和寻求帮助的基本素养
针对软件开发(包括算法实现、性能优化)、软件测试(测试开发、测试)遇到的bug或问题,提问者的一些注意事项。
态度篇
- 礼貌提问, 保持谦卑:
- 是要提问,而不是要怪对方写了bug
- 通常是你使用方式不当; 你没有收集整理基本信息、没有自行尝试过就来提问,这不礼貌 - 保持好奇, 得到解决方案后你是否理解原理?
- 得到回答请说“谢”
- 回答者给了答案, 你提问者忙, 晚点再试, 那你试完了给个反馈,是能用了还是继续报错?回答者不是你的“提款机”
- 问题解决后, 你能否自行整理?
- 能否重新审视,先前自己对问题的描述,是否存在不准确的地方?不准确在哪里,原因又是什么?
- 能否整理最小复现工程,并审视自己先前提问时,给的描述/复现步骤,有明显多余的地方?
- 能否把问题描述、最小复现工程,整理到自己的知识库/博客中,下次遇到同样问题,快速得到答案?
认知篇
-
问题描述越准确,解决起来越容易
- 编译错误,链接错误,运行crash, 这是三种不同的描述,不是同一类问题
- 程序挂了,程序只在 Release 模式下挂了, 程序在 Release 模式下在第一帧就挂了, 程序在 Release 模式下在第一帧稳定的挂, 程序在我的电脑上在 Release 模式下第一帧必挂、在另一个人电脑上不挂, 这是逐渐精准的描述 -
最小复现例子
- 最小化复现代码
- 你实际写的代码有300行,调用了5个API,能否只用10行代码,只调用1个API,也能触发同样报错?
- 最小化构建步骤
- 你实际遇到的问题,链接了5个库。 能否只用一个库,也能触发同样报错?
- 最小化运行环境
- 能否用 docker 运行你的程序?
- 使用不当的错误, 往往在整理最小复现例子后容易发现
- 调用代码不当(如传参错误、内存非法访问)导致的报错
- 构建步骤不当(如链接库顺序不正确,同名库文件有多份)
- 运行环境里的干扰因素,能通过 docker 避开, 或发现关键的环境变量
- 如果不能复现,说明“砍多了”
- 对于代码的精简, 你可能需要结合使用 git
- 对于构建脚本的精简, 你可能要查看最终传给 gcc/g++ 的命令,而不只是看 CMakeLists.txt
- 对于不同环境下的不同结果, 考虑把环境具体化,把每个具体的环境因素,查看版本信息然后比对 -
提升问题描述准确度的方法:
- “剥洋葱”法: 整理最小复现例子、用 gdb 调试并查看 callstack、查看C/C++的反汇编
- 小黄鸭调试法: 把你的问题讲出来,小黄鸭能听懂的级别
- 打 log 法: 查看现有log,增加打印 log, 开启 verbose 输出
- 检查系统法: 重启系统、查看CPU/内存信息等
- 版本控制法: 用 git 管理代码, 二分查找
- 搜索提问法: 问 GPT4, 查google, 在 stackoverflow/QQ群提问
- 笔记/博客记录法:吃一堑长一智,准确记录错误现象、根因和解决步骤,下次遇到同样问题可快速查询已有解决方案。
报告篇:
- 用一句话/100字以内,简要描述你的问题
- 场景:可以是纯粹的技术场景, 也可以是结合公司/产品/业务情况的具体场景
- 步骤:做了哪些操作, 也就是达到“场景”前做了什么
- 预期:明确写出你想要的预期行为, 而不是觉得“很直白、很明确”。 例如预期是程序运行不报错, 或预期程序报错并且错误码是123。
- 报错:提供报错的信息, 并提取报错的关键文本描述, 如 undefined reference to x86_xxx, 这个信息用于索引你的问题 - 报错信息(文本和截图)要完整
不要以为截图了就完整了,不要自以为关键报错都截进去了,都在里面的话您还来问什么呢? - 环境说明清楚:
- 操作系统情况?
- 是 Windows, Linux, 还是 macOS, android, QNX?
- 操作系统版本是多少?比如 ubuntu 和 centos, 各自有不同的发行版, ubuntu 18.04 和 centos 7.0.2009 是具体的
- 编译工具链情况?
- 是 Visual Studio, GCC, Clang, AppleClang, 还是 android ndk, 车载的 qnx710 交叉编译器? qnx 和 qnx710 也不一样
- 编译器没按预期工作,那么各自的 glibc 版本是多少?要把 GCC 版本, GLIBC 版本都标明,而不是只说 GLIBC 版本,让人云里雾里。 - 预期结果要讲清楚
- 不符合预期的现象要标明
- 如果尽你所能,还是无法准确描述问题,请尝试和 ChatGPT 提问, 也许它让你觉得啰嗦, 但那些也许正是你忽略/没注意到的关键线索
归因篇
- 看不懂报错:
1. 报错信息中有单词不认识(技术层面不了解),干扰了理解,忽略了路径等问题
2. 眼神不好使,或者错误信息本身不够清晰(例如C++模板相关编译报错) - 路径错误:
1. 报错信息包含了路径,但被你忽略;
2. 报错信息没有直观的路径,你不知道如何查看/懒得查看
3. 找人提问对方提示了检查路径,你没听进去 - 环境变量问题:
1. 终端程序, 需要新开 shell/terminal/cmd 生效
2. GUI软件需要重启生效 - 问题不简洁
种种原因导致的工程代码复杂,需要具体分析
1. 你可以怀疑是用的别人的库的 API 有 bug, 但要提供明确证据
2. 你不能犯懒,只把报错截图、调试器输出、调用代码截图给对方。你应该自己整理。
3. 对方吭哧吭哧整理20分钟,没复现; 你换了版本, 对方又吭哧吭哧整理20分钟,还是没复现。你这态度不对,你为什么不第一次提问前就整理最小复现工程?
案例
贴一些实际遇到案例, 略去敏感信息, 只针对提问方法学做记录
5.1 编码库运行 crash
提问者的关键描述:
师兄,我用你的编码库源码库, 遇到 crash 了
师兄,我用你的原版工程构建, 没有 crash 了
点评:
-
为什么第一次提问时, 没用原版工程的构建方式?
例如:原版工程是基于 CMakeLists.txt, 里面标记了依赖的 protobuf 库是使用 3.21.9 版本的静态库, 是在 VS2019 x64 MD/MDd 的 CRT 下使用; 而提问者自行按 CSDN 博客上编译 protobuf 为 DLL 的步骤编译了 protobuf,版本也不是 3.21.9; 最终程序 crash 时的堆栈, 在 protobuf.dll 中。
那么很可能是 protobuf 库的使用方式的问题。 -
第二次提问时,提问者没有自行分析原因和差异。
这其实是没找到根因, 导致后续有人遇到同样问题时, 没有有效的参考。问题根因也许并不是 protobuf.dll 和 protobuf.lib 的区别。
5.2 company_cv 库运行不起来
提问者的关键描述:
同一份代码,在ubuntu上能编译运行,在centos上编译后运行报错。是链接了 company_cv 库。 是不是和 glibc 版本有关系?
构建的 CMakeLists.txt 中,链接的库是【截图】, 报错是【截图】,调用的代码是【截图】
点评:
- 描述的内容比较丰富, 超过相当一部分提问者
- 仍然不够准确,在关键问题上信息不足: ubuntu 和 centos 版本分别是多少? 编译器版本分别是多少?
- 没有自行整理最小复现工程: 三次【截图】都是原始工程里的截图,问题过大,应当简化: 能否只用一个库、只调用一个函数来触发问题?
- 没有搜集信息: 是链接 company_cv 库时报错, 链接自行编译的 gtest 没报错, 那么应当明确提问: 编译 company_cv 时的 GCC 和 glibc 版本各自是多少?提问者有时候需要“反客为主”,可以是自行用二进制工具查询,也可以是向对方提问
- 没有找到 “静态链接” 的解决思路:可能是还不太会用 ChatGPT
又一次问答:
[一个周四下午]
A: 静态链接glibc应该可以解决,你试一下?
Q: 行(大概率不知道那是什么)
A: 到ubuntu环境下,在CMakeLists.txt开头,project()后,加两行
A: set(CMAKE_EXE_LINKER_FLAGS "\({CMAKE_EXE_LINKER_FLAGS} -static") A: set(CMAKE_CXX_FLAGS "\){CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
A: 删除原有build,重新构建,得到的testbed,拷贝到centos上运行,看是否有报错。
Q: 好的,我试下后告诉你结果[周五等了一天,A君没得到回复]
[周日, 晚上8点]
Q: 放弃了,更新centos版本,然后用的glibc2.28版本
[第二天早上, 周一]
A: 这个替换是一劳永逸的,以后比较方便。
A: 静态链接的方法,试了后不能直接用吗?还是说没有尝试?
Q: 静态链接试了后,不能直接用
A: 报错是什么呢?
[没有回复]
点评:被提问人A提供了方法(静态链接),很希望提问人Q去尝试,如果失败给出报错信息。结果Q用了别的方法,关键报错也没提供给A。下次提问,你觉得A还应该给出回答吗?
5.3 company_cv::transform_color() 结果不对
提问者的关键描述:
第一次提问:
Q: 你好, company_cv::transform_color() 结果有点问题, NV21 时结果对的, RGB 时候错的。
Q:【截图】(一张把人眼区域贴图回到原图的截图,存在错位、复制多次); 【截图】(工程里调用代码截图)、【截图】(vs2022调试界面截图)
A: 【一番查看代码】在新版修复了,你换新版试下
第二次提问:
Q:你好,换了新版后结果还是不对,【截图】
A: 我试下复现。【一番尝试后】复现不出来。
A:【文件】这是我用的复现代码
Q: 我改了了下。【文件2】。能复现吗?
A: 试了,复现不了
Q: 用别的尺寸的 roi, 能复现吗? 如 50+
A: 试了,复现不了
点评:
- 没有提到 company_cv 库的版本。 实际发现 changelog 网页提到了, 新版修复过这个问题
- 提问者自己不整理复现代码, 回答者提供后, 提问者也不尝试运行, 直接手写代码, 又丢给提问者。
- 提问者总体上问了两次, 浪费了两个人各自一小时的时间, 毫无进展。 如果自行整理复现代码, 起码省出来一个人的时间。
5.4 链接 company_cv::transform_color() 报错
提问:
Q: 你好,我要用 company_cv 库, 怎么申请?
A:[回答者开会开了一上午,刚开始一天的真正工作,没空回复]
Q: 【飞书加急,电话打过来】你好,我要用 company_cv 库。怎么申请?
A: 你能说下是哪个角色(算法/开发/测试)吗?(您可是第一次用啊,能不能介绍下自己)
A: 这个库不是设计为给测试开发用的。你们需要用别的
Q:测试代码之前就用了这个库
A: 好吧,先给你开通下载权限了。
提问2:
Q: 你好,我链接报错了,没有这个函数吗? company_cv::transform_color()
A: (你也不说是下载了哪个版本的 company_cv, 你的测试开发代码我也不知道怎么写的,我怎么回答?)company_cv 有这个函数的
[没有对话了]
点评:
- 提问者大概率是个新人,接手了老代码。
- 提问者的提问,信息不足: 你是第一次使用 company_cv 库,你也看到网页上介绍说, 请说明情况; 但你没有说明自身角色。开通权限的人没法弄清你的情况,自然没法开通权限。
- 老代码的编写者,使用库不当: company_cv 库并非为测试开发人员开发的, 先前已经反复交涉过不止5次。硬是要用,太倔强了。
- 提问者没有整理问题就提问,太随意: 用到的 company_cv 库是哪个版本的? 编译时和链接时,版本分别是多少? 构建脚本是怎样的? 有没有自行用 nm 命令去查询,当前使用的库里面,有没有 transform_color() 符号?
5.5 怎样实现某个查询功能?
亲戚的孩子大学1年纪,做网页项目来提问。
Q: 做了一个查询考试分数的网页。有个功能是xxx,写了代码但是结果为空。能帮忙看一下吗?【代码压缩包】
Q: 这问题也问了好多老师和同学,他们都说不会
A: 这代码不完整,跑不起来. 缺少需要查询的数据。能提供一下吗?
Q: 数据是考试分数,太敏感,不能提供
A: 能否制作类似的数据, 模拟一下, 用来调试
A: 哎呀,你看这样行不? 这样操作。 我找了网上的js代码,你看这代码为啥不行?
Q: 我做不了。
点评:
- 这是一个典型的, 不会整理最小复现例子的案例
- 这个一个典型的, 提问者想法太多, 过于主观, 无效提问的案例
- 很多老师、同学,并非不会, 而是问题本身描述不清晰、 不完整
- 数据敏感和模拟数据是两回事,搞混了
5.6 使用包管理器 company_package.cmake 导入 OpenCV 报错的排查
Q:你好,我用你的 company_package.cmake 导入 OpenCV, 报错了。 帮忙看下?
A:【截图】(不完整的信息,没有 CMakeLists.txt, 只看到 cmake configure 的部分报错)
A:请更新 company_package.cmake 到最新版后再试下。
A: 更新命令是 cmake -P company_package.cmake upgrade-company_package
Q: (不说话)
Q: 我更新好了,错误没变
A:需要提供 CMakeLists.txt 和 cmake configure 的 log 输出。
Q:【CMakeLists.txt文件】
A:CMakeLists.txt 看起来没什么问题
A:cmake configure 的log发我一下
Q:【CMakeCache.txt文件】这个文件能先看一下吗?
A:这个文件信息不全,直接看log
Q:怎么得到 log? 【给人的感觉是,小白,不知道什么是重定向】
A:rm -rf build && cmake -S . -B build -P company_build.cmake ... > cmake-configure.log 2>&1
Q: 我这里没有 company_build.cmake 文件【给人的感觉是,过于钻牛角尖】
A:这里的关键是重定向。你把你执行的 cmake configure 的输出内容重定向到文件。
Q:控制台输出里,没有你需要的内容。【给人的感觉是,过于自以为是;你不是 company_package.cmake 作者,你怎么判断有没有有有效信息?】
A:是否有需要的内容,需要你先提供log文件,我来判断。
Q:【make.log】(你就不能命名为 cmake-configure.log 文件吗?有点脑残了)
A:没看出来问题。我试了下没能复现。
...
5.7 来学习微软员工的回复方式
Thank you for reporting the issue! According to the information you provided, we could not reproduce the issue. In order to be able to investigate your issue, could you please provide an entire self-contained code/project that could reproduce the issue and the command line?
Please refer to https://docs.microsoft.com/en-us/cpp/overview/how-to-report-a-problem-with-the-visual-cpp-toolset?view=vs-2019 about the repro.
We look forward to hearing from you!
Thanks.
“感谢反馈问题!根据你提供的信息,我们无法复现问题。 为了弄清楚你的 issue, 你能否提供能复现问题的、自包含的代码/工程和命令行执行步骤? 请到 https://docs.microsoft.com/en-us/cpp/overview/how-to-report-a-problem-with-the-visual-cpp-toolset?view=vs-2019 了解如何提供最小复现。 期待你的回复!谢谢”
5.8 开源社区问答一则
https://github.com/progschj/ThreadPool/issues/36
由于提问者的描述含混不清,得到了5个downvote。显然提问者没什么礼貌。如果要提问,请说清楚。