在以前的文章中,曾经提过“技术人员的价值,不在于你能写出多么优美的代码,也不在于你能设计出一个多么大而全的高屋建瓴的架构,而在于你实实在在的解决问题的能力,在于你使用技术手段服务于业务的能力”。

最近一段时间,因工作中遇到一些现象,让我重又想起这句话,并且试图思考如何来提高解决问题的能力,有没有一种方法论的手段或者技术性的框架来实践?

先罗列一两个遇到的现象:

  1. 某同事汇报,测试提了一个Bug,当某个用户绑定的卡信息超过50个的时候,后台显示数据就会出现混乱,问能不能限制绑定的卡不超过50个。我问:数据显示出现混乱是什么意思?答:不清楚;我再问:为什么超过50个就会混乱了,少于50个有没有可能出现混乱,造成混乱的原因是什么?答:不知道。我说你先去搞清楚什么叫“混乱”,然后再搞清楚为什么会出现“混乱”再来说解决办法。经过与测试人员的一番沟通后,跟我反馈说不是显示混乱,是显示不全,自己通过查看实现是因为在服务端做了字符串拼接,超过多少就被截断了。

  2. 某同事在抱怨,这个问题很难复现,我不知道怎么解决,要不要把这块整体优化下算了。我问他你优化的目的是什么,是优化目前实现的流程、结构?还是通过优化来解决这个难以复现的问题?答:来解决这个问题。我说你问题都没定位到,怎么通过优化来解决,不怕老问题没解决,优化出新的问题出来了?

你有没有也曾经说过或听过“这个问题太复杂了, 我解决不了”,“这个功能我没办法实现”,“我也不知道为什么会出现这个问题”之类的话语。

以上的现象与话语,可能都是一个人解决问题的能力或方式方法还不成熟的体现。那么如何来提高解决问题的能力,我想首先需要先从思维方式或思维习惯上寻求改变。在网上看到有这么一篇文章——《How to think like a programmer — lessons in problem solving》(文章地址见文末参考部分),介绍了通过5个步骤来帮忙人们建立高效解决问题的思维框架。本文以这5个步骤为基础,结合自身的理解与体会进行介绍。

Jobs

“这个国家的每个人都应该学计算机编程,因为它会教你如何思考”

像程序员一样思考

像程序员一样思考,到底意味着什么,需要如何来做?

像程序员一样思考本质上来说,是一种更为有效的解决问题的方法。

解决问题的能力是一项元技能

什么叫元技能?
类比于元数据——描述数据的数据叫元数据,我理解元技能就是提升技能的技能,就是说当你掌握了解决问题的能力,你就可以通过这种能力去提升其它各项专业技能。

解决问题的能力也是最重要的能力,比精通编程语言,调试能力,以及系统设计能力都更为重要。

提高解决问题能力的方法

我们平时解决问题的方式可能是:

  1. 尝试一种解决方案。
  2. 如果这种解决方案无效,再尝试另一种方案。
  3. 如果还是没有用,重复第二步直到你碰巧把问题解决了。

这种方法被作者 Richard Reis 定义为解决问题最糟糕的方式。因为它不但浪费时间,而且能不能达到目的还得看运气。

经过对优秀程序员在编程时的思维框架的分析,作者总结出提高解决问题能力的最好方法包括:

  1. 有一个处理问题的框架
  2. 按照这个框架反复练习

那么,当你遇到一个新的问题时,该如何来解决?

第一步:理解

遇到问题时,我们应该先要弄明白问题本身。大部分情况下,问题之所以难解决只是因为你没真正理解它们(很多时候是出于沟通的不充分),理解问题是解决问题的第一步。

如何确定自己是否真正理解一个问题?

最有效的方法是,尝试用自己的语言来说出它,看有没有逻辑漏洞。当你能讲清楚一个问题时,说明你理解了它。优秀的程序员编程时,一般都会写下自己遇到的问题,画出流程或序列草图,或同产品经理、其它开发人员、测试人员等一起讨论确认。这个过程,就是在确定自己对问题的理解有没有偏差。

“如果你不能用简单的语言来解释一个事情,那意味着你根本就没有理解它” —— Richard Feynman

面对一个新需求时,你应该了解这个需求产生的场景——什么人,在什么时候通过执行什么操作,来达到什么目的?这个场景及其中的行为逻辑是否合理,设计是否存在漏洞,然后带着问题来与需求提出方讨论确认,而不是断章取义或不经任何思考直接编码开干。不做代码的搬运工,要做有思想的程序员。

同样,面对一个 Bug 时,你应该首先了解这个 Bug 产生的场景——什么人,在什么场景,通过什么操作会产生这个问题?要追本溯源,定位问题的本源在哪里。
我认为定位问题的本源比解决问题更重要!因为你只有正确地找到了问题的症结,才有可能去解决它,而解决办法却可能有多种。且从花费的时间来说,定位问题往往会占整个解决问题时间的一半以上。

如果没有找到问题的本源,只是头痛医头脚痛医脚,那么可能不仅对解决问题无事无补,甚至还可能引进新的问题。常见的头痛医头脚痛医脚的处理方式包括,CPU占用高了,内存溢出了——升级服务器配置(可能过两天又得升级了!);接口超时了——增大超时时间(可能导致用户投诉或其它依赖的服务级联超时),等等。

