[ 这里特别说明一下用户界面的重要性。用户界面的设计按理来说是软件设计的责任,当然客户自己对界面有特别提出要求的除外。但是,如果把它提前到需求调研时(紧接着原有系统调研分析和系统模型完成之后)与客户进行讨论,则可以大大改善需求调研的效果。因此不少需求分析的著作把用户界面说成是“设计层”的需求之一。因为这时客户对于将来的系统还没有一个形象上的概念,或者有一个模糊的预想的概念需要表述、验证、明晰化、完善化。以笔者的经验,画出用户界面草图与客户进行讨论,可以大大激发他们提供更为准确全面的需求。原来收集资料,描述业务,说明系统模型到了山穷水尽的时候,这种方法可以达到柳暗花明又一村的效果。在《微软项目:求生法则》的第8章“需求开发”中,从头到尾都是围绕着“使用者接口”(USER INTERFACE也可以翻译成“用户界面”)进行讨论,如“建立简单的使用者接口雏形”、“不断修订使用者接口雏型,直到使用者对软件感到兴趣盎然为止”、“完全扩展使用者接口”,同时还要“区分一份非使用者接口需求文件”,等等。因此,所谓需求就是“当你按下各种相关按钮(或输入各种相关命令)时系统做什么”,所谓设计就是“当你按下各种相关按钮(或输入各种相关命令)时系统怎么做”。虽然在英语中“接口”与“界面”实际是同一个单词,但“接口”的含义似乎比“界面”来得广泛,如功能之间的接口、与其他软件的接口、与其他硬件的接口等等。需求的最终目的实际上是完整准确地描述系统需要的各种接口或“界面”,及它们的相互关系或与外部环境的关系,如界面中的某个按钮按下去时,可能产生新的界面、新的按钮、或者调用其他软件硬件完成某些功能。自顶向下,把这些界面及涉及到的数据描述清楚,就是一份不错的需求。 4、与其他项目小组成员共同协作、持续完善系统需求 需求文档完成之后,并不是万事大吉,把它扔给后面的设计人员就了事了。作为项目干系人之内的项目组其他成员,对需求的有效性也起到某种程度的验证作用。虽然软件项目的生命周期按照各种开发模型有不同阶段的划分,但每个阶段的结束不是简单地把阶段工作成果塞给下一阶段的成员就可以了。特别是高科技的软件开发项目,上一阶段的工作成果往往要通过多次的沟通才能更为清晰地被下一阶段成员接受,其有效性、合理性也要被下一阶段的工作所检验,通过检验有时也有必要对上一阶段的工作结果进行相应的调整,需求更是如此。因此,无论是同一阶段不同人员之间,或是不同阶段人员之间都应根据需要相互协作,相互配合,共同完成软件开发任务。 二、在软件工程的方位内,尽量减少需求变更的影响 系统的各模块应该设计成送耦合的,采用OO 技术可以建立易于改变和加强可重用性的软件系统。对于OO 技术,我想现在已经不是什么陌生的概念: 1 封装(Encapsulation )可以把问题影响的范围缩小,外部的变化要求对系统的影响可以限定到某个类层次或某些类层次中,从而改变系统的一部分相对简单; 2 继承(Inheritance )可以使改变基于原有技术基础,很大程度上减少重复开发工作; 3 多态(Polymorphism )的应用可以使开发和设计人员在相对统一的接口下更改系统的实现细节,从而改变系统的行为; 4 而且由于对OO 的类体系结构业界有非常清楚明晰的描述方式,就是目前规范的描述语言-UML ,非常易于被开发组的理解并达成共识,促进开发组成员之间的合作以及加强软件开发工作的可延续性; 可见本身即是一种增强软件可维护性、健壮性以及保持设计稳定性的一种分析和设计方法,本身可以在一定程度上快速对需求变更进行反应,并可相对减少需求变更需要的成本。(OO 的意义在于分析和设计软件系统的思考方式,以及建立对象库以后的软件重用将给软件系统的开发带来质的改变,但是在建立OO 开发体系之前的过程,一定会是一段荆棘遍布的路,需要付出加倍的努力以及达成思想的转变。这里还有一个误区需要澄清的是很多人以为用了C++,PB ,VB ,DELPHI 就是面向对象的开发了,其实只是用了一些面向对象的工具,骨子里仍然是结构化的分析和设计方法,套上一层OOP 的外壳而已。) 可扩展性设计(Extensible-Design ) 其次,从我们可以控制的软件设计来说,怎样进行合适的设计才能最大程度减少需求变更带来的代价? 也许有人说,我的设计极为灵活,我已经预计了客户可能提出的要求,并设计几种应对的方式,到时候客户提出来,呵呵,我已经解决了。这样的想法不错,至少比僵硬的设计强,但是谁可以保证设计者可以预知以后的需求变化?而同时为了达到这种灵活(万能/多能?)的设计,设计将变得复杂,而且可能那些多余的设计从来不会被用到?复杂的设计将增加实现的难度和提高成本,并有可能带来潜在的Bug ,使得系统难以维护。 设计的思想应该有一些小小的转变,那就是,设计确实要灵活,但是要体现在可扩展性上面,也就是说,设计可以简单,但是一定要易于转变,需要给出便于改变的接口,这一点很重要。 例如,现在有一个类叫做TCPConnection ,来代表计算机网络通信中典型的TCP 连接,对于这个连接而言,它可能处于以下几种状态:Established (连接已建立),Listening (正在侦听),Closed (连接关闭)。一个连接对象需要从其他的对象接受请求,至于它的反应则决定于连接对象所处的状态,对于(打开连接的请求),如果是在连接关闭状态,则进行Open (),处于其他状态则不做反应;同样,如果在连接建立和侦听状态,可以进行Close (),在连接建立状态可以进行Acknowledge (),即接收数据。 对于这样的状况,最不可取的设计应该是用一系列的Switch 语句(甚至If/else 语句)进行Hard 设计,对于以后每一次需求改变,都需要改变源代码,接踵而来的系统一致性、文档更新等工作将使开发人员不可避免地陷入一场灾难,这样的后果将导致原来就不合理的设计变得更加支离破碎,系统维护的代价将越来越大;就算没有需求变更发生,这些设计的可重用性也会极差。 稍好一些的设计是预先估计并设置TCPConnection 类所有可能的状态,并预先加入设计,这种需要付出更多的设计、开发、维护的代价,而且也很难达到完美的效果,所以不多说了。 [本文共有 4 页,当前是第 2 页] <<上一页 下一页>> ]
|
|
|
|
|
|
|