完备的需求分析
需求分析的目的是让项目组明白要做什么,是决定所开发出来的软件应当是“长什么样的”,显然完备的需求分析是高质量软件的前提。如果所开发出来的软件与用户所希望的并不一致,那不可能让用户说“这个软件的质量很好” 。如果方向不对,软件开发得再“好”也没有意义。需求分析失误所带来的开发成本是高昂的,这一点在《软件工程》这类书籍中都会提及,因此,整个行业对于需求分析的重要性都具有足够的认识。当然,知道其重要性与如何获得完备的需求分析又是两回事,至于如何做好需求分析请读者参考相关书籍。
需求分析如果出现失误的话有一个特点 —— 它一定会暴露!只不过存在是暴露在软件开发过程中还是在用户手中之别。因此,需求分析所造成的问题尽管严重,但它能被发现进而能得到项目组的重视,从而也一定能被修复,只是不同阶段发现这类问题所花费的成本将有所不同。
设计
设计阶段是通过设计方法找出软件实现更好的方法,注意这里是“更好”两个字,而不是强调最好。
不良设计并不会象需求分析失误那样很容易暴露出其本质,相反,它所暴露出的更多是表象,比如逻辑复杂、维护时举步为艰等等。如果参与者不具备一定的洞察力以发现隐藏在现象背后的不良设计本质,则很有可能身受其害却不能自拔,还以为“本来就有那么复杂”。
项目的开发是一个逐步演进的过程,项目组成员对于需求的理解也是逐步加深的,一开始合适的设计到后面看来很有可能就不够全面或显得力不从心,如果仍沿用以前的设计则自然将暴露出它的不足,进而会出现需要更高的维护成本。重构思想的提出,就是用于帮助项目演进设计的,当然,在运用重构方法时,应尽可能保证项目有足够的单元测试用例,以预防重构时又引入新的缺陷。重构不只是一个词,其核心应当是一个方法论,一个用于优化设计的方法论。
编程好习惯
设计阶段输出的结果就是蓝图,但好的蓝图并不能保证最后的质量一定就好。拿造房子打个比方,图纸设计得再好,如果建造时用的材料不过关,那最终的房子一定好不了。那软件开发中的“建筑材料”又是什么呢?就是程序员所编写的代码。如何保证其质量呢?这需要通过良好的编程习惯去保证。
在现实的项目中,设计有可能与编码会有一定的揉合,即通过进行一定的编码来辅助设计。这种实践方式并不影响这里将设计与编码分为两个质量保证关键要素。
验证
验证很容易让人想到质量保证的常用方法之一,即测试。但验证应当包含更多的内涵,比如求证软件需求是用户所希望的就是其中的一种。
对于验证的理解仍需要拿房屋的建造作为一个比方,以便加深理解。在房屋的建造过程中,当建筑材料到了工地以后,需要对其进行检验,以保证它的质量是合格的,否则不能用于建造。对应于软件开发,这个阶段就是单元测试。当软件工程师编写了代码以后如何保证代码的行为是其所希望的呢?那只能通过单元测试去验证。房子建造好了以后,还得对房子进行整体的验收以确保其最终是合格的。比如抽查墙壁所使用的水泥与沙的配比是合适的。虽然水泥和沙在进入工地时都经过了质检且是合格的,但在建造的过程中需要按一定的比例混合它们以作建筑粘合剂,而混合比例将确定粘合强度。在软件开发过程中,软件集成测试就如同房子在建造好了以后的验收。
从上面的比方能得出几个结论。第一,在软件开发过程中单元测试是必不可少的。它的缺少如同将没有检验过的建筑材料用于建造一样。第二,单元测试应当在集成测试之前完成。有的项目在一开始时并没有单元测试流程,但后来发现需要增加这个环节,于是出现了集成测试完成了以后,再进行单元测试这种情形。这种情形还是有点怪怪的,这如同房子已造好了,再将墙打掉去检查里面的砖是否是好的一样。“将墙打掉检查砖”这种行为的勇气虽然可佳,但是如果尽早地在项目中部署单元测试就能避免这种怪现象的发生。
集成(包括开发集成和系统集成)测试在软件行业被广泛采用以保证软件质量,但单元测试对于软件质量保证的重要性在整个行业还缺乏广泛的、深刻的认识,其更多地被当作是负担而不是一种有效的质量保证手段。
必要的流程
对于流程的认识可能每个项目团队的理解都有所不同,但无论如何必要的流程对于软件质量的保证是一种保障。需要设计审查以确保设计质量;需要将单元测试、静态分析和动态分析作为流程以控制编码质量;需要代码版本控制流程来实施并行开发;需要需求管理流程来确保开发部门开发出用户所需的产品以及保证测试部门没有遗漏地对产品进行验证;等等。一个软件项目是否存在必要的流程是检验它是否是“手工作坊”的重要指标,无论项目的规模大小,必要的流程都应当是不可或缺的,否则只能完全靠人的主观意识去行事,而这不可避免地更容易犯错。流程的目的在于帮助避免没有必要的“低级错误”,或者说是通过外在的、具体的方法帮助项目团队维持良好的工作秩序。
当然,流程不是万能的,千万不要迷信流程的作用,建立与自己的项目团队相匹配的流程才有意义,否则会出现团队为了流程付出很大的努力却效果不好,进而得出“流程无用论”。如果发现流程的运用使得团队没有时间去做真正有意义的事情,那应当进行流程上的反省,以找到其中没有价值的内容并改进之。千万不要为了流程而“流程”,在国内存在大量的采用流程却不能理解其本意以及不能很好执行的例子。流程的运用不在于只执行流程所规定的动作,而在于明白其背后的思想,以及站在开发团队的角度去理解每一个动作所带来的有利于按时交付高质量软件的益处。
要让流程在组织中得到真正地被运用需要时间,流程刚部署的开始不可避免的会招到抵触,这是因为部署流程其实就是改变人的行事习惯,而人一旦涉及自己行为的改变则多少都会有些情绪。要使流程做到深入人心,应当从上层领导开始重视并深刻理解其所给组织带来的意义,并进而鼓吹“这是我们走向成功的必要保障”。如果上层领导不能深刻理解流程的作用,那可以断言被部署的流程在组织中极有可能得不到真正有效地运用。
流程最好是与项目的开发环境进行“无缝”整合,并做到对于流程的运用所需的努力尽可能的小,总的来说就是提高其可操作性。另外,流程还应尽可能的工具化或自动化,一个运用起来很复杂的流程注定其将会是另一个摆设。
敏捷软件开发在最近的十多年来很受欢迎,它的核心思想就是“简化”,将软件开发的流程进行简化。当然,简化的目的不是为了偷懒,而是为了更加能应对软件开发过程中的不确定性以尽可能保证项目的成功。笔者认为,运用敏捷思想指导软件开发需要较高的水平,它的本意是需要使用者先理解软件行业的特点,再进行简化。可是,有些项目组其实根本没有什么流程,只是因为没有才将自己称之为运用了敏捷的思想,更有甚者将敏捷中的片面内容当做了不做某事的借口。比如,敏捷软件开发中对于编写软件设计文档的要求就相对低,但有些人却将其当作借口说“你看,敏捷思想就不提倡写文档”。
合适的工具
对于软件开发的流程靠什么去支撑它呢?那就是工具。对于设计需要UML工具进行支撑;对于代码的静态分析和动态分析则需要相应的分析工具进行支撑;对于代码版本控制需要版本控制工具进行支撑;对于需求管理则需要需求管理工具进行支撑;等等。可以说,软件的开发离不开合适工具的支撑,否则项目组很有可能是另一种形式的“手工作坊”。
项目组应当乐于去寻找和运用新的工具以简化流程进而提高开发效率,在开源软件大行其道的现在,有着大量的开源工具可以帮助提高软件质量和开发效率。比如,Splint是开源的代码静态分析工具,Valgrind是开源的代码动态分析工具,Gcov是开源的代码覆盖工具,Cvs、Subversion和Git是开源的源代码管理工具,Bugzilla则是开源的缺陷跟踪工具,等等。
开发文档
前面谈到软件高质量还应当包含高效地工作,而文档在这一点就起着非常重要的作用。文档可以包括软件设计文档、用于指导开发人员进行开发工作的开发指南,以及用于指导测试工作的测试手册,等等,这些文档都能帮助团队提高开发效率。
随着敏捷软件开发思想的兴起,有些开发团队将不写文档变成了理所当然的事,但作者认为软件开发不写文档等同于慢性自杀。文档的重点在于阐述设计思想或工作方法,其着力点应当是 “点到为止”地将问题说清道明,而不在于“又长又臭”。写文档的目的到底是什么呢?为了够长才显得专业?还是为了沟通和提高效率?如果将加强沟通和提高效率当作是写文档的目的,或许能让写文档一事变得更简单一点,进而也会有更多的人愿意去写。另外,一页纸能写完的如果用了两页纸,那就会造成阅读这一文档的每一个读者都浪费时间。作者在工作中审查设计文档时,会通过问“这段话写在这的目的是什么?会不会有些多余呢?”,或“这里好象缺少一点背景知识?”等问题,来提醒文档作者是否可以简化文档或将其写得更易懂。
除了设计文档,开发指南、测试手册这类文档也非常的重要。对于大型的项目,其中存在很多的工作流程,包括如何准备开发环境、编译等等。有了指导性文档以后,当项目有新人加入时,它们有助于显著地节约项目组培养新人的时间,否则新人的加入还得让老员工花不少时间去帮助他,进而加剧了人力资源缺乏这一困境。指导性文档还有助于帮助项目组沉淀开发活动中的知识,大型项目不可避免地在开发过程中会出现很多非软件缺陷问题,而在指导性文档中记录问题的解决方法有助于加速开发进程。
写好的文档不应成为摆设,让文档成为真正有用的关键是倡导一种习惯于使用文档的团队文化,要做到这一点,文档的作者是关键。就作者的观察,不少人写了文档以后,别人向他请教已写入文档中的相关内容时,他却仍乐此不疲地回答,但这不是一种让大家形成使用文档习惯的好方法。作者在碰到这种情形时往往会说,“文档中已经写了这方面的内容,你可以先看一下,如果有不清楚的地方我再修订它”,只有通过这种方法大家才会重视使用文档以及提高文档的书写质量。