前言

我在工作中总会有如下对话:

某测试:“张,XX 功能报错了!”

我:“报什么错?”

某测试:“我用了下这个功能就报错了!”

我:“……(可能对方没理解我的意思?)有什么提示吗?怎么操作的?日志发来我瞧瞧。”

某测试:“我就是调用了一下,他就报错了,我没看日志!张你研究下!”

我:……

每天在这种对话上要浪费不少时间,并且花费时间排查后,大概率是对方不看文档导致的错误使用。不论是技术人员还是非技术人员,都应该懂得如何提出一个有效的反馈,节约大家的时间。

当你反馈问题的时候(既然已经这么做了),一定是希望问题得到及时解决。所以此时针对程序员的任何过激或谩骂的言语都是与事无补的——因为这可能是程序员的错误,也有可能是你的错误,也许你有权对他们发火,但是如果你能多提供一些有用的信息(而不是激愤之词)或许问题会被更快的解决。

因此,我整理了如下几点建议,希望可以帮助大家提出一个有价值的反馈。

提问前

遇到问题时,心里一定很着急,可以理解。但是在决定向开源社区或开发人员提交问题前,最好先简单尝试自己解决下:

阅读文档

可以去看看官方文档,利用好搜索功能,查询问题、功能的关键字,这也许能够快速解决一些问题。

搜索引擎

90% 你遇到的问题,很可能别人也遇到过。这时通过 Bing、Google、StackOverflow 等网站进行搜索(不建议看 CSDN,浪费时间),可以帮你快速定位并解决问题。永远记住,地球上的你并不孤单,包括你遇到的问题。

问问身边的人

如果你身边的人也曾用过同一个功能,那么可以尝试着问问他。没有人会拒绝善意的探讨。

如果以上 3 步都无法解决你遇到的问题,也别犹豫,立马向开源社区或开发人员提交问题就好。

提问时

提问有很多种,比如你认识作者,直接面对面请教就行。下面探讨的是如何通过互联网的方式来问问题。

平和对等的心态

提问时,不要把自己摆在顾客的位置,比如:

项目马上要上线了,请务必帮忙解决!

另外,也不要把自己摆在乞食者的位置,比如:

救命啊,这个功能我今天急用!

不论是在开源社区,还是公司部门之间,一切皆是朋友。无论对方是 Linux 内核的作者,还是新来的实习生,你和作者都是对等的。你的提问是在帮助软件完善。平和对等的心态,可以让你的问题赢得更多人的阅读和思考。

通过正确的途径提交

如果有专门的反馈邮箱或 Bug 管理系统,请最好到这些指定系统中提交。

最不好的途径是:

  • QQ 、微信等群组。这些群组主要是用来休闲的。对开源项目来说,在这些地方提问,作者一般不会关注,效率非常低。
  • 微博、Facebook 等社交网络。不少人在微博上通过 at 或私信询问问题,这些我经常看不到。看到了,也不情愿回复。微博是扯淡、交流情感的地方,一般是写代码写累了,才去逛逛,很少会有在社交网络上回答技术问题的心情。

通过正确的途径提交问题,一般可以让你的问题得到及时准确的回复。

使用明确、有意义的标题

抱着平和对等的心态,找到合适的途径后,就得静下心来将遇到的问题写成文字。书写文字不是一件简单的事情,我们可以从遵循一些简单的规则开始。

首先是提问标题要简洁清晰,要言之有物。比如:

XX 功能出错,求大神指点

XX 功能在我的浏览器上运行不了,别人的可以

上面举例的标题很糟糕,光看标题作者无法知道发生了什么事。当开源社区的问题很多时,上面这类标题,经常会让作者直接忽视或将优先级降到很低。更妥当的标题是:

XX 功能提示 XXXXX(错误码)

XX 功能在 Chrome 69 无法使用

明确、有意义的标题,可以帮助作者确定问题具体是什么类型、预估需要多少时间解决、是否现在马上解决等。一个好的标题,也有利于社区知识的沉淀和后期搜索。标题有如一个人的颜面衣着,虽然不是关键,但在嘈杂的信息社区中,这很重要。

遵循良好的模板

如果社区提供了问题模板,一定要仔细看下。比如我的开源项目,当你创建一个问题时,会自动提供以下模板:

# 前言

请确认你已经做了下面这些事情,若 bug 还是未解决,那么请尽可详细地描述你的问题。

  - [ ] 我已经安装了最新版的 Hobby
  - [ ] 我已经搜索了已有的 Issues 列表中有关的信息
  - [ ] 我已经阅读了 Hobby 的 相关文档

# 描述错误

<!--简洁而清晰的描述这个错误。-->

# 复现方式

<!--复现该行为的步骤。-->

# 预期行为

<!--对你期望发生的事情进行简洁而清晰的描述。-->

# 截图

