(04)问题解决篇(下)

关于本系列文字的来源,初衷和内容定位可以参考第一篇的开头部分,链接地址如下:
http://blog.csdn.net/binarytreeex/article/details/8174445
http://www.cnblogs.com/WideUnion/archive/2012/11/12/2766397.html
本文前一篇地址如下,感兴趣的可以访问下面的连接:
http://blog.csdn.net/binarytreeex/article/details/8625156
http://www.cnblogs.com/WideUnion/archive/2013/03/01/2938315.html

在实际工作中软件工程师大部分情况下都是在攻城拔寨,解决一个个自己遇到的问题。这些问题往往是在自己的知识和经验可以覆盖的范围内,所以基本上可以说是顺利的。但是也会有另一些情况的存在,那就是遇到一个自己不会的问题。这些问题具有这样一个外在的现象:问题涉及的内容是在职责或者当前开发任务范围内的,但是对如何实现或者解决这个问题没有思路和办法,简单的说就是第一反应之下是不知道该怎么做来解决这个问题。为了行文方便在下文中,我把所谓不会的问题命名为“难题”,所以在本文中难题这个说法特指程序员不会解决的问题,而不是其它的含义。

一般来说,我们总是力求用简单的方法来解决问题,所以一旦我们遇到一个自己不会解决的问题时,往往表示我们的处境已经不是很妙了,或者说我们的处境有点困难了。本文就是主要分享我个人在应对这些局面时的一些体会。希望帮助软件工程师们能更好的来处理这样的难局和困境。当然这里以难题必须被解决为前提来讨论问题,对于如何规避难题和是否需要解决难题就不讨论了。在这里还要对所谓的不会的问题做一个假设的前提。本文假设如果这个问题能被解决,那么我们缺少的不是知识,也不是经验。否则的话我们的话题会聚焦在学习和经验的积累方面,而不是直接讨论如何去解决一个自己不会的问题。当然我还是同样的再次强调,本文介绍的内容来自个人的实践,对于解决问题这样一个宏大的话题和全体开发者这样一个宽泛的群体来说,局限性和片面性是在所难免的。所以请同行们自行取舍,同时也要根据自己的经验,实际应用场合做出适当的变化,这样才能更好的应用本文介绍的内容。如果分享的内容可以为同行们解决实际工作中的问题起到积极作用的话,那么我的目的就达到了。当然如果能够达到庖丁解牛那样游刃有余的境界那是最好的。

一.难题是什么样的问题

这主要是和一般问题相比而言的,先从来源上来说。一般来讲我们不应该遇到难题,无论从风险还是进度来说,与项目有关的每一个人都应该在力求避免这种情况的出现。但是在某些情况下,难题还是会来的。其中原因是难题的客观存在性。工程师尝试解决实际的问题,而这些问题的难度并不以工程师的主观意志决定的,而是问题本身决定的。另一个原因可能项目本身的要求,比如为了有竞争优势等等,会在实现上提出一些有难度的要求。

从难度上讲,这类问题对于工程师而言在第一反应之下是不会的,工程师所具有的知识经验并不能直接告诉工程师能解决问题。这就是所谓的难。所以在尝试解决问题时问题解决篇(中)里面提到的行不行,在这里就格外重要了。如果一个难题是不能解决的,那就没有必要再去花时间了。

从方法上讲,难题的解决会多出一个步骤,那就是分析。这个分析是对问题本身的认识和理解,这是能够解决问题的先决条件。当然这个理解不仅仅只是审题层面的理解,而是问题本身结构上的认识。为了达到这样的认识往往要求工程师在动手解决问题前需要有一定量的实践活动,用于认识问题。

从策略上讲,解决难题时需要明确自己的战略,因为难题往往是一个产品或者项目的成败关键。所以往往也是资源投入比较多的地方,如果没有好的战略来应对问题,同时从全局把握的话,那么难题引入的风险有可能会失控,这有可能会带来很严重的后果。所以需要有一个恰当的战略。

二.处理难题的战略

