首页 > 代码库 > 软件产品品质的探索与实践(一) —— 开发品质提升

软件产品品质的探索与实践(一) —— 开发品质提升


     每次解决用户最关心的前三个问题, 不为无关痛痒的事情浪费时间、精力和资源。

     首先是功能与服务,功能与服务是核心,是存在的价值;
     其次是设计,设计使功能与服务更加突出具有吸引力,更好的使用品质;
     接着是成本和传播。保证优秀功能和设计的基础上降低资源时间和人力成本,同时良好的传播和使用让边际成本更低。

       软件产品品质主要可以分为四个要素:  开发品质、测试品质、项目品质和产品品质。

        
  一、 开发品质提升

      1. 代码可读性,易理解
      a.   仔细斟酌命名,望文知义,使用通俗易懂的词汇;
            b.   代码风格自然一致,排版整齐;
            c.   注释适宜, 特殊处理注明原因;
            d.   阐述算法设计思想或注明引用出处
            e.    API、公共函数的文档简洁清晰,注明用途及原因;
            f.    探索和使用正确良好的代码模式,避免生僻写法;
            g.   单一职责划分, 编写短小类/短函数/短方法。

      2.  功能/异常处理/健壮性
    a.  准确处理常用场景。
                    a.0   沟通, 准确理解需求、场景及业务流;
                    a.1   仔细挑选开发使用的工具箱、库与框架; 
                    a.2   常用子任务使用公认主流开发库并仔细测试; 
                    a.3   完整理解API, 包括其功能、原理、适用场合与局限性;
                    a.4   编写类/方法/函数时注明使用契约及特殊处理;
                    a.5   每个类/方法/函数各司其职,相互协作。     
            b.  错误情况友好提示。
                    b.1  错误码和错误消息使用配置文件,与代码分离;
                    b.2  不同类型的参数检测使用不同的参数验证器(通常是正则表达式);
                    b.3   使用全局统一的错误检测函数尽量在一个地方集中检测错误。
                    b.4   错误处理全局框架
                                 错误检测函数注册器: 不同的参数对应不同的检测函数
                                           Map<paramName, ErrorDetectFunc>  errorDetectFuncMap;
                                           ErrorMsg ErrorDetectFunc(paramName, paramValue);
                                 全局统一的错误检测函数:  
                                           def   Map<paramName, errormsg> detectError(Map<paramName, paramValue> params) :
                                                  Map<paramName errormsg> allErrorMsg = new Map<String, ErrorMsg>();    
                                                  for paramName, paramValue in params:
                                                         ErrorDetectFunc  func = errorDetectFuncMap.get(paramName);
                                                         ErrorMsg errormsg = func(paramName, paramValue); 
                                                        allErrorMsg.put(paramName, errormsg);
                                                       return  allErrorMsg;  
                                    全局统一的错误处理函数:
                                             def  ShouldResponse processError(Map<paramName, errormsg> allErrorMsg):                                                 
                                                    
            c.   异常场景疏而不漏。 
                    c.1  细分应用中出现的各种异常并进行不同的处理;
                    c.2  在系统底层处理能够处理的异常, 无法处理的使用异常转译传给顶层;
                    c.3  在系统顶层统一处理各种应用异常并返回友好提示;
                    c.4  提示和异常消息放置在配置文件,与代码分离。
                    c.5  代码模式:
            try {
                if (err1) { errProcess1 ; }
                ...
                if (errN) { errProcess2 ; }
                // normal doing
            } catch (someException1) {
                // do with exception1 
            } catch (someExceptionN) {
                // do with exceptionN
            } catch (Exception) {
                // do with other exception unexpected
            } finally {
               // clean up
            }

     3.  性能/流畅性: 
   a.   大数据量结果集使用多线程技术获取子集并汇总;
           b.   多IO任务使用异步方式来处理;
           c.   耗时长的任务进行分解/并发/异步处理;
           d.   避免不必要的重复创建/计算开销;
           e.   耗内存的大对象的延迟创建与复用;
           f.    耗时长/频繁读操作适当利用缓存;
           g.   短时操作控制在 0.5-1s 内, 长时操作采用“异步+消息通知”模式;
           h.   测量时间,对热点区域进行适宜程度的优化;
           i.    测量和改进响应时间与吞吐量, 使之达到良好的平衡;
           j.    使用更好的硬件提升性能;
           k.   减少启动加载组件,按需加载和缓存;
           L.   使用异步模式逐步加载与展示;

     4.  稳定性和可靠性: 能够持续长时间良好运行且不出差错,出现问题时能降级/限制运行而不崩溃。
   a.   确保软件的运行环境正常稳定,包括硬件、操作系统、依赖系统;
           b.   软件能够有效应对环境波动(比如网络中断)而不至于终止;
           c.    外部系统服务调用的影响局部化, 不影响整体运行;
           d.   系统组件服务模块的影响局部化, 不影响整体运行;
           e.   避免内存泄露,死循环,死锁等会导致程序崩溃的问题;
           f.    批量资源释放问题要仔细检查,是否会因为错误或异常导致内存泄露;
           g.   操作失败可回滚;
           h.   负载均衡避免单点故障;
           i.    主备容灾应对紧急情况;   
           j.    高负载/性能测试;
          k.    添加系统监控, 展示指定时间间隔内的系统各项指标/服务/资源的运行状况。

     5. 安全性: 数据、权限与隐私保护良好
           a.   用户角色与权限分级;
           b .  只读与操作权限分离;
           c.   机密数据加密保护/权限控制/操作限制/身份认证;
           d.   权限申请加入审批流程制度;
           e.   记录请求日志与用户操作日志;
           f.    请求连接进行加密;
           g.   避免显示请求 URL;
           h.   防止注入攻击,识别非法请求模式。

     6.  可扩展性:  在原有系统基础上容易扩展,添加新特性。
           a.   整体架构模块化设计, 组件服务化, 最小化公共服务接口;
           b.   设计时总是考虑变化;
           c.   使用配置参数, 避免硬编码;
           d.   编写自包含、自封装、不修改外部状态的代码,最小化依赖;
           e.   使用设计模式优化代码表达结构, 增强软件的“柔韧度”;
           f.    文档化顺序与依赖关系, 定期整理、更新依赖关系。

          可伸缩性:  在不改变系统功能服务的基础上提供更强的处理能力和更大的处理容量。
           a.  水平扩展:   增加多个逻辑单元资源并使他们作为一个整体在工作, 比如集群、分布式、负载均衡
           b.   垂直扩展:   在同一个逻辑单位添加资源以增加容量, 比如增加CPU、内存、磁盘空间。
    7.  可维护性: 能够持久提升品质并保证简洁
           a.   参见:《保持应用系统可维护性的八个实际措施》
           b.   参见:《如何编写可信赖的代码》;
           c.   在回归测试的保护下持续小步重构。

    8.  可定制性/热升级:能够根据客户的不同需求进行定制版系统, 动态加载/卸载模块。
           a.   模块化应用程序和系统服务组件;
           b.   每个独立组件有一个标识, 标识其是否可显示/加载;
           c.   通过配置文件指定启动或初始化时可以显示/加载的模块和组件;
           d.   使用定时Job或有时限的缓存机制来加载配置文件;
           e.   使用观察者模式检测配置的变化并重新加载配置到应用中;
           f.    当检测配置变化时,可以发送外部命令给应用系统触发其重新加载配置;
           g.   提供界面修改配置文件参数并实时更新应用和配置文件(可能有安全隐患);
           h.   使用全局单例管理者来负责根据配置文件的变化动态显示/隐藏和动态加载/卸载模块。

    9.  可移植性:能够在不同平台和设备上运行
            a.  使用抽象屏蔽不同平台之间的差异
            b.  尽可能遵循可移植的标准;
            c.   尽可能采用标准写法。
 
   10.  人机交互:
            a.   知识与信息的准确性和丰富度,符合或超出期望;
            b.   操作的引导设计、正确性与舒适度;
            c.   外观与设计的实用美观,赏心悦目;    
            d.   使用动画或添加趣味内容消弱等待时间的影响;
            e.   使用变化效果提示用户请求已经发送,正在处理。

    

     每次解决用户最关心的前三个问题, 不为无关痛痒的事情浪费时间、精力和资源。

     首先是功能与服务,功能与服务是核心,是存在的价值;
     其次是设计,设计使功能与服务更加突出具有吸引力,更好的使用品质;
     接着是成本和传播。保证优秀功能和设计的基础上降低资源时间和人力成本,同时良好的传播和使用让边际成本更低。

       软件产品品质主要可以分为四个要素:  开发品质、测试品质、项目品质和产品品质。

        
  一、 开发品质提升

      1. 代码可读性,易理解
      a.   仔细斟酌命名,望文知义,使用通俗易懂的词汇;
            b.   代码风格自然一致,排版整齐;
            c.   注释适宜, 特殊处理注明原因;
            d.   阐述算法设计思想或注明引用出处
            e.    API、公共函数的文档简洁清晰,注明用途及原因;
            f.    探索和使用正确良好的代码模式,避免生僻写法;
            g.   单一职责划分, 编写短小类/短函数/短方法。

      2.  功能/异常处理/健壮性
    a.  准确处理常用场景。
                    a.0   沟通, 准确理解需求、场景及业务流;
                    a.1   仔细挑选开发使用的工具箱、库与框架; 
                    a.2   常用子任务使用公认主流开发库并仔细测试; 
                    a.3   完整理解API, 包括其功能、原理、适用场合与局限性;
                    a.4   编写类/方法/函数时注明使用契约及特殊处理;
                    a.5   每个类/方法/函数各司其职,相互协作。     
            b.  错误情况友好提示。
                    b.1  错误码和错误消息使用配置文件,与代码分离;
                    b.2  不同类型的参数检测使用不同的参数验证器(通常是正则表达式);
                    b.3   使用全局统一的错误检测函数尽量在一个地方集中检测错误。
                    b.4   错误处理全局框架
                                 错误检测函数注册器: 不同的参数对应不同的检测函数
                                           Map<paramName, ErrorDetectFunc>  errorDetectFuncMap;
                                           ErrorMsg ErrorDetectFunc(paramName, paramValue);
                                 全局统一的错误检测函数:  
                                           def   Map<paramName, errormsg> detectError(Map<paramName, paramValue> params) :
                                                  Map<paramName errormsg> allErrorMsg = new Map<String, ErrorMsg>();    
                                                  for paramName, paramValue in params:
                                                         ErrorDetectFunc  func = errorDetectFuncMap.get(paramName);
                                                         ErrorMsg errormsg = func(paramName, paramValue); 
                                                        allErrorMsg.put(paramName, errormsg);
                                                       return  allErrorMsg;  
                                    全局统一的错误处理函数:
                                             def  ShouldResponse processError(Map<paramName, errormsg> allErrorMsg):                                                 
                                                    
            c.   异常场景疏而不漏。 
                    c.1  细分应用中出现的各种异常并进行不同的处理;
                    c.2  在系统底层处理能够处理的异常, 无法处理的使用异常转译传给顶层;
                    c.3  在系统顶层统一处理各种应用异常并返回友好提示;
                    c.4  提示和异常消息放置在配置文件,与代码分离。
                    c.5  代码模式:
            try {
                if (err1) { errProcess1 ; }
                ...
                if (errN) { errProcess2 ; }
                // normal doing
            } catch (someException1) {
                // do with exception1 
            } catch (someExceptionN) {
                // do with exceptionN
            } catch (Exception) {
                // do with other exception unexpected
            } finally {
               // clean up
            }

     3.  性能/流畅性: 
   a.   大数据量结果集使用多线程技术获取子集并汇总;
           b.   多IO任务使用异步方式来处理;
           c.   耗时长的任务进行分解/并发/异步处理;
           d.   避免不必要的重复创建/计算开销;
           e.   耗内存的大对象的延迟创建与复用;
           f.    耗时长/频繁读操作适当利用缓存;
           g.   短时操作控制在 0.5-1s 内, 长时操作采用“异步+消息通知”模式;
           h.   测量时间,对热点区域进行适宜程度的优化;
           i.    测量和改进响应时间与吞吐量, 使之达到良好的平衡;
           j.    使用更好的硬件提升性能;
           k.   减少启动加载组件,按需加载和缓存;
           L.   使用异步模式逐步加载与展示;

     4.  稳定性和可靠性: 能够持续长时间良好运行且不出差错,出现问题时能降级/限制运行而不崩溃。
   a.   确保软件的运行环境正常稳定,包括硬件、操作系统、依赖系统;
           b.   软件能够有效应对环境波动(比如网络中断)而不至于终止;
           c.    外部系统服务调用的影响局部化, 不影响整体运行;
           d.   系统组件服务模块的影响局部化, 不影响整体运行;
           e.   避免内存泄露,死循环,死锁等会导致程序崩溃的问题;
           f.    批量资源释放问题要仔细检查,是否会因为错误或异常导致内存泄露;
           g.   操作失败可回滚;
           h.   负载均衡避免单点故障;
           i.    主备容灾应对紧急情况;   
           j.    高负载/性能测试;
          k.    添加系统监控, 展示指定时间间隔内的系统各项指标/服务/资源的运行状况。

     5. 安全性: 数据、权限与隐私保护良好
           a.   用户角色与权限分级;
           b .  只读与操作权限分离;
           c.   机密数据加密保护/权限控制/操作限制/身份认证;
           d.   权限申请加入审批流程制度;
           e.   记录请求日志与用户操作日志;
           f.    请求连接进行加密;
           g.   避免显示请求 URL;
           h.   防止注入攻击,识别非法请求模式。

     6.  可扩展性:  在原有系统基础上容易扩展,添加新特性。
           a.   整体架构模块化设计, 组件服务化, 最小化公共服务接口;
           b.   设计时总是考虑变化;
           c.   使用配置参数, 避免硬编码;
           d.   编写自包含、自封装、不修改外部状态的代码,最小化依赖;
           e.   使用设计模式优化代码表达结构, 增强软件的“柔韧度”;
           f.    文档化顺序与依赖关系, 定期整理、更新依赖关系。

          可伸缩性:  在不改变系统功能服务的基础上提供更强的处理能力和更大的处理容量。
           a.  水平扩展:   增加多个逻辑单元资源并使他们作为一个整体在工作, 比如集群、分布式、负载均衡
           b.   垂直扩展:   在同一个逻辑单位添加资源以增加容量, 比如增加CPU、内存、磁盘空间。
    7.  可维护性: 能够持久提升品质并保证简洁
           a.   参见:《保持应用系统可维护性的八个实际措施》
           b.   参见:《如何编写可信赖的代码》;
           c.   在回归测试的保护下持续小步重构。

    8.  可定制性/热升级:能够根据客户的不同需求进行定制版系统, 动态加载/卸载模块。
           a.   模块化应用程序和系统服务组件;
           b.   每个独立组件有一个标识, 标识其是否可显示/加载;
           c.   通过配置文件指定启动或初始化时可以显示/加载的模块和组件;
           d.   使用定时Job或有时限的缓存机制来加载配置文件;
           e.   使用观察者模式检测配置的变化并重新加载配置到应用中;
           f.    当检测配置变化时,可以发送外部命令给应用系统触发其重新加载配置;
           g.   提供界面修改配置文件参数并实时更新应用和配置文件(可能有安全隐患);
           h.   使用全局单例管理者来负责根据配置文件的变化动态显示/隐藏和动态加载/卸载模块。

    9.  可移植性:能够在不同平台和设备上运行
            a.  使用抽象屏蔽不同平台之间的差异
            b.  尽可能遵循可移植的标准;
            c.   尽可能采用标准写法。
 
   10.  人机交互:
            a.   知识与信息的准确性和丰富度,符合或超出期望;
            b.   操作的引导设计、正确性与舒适度;
            c.   外观与设计的实用美观,赏心悦目;    
            d.   使用动画或添加趣味内容消弱等待时间的影响;
            e.   使用变化效果提示用户请求已经发送,正在处理。

    


软件产品品质的探索与实践(一) —— 开发品质提升