Chinaunix首页 | 论坛 | 博客
  • 博客访问: 308347
  • 博文数量: 40
  • 博客积分: 1
  • 博客等级: 民兵
  • 技术积分: 670
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-31 11:19
个人简介

从事银行核心系统设计开发的程序猿

文章存档

2019年(1)

2018年(4)

2017年(11)

2016年(6)

2015年(18)

分类: 信息化

2015-07-28 10:58:00

我记得小时候要写数学作业时,如果遇到那种大家都解不出来的问题时,通常会有一个高手会先把解法解出来,剩下的人再依样画葫芦,照着抄一遍。只要高手没有写错,不会是每个人都错同样的地方,老师通常不会发现。只是有些时候,有些人抄的时候,把过程给写错了,却可以算出正确的答案,就有可能会被老师逮到。

很多人把相同的观念用到了软件开发上,特别是在面向对象开发盛行之后,很多人通常会希望在开发软件时,应该有人先开发出一些可以共享的对象,然后让大家可以在不同的场合,不同的时机里重复使用(reuse),经过这样子产生的综效,就可以减少重复的工作,并且加速开发的流程,提高整个团队的生产力。

这通常给程序开发人员一个很好的借口,当他的进度落后时,他只要把reuse放在口上,大部分的项目经理都会愿意投资一些小小的时间与资源,在进行这样的工作上,特别是这样有机会让日后的生产力有倍数的成长。

在某次整个开发团队的status review meeting中,我们听到这样的对话。

布鲁斯(带着质疑的表情):强森,我从你的status report中可以看到,你目前的进度正在落后。你这个礼拜正在忙什么?
                       
强森(有点兴奋):我这个礼拜正忙着设计跟开发一个可以共享的component,所以花了不少时间。我想如果一切顺利的话,大概再两个礼拜就可以完工。所以整个进度大概目前会比目前的plan晚三个礼拜。可是如果这个component写的好的话,我们就可以马上发挥它的威力。如果每个人都用我新写好的这个comonent的话,我预估可以省下我们一半的开发时间。我想如果没有出大问题的话,应该可以让大家提早两个月完成。

布鲁斯:Good job。(面对其它的人) 我常常说,要work smart,不要work hard。你们要好好跟强森学习。艾力克斯,你的进度怎么样?…

一个月后的status review meeting....

布鲁斯(带着没有耐心的表情):强森,你的那个共享的component现在进度怎么样了?你不是说,两个礼拜就写完了吗?现在都已经一个月了。

强森:我目前遇到几个比较tricky的bug,所以花了不少时间在找问题,现在还差一些小地方还没做好。我想应该再给我一个礼拜应该就没有问题了。我想应该还是可以让我们提早一个月完成implementation。

布鲁斯:要注意时间喔,还有quality。Quality是最重要的。

Implementation delay了一个月时的status meeting...

布鲁斯(带着没有耐心的表情):强森,汤米跟艾力克斯还有洁西卡,都是call你所写的那个共享的component,可是每个人都遇到不一样的问题。你写的这个component到底还有多少bug?到底什么时候才会稳定下来?

强森:我想可能是上次debug时,带来的side effect。我想再给我一个礼拜的时间,应该就可以稳定下来了。不过我想对于日后的项目应该可以有相当大的帮助。

布鲁斯:不是早告诉过你要注意Quality了吗?(对着整个team) Quality是最重要的。我们做什么事情,都要确保它的quality…

Implementation delay了三个月之后,强森离开了公司。留下一个勉强可以运作的component。在日后的project里,这个写好的component从来都没有被reuse过…

当然这里可以从对话中,发现一个有趣的现象:

- 一般的程序开发人员,非常喜欢使用If then else的描述。而管理人员,通常只会听到他想听的部分。

我用这句话来做比喻:『如果太阳从西边出来的话,天上就会掉下来很多很多的钱,让我一辈子也花不完。』

对一个程序设计师来说,这是一个完全make sense的statement。因为程序设计师通常都拥有良好的逻辑观念:『若A则B,如果A的值是false,B的这个block当然就run不到』。可是对于老板来说,他只听得到『天上会掉下来很多很多的钱,让我一辈子也花不完。…』