<!--如果可以的话,请添加一些截图以帮助描述你的问题。-->

# 系统版本和运行环境

<!--请描述你的版本以及运行环境。-->

# 其他

<!--在此处添加有关该问题的其他内容。-->

遵循这个模板去描述问题,经常能省很多事。作者一般也非常欢迎通过模板提交的问题。如果社区没有提供模板,也可以自己遵循以上模板来提交。

下面针对问题内容,具体说说一些需要注意的点。

语法正确、格式清晰

虽然我们不是作家,但正确的语法、清晰的格式,可以让读者赏心悦目,也就更有心情帮你一起思考解决问题。

对于很多需要代码来描述的问题,要尤其注意格式,比如:

List<Category> children = categories.stream().filter(category -> Objects.equal(parentCategory.getId(), category.getParentId())).collect(Collectors.toList());

可读性不如:

List<Category> children = categories.stream()
            .filter(category -> Objects.equal(parentCategory.getId(), category.getParentId()))
            .collect(Collectors.toList());

良好的代码排版能让你的内容看起来很专业,大家也就更有意愿会去帮助你,否则糟糕的排版,经常带来的是提问之后的石沉大海。

描述事实、而不是猜测

事实是指,依次进行了哪些操作、产生了怎样的结果。比如:

我在 XX 环境下,通过 XX 操作后,点击 XX,这时浏览器弹出 XX 错误提示。

上面是一段比较好的事实描述(更好的是把错误提示也截图上来),而不要像下面这样猜测:

XX 功能在 XX 环境下运行不正常,我怀疑是源码第 213 行有问题。

上面的描述,会让作者一头雾水、甚至很恼火。尽量避免猜测性描述,除非你能先描述事实,在事实描述清楚之后,再给出合理的猜测是欢迎的。

如果能提供可重现错误的在线可访问代码,那是最好不过的。一旦你这么用心去做了,作者往往也会很用心地立马帮你解决。

描述目标、而不是过程

经常会有这种情况,提问者在脑袋里有个更高层次的目标,他们在自以为能达到目标的特定道路上卡住了,然后跑来问该怎么走。比如:

XX 应用如何手动指定 JDK 路径?

上面这个问题的背后,提问者实际上想解决的是如何通过手动指定 JDK 路径来实现单机安装多个 JDK 的问题。提问者选择了手动指定 JDK 的方式来实现,但这过程中遇到了问题,因此跑过来继续怎么走。然而,如果只是描述过程,往往会把作者也绕进去。

实际情况却是,提问者选择的路本身就是一条崎岖之路,对于要解决的问题,实际上有更好的方式。这种情况下,描述清楚目标,讲清楚要干什么非常重要。

在描述自己是怎么做之前,一定要先描述要做什么。提问题时,What 往往比 How 更重要。

要有具体场景

无论在开源社区,还是微博、知乎等平台上,有一种非常常见的问题:

如何维护 Java 代码?

如何使用 maven 进行模块化开发?

这类问题还有很多,每每遇到,只能笑笑,然后悄悄地忽略掉。因此这类问题很难回答,就如下面这些问题一样:

如何才能让生命有意义?

如何打败阿里?

这类提问者,一般比较浮躁,经常对问题本身也没有经过思考。踏实的提问者,不会让问题浮在空中无法回答,而会在具体场景中让问题落地:

我的项目有 20 多个 Java 模块,接下来还会急剧增加。目前遇到以下问题……(省略五百字)…… 请问如何维护?

正确描述问题

记录问题

当程序出毛病的时候,立刻停止正在做的任何操作。不要按任何健。仔细地看一下屏幕,注意那些不正常的地方,记住它或者写下来。然后慎重地点击“确定” 或“取消”,选择一个最安全的。学着养成一种条件反射——一旦电脑出了问题,先不要动。要想摆脱这个问题,关掉受影响的程序或者重新启动计算机都不好,一个解决问题的好办法是让问题再次产生。

演示问题

报告问题的最好的方法之一是“演示”给程序员看。让程序员站在电脑前,运行他们的程序,指出程序的错误。让他们看着你启动电脑、运行程序、如何进行操作以及程序对你的输入有何反应。

口述问题

“演示”是很好的办法,但是常常做不到。那我们应该尽可能确切地告诉程序员你做了些什么。如果是一个图形界面程序,告诉他们你按了哪个按钮,依照什么顺序按的。如果是一个命令行程序,精确的告诉他们你输入了什么命令。你应该尽可能详细地提供所输入的命令和程序的反应。

把你能想到的所有的输入方式都告诉程序员,如果程序要读取一个文件,你可能需要把这个文件发给他们。如果程序需要通过网络与另一台电脑通讯,你或许不能把那台电脑复制过去,但至少可以说一下电脑的类型和安装了哪些软件(如果可以的话)。