在准备或者开始着手解决难题时,要求工程师对于解决问题的战略有一个清楚的认识,并且在解决问题的过程中严格恪守这个战略。这样做的目的是为了减少失败的损失。难题的解决往往需要时间,更有可能会增加对其它资源的消耗,那么万一解决难题失败,我们改如何应对?不成功则成仁的作法是不可取的,也不是一个聪明的选择。所以在遇到难题时,工程师就要确保自己处在进退都有余地的状态,这就是处理难题的战略。

处理难题的战略的第一条是尽量避免自己面对难题。这个意思当然不是说遇到难题时推卸掉或者踢皮球,而是说在构架,分析设计,算法,思路等等每个步骤和细节上都要注意采取简单化的策略,避免出现难题的情况。这个策略是有点矛盾的,但是和特警解决危机事件的策略一样。一方面要求特警的枪法尽可能的好,另一方面在临场处理事件时则采取尽量不开枪的策略。当然如果一定要开枪的话,那肯定要求一枪解决问题。不要为了显示个人的才能或者为了出风头而有事没事的就去挑战难题,这是非常不明智的作法,早晚会挂的很难看的。

第二个策略是时间管理。事实上解决任何问题都是需要花费时间的,只是简单的问题所花费的时间完全在可接受的范围之内,所以时间这个最重要最基本的限制条件往往不被我们意识到。但是解决一个难题所需要花费的时间是多少,往往是不确定的,当时间超出甚至远远超出我们预计时,就会产生很大的麻烦。所以团队中的leader最好能够预先确定可能出现的难题,并预留足够的时间来应对这个情况。这当然是消极的一面,但是也有积极的一面。因为我们也可以假设预留时间以后,难题是可以解决的,很多时候这个假设也是合理的。那么这样再安排开发计划时就可以方便一点了。

第三个策略是风险管理。这个意思就非常明确了,只需要考虑一点,那就是一旦解决难题失败,那么我们是否可以承受一切的后果。这是风险管理的底线,如果这点都做不到,那么在决定解决难题时就要非常非常慎重了,我的看法是最好就放弃吧。另一个一般尺度的作法是,如果难题解决失败,那么应该有一个候选方案可以选择。这样我们就能进能退了,会比较主动一点,心里也会踏实一点,这是一般分寸的作法。当然实际情况会更为复杂一些,往往是问题难度估计不对,或者有些难题没有预估到,等等。所以最终被遇到难题的局面是有可能出现的,尤其是处在一个新产品的研发或者做原型阶段时。这时候就要看内力和运气了。强调一下,至少不要在战术层面上肯定自己能够解决难题,永远不要这样。

三.处理难题的方法以及解决难题的基础条件

当面对一个会解决的问题时,我们一般就直接动手去解决了,即便是需要思考也是在“自己会的”这个前提下作思考。当然这是一种思考,但是面对一个难题时我们需要另一种思考,这种思考就是对问题本身的认识。我们需要通过一定量的反复的实践(或者说尝试)和思考,才能逐步的认识清楚我们面对的是一个什么样的问题,问题究竟是什么样子的。从而让我们对问题本质有一个清楚的认识,进而可以使用我们的知识来描述问题,或者看清楚问题的结构,知道一个难题是由什么和多少简单问题组成的。我把这个过程称之为分析。然后直接使用我们的知识或者依次解决每一个简单问题来解决这个难题。与问题解决篇(中)里面讨论的内容相比,这是一个重要的新的步骤。一旦分析的步骤完成,那么后面的工作就可以按照处理普通问题那样来做了。

上一篇中提到了两个解决问题的基础条件,这里需要再说一个,那就是智商或者说你有多聪明。我觉得智商是这个三个基础条件中是最重要的。当然这听上去不是一个什么好消息,因为智商貌似是老天给的。但是事实上不是这样的,后天的努力可以在很大程度上改善先天的不足。

上一篇中提到的知识在解决难题时当然还是毫无疑问的有用。于上一篇中使用的场景相比,在解决一个难题时如果只是简单重复使用自己的知识恐怕是不充分的。工程师们需要用更具有创造性的思维方式来使用自己的知识。在实践活动中还发现一些简单的知识,甚至是很基础的知识在解决问题时往往能够发挥更好的作用,扮演着主力的角色。

