14条原则 (2) 首先检查最简单的:例如,MFC播放avi的时候在上面画东西

14条原则 (2) 首先检查最简单的:例如,MFC播放avi的时候在上面画东西

我见过不少小孩撞了头以后,一边哭一边踹柱子。你一定也见过不少程序编译未
通过,或者逻辑错误,或者在游戏里被PK死了,然后摔鼠标砸键盘的。

还有程序出了问题以后,大骂微软这垃圾编译器,或者操作系统的,断言,一定
是"这垃圾的XX有问题。"

第二条原则是,首先最简单的。也就是,先检查最容易检查的。如果你病了,大
夫看了一眼,然后就断言,一定是某某病,回去吃某某药吧。你可能根本不敢相
信,虽然他要求你一圈检查,你又觉得他是有意让你多查以便赚钱。马上断言
的,大多是扯淡,只有一项一项排除的,才更可信一些。

一项一项排除,从哪里开始呢?从最简单的。

一个故事。一次,我在吉林大学某机器上,刚好主人不在,同时授权我使用。我
打开机器,看到了登录界面,用户名已有,要求口令。我开始试各种弱口令。姓
名缩写,电话号码,房间号,我甚至试了空格,无一命中。

终于主人回来,告诉我,口令是:没有口令。只需回车,就会登录上去。但是这
最简单的可能,我没有试。

另一个故事。当年还是novell网络横行时候,组一个游戏网。novell公司的
netware有个特性,可能是承袭自unix,登录的时候敲的键不会有任何回显,不
像微软会显示"*",你敲一个键,微软就显示一个"*"。所以有人开玩笑,你的密
码都被我看光啦,不就是星星星星星星星么。novell连个星号也不显示。

当时我组一个网络,用一般用户什么的都登录正常了,就差用管理员,我记得是
叫admin还是supervisor登录,设置各种权限。就在这时,我卡住了。我登录不
上去。这种活经常干,按说不应该哪里出错。我开始排查,翻过来倒过去,就差
把整个网络重做了。

半个小时还是两个小时,时间太久远,我记不清了,终于我想到了一种可能--键
盘上有个键坏掉了。而那个键,正好就在我的密码当中。所以,在系统看来,我
的密码总是错的。

问题一旦找到,解决就容易至极,换个键盘。

我没有试最简单的可能,有各种原因。阻止我想到那是最简单的可能的一个关键
因素是,我认为那是不可能的原因。

很多年以后,有同学跟我说:老师,我编程序什么都觉得还顺利,就是建VC工程
太慢了,老是记不住。

我答:那你就只建空工程,连续建20次。然后就记住了。

对于那些被视作简单的练习,我都是这样回答的。如果你认为这个练习非常简
单,它一定花不了你多少时间,那么做一次也不费事;如果你认为这个练习太花
费时间了,那么,这一定是一个足够复杂的练习,非常值得一做。

那些我们以为最简单的练习或者检查,如果花费的时间不多,为什么不执行一次
呢?断定一个程序正确的最佳方法,不是趴显示器上看两个小时,而是跑一遍。
跑一遍并不能断定它是正确的,但是如果跑不出正确结果,我们却可以飞快地证
实,它是错的。

所以,如果程序不是特别大,你可以不停地编译,每隔一小段时间。让编译器保
证你始终走在正确的或尚可挽回的局面中。

类似的,有同学问我,WORD写文章的时候,应该多长时间保存一次呢?答案不是
几分钟几小时,而是"你能够承受损失之前"。如果你一分钟能打个百八十字,而
且你不在乎损失这一分钟,那么这时你不必存盘,如果你一分钟只能打个二三十
字,而万一这时断电你会非常难过,你可以十秒钟就存盘一次。文章是由一次次
存盘构成的,而不是一个键入的字构成的,因为只有存盘的结果才能呈现与人。
不然,你就只能吹:我已经有了一个巨完美的证明,只是没有存盘。

每次存盘,是可见的微小进步。那些微小的,应该引起我们最大的重视。

有的同学可能会问:为什么要先检查最容易检查的,而不是先检查最可能的故障。
因为除非有十足的证据,仅凭猜测,你无法断言"最可能"的是什么。而获取更多
证据的方法,就是检查。如果你假设故障来自某个原因,准备开始检查,这检查
已经变成了一个新的实验,这时,你也应该首先检查一新实验中最容易的一项。

当撞到柱子上,先检查完柱子没有移动过来主动攻击你,这几乎瞬间甚至我们没
有觉察就已经完成了;编译失败,逻辑错误,先检查自己的程序,而不是先假设
编译器有毛病,因为你假设编译器有毛病太困难了,通常超出了大多数同学的水
平。关于断言编译器有毛病,参见此系列后面的对比法。

大骂微软编译器垃圾,十有八九最终发现垃圾的是自己。也许它的确很垃圾,但
我们编程的时候,肤浅到通常远未触及到它垃圾的部分。

又一个故事,雷锋修车。传说雷锋修车的时候有个螺丝找不到了,找了半天也不
见踪影。战友说,算了吧。雷锋说,不行,万一掉到汽车里的某某地方,汽车就
要出大故障了。然后他们又找了很久,终于在就是那个某某地方找到了那个螺丝。

这个故事原意说的是雷锋是个认真的好青年。我当时一直不明白,他们为什么不
先找那个某某地方呢?

现在想想,如果这个故事是真的,也许他们有找螺丝的程序,先找最容易的,然
后步步向下。虽然过程漫长,但是最终总能解决问题。