所以当强森说:『我想如果一切顺利的话,大概再两个礼拜就可以完工。』指的其实是:『如果你运气好,再给我一个月就会写好了。这个component多有用啊。绝对值得花一个月的时间开发。可是如果你知道要花那么久,你一定不会support这件事。没关系,预估本来就会有误差。』要特别注意到的是,连他内心的想法,都包含了if then else的架构:

If (你运气好) then {再给我一个月就会写好了。};

component = 非常有用;

非常有用 = 绝对值得花一个月的时间开发;

If (你知道要花那么久) then {你一定不会support这件事};

嗯,这就是软件工程师跟一般人最大的不同。

然而对于布鲁斯来说,他只听到:『花两个礼拜,就有一个可以让整个team提早两个月完工的秘密武器,以后还可以reuse,我们以后就会有超高的生产效率,可以把对手远远拋在后面…这简直就像是拥有自己的印钞机一样嘛。就算这个家伙慢了两个月,我还是可以从日后整体加速的时间补回来啊。我要不要跟吉娜报告这个好消息?因为我卓越的领导,才会有这么高的生产力,表现这么优秀,今年一定可以领一百张股票…』嗯,这就是老板跟一般人最大的不同。

根据非正式的调查(作者注:可以参考我跟灵犬莱西的访谈纪录为证),reuse通常没有带来如同预期的生产力改变。在某些特殊的案例中,太强调要reuse还造成了schedule的严重落后。我尝试着归纳出下列原因:

* 自以为厉害的程序设计师只想用他自己开发的component。

* 开发软件最花时间的部分,并不是在于写程序本身。

* 低估学习使用component所需要花的时间。

* 错误的component设计理念,以至于reuse这些component反倒会降低生产力。

* 低估开发component的困难程度以及测试component的困难程度。

* 开发出来的软件,响应速度太慢,需要进行大幅度的改写。

以下我会针对这些原因,进行更详细的说明。


***自以为厉害的程序设计师只想用他自己开发的component***

对很多号称是程序设计师高手的人来说,开发自己的component,比起使用别人的component,要来得有成就感多了。使用别人的component,固然可以增加批评的乐趣,可是对于这些人来说,带来的不适可远大于带来的便利。最主要的原因在于:

-使用别人的component,就像把别人用过的保险套洗一洗,再拿出来用一样,虽然看起来外表没什么问题,可是,恶!谁知道里面藏什么脏东西?

女性读者如果没有用过保险套的经验,可以想象把别人用过的卫生纸晒干再来reuse…很恶心对不对?觉得很脏对不对?使用别人写好的component,大部分时候,差不多就是这样的感觉。

对于这些人来说,别人开发的component总是有不够完美的地方,即使外在接口定义的清清楚楚,使用各式各样的数据进行测试看起来没有问题,里面还是可能会暗藏玄机。想想看在电子表格的程序里面,居然可以玩仿真飞行游戏?…别人写的东西,你如果拿不到原始码,你永远不知道到底藏了多少后门跟bug在里面…还是自己来吧。

然而当你写出自己的component,那故事就完全不一样了。大部分的人都希望自己写的东西可以造成轰动,让自己做好的这个小螺丝钉,可以使用在各式各样不同的场合。这很像是看着自己养大的孩子长大成人一样。即使它不成材,你还是认为它可以承担重要的责任,每次看到有人在用它,就会忍不住内心窃喜。当然,总有人不识货,会低估我们所撰写程序的一般性与超高的弹性。遇到这种状况,当然得要指责这种不具团队合作精神的行为。除此之外,建立一套一定要使用你开发对象的标准,在把这个文件列入你们公司的ISO文件中,就可以强迫使用这个component。对了,如果有谁看到我所写的薪资计算模块,请帮我告诉它,我很想念它。我还是觉得它是最棒的。

因为文人总是相轻,所以要说服其它人使用你所开发出来的component,就得要花相当大的力气。所以很多时候,所谓的reuse,其实都只有自己在reuse自己写过的component。