四.思考方法

介绍几个思考问题的方法,这些内容在我看来是非常重要的,也是非常有实用价值的。

1.数学家的思考方法

先说一个数学家思考问题的方法。这个例子是很多年以前我在电视中看到的,当时没觉得怎么样,但是随着年龄的增加和处理的问题难度的加大,越来越开始体会到它的作用了。电视中在介绍数学家如何思考问题时举了下面这个烧水的例子。

假设我们能做一件事情,这件事情是将一个装满水的水壶放到炉子上,然后把这壶水烧开。所以当有人给你一个装满水的水壶,并要求你烧开水时,你是直接能够完成。好,现在假设有人把一个空的水壶拿给你,并且还是要求你烧开一壶水,那么你怎么解决这个问题?生活中处理这个问题是不用想的,直接把水灌到水壶中,然后放到炉子上烧就是了。但是我们用数学家的思维方式来解决这个问题时却需要费一点周折。数学家是按照下面步骤来思考的:

第一步,首先是意识到问题的差异,我们会处理的是装满水的壶,现在是空的水壶。放到实际工作中,这一步就是要求我们有足够的观察力,辨识能力和一种敏感的职业嗅觉来发现问题的关键点和解决问题的正确方向。这个和之前博文中提到的对比法是雷同的,只是使用的场合不同,当然难度也不同。实际上这也是一个分析问题的步骤,但是这个步骤只是一个简单的比较。通过这个比较让我们发现了差异,这个差异告诉我们难题和我们会解决的问题之间的联系。

第二步,然后考虑有没有办法把空的水壶处理成装满水的水壶。如果可以那么这个问题就解决了。数学家的思路的亮点是在这一步,这是一个开启解决问题之门的思考问题的技巧,让我们看到了从不会到会的希望。很多情况下这个时候,我们的想法是换方法,或者是简单就做出判断我不会,而不是想办法去创造或者说尝试创造我们解决问题所缺少的条件。这点上数学家的思维方式提供了一个重要的启示。

第三步,发现将空水壶处理成装满水的水壶方法之一(你也可以花钱让人替你做)是将水灌到空水壶中。注意这是一个发现,也是向解决问题迈出了一步,就这个例子而言还是关键的一步。所以这个发现非常重要。在实际工作的表现就是看你的知识,经验和获取的信息是否足够让我们来找到这个做法,同时对你如何使用你的知识也提出了要求。上面两个步骤是遇到问题和分析问题,这一步则是在分析的基础上发现解决问题的方法。

第四步,现在需要考察将水灌到空水壶中这件事情我们会不会做。在实际工作中的表现是在对一个问题思考分析后,对其中子问题(或者子步骤)的又一次思考。显然实际的情况是我们会做的,至少绝大部分能用手敲代码的程序员是会做的。好了,思考到这一步我们就可以知道这个问题是可以解决的。这里第二步是关键,第三,四步是主体。

这个例子或者说思考问题的方法,非常精彩的演示了如何使用已有的知识来解决一个自己已有知识没有覆盖的问题。当然这样的例子有很多,限于笔墨,就不在说了。

2.牛顿求解曲边梯形面积的方法

牛顿在他的传世名著数学原理中使用我们中学里的知识(现在的中学已经讲极限和导数了,这个不算,我是说我那个时候)定义并证明极限和导数,进而给出了曲边梯形面积的计算方法。这是我目前为止看到的用自己会的简单知识,解决难题的最终极的例子了。各位工科科班出来的都是学过高数的,建议看一下数学原理中那部分的推演和证明,就知道牛顿为什么是牛顿了。当然我想强调的是,这个例子告诉我们还不止是这些。

将数学原理中的证明过程,当然还包括遣词造句的论述部分,和我们学过的高等数学教科书中的证明做一个比较,我们会发现数学原理中牛顿的证明很简单,如果可以的话我想说是简陋。如果我用这样的描述来证明一个题目的话,那么我的高数老师是不会允许我过关的。教科书中极限的概念是用ε-δ语言来描述的,而牛顿基本上使用的是自然语言,甚至连符号都没有(这里申明一下翻译的水平问题不考虑在内),相比较而言牛顿的证明不算什么。这个事实给我们的启示在于,当我们在解决难题时,不一定就可以很快发现一个满意的解,而往往只是一个看上去有可能是解的解。这个时候我们还是要坚持下去的,因为有一个解相对于没有解你已经是一个很大的进步了,毕竟离目标近了一步。如果当年牛顿一定要等到用ε-δ语言描述极限概念时才来完成微积分的建立,那么工业革命有可能就会推迟一百年了。