如果你给了程序员一长串输入和指令,他们执行以后没有出现错误,那是因为你没有给他们足够的信息,可能错误不是在每台计算机上都出现,你的系统可能和他们的在某些地方不一样。有时候程序的行为可能和你预想的不一样,这也许是误会,但是你会认为程序出错了,程序员却认为这是对的。

同样也要描述发生了什么。精确的描述你看到了什么。告诉他们为什么你觉得自己所看到的是错误的,最好再告诉他们,你认为自己应该看到什么。如果你只是说:“程序出错了”,那你很可能漏掉了非常重要的信息。

如果你看到了错误消息,一定要仔细、准确的告诉程序员,这 确实 很重要。在这种情况下,程序员只要修正错误,而不用去找错误。他们需要知道是什么出问题了,系统所报的错误消息正好帮助了他们。如果你没有更好的方法记住这些消息,就把它们写下来。只报告“程序出了一个错”是毫无意义的,除非你把错误消息一块报上来。

特殊情况下,如果有错误消息号,一定 要把这些号码告诉程序员。不要以为你看不出任何意义,它就没有意义。错误消息号包含了能被程序员读懂的各种信息,并且很有可能包含重要的线索。给错误消息编号是因为用语言描述计算机错误常常令人费解。用这种方式告诉你错误的所在是一个最好的办法。

在这种情形下,程序员的排错工作会十分高效。他们不知道发生了什么,也不可能到现场去观察,所以他们一直在搜寻有价值的线索。错误消息、错误消息号以及一些莫名其妙的延迟,都是很重要的线索,就像办案时的指纹一样重要,保存好。

间歇性问题

“间歇性错误”着实让程序员发愁。相比之下,进行一系列简单的操作便能导致错误发生的问题是简单的。程序员可以在一个便于观察的条件下重复那些操作,观察每一个细节。太多的问题在这种情况下不能解决,例如:程序每星期出一次错,或者偶然出一次错,或者在程序员面前从不出错。当然还有就是程序的截止日期到了,那肯定要出错。

大多数“间歇性错误”并不是真正的“间歇”。其中的大多数错误与某些地方是有联系的。有一些错误可能是内存泄漏产生的,有一些可能是别的程序在不恰当的时候修改某个重要文件造成的,还有一些可能发生在某一特定时间。

程序员想要了解任何与你发现的问题相关的事情。有可能的话你到另一台机器上试试,多试几次,两次,三次,看看问题是不是经常发生。如果问题出现在你进行了一系列操作之后,不是你想让它出现它就会出现,这就有可能是长时间的运行或处理大文件所导致的错误。程序崩溃的时候,你要尽可能的记住你都做了些什么,并且如果你看到任何图形,也别忘了提一下。你提供的任何事情都是有帮助的。即使只是概括性的描述。这虽然不能提供导致问题的直接线索,但是可能帮助程序员重现问题。

最重要的是:程序员想要确定他们正在处理的是一个真正的“间歇性错误”呢,还是一个在另一类特定的计算机上才出现的错误。他们想知道有关你计算机的许多细节,以便了解你的机器与他们的有什么不同。有许多细节都依仗特定的程序,但是有一件东西你一定要提供——版本号。程序的版本、操作系统的版本以及与问题有关的程序的版本。

仔细检查、确保准确

是人都会犯错误,特别是在如此快节奏的互联网环境下。好不容易把问题描述清楚时,不要急着立刻提交。在提交前,至少保证从头到尾再仔细阅读一遍,比如语法错误、错别字、标点符号、排版等等。做到这些,不光是尊重别人,也是尊重自己。

提问后

提交问题后,建议通过邮件等方式订阅回复。互联网上最有效的沟通方式是异步沟通,不要期待作者马上回复,也不要心烦意乱着急地等待。

尽可能补充信息

在接收到回复时,仔细阅读。最经常的情况是,社区回复的,经常不是你想要的。比如:

根据你的描述,问题无法重现。能否提供具体使用环境和重现步骤?

这时要淡定。仔细看看自己提交的问题描述是否足够清晰,如果有可补充的信息,尽量补充,以帮助作者能尽快定位问题。比如:

很抱歉,我前面有一步描述不正确,实际情况是我是在 Firefox 中运行的……

谦和淡定的交流,不光能帮助你解决问题,还有助于你结交更多朋友。

适当的总结

当问题终于解决时,建议对问题进行总结。可以编辑原帖,也可以通过博客等方式总结。你的总结,会让遇到同样问题的朋友们受益,并且对自己的技能也是一种提高。无论国内还是国外,有很多牛人之所以成为牛人,很大程度上都是因为有总结思考的好习惯。

不要忘记感谢

最后,记得感谢。很多开源软件的作者,都是利用业余时间在创作代码。你的感谢,会让开源社区充满爱与力量。