使用别人的component,是否可以提升生产力,其实还跟下一个问题有关:


***开发软件最花时间的部分,并不是在于写程序本身。***

共同开发软件,其实象是把一堆来自欧美非各个大陆,不同国家的人,共同聚集起来,用文言文来写新诗一样困难。最困难的地方,在于要能够彼此沟通,清楚了解到底要开发什么,还有要怎么开发这个东西。观念的沟通,是最花时间的。写程序本身其实并不是最花时间的部分。即使你看着良好的设计文件,你还是需要消化别人的想法,仔细地思考,再转化成你自己的想法,最后才会变成程序。而这个过程,并不是任何共享的component可以加速的。

所以对于生产力的提升,其实是在一个人已经清楚地知道他要负责撰写什么样的程序以后,并且也了解component要怎么使用以后,才会带来这样的效益。如果component的引进,可以让沟通观念的速度加快,只有在这个时候,才会带来生产力的提升。不过有关生产力的提升,事实上还是有极限的。

布鲁斯:你们不是拥有共享的component吗?所以生产力不是已经提升了50%吗?你们不是对它越来越熟悉吗?应该可以越做越快啊。上次写了三个月的程序,现在应该只要三天就可以写完了吧,咦,不是吗?

况且除了沟通以外,我们不可以低估找东西所需要的时间。你需要一个component,可是这个component到底在那里呢?有谁写过类似的东西呢?如果你运气不好,可能你会花三天的时间去找一个你一个下午就写好的东西。很多人都会选择自己动手写,而非找共享的component。所以越简单的小程序,就会有越多人想写写看。况且写写小东西,本来就是程序设计师在学习一项新把戏时,最常做的事情。所以轻量级的component,数量可能最多。累积起来也花掉最多开发的时间。

还好一家公司通常都会有几个超人,可以迅速帮你找到你要的信息。类似搜寻引擎的程序,可能可以帮你一点忙,可是这些程序运作的前提是,必须要有人整理过这些信息。而这个假设的不成立,通常也说明了为什么要推共享的component会相当困难。因为要使用的人,不知道你这里有好康的东西。

当你找到了这个component,你也了解在你完成你的工作时,会需要用到这个component时,这时候所面临的问题,就被提高到了另一个层次...(待续)


***低估学习使用component所需要花的时间***

如果你对这个component完全地不熟悉,你到底要花多久才能了解要怎么样来使用它呢?如果你能够了解它背后的设计理念,你可能不用花太多时间,就可以了解它的意义。问题是,大部分可以称得上是component的东西,通常都十分复杂。即使拥有相当多的参考文件,许多人的学习,还是需要透过从使用这个component的经验中,慢慢观察,多多练习,才可以渐渐掌握它的精髓。这跟学习骑脚踏车与游泳的道理是一样的。

这个过程,非常像是透过component与原作者进行心灵上的沟通。然而我们常常会低估这样的学习,所需要花的时间。这通常还得要视你是否可以得到原创者的开示灌顶有关。如果你可以获得原作者的现场指导,通常会有机会顿悟;如果你只是透过文件想要了解他的神奇功用以及微言大义,要花的时间差不多就是跟你要透过电话性爱达到高潮的时间差不多久。

对于撰写component的人来说,每次有人用他所写好的component,带来的兴奋可能就真的跟透过电话性爱带来高潮差不多。刚开始会很新鲜,久了以后就没啥子感觉了。再久一点,等到所有使用的人把他们的问题跟抱怨用email把你淹没,或是又有一个菜鸟,希望大师可以拨冗指点迷津之后,这种心情,可能就会转变成跟专业的色情电话接听小姐一样吧。只会剩下虚假的高潮,跟交差了事的应付吧。

当然,这还算是你运气好,也就是说你所用的component,是真正有用的。然而有些时候,你会遇到这样的状况:


***错误的component设计理念,以至于reuse这些component反倒会降低生产力。***