3.大爆炸理论的线索

天文学家观察到一个现象,那就是所有的星体相互之间的距离越来越远。基于这个事实我们可以得出什么结论?科学们就此提出了宇宙大爆炸理论,就是说宇宙从一个非常小的所谓奇点开始爆炸,从而产生了现在的宇宙。那么科学家是如何从这个简单的事实推出大爆炸理论的呢?其推演过程简单的令人吃惊。如果现在此时此刻所有的星体正在彼此远离,那么过去的某一个时刻,所有的星体的位置就比现在的位置要近,这个结论很显然是对的。那么过去的过去的某一个时刻,所有星体的位置就比过去的某一个时刻的距离会更近一些,这个显然也正确。好了,照这个思路推理下去,星体的距离就会越来越近,最后只能在一起。于是大爆炸理论(当然刚开始应该只是一个假说)就这么诞生了。从这个例子可以看出优秀或者巧妙的思维方式对解决问题会产生不可估量的作用。在大爆炸这个例子中根本没有用到天文相关的任何专业知识,只是通过正确的推理,就得出了这个假说。希望开发者能够体会一下并从中吸取营养。

上面的三个例子是给我留下印象并对我产生指导作用的例子,我相信类似的例子会有很多,大家可以找出适合自己的。数学家例子是最基础也是最重要的,我觉的所有的方法都可以从这个例子中推演出来。牛顿的例子说明的如何创造性的使用知识,最后的例子是考验我们的智商了,或者说观察力了。

五.破解难题的方法

破解难题之难有两个方法可供参考,第一个就是所谓的分析。这个分析通俗来讲就是认识问题,当然认识的内容除了审题和正确理解外,我们更关心的是能不能用一个严格描述来表达难题的结构。如果一旦可以做到这一点,那么解决问题的可能性就极大提高了。从分析的手段来说,大概只有一个那就是实践,通过和事务的接触和互动来考察问题的结构和性质,进而达到认识问题的目的。我有一次去面试,考官出了一个题,说是有三种图形:矩形,圆和椭圆,要求如何设计类来表示这三种图形。我当时没有仔细考虑,第一反应就是按照几何上的定义来设计类。对于矩形就是矩形类,属性是一个左上角的坐标,另外两个是宽和高;圆类的属性是两个:圆心坐标点和半径;椭圆的定义当时我忘了,所以向考官说明想法就不写了。如果这时让我用UML或者OOD来解释一下的,有可能我会说上一段。但是,实际使用的数据结构只有一种:矩形。这一点在以后接触GDI+编程时得到了证明。这个例子告诉我们看出三种本质在几何上完全不同的图形的外在差异,而问题的本质只是一个矩形,这才是表述问题的正确结构。

在分析问题或者说在采取某些活动尝试了解问题时,观察力是一个重要的辅助能力。因为很多活动是通过人机交互完成的,那么观察计算机的输出设备(一般是显示器)显示的信息是认识问题的极为重要的手段。任何细微的变化或者结果都有可能是破解的难题的重要线索。我曾经有过这样一个例子,要让控件的背景显示指定的颜色,当时我还在用VC,于是我就用红色做了一下尝试。结果是控件的背景色没有变化,当时就很被动了,纠结在绘制了红色为什么红色不显示,于是不知道该如何解决。结果在一次偶然的操作中,好像是窗口的最小化以后再最大化,结果发现控件的背景有一次闪动,重复操作一次再观察发现是红色闪了一下。这个现象说明,红色的背景被画上去了,但是又被控件当前的背景色覆盖了。于是破解问题的线索是如何不让控件的背景色覆盖我绘制的颜色。从这个线索出发最终还是解决了问题。

