软件开发过程解
在这里,在下提到这个题目原因有二,一是国内软件行业对编码的重视远超过其他过程,二是对新技术的学习热情远大于对基础课程的学习。本文的目的也有二,都是旧事重提,把老师说过得加上一点自己的体会,一是分析软件开发过程,强调软件工程中其他部分在软件开发开发过程中对开发成本的控制和吸收,吸收主要是管理技术针对由于不同的开发技术所引起的成本;二是剖析时下流行的技术,打破“技术崇拜”。本文尽可能用朴素的描述,避免各位看客又陷入术语游戏中。所以,希望通过本文学习具体技术的朋友大可换个网址了。
技术都是随着需求应运而生的,在下在这里拟若干例子,用以说明问题。
例1:某公司需要一套结算系统,结算代理商的费用。不同地区、级别、签约时间、签约部门、代理产品的代理商享受不同的结算规则,并且规则随着环境的变化而变化。同时,这套系统要提供给不同地域的所有子公司使用。
好,先分析一下!
上面的文字描述了结算系统的基本需求。根据需求,我们可以整理得到如下关系描述。
服务对象:某公司及其子公司。
目标:精确的计算代理费用。
基本功能:代理关系注册,代理费用结算,结算规则订制。
图表 1金额算系统概要分析-用例图
进一步作需求。假设总公司和子公司有相似的五层组织结构,如下图:
图表 2组织关系图
代理商可以同总公司、子公司及其部门就其所提供的产品签订四级协议,并享受协议中所制定的结算规则。
由上面的描述,我们可以得到以下更详细的列表:
服务对象:总公司代理商负责人(总经理或副总经理),总公司部门负责人(部门经理、部门主管)、子公司代理商负责人(子公司总经理或副总经理)、子公司部门负责人(子公司部门经理、部门主管)
目标:精确的计算各级代理费用。
基本功能:代理关系注册,代理费用结算,结算规则订制。
图表 2用例图2
有点儿乱是吧,其实就是加了几个角色。
接下来是对系统功能的分析。“结算”在这里是核心用例,我们有必要重新分析这个用例,下表希望能穷尽所有“结算”得情况。
参与者 | 动作 | 系统响应 |
总公司代理商负责人 | 与代理商发生代理关系 | 1、注册次代理关系 |
|
| 2、在新代理盥洗上增加默认的结算规则。 |
|
| 3、结算条件到达时,发生结算操作 |
总公司代理商负责人 | 确认结算结果 | 记录确认动作 |
总公司代理商负责人 | 结束代理关系 | 注销代理关系 |
代理商 | 确认结算结果 | 记录确认动作 |
但是,这样的描述有一个问题,团队中其他人拿到以后看得明白吗,是不是会有歧义出现?解决的办法就是规范化用语(用大家都听得明白的词语说),比如给一张列表,把常用的名词、动词的解释加上。还有更通行的办法,也省了开发词语解释列表的麻烦,就是UML。
这里看一下成本的问题。1、需求人员完成的需求如果用普通的文本描述而没有详细的解释就会有歧义发生。此时,开发人员所做的一切活动都是徒劳。2、如果需求人员为了避免歧义而增加大量的文本注释一来增加了工作量,二来还是会引起歧义。3、如果团队给出一张常用词语列表来解决歧义性问题,一来要投入一定的成本来开发,二来不一定能穷尽所有可能出现的情况。4、使用开放性的描述语言,比如UML,当然,其他的建模型方式也在其中,带来的成本是培训成本。无论用那种方法,文本语言的歧义性上不可避免的,只是尽量减少而已。团队工作更多的需要队员之间的配合,所以团结是一件要紧的事。
图表 3结算用例图
关于“订制结算规则”这里要多说几句。还记得第一次作需求时提出的规则要“随着环境的变化而变化”吗?客户不是技术专家,他们提出的只是“感觉如此”,而不是明确的指导意见。麻烦就在这里,我们分析需求就要和客户更多的交流,弄清楚客户的意图。这里,我们假定客户的意思指的是如下几点:
1、 系统工作方式包括:按指定时间自动结算两种按触发事件制定结算。
2、 可以订制具体的系统工作方式,比如制定自动结算得时间等等,至于订制过程是如何的先不管他。
3、 可以订制结算公式
这样一来,我们可以给出一个这样的表,描述可能发生的情况。
参与者 | 动作 | 系统响应 |
总公司代理商负责人 | 订制结算规则 | 记录结算规则 |
| 订制事件发生器 | 记录事件发生规则 |
| 将结算规则赋予事件发生器 | 增加事件发生器监听对象 |
总公司代理商负责人 | 指定具体的结算方式 | 记录事件发生规则(修改/删除) |
图表 4结算规则
由于其它的代理商负责人与总公司代理商负责人的情形相似,我们抽象出一个“代理商负责人”角色,其它角色继承他。至于在图表1中出现过的“向系统注册代理关系”用例已用来扩展“结算”用例,也就不用再单独分析了。
图表 5代理商角色
OK!现在分析到这一步好像有点儿意思了,一开始觉得应该很简单是吧。需求分析到这里算告一段落,接下来就是如何满足需求的问题了。当然,这并不是说需求分析做完了,在设计过程中遇到疑惑还是要返回这一过程的。
首先还是满足“结算”用例。“结算”用例涉及到的对象我们可以以名词为标准挑选。下面的列表就是以这个方法挑选的。方法是糙点儿,不过还好用。
名词 | 对象 | 描述 |
代理商 | Agent |
|
代理商负责人 | AgentManager |
|
总公司代理商负责人 | AgentManagerInParentCompany |
|
总公司部门负责人 | AgentManagerInPartOfParentCompany |
|
子公司代理商负责人 | AgentManagerInSubsidiaryCompany |
|
子公司部门负责人 | AgentManagerInPartOfSubsidiaryCompany |
|
事件发生器 | EventCreater | 根据规则触发结算运算器执行运算 |
事件 | Event | 由事件发生器产生,向规则运算器提供运算参数 |
规则 | Formula |
|
规则运算器 | FormulaProccess |
|
代理费用 | FeeOfServices |
|
以下是概要模型
图表 6概要模型
这里我们要考虑几个问题。1、EventCreater类和AgentManager接口的关系,是一对多呢还是一对一呢?2、EventCreater和FumuleProccess的关系。
如果采取如左图所示,那么EventCreater在整个服务例程中只有少数的几个实例,更常见的是由服务器维护的单一静态实例(比如在C/S体系结构中的Server部分)。可以实现更复杂的功能,但是开发成本更高,考虑得更多。
如果采取如右图所示的一对一关系,那么每一个AgentManager实例都要维护一个EventCreater对象,这样实现起来相对简单。
如果EventCreater和FormuleProccess之间是一对一的关系,那么EventCreater要维护自己的FormuleProccess对象,相对简单。
如果他们之间是一对多的关系那要处理的问题就多了,比如同步的问题,比如相关性的问题,总之一大堆。
好,来整理一下思路!我们需要一个触发器来触发事件,同时,我们需要一个处理器来执行计算任务。那么触发起是怎样的呢?按照对“结算”工作方式的要求,触发器要求能够按照系统时间来触发“结算”,一个自然的思路是不停的取系统时间,和约定的条件比较,成功了就触发“结算”。一个简单而且实现起来很容易的思路!但是有一个问题,如果AgentManager与EventCreater是一对一关系得话,那么只有AgentManager起作用的情况下EventCreater才会工作,这样自然不能有效完成自动任务;而换成多对一的关系又不能很好的处理与FormuleProccess的关系。既然如此我们维持EventCreater和FormuleProccess的一对一关系,并且提供两种EventCreater,一种常驻内存,留下来完成自动任务,另一种由AgentManager维护。好,换一个思路。只有一种EventCreater,接受服务器(或容器)的管理。实现的方式很多,我只提一种思路,算是抛砖引玉。我们在服务被启动的时候创建一个EventCreater实例,在服务被终止时销毁它。言归正传,看下面的图解。
图表 7两种EventCreater
接下来定义触发条件。触发条件根据需求而定,这里只是假设情景,直接给出DTD。
<!ELEMENT start(event*)>
<!ElEMENT event(prop)>
<!ELEMENT prop (#PDATA)>
<!ATTLIST event name CDATA>
<!ATTLIST event model(true|false)>
<!ATTLIST event content CDATA>
<!ATTLIST prop name CDATA>
<!ATTLIST prop type CDATA>
显然,这里利用了XML技术,至于其他情况(比如说要记录进数据库)自然有其他的定义方法。OK,触发器就说到这儿!
歇会儿,累了,喝口水!