高等软工第三次作业——设计也可以按图索骥
一 前言
本博文为软工项目设计阶段的博客总结。所在12345组的选题是“基于订单的家庭工厂协作系统”。
1.1 项目需求简述
典型的生活日用品制造业往往由一组家庭式工厂协同配合,共同生产和组装,完成最终订单。系统有几个关键功能:下单(接单)、订单分解、订单分配、订单进度追踪、订单完成风险评估、订单完成效果分析等。要求实现基于网页或手机端的系统。
二 设计答疑
正式设计需求答辩前一周,我们根据需求答辩后的分析讨论准备了新一轮迭代的模型,将需求分析时设计的骨架填充得更饱满,以期看起来可以直接落实到代码实现上。
这两周课上有新的收获,认识了一个语言OCL(Object Constraint Language,对象约束语言)。UML这种图形描述语言展现出来的关系虽然直观易懂,但在画完用例图、类图和状态图等后发现模块间逻辑和模块内在约束限制还是难以明确表达,当想要通过UML去阐述设计阶段中更详细的逻辑的时候难免捉襟见肘。比如订单、任务类的状态属性是枚举类型的,类的实例(或者说其对应的数据记录)有唯一标识符,类的众多方法各不相同的前置后置条件。为弥补UML的局限性,通过课堂学习和课外资料查询学习了一些OCL语法,去更详细地表达出需求分析阶段产出的模型中的对象及其属性、方法的约束。下面以几种典型应用为例:
(1)订单类状态属性只有四种,是枚举而不是普通变量
Context Order
Inv: set(self.status)=set{‘预生效’,’已生效’,’已完成’,’已取消’}
(2)订单中订单ID是唯一标识符(UNIQUE)
Context Order
inv: self.orderId->forAll(e1, e2 | e1.orderId<>e2.orderIdimplies e1<> e2)
(3)家庭工厂完成修改任务属性状态
Context Factory::finishTask(Task) :boolean
pre: Task.getStatus()=‘生产中’
post:Task.getStatus()=‘已完成’
(4)分配给家庭工厂的数量小于剩余意愿值
Context Calculate::allocateTask(Order, factory[])
pre: self.factory.produceAbility.enable()=Ture
post:self.task.num<=self.factory.produceAbility.willingness-self.factory.produceAbility.acceptNum
由此可见,虽然OCL不能直接刻画方法内在流程(这部分自然留到代码实现阶段去填充),但可以充分描述了执行操作前后的约束。
三 设计评审
设计阶段还要进行组件、接口的设计。对组件接口进行明确的约定,有利于组件间的解耦合,更是方便了开发过程中的分工。本次项目关注核心价值,类的数量不多,开发人员只有五个,还不能明显发挥这样设计的价值。当项目开发维护规模变大、功能模块增多、可扩展需求变高时,组件接口的明确让各开发人员只关注自己责任内的模块和接口,不必在意其他模块/组件的内在实现。以前后端交互接口为例:
Description:用户登录
Value(URL):/admin/login
Method(请求方式):post
Body(前端请求参数):{admin_name,admin_password}
Return(后端返回参数):{status,msg,data:{admin_id,admin_name,admin_password}}
四 补充总结
4.1概要设计与详细设计
设计阶段在软件工程教材上往往被分为概要设计和详细设计,且看起来像是顺序进行。简单来说,概要设计只说明系统有多少个模块,各模块之间的接口和个模块本身的功能。详细设计说明某个具体模块如何实现。但是各个模块之间既有层次关系,也有先后序关系。如果将此两阶段顺序执行,那在概要设计过程中,需要考虑模块的实现细节,否则,你怎么知道这个模块下面要划分子模块?和各子模块的调用顺序?所以高软课程中将此两者并行迭代进行是很合理的。
4.2设计也可以按图索骥
“按图索骥”有两层意思。其一是比喻按照线索去寻找事物。其二是比喻做事拘泥于教条。前人在软件工程上做的科学研究工作帮助我们能规范地进行项目组织管理工作,在小型团队中虽然默契创新更为重要,但组织结构复杂庞大时,有可以依赖的“教条”可以大大提升大家协同工作的效率。。