另外还需要强调一下,在采取的认识问题的活动,我认为应该是多样的并富有变化的,可以尽可能多的让自己了解问题。有些时候我们采取了一些行动,但是往往收获不大,这个时候就需要思考了。不能简单的重复活动,而是要采取不同的活动来认识问题,关键点是变化。举一个简单例子,如果我们实现一个文件复制的功能,结果复制失败。这里先忽略复制函数的返回值或者抛出异常的信息这些内容,直接问自己如何采取活动来了解不成功的原因进而帮助解决问题?如果是我的话,我采取的活动可能会是这些:
1.不写程序,新建一个文本文件,然后直接复制该文件

2.不写程序,直接复制程序中需要复制的文件

3.在程序中以直接执行命令的方式复制文件

4.不读取文件内容,而是将一个固定的字符串写入到目标文件

5.在目标位置新建文件是否可以

6.直接在目标位置新建一个同名文件,并且不读取文件直接向新文件写入需要复制的内容

7.读取文件内容,写入到一个已经复制成功过的文件中

8.读取文件内容,但是只写入成功复制文件的那部分内容

我估计这些活动基本上可以找出问题的原因了。发现不同的尝试途径和内容,有时候不难,有时候却相当有难,我建议大家要学会思考。当遇到这种场景可以考虑将双手离开键盘,人站起来离开电脑,到外面散散步,在散步中仔细考虑应该采取的尝试方法。

分析问题的另一个有力工具是排列组合,简单来说就是中学里学的加法定理和乘法定理,更完整的说法就是组合数学中的那些计数方法,定理及其性质。排列组合实际上只有两个核心内容:计数和枚举。如果能够对问题做到计数,那么我们就完成了对问题在结构上的认识;如果对计数结果能够完成枚举,那么枚举的方法和过程也就是解决问题的方法和过程。所以再次强调一下,书本上的知识是有用的,并且是最有用的。

难题破解的第二个方法是简化。假设有一个问题A我们解决不了那么就可以考虑先忽略一些问题中的要求,使得问题的难度降低,然后再尝试去解决这个简化后的问题。如果还是不能解决,那么可以考虑再次简化,或者可以考虑不断的简化。这个做法和迭代开发很类似。这里举一个WideUnion团队实际遇到的问题。Entity Model Studio支持图形化的UML建模,那么当初设计了一个功能,在生成代码前对用户设计的UML模型做语法检查,其中的一项就是不允许出现关系的环。比如继承关系的环:A类继承自B类,B类继承自C类,而C类又继承自A类。显然这个语言检查需要查出模型中所有的这样的关系环。更为规范的描述是:找出一个有向图中的所有的环。

在我学过的知识中,教课书只告诉我如何判断一个图中是否存在环而不是找出所有的环,所以这是超出我的知识范围的,第一反应当然是不会,真心不会。采取的第一个步骤是构造若干个构成环的实例,看着图让自己有一个感性的认识。然后简化问题,这里有两个策略可以走,第一个是假设是有一个环;第二个是有环并且是直接构成环,就是两个节点直接存在指向对方的边。我采取的是第一个策略。然后完善算法,使得算法可以完成这个功能:只要图中有一个环,那么一定能找出来。这样就进入到解决问题的第二个步骤,查找多个环,这一步实际上是分为两个小步骤来完成的。第一个小步骤是,限制构成不同的环只能出现不同的边,不能出现不同的节点。换句话说,新的环是有相同的节点之间的不同有向边构成的。然后再次完善算法,保证图中只要有这样的多个环一定都能找出来。完成这几步后,就可以迈向最后一步了。任何一个环都是由节点和边构成的,上述的步骤实现了相同节点中不同边构成的所有的环,这个算法简称为A的话,那么下面需要做的就是改变节点再次执行算法A就可以了。于是一个原来不会解的问题通过逐步简化就找到一个解了。最近在看书时偶然发现寻找哈密尔顿环的算法应该也是可以参考的。