从最简单的开始检查,其实对应着一种非东方的科学思考方法。相关笑话一个。
说中国老太太和德国老太太把针掉到地上以后的反应。中国老太太会根据针掉的
方向,大致去看看,然后就找到了。德国老太太会把地板画上方格,然后一个格
子一个格子找,凌晨之前也许能找到。

表面上看,中国老太太很有灵感,非常聪明。不过,德国老太太的方法的优势在
于,她一定能解决问题。她从某处开始找,可能就是最容易找的格子--虽然这个
格子并非最可能的方向,但是遍历之后,针必然在某个格子中。

我们排除故障的时候,可以准备一个checklist (检查表?),把所有的可能原因
列上,然后开始排查。从简单到复杂,当表格扩展到某一位置的时候,问题就显
现出来了。这也是我们为什么要训练写作实验报告的一个原因。

有经验的网络工程师检查故障的时候,不是凭直觉,而是先检查下三层,比如用
ping。如果下三层正常,再去检查DNS什么的。为什么先用ping,最主要的原因恐
怕正是因为这个工具用起来简单快速。

显示器不亮,最先要排除的原因是什么?不是主板不是操作系统不是厂商的人
品,而是,先确定通电了。尤其是远程诊断的时候,尤其远程的用户并非熟练技
术人员的时候,并参见此系列后面的"永远不要相信你的用户"。

编程的时候,我们通常正确的路线开始,用最朴素的方法。当然,什么方法才是
朴素的,是需要时间训练和一定的知识结构的。不是你最熟悉或唯一熟悉的方法
就是朴素的。

然后,很多同学会犯一个错误。那就是,如果这个朴素的方法最开始的时候没有
工作,很多同学就放弃这个方法,转向另一个,如果那个方法也不好使,就再转
向一个新的。

当你尝试某种技术路线的时候,一定要确保这种技术路线是不能用的。确保它不
能用的方法是,或者1.你了解到它不适合这个项目的缺陷,2.你有充分的实验证
明它不适合,然后你还需要保留证据。这些证据就是你实验报告的内容,用以自
己备忘或吵架用。

昨天,帮一个同学改MFC的程序。目标是用CAnimate控件播放avi文件的同时,在
上面画点东西。解决的步骤如下。

1. 该同学说,他在OnPaint事件响应中写了画线,但是这线不显示。

我请他演示,线确实不显示。我猜他没有发送OnPaint消息,所以响应函数没有
调用。他说他在OnPaint里写了弹出了一个MessagBox,验证这一点。我说,那你
应该看到好几百个MessageBox,如果OnPaint消息一直发送的话。他说,是的,
他看到了。

我们没有看到那么多MessageBox。事实上,只在程序载入的时候弹出一个。所
以,OnPaint消息响应里的那些东西都没有一次次被执行。

关于上述这一点,并非适用首先检查最简单的这一原则,而是适用"永远不要相
信你的用户",请见后文。

2. 我们改了程序,OnPaint源源不断发来,也能画线了。但是线被CAnimate的控
件挡住了。

我考虑到的方法: (1)在控件的上面放一个窗口,设置为透明,在那个窗口的工
作区里画东西; (2)网上查到的,设置控件为透明; (3)修改工作区所在窗口的
Z坐标,把它放到控件的顶上。

头脑不清醒,有的我还走了几步。反正都不怎么好。 方法(1)这个方法太复杂,
感觉上这样的任务不应该太复杂,尤其是rush一个粗糙原型,不然VC太弱了,违
背了一般较完善系统功能的规律。方法 (2)失败了,原因不明,现象没有任何变
化。方法(3)简单太笨了,当时真的可能没有带大脑,那样控件就会被工作区遮
住,avi的播放就看不到了。

然后我想到了一个方法,因为简单,所以马上试了试。简单,可能有效,是我们
选择一个方法的重要理由。

我们发现CAnimate派生于CWnd,而CWnd::GetDC()可以取得CDC设备上下文,而
CDC上面是可以画东西的。事情就这样成了。

在这个方案之前,还走了一小段弯路。我试图从控件的指针构造CDC。在控件没
有播放avi的时候,画的东西在控件上,当avi播放,画的东西消失了。我们猜
测,当avi播放的时候,CDC或者控件的指针不再安全地关联了。瞎猜的。MSDN中
对于handle,对象的指针,有一大堆文档,没有一一去读。

这个原型能跑了,虽然很粗糙,一个劲闪烁。不过简单的,能快速有点效果的,
不停的小恩小惠,正是人类所追求的。

其实,相对于这第2条原则,我有一个不良习惯。我往往最后才检查最简单的或最
可能的,尤其是年轻的时候。当时是希望借此积累经验。现在,我更希望把那些
用于积累经验的实验,放到解决问题以后。当然,问题解决以后,可能就没有情
致再去积累经验了。

相对于经历本身,我们原始的渴望直接想得到的,往往是终结那一刻的快乐。所
以,我们可以经常向心中的小兽投食:你看,又一个可能的原因排除了,又一个。
这些小奶酪,安慰我们,使脆弱的我们可以坚持走完全程。

虽然,那些都不是原因也不是结果,但是那些一路伴随我们的,该记录下来。在
最终审判以前,我们任谁都不知道哪个才是正解。如果没有记录的话,当那一刻
到来,你却早就忘记了如何走到这里。

正是那些最简单的所有伴随我们的事件形成了我们,当你开始忘记,你就失去了
自己。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值