那么日常工作中,如何来定位问题的根源?对于一般问题来说,可能通过查看日志大致就能找到问题所在,对于比较棘手的问题,针对问题的性质一般可通过如下方法进行定位:

  • 对于易复现的问题: 常用的就是 Debug,通过 IDE 断点来跟踪数据的流转与变更,一个个环节检查数据输入输出是否正确来进行排查。可借助条件断点、异常断点等技巧来提高 Debug 效率。
  • 对于不易复现的问题:可通过对比法——对比其它地方的类似功能或实现,寻找两者之间的差异,差异之处往往就是问题所在;分析法——走读整体流程代码,捋清各个环节的逻辑,分析定位问题;日志法——在各个关键环节添加日志,将场景镜像下来,当下次复现的时候,通过分析日志定位问题。

第二步:计划

理解了问题,接下来就是解决问题的方案。没有明确的方案计划时,不要轻易去着手解决问题,不要寄希望于碰运气蒙混过关。许多开发人员习惯于快速扫一眼需求,就打开 IDE 开始垒代码,垒完发现要么与需求不符,要么漏洞百出。

nobug

制定计划,就是制定解决问题的战略步骤。

不论面对需求还是 Bug,都应该好好计划你的解决方案。设计好解决方案中的各个环节,如业务需求的数据表设计、接口设计、流程逻辑,Bug 修复的具体实施步骤。并给自己一点时间思考与预演,该解决方案可能存在的漏洞与影响有哪些,除了这样处理,还有没有另外更好的解决方案。

在没有想清楚解决方案时,不要直接上来就撸代码,暂停一下,给你的大脑一些分析问题和处理信息的时间。

第三步:分解

这是思维框架中最重要的一步。

分解,就是化繁为简,就是我们常说的分治思想,拆分法——将大问题拆分为若干个小问题,然后逐个击破各个小问题,再合并总结。微服务架构,MapReduce 算法,都是这一思维(或思想)的体现。

不要尝试一次解决一个复杂的大问题,而应把复杂的大问题分解成若干个简单的小问题(或子问题),从最简单的子问题开始(最简单意味着你知道怎么解决它或它更容易被解决,也或者这个子问题的解决不需要依赖于其它子问题),一个一个逐步解决。一旦你解决了所有的子问题,把它们串联起来,一般就意味着你解决了之前的那个复杂的大问题。

分解问题的能力是解决问题的基石。这也是优秀的程序员在编程中最常用到的技能,对于他们来说,分解问题的能力,要比编程语言的熟练度、系统设计等技术更为重要。

第四步:卡壳了怎么办?

当你理解了问题,做出了解决方案的计划,将复杂问题分解为子问题后,在处理子问题时依然卡壳了怎么办?

首先,淡定!然后告诉自己,这很正常,每个人都会遇到。

优秀程序员或解决问题的高手,与普通人之间的差别就在于,他们对问题更有求知欲,更有耐心,他们的注意力更多地是在如何解决问题上,而不是为此恼火或甩锅发牢骚。

当遇到卡壳的情况时,可以试试这几种方法:

  1. Debug:与前面定位问题一样,一步一步调试,直到找出究竟哪里出错了。
    “Debug 的艺术关键在于你究竟让软件干了些啥,而不是你以为你让软件干了些啥。”—— Andrew Singer

  2. 重新评估问题:退回去,从另一个角度重新审视问题,别让自己迷失在细节里,有时候我们容易迷失在具体的细节中而忽略了更一般的原则。重新评估问题的另一种途径是推倒重来,可以删除(回滚)所有已做的事,重新开始,有时这是非常行之有效的方式。

  3. 搜索解决方案:利用搜索引擎找到类似问题的解决办法,向他们学习。使用搜索引擎需要学会提炼关键字,关键字越有代表性,越容易找到答案。对搜索结果应该抱着参考的态度,而不是照搬,要明白为什么如此这般处理就能解决问题,并在解决问题后能依次延伸了解其上下游或相关知识,比如SQL查询慢,发现是索引未生效,则可以延伸了解都有哪些场景会导致索引失效;比如并发问题,则可以依此了解如何保证线程安全,同步机制,锁机制等相关知识。事实上,即使问题已经解决,你也可以经常这么做,因为这样你可以从其他人的解决方案中及上下游知识中学到更多。

  4. 寻求支援:当通过以上方法都无法获得解决办法时,向你的同事、上级或朋友求援,如果是开源项目,到开源社区、技术群,或 github 的 issue 列表中发帖求援。

  5. 记录问题与解决方案:将你本次遇到的问题与最终的解决方案用(电子)笔记本记录下来,便于后面回顾或参考。

第五步:练习

罗马不是一天建成的,你也不可能期盼通过解决一两个问题就能成为解决问题的高手。但是,如果你能以学习的态度来寻求问题的解决办法,通过以上四个步骤来建立一套解决问题的思维框架,每一个问题的处理都是提高你能力的机会。那么距离成为一个解决问题的高手,就只差一步了,那就是:练习,练习,再练习。在问题中练习,训练你的思维方式与习惯。

lixiaolong
“我不害怕一次练习1000个踢打动作的人,但我害怕将一个踢打动作练习1000次的人”

总结

其实,解决问题的能力,不论在IT技术领域,还是在其它各个领域,都是一种最基本的技能。当你在说出“这个问题我解决不了”,“这个问题我没办法定位”前,试试本文介绍的理解、计划、分解、卡壳时怎么处理的建议方法,多一些耐心,一步步实践,说不定慢慢就看到曙光了。按照这个处理模式或习惯,在日积月累的问题处理中,你可能已在不知不觉成为了解决问题的高手。

参考:

  1. https://www.freecodecamp.org/news/how-to-think-like-a-programmer-lessons-in-problem-solving-d1d8bf1de7d2/

评论