有时候解决难题往往表现为缺少条件或者有些条件不明确。这个时候,有两个简单而实用的办法可以使用。第一个是假设,这方法在做逻辑判断题时经常使用,我们可以假设条件A成立,或者假设A的内容是XX,从而构造出一个明确的已知条件来帮助解决问题。另一个方法是非常熟悉的反证法。反证法的本质也是假设,只不过假设的是结论成立。一旦假设结论成立,那么结论成立所以依赖的条件也必须成立,那么成功构造出这些条件的方向往往就是解决问题的入口和起点。

六.实例分析

下面通过两个有代表性或者能说明问题的实例来讨论一下,如何使用上面提到的内容来解决难题。

我想先介绍一个偶然看到的电视节目。大概是3月中旬,央视的世界地理频道播出了一期节目,其中一个桥段是说一个大夫如何给一个小男孩致伤的事情。事件的来龙去脉简单的描述如下:

症状:小男孩的背部和大腿上大概有好几百根类似仙人球一样的刺。

问题:如何把这些刺拔出来?

方法:1.直接用器械一根一根的拔。大夫的实践证明效率极低,无法接受。

    2.用胶带纸粘掉刺。结果也不行,胶带纸的粘性不够,刺还是拔不出来。

    3.使用女性用的脱毛用品和胶带纸。成功,效果非常好。

这个故事和我们软件工程师如何解决问题的相关性是什么呢?简单来说有以下几点:

1.医生遇到的问题严格上来说不是治病,而是一种对人体的修理。同样的软件工程师遇到的问题也不一定是严格意义上的技术问题,但是只要你遇上了还是要你来解决的。不管会不会至少你要尽力去解决。

2.胶带纸的使用。我相信那个大夫在学校里读书的时候,他的教材上绝不会把胶带纸作为一个工具告诉学生去给病人治病的,但是在实际工作中他却这么做了。对软件工程师来说,问题的攻克往往也不是用正统的书本知识来解决的。所谓的“旁门左道”也是需要的。

3.脱毛用品的使用。这显然是一个亮点。如果说使用胶带纸是脱离了书本知识,那么脱毛用品的加入则是一个创造性思维的质变。这点对于程序员的借鉴意义在于,要求程序员们要有灵活和富有创造性的思维方式和能力。对于自己掌握的知识是否100%的用尽了,是不是创造性的使用了自己掌握的知识,而不是仅仅简单的重复。

还可以再提出几个问题,考察其中的若干细节,我们能发现这个过程中还有更多的内容可以给与我们启示与借鉴。
1.第一个方法是最正统的方法,但是效率低,那么什么理由决定放弃?
从节目看效率低是直接原因。但是一般来说同一个问题应该有不同的方法可以解决。我在看到这里时,第一反映是是否可以改进拔刺的动作,或者找另外的医生一起来做。那么与那个医生的选择就会不同,于是就有了不同的方法。工程师在解决实际问题时,就要根据自己所处的环境来决定方法的使用。

另外医生尝试后觉得效率慢,那么是不是就一定很慢呢?我相信不同的医生来做效率上是会有差异的。这个说明,解决问题是要发挥自己的技术特长,用长处来解决问题。

2.胶带纸的使用

刺插入身体,刺与身体会形成一个夹角,这个夹角导致刺和身体表面不是平行的。那么在用胶带纸时就会有一定的麻烦。另外在撕下胶带纸时,粘力和刺拔出的方向也不是平行的,显然这个动作对男孩来说是会带来痛苦的。这些细节告诉我们在方法的具体实施时,工程师自身的操作过程也很重要。操作技巧往往可以弥补方法的不足,也有可能会影响方法的效果。当我们决定是否放弃或者使用一个方法时,需要根据实际情况综合考虑的。所以可以看出胶带纸的使用表明那个医生确实遇到了麻烦。

3.脱毛用品的使用

大夫是在和护士不经意的聊天中获得了灵感,尝试使用脱毛用品的。这告诉我们解决问题的思路往往不是来自主战场,有可能来自生活中的点点滴滴的细节中。另外一个需要注意的是,一个创造性的方法的使用,需要考虑其负面的影响,这点非常重要,务必注意。比如,脱毛用品的使用不但没有解决问题,反而带来更大的麻烦,那么这个医生的处境会有多么的被动和狼狈?!