这跟你抄数学作业,抄到印刷错误的解答还是抄错题差不多。只是通常发现的时候,都已经太晚了,老师都已经把分数打完还给你了。也很像是剃头剃到一半,打了一个瞌睡醒来后才发现,原本打算扎个马尾,这下子已经半边是个大光头了,不剃成整个大光头,就得要打扮成清朝的辫子头。老实说,用了设计不好的component,差不多就像这样。

根据调查,设计不好的component,在这个业界还真常见。(再次感谢灵犬莱西能够协助进行调查的工作)。我想这可能跟component到底是怎么设计出来的过程,有绝对的关系。

很多人都认为,可以被reuse的component,是某个天才,坐在树下被苹果砸到就想出来的道理。这种故事只是说明了大多数人不知道牛顿花多少时间去观察天象,并研究别人所研究出来的结果。老实说我也不是很清楚,毕竟他在做研究时,我并没有在现场目睹。

然而对于不好的component,我可是看到过不少。我不否认会有会有像我一样的天才,可以一眼就看出事情的本质,然后设计出可以重复使用功能超强bug超少的component。可是这样的人呢,通常像凤毛麟角一样地稀少。大多数比较好的component,都是建立在对于某个领域的了解与经验,将许多类似的东西抽离出来,才有办法做出应用很广,很容易reuse的component。简单地说,component应该是演化的结果。

经过实际运用、改良、测试、再改良,才会有功能越来越强,应用越来越广的component。当然,即使是天才,通常还是要经历过这样的过程。只是时间可能会短一些就是了。

然而有许多人就是弄不清楚,自己到底是天才,还是一般的凡夫俗子。所以通常会把自己的小小心得,当成光芒万丈的创见。然后就会写出没什么用或是设计很不好的component。受限于经验,通常这些component都会有不太好用的地方,甚至根本就是把一件简单的事情,变得非常复杂。

然而有这个特权可以设计component的人呢,通常都具有一定程度的政治影响力,老板才愿意投资时间跟资源在他们身上。通常隐含的结果,就是这种不太好用的component,会被强迫应用在项目里面。所以一个不是植基于经验与实际应用的component,带来的坏处远远大于所可以带来的好处。

除了经验以外,很重要的一点就是模仿。毕竟一个人的经验一定有限。现在有许多open source(开放原始码)的component。当你花时间下去trace(追踪)这些component,并且从实战中累积使用的经验之后,通常透过这样的模仿与消化,你建构component的能力就会成长,这个时候才会比较有机会做出更stable(稳定)更良好的component。

然而,老板通常都相信牛顿原本是个白痴,被苹果打到以后,忽然开窍顿悟万有引力这一套,所以会对开发component的流程有错误的期待,间接就会造成这样的现象:


***低估开发component的困难程度以及测试component的困难程度***

如果component是由经验中推导出来,也就会从以前的实作经验中,抽出适合的程序,来加以归纳与整理。这样的流程,由于是根基于以前的程序,所以在开发上与测试上,相对都比较容易。

然而一旦老板接受了component的开发是天启的结果这种神奇的观念,灾难马上就会降临。Component的好坏,只能建立在天才的高超想象力之上。然而这种纯粹根基于想象力的component,通常基石不稳,所以即使设计好了,还会面临相当多的困难。因为你所预测的运用可能根本不会发生;你始料未及的需求可能不断出现。要开发component的困难程度,相对地就会变成非常高。加上以往可能没有相关的程序当作基础,所以整个component的测试就会是一个梦魇。

更不要提,不当的设计通常会伴随着无数的修改。每次的修改,就会带来新的边际效应。久而久之,很有可能就会叠床架屋,变成一个巨大的怪兽。这个效应,如果伴随着原作者离开,会有更显著的影响。

如果你有维护过大型系统的经验,你就会了解这种可怕的现象。有许多时候,每个人都只维护很小的一个部分,所以并不知道自己的程序会带来什么结果。所以只能就单一模块或是单一个component来看。问题是如果原作者离开了,通常要完全掌握他所写的程序,就需要从文件来了解他的想法。如果文件残缺不全,还是文件根本就写错了,那就只剩下程序代码可以告诉我们事实的真相。

