怎么去思考一个问题,提高解决问题的能力_提一个问题,解决一个问题不同觉悟-程序员宅基地

技术标签: 杂七杂八  程序人生  

怎么去思考一个问题,提高解决问题的能力

前言:

#:本文转发自【半路歌雨】
#:http://blog.jboost.cn/think-like-a-programmer.html
#:如有侵权,联系即删

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

导入:

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

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

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

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

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

一.怎么去看待问题

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

像程序员一样思考
像程序员一样思考,到底意味着什么,需要如何来做?
像程序员一样思考本质上来说,是一种更为有效的解决问题的方法。

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

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

提高解决问题能力的方法
我们平时解决问题的方式可能是:

尝试一种解决方案。
如果这种解决方案无效,再尝试另一种方案。
如果还是没有用,重复第二步直到你碰巧把问题解决了。
这种方法被作者 Richard Reis 定义为解决问题最糟糕的方式。因为它不但浪费时间,而且能不能达到目的还得看运气。

一.怎么去解决问题

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

有一个处理问题的框架
按照这个框架反复练习
那么,当你遇到一个新的问题时,该如何来解决?

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

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

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

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

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

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

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

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

对于易复现的问题: 常用的就是 Debug,通过 IDE 断点来跟踪数据的流转与变更,一个个环节检查数据输入输出是否正确来进行排查。可借助条件断点、异常断点等技巧来提高 Debug 效率。
对于不易复现的问题:可通过对比法——对比其它地方的类似功能或实现,寻找两者之间的差异,差异之处往往就是问题所在;分析法——走读整体流程代码,捋清各个环节的逻辑,分析定位问题;日志法——在各个关键环节添加日志,将场景镜像下来,当下次复现的时候,通过分析日志定位问题。
第二步:计划
理解了问题,接下来就是解决问题的方案。没有明确的方案计划时,不要轻易去着手解决问题,不要寄希望于碰运气蒙混过关。许多开发人员习惯于快速扫一眼需求,就打开 IDE 开始垒代码,垒完发现要么与需求不符,要么漏洞百出。

nobug

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

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

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

第三步:分解
这是思维框架中最重要的一步。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_26129413/article/details/110138344

智能推荐

微信公众号授权链接有#的问题_微信公众号带#-程序员宅基地

文章浏览阅读1.7k次。我们做微信公众号项目的时候,肯定会进行授权,但是这个授权有一个很大很大的bug,就是重定向的时候会默认把#后面的内容给截取掉,然后很容易造成死循环等一系列问题我们就当需要跳转的链接是这样的:http:22.22.22.22:8080/index.html#/transformAp?Village_id=2做公众号项目肯定要截取url上的参数对吧,因为这个链接有’#’,所以获取不到Village_id咋解决呢?解决方法一:把链接换成这样的http:22.22.22.22:8080/index._微信公众号带#

在vue中插入echarts图表_vue如何引入 charts-stat-程序员宅基地

文章浏览阅读252次。总之,这个Vue组件的作用是在页面上渲染两个ECharts图表,每个图表都有自己的数据和配置选项,并在组件挂载后自动初始化。这段代码是一个Vue.js组件,用于渲染两个ECharts图表(mychart1和mychart2)。这是Vue组件的JavaScript逻辑部分,包含了ECharts图表的初始化和数据配置。:这行代码导入ECharts库,使你可以在组件中使用ECharts的功能。这是Vue组件的模板部分,用于定义组件的外观和结构。在这个钩子中,你将调用。的方法,用于初始化ECharts图表。_vue如何引入 charts-stat

【ABAP】OPEN SQL(六)「DELETE语句 | MODIFY语句」_sap modify-程序员宅基地

文章浏览阅读7.3k次,点赞63次,收藏49次。各位小伙伴们大家好呀!今天继续SAP ABAP系列文章的讲解,本节继续讲解OPEN SQL中的DML语句,本节内容涉及到DELETE语句和MODIFY语句,希望大家喜欢!_sap modify

python计算均方根误差_如何在Python中创建线性回归机器学习模型?「入门篇」-程序员宅基地

文章浏览阅读1k次,点赞3次,收藏2次。线性回归和逻辑回归是当今很受欢迎的两种机器学习模型。本文将教你如何使用 scikit-learn 库在Python中创建、训练和测试你的第一个线性、逻辑回归机器学习模型,本文适合大部分的新人小白。线性回归机器学习模型1.要使用的数据集由于线性回归是我们在本文中学习的第一个机器学习模型,因此在本文中,我们将使用人工创建的数据集。这能让你可以更加专注于学习理解机器学习的概念,并避免在清理或处理数据上花..._均方根误差python

2019腾讯春招暑期实习提前批编程题_2019互联网企业暑期实习-程序员宅基地