第二个例子来自Entity Model Studio产品,这个问题是我们在开发时序图时遇到的,先简单交代一下问题的背景。在绘制时序图时,用户可以通过鼠标拖动消息,从而改变消息和消息生命线在时序图中的位置,这是所有时序图都应该支持的功能。以Visual Studio中的时序图为例,当用户拖动消息后,直接相关的以及依次相邻的图形都会根据拖动的消息的新位置做出调整,从而保证拖动后各个图形还是在一个合理的位置,这个称之为自动调整。这就是我们想实现的功能。下面依次讨论几个要点。

1.问题的提出

这个功能如果能得到实现的话,用户操作会非常方便,否则用户就必须自己手工调整每一个相关的图形,很麻烦的,体验非常差。所以出于这个目的就提出了实现该功能的要求

2.实现的风险和难度

在我们考察的几款产品中,没有实现该功能的产品也是有的。所以从战略层面上来说,这个自动调整功能不是必须的。这样我们的风险就小很多了,因为就算实现失败,产品也是可行的,当然能实现是最好的。实现该功能的难度在于,这是我们第一次尝试解决图形位置自动调整功能,对相关的算法和知识我们一无所知,也没有相关的任何经验,所以在最初我们不知道该如何去解决这个问题。但是最终决定去的原因,除了风险不大之外,我确实想或者说非常非常想实现一个微软做到的功能,因为在历史上我曾两次挑战失败,所以这次想雪耻。

3.问题的分析

对这个问题的分析,是从使用Visual Studio的时序图开始的,反复的构造不同的图,然后拖动消息,考察其行为,从而找出规律,对这个问题有一个最初的感性认识。通过这个过程,认识到数据结构的设计是需要改动的。通过观察这些行为表现,我们还意识到有可能需要使用到某些我们不了解的定理和算法,这才是最可怕的。为了确认这个疑问,于是又做了进一步的分析。实践表明可以有变通方法解决,这个情况和牛顿用中学知识定义极限是有点类似的。都是在用已知的简单知识去描述一个未知的新的内容。这个过程中,观察力和思考力起着非常重要的作用。

4.问题的简化

问题简化分两步走,第一步尝试最简单的情况,然后考察实现的过程和结果,从反馈中获得信息,判断我们的认识是否正确,难度是否可以接受。第二步是分析可能的存在的各种不同的结构,对每一种不同的结构依次处理,从而把问题肢解掉。这里需要用到一些基础的知识,比如计数方法之类的。

通过上面几步,基本上就可以确定该问题从一个不会做的问题,变成了一个可以解决的问题。当然方法不是唯一的,我相信同行们会有更好的作法。

七.最后想说的话

总体来说解决难题是一项很具有难度和挑战的事情。从使用的方法和思路上来说,我发现扮演主力角色的非常意外的是一些简单的方法和知识,其难点是在于如何应用。医生拔刺,数学家,牛顿和天文学家的思考方法,给我们的启示是:解决问题的方法和思维方式是互通的,没有行业和领域的限制,正所谓它山之石可以攻玉。我们要学会去点滴积累这样的经验,吸收营养,丰富知识,扩展思路从而提升我们分析问题并解决问题的能力。这种现象可以用这样一句话来概括:功夫在题外。

解决难题的过程是一个痛并快乐着的过程,工程师们要有勇气和胆识去面对这样的挑战。你会经受折磨但是也会有快乐的体验。如果你爱一个就让他去解决难题吧,因为那是天堂;如果你恨一个人那也让他去解决难题吧,因为那是地狱。鉴于一些非常令人不愉快的行为,我这里申明一下如果达内需要转载或者修改本人写的任何博文,那么请先获得本人的许可。

好了,这次就写到这里,如何解决问题的话题到这里就算是告一个段落了,通过这次回顾我自己也有相当的体会,确实也收获了一些东西。同行们有兴趣进一步交流的可以加我的群:244054966,这个群定位是创业,新手就不要去了。另一个是:231233168,这个群没什么限制。入群时请加上消息:CSDN博客。下一篇谈谈能力相关的话题,名字暂定为:能力养成篇。

文章导航