问题是如果是维护一套既有的系统,通常我们还没有能力掌握事实的真相,就会收到要我们修改程序的需求。这些需求通常都会有蛮大的时间压力,不改不行。这时候就精彩了。你要对一个你不是完全了解的东西去做修改。所以边际效应会不停发生。为了降低边际效应,也因为他们没有时间跟精力去研究成千上万行的程序代码,所以通常的做法就是写一段程序,把原有程序计算出来的结果,加上一些新的运算,产生新的结果。

如果运气好,这个人还会写一些文件跟批注。问题是如果当你前面已经有数十个能力习惯不一的人做过这种事情时,事情的真相就没有人会了解了。你会看到有莫名其妙的循环,乱七八糟的程序流程。以及缺三落四的开发文件。你要了解一项东西,可能得要从第一个人的原始文件,一路读到最后一个人的文件,才能掌握大概的情况,还不要提第七个人文笔很烂,写的英文不知所云,第十五个人写的文件根本就写错了。

通常到了这个时候,我们会建议来个改版。对于大部分的人来说,资讯科技的不断进步,顺道解决了这个痛苦的维护问题。

然而如果你还没有机会遇到大改版,这时候通常你会需要解决下面这个问题:


***开发出来的软件,响应速度太慢,需要进行大幅度的改写***

不管使用什么开发模式,是演化型,还是天才型的,其实都有可能面临这样的问题。有很多时候,你写的东西不是弹性不够,而是弹性太高,以至于每次要产生出来这样的结果时,需要蛮长的运算时间。当然,那种因为维护的人更替太多,造成叠床架屋的component,更会有performance的问题。

使用者:以前我们只要20秒,就可以打完一张订单了。现在你们的做法的确比较有弹性,我们可以动态地去改变每张订单所需要输入的栏位。可是你们新版的程序,却需要花20分钟的时间,才有办法打完一张订单,单单那个画面要出现就要5分钟了!你们已经tune了三个月了,是有变得比较快啦,现在只要花15分钟就可以打完了,画面只要1分钟就跑出来了。可是还是很慢啊,你们打算怎么解决这个问题?

布鲁斯:可是你要注意到现在我们所提供的弹性啊!我们这个功能开发了这么久,功能这么强大,又把以前的bug都解决了…

使用者:我不管,我可以接受的是30秒。你们都是IT方面的专家,我相信你们一定有办法的…

任何时候,只要你所开发出来的软件,超出使用者的耐心以后,就会有改写的需求。使用者通常都会期待超高的响应速度,加上超级弹性的设定。问题是这两者通常是不兼容的。如果你要负责调整一个设计相当复杂的component的响应速度,通常所需要耗费的资源与时间,是远大于开发与测试component原型所需要花的时间与资源。所以很有可能会因为component的引进,反而项目造成进度的延迟,以及经费的超支。

还是回到component设计的过程来说,经过演化所形成的component,因为经过实际应用的洗礼,所以通常前几次的使用者,会负责逼出回应速度还可以接受,以及系统还保有一定弹性的component。经过整理出这些东西,建构出可以reuse的component,所能够造成的生产力改变会比较明显。所要担负的风险也会比较小。


***结语***

项目管理,原本就存在许多迷思。有一些植基于直觉的思考,可能会带来完全相反的结果。面向对象开发,其实并不是很新潮的理念。如果component都能reuse,那为什么我们还是需要越来越多的程序设计人员?为什么这些程序设计人员,还是需要日以继夜的工作,才写得出勉强可以运作的系统?

我想建立一套可以集体学习,共同开发的开发环境,加上演化式的component分析设计开发流程,才是发挥reuse component最大功效的基础。如果没有做到这点,任何期待引进component就可以改善生产力的想法都是不切实际的幻想。

即使如此,当你的老板还是要你开发可以reuse的component时,千万不要放弃这个难得的特权,毕竟,不是每个人都有机会把项目搞垮的,不是吗?


阅读(2005) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~