体系结构风格(精)

  • 格式:doc
  • 大小:37.50 KB
  • 文档页数:3

体系结构风格:
我以前做的都是ERP和OA系统,所以体系结构的选择是基于怎么更好的完成业务处理
1、 事务处理
a) 简单系统可以采用数据库的事务处理功能
优势:简单、易学、性能高
劣势:将业务逻辑绑定在数据库一层,很难使用高级语言来实现
b) 复杂系统可以使用EJB来实现
优势:支持分布式不同厂家数据库上的事务处理,可以使用高级语言来实现
劣势:开发复杂,执行效率低
c) 注意:需要事务处理的地方不能选用MS的产品和框架,他们的事务处理完全依靠
数据库完成,基本没有扩展的可能。WebService不支持事务,不能承载业务处理
接口,只能提供一些可出错或出错后可重试的功能。
2、 业务逻辑的实现:高级语言vs存储过程
除非使用EJB,否则使用存储过程来实现业务处理。从数据库中读取出数据,经过计算,
写回计算结果。这样的过程是无法做到访问互斥的。如果同时有线程在处理这些数据,
就会产生冲突。就算使用数据库事务也无法解决这个问题,因为数据的读取并不受事务
控制,系统不会保证读取、计算和写回的原子性。
所以,使用存储过程来实现复杂业务逻辑是可靠的。特别是如果系统是采用结构化的开
发风格,存储过程可以作为最底层的模块供高级语言实现的模块调用。
3、 软件系统的分层
a) 数据库
b) 数据持久层:如果需要用高级语言来实现业务逻辑,则这一层需要提供读写锁操作。
Hibernate好像提供了这种功能,一般还是使用ejb。
c) 业务逻辑层:实现核心业务逻辑,例如:入库操作
d) 业务外观(facade)层:组织业务逻辑层发布的接口完成业务逻辑处理,还负责一
些外围工作:数据校验、错误处理、日志记录等等
e) 界面表现层
i. 界面构件:一些基础界面构件,页面框架,样式表等
ii. 界面程序

对象化编程风格:
1、 和OO课上讲的差不多

结构化编程风格:
1、 模块间公共的常量要用宏定义,模块内的公共常量要用静态变量定义
2、 不被外部调用的函数不要在头文件中申明
3、 模块对外的接口要使用简单数据类型:不要为了接口函数看着简单而把多个参数包装成
一个结构体,而是直接使用多个简单数据类型的参数。好处:易于理解、便于复用、不
会造成模块之间依赖关系复杂
4、 模块对外的接口中不变的参数需要描述为const,告诉调用方这些数据不会被破坏
5、 模块分通常划分为三类:
a) 定义类模块
i. 定义一些公共变量和公共数据结构。针对公共数据类型的公用操作函数,例如:
结构的初始化、释放、序列化等等函数
ii. 还有一个逻辑无关的处理函数可以放在这里,例如:日志打印
b) 逻辑处理模块:这类模块一般有很强的内聚性,一般不依赖或少依赖其他模块。一
般只依赖一些定义类模块。这类模块一般针对特定数据结构进行计算操作,不会访
问文件、网络等等外部设备。
c) 组装模块
i. 接口模块:负责在对逻辑处理模块进行包装。例如:为了使用方便,将逻辑处
理模块中的一个处理函数包装成多种参数的多个函数。在这类模块中,接口函
数可以使用结构体作为参数,而不用严格遵循接口函数简单变量的规定。
ii. 调度模块:负责调度各种多个处理单元合作完成工作,及一些高层逻辑,例如:
多线程管理、网络套接字管理、缓存管理等等

代码风格:
1、 函数头要写注释,说明函数的用途、输入变量的含义和取值范围,输出的结果
2、 变量名不要怕长,多个小写英文词用下划线连接
3、 函数要进行分类
a) 功能简单明确的函数:需要写注释描述函数头
b) 将上述简单函数组合起来完成复杂功能的函数:需要在内部写注释说明为什么进行
分支判断和调用那些简单函数
4、 不能省略大括号,即:
if (xxx==yyy) {
do_somthing();
}
虽然只有一行,但不要省略大括号,便于别人阅读时知道判断的作用范围
5、 不能使用魔鬼数字:不要告诉别的开发人员1代表什么,2又代表什么。把这些都定义
成宏或常量
6、 goto一般用于出错处理(跳到错误处理段,通常在函数最后),不允许往上跳
7、 避免用同一个函数名来定义不同参数的多个函数
8、 避免使用递归函数

