时下是个概念横行的社会,比如各种概念车、绿色空间、新新人类、web2.0.......反正是概念嘛,不管概念包裹下的东西新旧,只要概念新,包装形式稍有改变即可作为创新推出。众人闻风而动,唯恐落后,各种商机也随之显露,放风者自然不会错过亲自制造的东风,不失时机地提供产品或服务,最终满载而归,而众人也在追逐这些概念中得到满足,皆大欢喜。
既然如此,软件开发自然也不免俗。各种开发方法都以个性化的概念涌出,如近几年的CMM、CMMI、RUP、Agile、XP......让人眼花缭乱,每个看起来都是那么诱人,可是又有很多地方互相“矛盾”,该信哪个呢?
既然不知道哪个更好,不妨先自己捉摸捉摸。软件开发要达到的目标是什么呢?以老板们的想法,当然是“多快好省”了。
多:要功能尽量地多,最大化地满足用户需求。
快:开发速度越快越好,早点推出也许就能把收入计入这个财年。同时用户当然也希望早点投入使用,尽早产生效益。
好:质量要好,bug得少。
省:省钱!每月开出的工资越少越好,总成本越少越好。
实际上,老板们一般都是“旧旧古董”,接受能力较低,因此对于种种概念并不感冒。只要能“多快好省”,才不管他东南西北呢。因此,只盯着上面的四个字,其他的随便。虽然有点不讲道理,但也没有错,并且往往还对我们这些geeks有利,这也算是一种授权嘛。
不管这些华丽的概念,先按照基本的主要开发过程罗列一下,看有什么办法能达到目标。
需求分析
为用户设计软件,需求当然来自用户,因此不管哪种开发方法,都强调需求的收集及分析。XP更是达到了极致,在整个开发过程中让用户代表参与,随时获得需求信息,验证是否符合用户需求,快速响应用户需求。和以前的一开始从用户处收集需求,到最终开发完成再让用户验证,当然有进步。
但是这基于一个假设的前提:能找到用户参与到开发过程中。幸运的情况下,也许真的有这样的用户能提供这样的帮助。但是现实情况中这应该是很少见的(开发为软件开发提供支持的软件的除外),因此遇到一次应该去买点彩票,说不定就能顺便中个大奖。另外,用户代表能否代表用户也是有疑问的,单个或几个人总是有个人偏好的,如若不信,看看人大代表能在多大程度上代表民意就知道了:(
因此,更实际的方法可能还是传统的方法,在项目准备或开始的时候认真做需求收集分析,能做原型设计更好。为了控制对用户需求的偏离,如果项目较大,可以分成多个release,每个release完成后邀请用户体验反馈。
由于处于开发的前期,因此出现偏差对以后影响很大,所谓“差之毫厘,谬以千里”。为了减少不必要的返工,并且为以后开发扫除障碍,大家都知道要尽早确定需求。能有确定的需求当然好,但实际情况是大部分用户需求会变,或者说很难获取真实需求,往往到他能用的时候,他才能知道自己想要什么,也才能告诉你这些。因此,之前的努力是否有效就看需求分析人员的功力了,对用户的领域知识越多,以用户的思维考虑越多,越可能往正确方向走。另外,可以把客户化需求多的模块尽量放在后面做。
需求分析的结果形成需求文档。描述用户的需求,最好由一人来写,其他人支持,尽量保持内容的一致性及完整性。多人写的东西往往各部分“独立自主”,没有呼应,甚至因矛盾而“兵戎相见”。另外,多人写的内容,如果没有人通盘考虑,相互依赖,会造成“缺胳膊少腿”。
设计
在需求确定或大致确定后,可以进行设计,包括高层设计HLD和低层设计LLD。在XP中,对设计基本越少越好,因为其对需求的理念是易变,自然对设计不能做的很详细,需求一改变,以前的设计作废了,因此从经济的角度看,自然设计要少做,重要的是快速写出代码,让程序跑起来,然后让用户看是不是想要的东西。
而较传统的设计方法强调设计的详细、周到,恨不能把把伪码都写出来,然后再找几个“印度蓝领”翻译成IF...Else等等。好像日本的公司推崇这种设计程度。
其实这是两个极端,知道中庸这个词的中国人大概都知道走极端是不好的。因此不会有太多人有意采用上面的两个极端,尤其是第二种,估计大家不会犯这个“错误”。但往往有人不自觉地就采用了第一种不设计的方法,这倒并不是因为什么XP,而是不知道软件开发还有设计这一步,于是随心所欲,走哪算哪:(
实际情况往往采用折中,既不过于设计也不缺少设计。一般做到:
1. 模块之间的分割及接口设计
一般由一个人完成
2. 共用类、库的抽取
可以由一个人完成,也可以由相关人员协商
3. 各个模块的主要算法及流程设计
各自完成,无需很详细,能说明问题及其解决方法即可,无需达到UML图级别。
同样,要形成设计文档。同样的原因,建议由一人主笔。
编码
如果从最终产品来看,真正能运行的是编译后的代码,因此编码的重要性就不用多说了。在XP中,很快进入编码阶段,同样,这也是基于需求易变的理念,尽快写出代码好让用户体验反馈。为了支持需求易变,代码于是也不得不变,这样产生的代码会不会越改越滥呢?不用担心,XP有法宝:重构(Refactering),从一行行代码开始,不断改进,自低向上,越改结构越清晰。有了这个法宝后XP才敢不进行设计就恣意妄为。
和那种设计到伪码或画出UML类图相比,我是肯定采用Refactering的。如果在写伪码或画UML类图上花和写代码同样多的时间,当然选择直接写代码,最终要的是可执行的软件而不是这些文档。当然有人会抗议说没有文档难以维护,那只能说明代码写的不够好。好的代码应该对有能力进行维护的人员易读的。这点完全是可以做到的。
XP中还有一个颇受争议的武器:结对编程。即两个人坐在一台电脑前,一个人写,另一个看的同时思考下一步,轮换上阵。虽然很多人很反感这个方式,但是在某些方面还是很有用的:例如相互学习(训练新人),避免开发过程中某个人离去对项目的影响,发现一些低级bug等等。另外,两个人在一起可以更好地集中注意力,当然相互闲聊除外。
其实,无论有什么武器或法宝,编码还是得靠人。只有优秀的程序员才能写出好代码。优秀的程序员和平庸的程序员写出的代码明显是两个“味道”。
测试
测试其实是个大题目,有很多种测试。至少两种测试需要进行:单元测试和集成测试。
XP中,单元测试被放在很重要的位置。这也是有原因的,因为需求易变代码总改,怎么能保证修改的代码没有影响其它代码呢?当然只能是谁测谁知道了,于是,只要有代码,就得有相应的单元测试来对应上,以便在改任何一行代码都可以通过运行所有的单元测试保证修改没有破坏其他功能。既然单元测试如此重要,干脆在写代码之前就写单元测试得了,于是单元测试代码的编写就放到编码的前面了。
由于本人也是重构的拥护者,因此还是比较认同这种测试先行的理念。但是往往发现写完全的单元测试需要花费太多时间,另外涉及到很多数据库的代码不太容易做单元测试。这方面还需要继续探索。
集成测试是代码完成后各个模块一起做的测试。在Agile开发的Continuum Integration理念中,集成是在编码过程中就需要经常做的,以便能尽早发现bug。于是集成测试也就得一遍遍地重复进行了。这么繁琐的工作当然得有工具支持。于是有很多开源的工具被开发出来,如CruiseControl等,能定时从CVS/SVN等代码库里取出代码进行集成,集成后进行自动测试,把测试结果自动发送到相关人员的邮箱中。当然是好工具,把这些工作都自动化了,保证质量的同时提高效率。当然,前提是集成测试案例得准备好。
综上所述,需求分析、设计、编码、测试每个过程中都存在方法的选择,以实现多快好省的目标。在根据实际情况作出分析后,权衡利弊,择其善者而从之。