文章浏览阅读2.1k次,点赞2次,收藏9次。错过了腾讯的春招编程题(在牛客笔试前已经电话面所以就没参加,有自己做C++的笔试,对C++不熟,感觉已经凉了),但是朋友做了便截图下来然后自己练习一下,给我的感觉就是,会做的就很快写完,不会的基本没有什么思路,总之很快写完了三道题,但是有两道是不会的。下面按题目给出我的代码,有错的恳请指正。1、不要看到这个就以为是背包问题,这个是从大到小的,也就是说什么面值的货币都有,所以就不存在比如..._2019互联网企业暑期实习

针对开发的项目的个人NABC-程序员宅基地

文章浏览阅读84次。首先我们的创意是结合我们所学的专业知识,由于每次周在野外进行大地测量实习的时候关于计算问题有遇到很多问题,对于手算,有可能会出现人为错误,再次回去重新计算,会浪费大量时间,而且会很麻烦,也不一定会完全正确。N(need)需求1对功能的规定1.1精度符合测量规范1.2满足的要求我们的创意将会满足测量的同学对于导线和水准测量方面的计算问题。1.3对与已有的软件有些方面比如..._nabc项目表格

随便推点

Windows SDK(五)按钮静态文本与编辑框控件-程序员宅基地

文章浏览阅读864次,点赞14次,收藏13次。我们首先应该知道,所谓按钮静态文本等等控件都是窗口,他们都是隶属于父窗口下的子窗口,所以在创建控件前,我们要首先创建一个父窗口,此处我们直接使用Windows桌面程序创建时,程序自动为我们创建的一个窗口,该窗口如下表示:nullptrnullptrnullptr此时我们已经有了一个主窗口,接下来开始讲解控件的创建和应用在以下控件内容中,我们首先在全局变量中定义我们的控件ID,以便我们后续控件的查找#define0#define1#define2按钮的创建。

vue-antd使用Table+Drawer做管理系统增删改查操作_用ant-design-vue4.0实现table表格的增删改查不调用接口写法-程序员宅基地

文章浏览阅读7.4k次,点赞4次,收藏53次。一、查Table显示查询数据,官方api1、常用到的属性属性名 描述 数据格式 columns (必选)表头 [ {title: '姓名',dataIndex: 'name'}, {title: '年龄',dataIndex: 'age'} ] data-source (必选)表头 [ {UserID:13,name: '张三',age: '12'}, {UserID:16,name: '王五',..._用ant-design-vue4.0实现table表格的增删改查不调用接口写法

Linux上如何查看某个进程的线程_linux thread 查看进程下面的 线程-程序员宅基地

文章浏览阅读1.2w次,点赞4次,收藏13次。问题: 我的程序在其内部创建并执行了多个线程,我怎样才能在该程序创建线程后监控其中单个线程?我想要看到带有它们名称的单个线程详细情况(如,CPU/内存使用率)。本文参考了百度百科。线程是现代操作系统上进行并行执行的一个流行的编程方面的抽象概念。当一个程序内有多个线程被叉分出用以执行多个流时,这些线程就会在它们之间共享 特定的资源(如,内存地址空间、打开的文件),以使叉分开销最小化,并避免大量高..._linux thread 查看进程下面的 线程

5.MySQL高级语句,你给我学!-程序员宅基地

文章浏览阅读959次,点赞2次,收藏6次。视图(view)是在基本表之上建立的表,它的结构(即所定义的列)和内容(即所有数据行)都来自基本表,它依据基本表存在而存在。一个视图可以对应一个基本表,也可以对应多个基本表。4.视图是查看数据表的一种方法,可以查询数据表中某些字段构成的数据,只是一些SQL语句的集合。从安全的角度说,视图可以不给用户接触数据表,从而不知道表结构。3.表只用物理空间而视图不占用物理空间,视图只是逻辑概念的存在,表可以及时对它进行修改,但视图只能有创建的语句来修改。6.视图的建立和删除只影响视图本身,不影响对应的基本表。

信息学奥赛一本通(2036:【例5.3】开关门)_奥赛一本通2036-程序员宅基地

文章浏览阅读5k次,点赞3次,收藏3次。2036:【例5.3】开关门时间限制: 1000 ms 内存限制: 65536 KB提交数: 723 通过数: 457【题目描述】宾馆里有n(2≤n≤1000)n(2≤n≤1000)个房间,从1∼n1∼n编了号。第一个服务员把所有的房间门都打开了,第二个服务员把所有编号是22的倍数的房间“相反处理”,第三个服务员把所有编号是33的倍数的房间作“相反处理”…,以后每个服务员都是如此。当第nn个服务员来过后,哪几扇门是打开的。(所谓“相反处理”是:原来开着的门关上,原来..._奥赛一本通2036

curl连续请求页面卡死解决办法_curl_easy_init 重复-程序员宅基地

文章浏览阅读6.5k次。今天项目中遇到一个问题就是在后台用curl请求数据,连续请求url链接后页面会卡死502错误,最后解决办法是在 curl请求方法中加了CURLOPT_TIMEOUT就可以了,这样如果超出设置时间不影响页面其他的请求,到了设置时间请求也会停止curl方法如下:function get_request($url){ //初始化 $ch = curl_init(); c..._curl_easy_init 重复

推荐文章

热门文章

相关标签