基于CVS的分支开发方法
本方法适合多人针对同一个模块进行开发,各人的开发都是在原有模块上增加无关的新功
能。为了避免别人的修改造成自己开发和测试中发生问题,所以使用CVS的分支开发功能
1、 针对每个新功能,在当前最新版本的基础上建立代码分支XXX_BRANCH
2、 在分支上进行开发,版本号的最后一位表示送测次数。如果一次就测试通过则版本号最
后一位为0,如果测试发现错误后修改了再送测则版本号最后一位加1
3、 分支开发、测试完毕,则将模块最新版本合并到当前分支上。创建分支时,模块发布的
最新版本号可能是x.y.z,分支测试完毕后x’.y’.z’可能已经发布了。就需要在
XXX_BRANCH分支中合并版本x.y.z到x’.y’.z’版本之间的变更。可以使用cvs up –j
x’.y’.z’实现。合并完毕后再对合并结果进行回归测试。把XXX_BRANCH定一个版本号,
例如:t_XXX_BRANCH
4、 合并测试之后,需要将XXX_BRANCH合并到当前release版本x’.y’.z’上。首先使用cvs
up –dr x’.y’.z’把当前目录下的代码切换到x’.y’.z’版本。再使用命令cvs up –j
t_XXX_BRANCH –j x’.y’.z’来合并从t_XXX_BRANCH到x’.y’.z’的代码变化。(由于
t_XXX_BRANCH分支已经合并过一次x’.y’.z’,所以这一步一般不会发生什么变化,如
果发生变化则说明x’.y’.z’之后又有人发布了新版本,哪么就需要重新合并分支并重新测
试)
5、 发布t_XXX_BRANCH,并确定新的基线版本号为x’.y’+1.z’

单元测试风格(一般是开发人员完成,测试人员没有能力干)
1、 测试框架:测试框架一般分两部分
a) 测试数据的自动生成和结果的比对
自动生成比较困难,一般都是在单元测试中由开发人员写程序来模拟产生。但多版
本程序的输出数据的存储、管理、比对应该由框架完成
b) 测试用例的承载
这部分需要解决的是测试用例该如何编写,以及系统怎么执行这些用例及怎么反馈
测试用例的执行情况
2、 函数级测试
根据函数的重要性可以决定是否对其编写测试函数。测试函数中可以硬编码许多(20-100
个)测试数据,在调用被测试函数之后判断返回结果是否符合预期。
3、 模块级测试
针对模块对外提供的接口进行测试,由于模块的输入输出可能很复杂,可以用数据文件
作为输入。测试框架应当提供将被测函数的输出数据存储成文件的功能。若该模块经过
其他测试能保证质量,则生成的输出文件可以作为标准输出供下一次模块测试使用。例
如:对该模块进行修改后可以用相同输入文件进行测试,获得新输出数据文件。比较这
两个文件是否存在差异。
4、 系统级测试
系统级测试的正确性测试方法和模块级测试完全相同。系统级测试过程中还应当考察一
些特殊内容。例如:性能和容错性
可以使用一些dummy模块来模拟该模块被破坏的情况下系统整体运行情况,一个模块
发生错误系统可能采用以下方式进行处理:容忍错误(整体系统能“正常”运行)、错
误报警(需要测试是否发出报警及多快发生报警)、修复错误(一般来说是通过重新启
动出错模块来完成的。。。)
性能测试需要测试系统在不同的压力下的表现,需要在日志中记录一些关键性能因素。
比如说一个常见任务的处理时间和资源消耗。还可以开发一些工具记录系统的状态,例
如:每隔一秒记录cpu,memory,io的利用率
5、 bad case处理
系统升级及维护的过程是围绕bad case展开的,至少要能在日志中记录这些bad case,
而后还要能对这些bad case进行分析找出原因