十八、设计,软件质量之本(上)
1. 软件设计是什么?
- 一种创造性活动,力求以简单优雅的方式解决实际问题
- 软件设计是一门技术
- 数据结构,组成原理,操作系统,编程语言,。。。
- 软件设计是一门艺术
- 并不是技术知识的简单堆砌
- 分析,抽象,取舍,。。。
- 软件设计是一门技术
2. 软件设计的意义(架构的意义)
3. 软件设计的特点
- 软件设计是一个塑造模型(概念)的过程
- 软件设计是一个取舍的过程
- 软件设计是一个分而治之的过程
- 软件设计是一个在理性范围内追求完美的过程
4. 什么是软件质量?
- 用户角度
- defect 和 bug 的数量越少意味着质量越好
- 开发角度
- 整体架构设计易于扩展
- 模块之间耦合性低,易于复用
- 代码简洁易懂,易于维护
5. 实例分析:质量对团队的影响
6. 如何提高软件质量?
- 编码前,架构设计质量必须得到保证
- 编码时,代码质量必须得到保证
- 编码后,测试质量必须得到保证
7. 架构设计 VS 软件质量
8. 开发流程 VS 软件质量
9. 软件测试 VS 软件质量
10. 为测试正名
- 在需求分析结束后,测试人员就需要介入项目
- 根据需求分析进行功能测试用例的设计
- 根据架构设计进行模块测试用例的设计
- 根据产品标准进行压力测试用例的设计
11. 开发中的常见问题
- 测试是替罪羊或救命稻草
- 但凡出现bug,就是测试不给力
- 资源永远不足
- 现在没有时间和精力去做重构
- 不改变就可以规避风险
- 虽然有缺陷,但是功能不受影响,不做改变
12. 如何提高自身的软件设计能力?
- 对架构的完美性有精神上的追求,不满足功能正确
- 积极思考方案,不停反思是否能做得更好
- 勇于实践与模仿,进而形成自己的风格和思想
- 推敲前辈们的经典设计,尝试用于自己的项目
- 总结设计原则,体会各个设计原则的内涵
- 软件设计不是原则的叠加,而是一个平衡利弊的过程
13. 设计思想,设计原则,设计模式
14. 小结
- 软件设计(架构)的质量决定了软件产品质量的基调
- 测试质量和代码质量直接夫定最产品的质量
- 正规开发流程中测试人员先于编码人员介入项目
- 软件架构设计能力需要通过实践提高,需要总结和体会
十九、设计,软件质量之本(中)
1. 设计原则 – 1:以人为本
- 核心:将现实世界直接映射到软件世界
- 意图:便于沟通和理解,降低复杂性,增加维护性
- 要点:使用现实世界中的概念
2. 案例:任务与内存访问
3. 架构设计图
4. 设计原则 – 2:简单即是美
- 核心:用最简单的方法描述解决方案
- 意图:便于沟通和理解,降低复杂性,增加维护性
- 要点:使用团队熟悉的技术进行设计
5. 案例:删除格式化字符串中的指定子串
方案2相对最好。
6. 简单性 VS 灵活性
- 简单性不等于灵活性
- 简单的设计易于催生灵活的设计
- 过于追求灵活的设计可能导致复杂性的增加
7. 设计原则 – 3:让模块善始善终
- 核心:模块的初始化与模块的终止同等重要
- 意图:确保模块状态的恢复和保存
- 要点:对称式设计
8. 案例:模块的动态加载(初始化)与卸载(终止)
9. 设计方案
10. 设计原则 – 4:重视运行时数据的收集
- 核心:考虑程序运行状态数据的收集模块
- 意图:监控程序运行状态,便于调式与测试
11. 案例:统一日志模块的设计
12. 案例:程序状态统计模块的设计
13. 小结
- 架构设计时尽量将现实中的概念映射到程序中
- 开发过程中的任意阶段都提倡简单优美的设计方式
- 模块设计时需要同时考虑初始化过程与终止过程
- 架构设计时需要考虑保证产品质量的辅助手段
二十、设计,软件质量之本(下)
1. 设计原则 – 5:代码自注释
- 核心:代码自身就能够很好的进行功能性说明
- 意图:便于沟通和理解,增加维护性
2. 案例分析
3. 代码质量
- 最终的产品代码应该 “非常容易” 读懂
- 注释作为补充说明必不可少,但不是越多越好
注释应该起到画龙点睛的作用,用于简要的描述代码意图;避免使用注释描述程序的运行流程。
4. 设计原则 – 6:通过机制解决问题
- 核心:考虑当前设计是否存在 “漏洞”
- 意图:杜绝类似问题的再次发生
5. 案例:消息传递
6. 问题
- 当A设备无法收到B设备的RSP消息时,会发生什么?
- 相互等待
7. 设备状态
8. 解决方案一
让设备B定时重发RSP消息
9. 解决方案二
- 加消息中转层
- 功能定义:
- 负责所有设备间通信消息的发送和接收
- 处理所有通信异常的处理(阻塞重发,报告错误,etc.)
- 功能定义:
10. 正常消息交互
11. 异常消息交互
12. 架构经验
- 设计不是一次性完成的,需要根据实际问题进行重构。
13. 设计原则 – 7:防御性程序设计
- 核心:防止他人的“意外”错误
- 意图:提高代码鲁棒性
14. 案例:定时器模块的设计与实现
- 创建定时器后每隔指定的时间能够触发事件
- 事件的具体表现为关联的回调函数被调用
15. 设计草图
16. 实例分析定时器的设计与实现
#include #include #include #include "timer.h"#define MAX 32#define GAP 10struct STimer{ int id; int interval; int current; int in_callback; int to_delete; TimerCallback* callback; void* data;};static struct STimer* g_timers[MAX];static volatile int g_run;static pthread_mutex_t mutex;static void* Runtime(void* args){ int i = 0; while( g_run ) { pthread_mutex_lock(&mutex); for(i=0; (icallback != NULL) ) { st->current += GAP; if( st->current >= st->interval ) { st->in_callback = 1; st->callback(st, st->data); st->in_callback = 0; st->current = 0; if( st->to_delete ) { g_timers[st->id] = NULL; free(st); } } } } pthread_mutex_unlock(&mutex); usleep(GAP * 1000); } for(i=0; i<MAX; i++) { free(g_timers[i]); }}void TimerInitialize(){ if( !g_run ) { pthread_t tid = 0; g_run = 1; pthread_create(&tid, NULL, Runtime, NULL); }}void TimerFinalize(){ g_run = 0;}Timer* CreateTimer(int interval, TimerCallback* callback, void* data){ int id = 0; struct STimer* ret = (struct STimer*)malloc(sizeof(struct STimer)); if( ret != NULL ) { pthread_mutex_lock(&mutex); for(id=0; id<MAX; id++) { if( g_timers[id] == NULL ) { g_timers[id] = ret; break; } } pthread_mutex_unlock(&mutex); if( id id = id; ret->interval = interval; ret->current = 0; ret->to_delete = 0; ret->in_callback = 0; ret->callback = callback; ret->data = data; } else { free(ret); ret = NULL; } } return ret;}void DestroyTimer(Timer* timer){ if( timer != NULL ) { struct STimer* st = (struct STimer*)timer; if( st->in_callback ) { st->to_delete = 1; } else { pthread_mutex_lock(&mutex); g_timers[st->id] = NULL; pthread_mutex_unlock(&mutex); free(st); } }}
#ifndef _TIMER_H_#define _TIMER_H_typedef void Timer;typedef void(TimerCallback)(Timer*, void*);void TimerInitialize();void TimerFinalize();Timer* CreateTimer(int interval, TimerCallback* callback, void* data);void DestroyTimer(Timer* timer);#endif
17. 小结
- 尽量使用代码自注释的方式编写代码,便于沟通维护
- 注释作为补充说明必不可少,但不是越多越好
- 思考bug是否因为设计不当造成,通过机制解决问题
- 通过防御性程序设计提高代码鲁棒性