软件中的质量属性(二)

现在我们接着上一次的话题来看看其它的质量属性。
互操作性 (Interoperability
互操作性指的是系统内或者系统之间不同的组件可以有效地进行信息交换,通常是以服务(Service)的形式来进行的。互操作性的关键因素包括通信协议,接口定义,数据格式的定义等等,而标准化是实现互操作性的重要手段。
实现互操作性的主要挑战有以下这些方面:
  • 系统内部或者和已有的旧系统(legacy system)之间的数据定义不一致
  • 系统的边界模糊,模块之间耦合严重,导致数据冗余
  • 缺乏标准,或者各方对标准的实现和认识不一致
我现在所在的商务智能团队的总架构师(Chief Architect)就一直在部门间推动对数据文档统一格式标准的定义和实现。这本身对于我们产品内部的互操作性是非常有必要的,然而BI的团队分布在各个大洲(主要是德国,法国,加拿大,中国和印度),每个部门对各自产品优先级的认识不一致,在加上对旧系统兼容性的要求,这项工作的进展非常非常的缓慢。BI的各个产品仍然很难互操作。
我之前开发过通信网管,当时做的产品是统一网管平台,就是把各个厂商(华为,中兴,朗讯等等)的电信设备统一的管理起来。当时已经有了相当成熟的电信网管理标准(TMF,ISO等标准)和技术标准(Q3,Corba)。然而理解的不同,厂商对标准的实现千奇百怪,所以实际上需要给每一个厂商定制不同的接口适配器。我当时就在负责一些这样的接口开发。
面向服务的架构(SOA)曾经是一个非常热门的词汇,现在似乎不怎么提起了。我司当年曾经大张旗鼓的宣传SOA。其实这样的架构能够解决的一个主要的问题就在能够把企业内部各种已有系统通过暴露标准服务接口的方式有效的协调起来。
为了实现互操作性,我们一般需要
  • 定义标准的数据格式和语义
  • 定义标准的服务接口,并使用基于服务的架构
  • 设计高内聚,低耦合的模块以获得最大的灵活性可重用性
可维护性 (Maintainability
可维护性有两个不同的角度,一个是指从软件用户和运维人员的角度,另一个是从软件开发人员的角度。
从用户和运维人员的角度,软件的可维护性是指软件是不是容易安装,升级,打补丁,有了问题是不是容易修复,能不能很容易的获得支持。
从开发人员的角度,软件的可维护性是指软件的架构是不是清楚简单,代码是不是容易阅读,有了问题是不是容易定位错误的原因,有没有可以提供帮助的文档,等等。
软件系统可维护性的主要问题有:
  • 模块之间紧耦合导致无法或很难对单独的模块进行修改,替换和升级
  • 在高层直接使用底层协议和接口,导致无法替换物理设备实体
  • 没有有效的分层和责任的划分,导致一个肿大的模块以及巨大的代码出现在同一个文件甚至函数中。
  • 没有帮助和设计文档
  • 为了兼容旧系统而不得不同时存在两个以上的复杂的代码栈甚至技术不同的实现
知道了问题,改进的建议是非常明显的,我要讨论的是一个关于代码可读性的有趣话题。
很多人都认为,代码是写给人看的,它碰巧也能被计算机读懂。所以我们应该像写文学作品那样写代码。碰巧我也非常的赞同这样的观点。然而,最近的一篇文章提到另一种观点,代码不是文学作品,我们不是阅读而是评审。这篇文章也许能够帮助你改善代码评审。不管代码是不是文学作品,写出容易阅读的代码对于提高软件的可维护性的好处是不言而喻的。

性能(Performance
性能也许是软件开发中最被重视的质量属性,也是最特殊的一个,从它的英文名字中不以(-ility)为后缀,我们可以看到他的特殊性。我们通常以系统执行某操作所需要的响应时间(latency)或者在某单位时间所能完成的任务的数量(throughput)来定义性能指标。
性能和其它的质量属性的相关性很高,有一些会对性能产生正面影响,有一些则是负面的。
记得我当年参加一个关于C++性能优化的培训,有一道算法,要求大家试着用最快的方式实现。因为C++中的指针操作按数组索引访问要快,于是当时最快的一个解决方案是用了一大推复杂指针访问来实现算法。然而这样的代码很难维护,而且容易出错。所以为提高性能就牺牲了可维护性。
一般而言,计算机提供了许多的资源,包括CPU,内存,硬盘等等,提高性能的核心就是充分利用这些资源。要保证对资源的使用是正确和有效的。通常提高性能的考虑包括:

  • 利用缓存(空间换时间)
  • 设计高效的资源共享,多线程,多进程,锁
  • 异步
  • 减少模块见得信息传递
  • 使接口设计传递最小所需的信息
  • 增加系统的可伸缩性,是系统能够有效的部署在分布式的资源上
另外我们还需要考虑另一个性能,就是程序员实现功能的性能。随着软件的发展,现在的程序员可以更高效的实现功能需求。一方面编程语言和方法在不断进步,另一方面大量的可重复使用的组件,服务,开源的库使得想在实现同样的功能的时间和需要的开发人员的数量比以前极大的缩小了。whatsapp以区区55人的团队开发出价值190亿美元,拥有4.5亿用户的软件产品,这在以前是难以想象的。所以软件架构设计者应该把软件的开发效率看成是更重要的性能指标。

可重用性 (Reusability
老板一般都非常重视可重用性,因为如果把软件代码看成产品,那么如果该产品如果只能用一次就扔掉,那他显然是很不开心的,因为这是一笔很糟糕的投入。在我的软件开发生涯这么多年以来,我体验的软件的可重用性都不是很高,也许是我大多在大型的软件企业服务有关。大企业的特点就是团队非常多,产品非常丰富,老板经常更换。每一个新的老板上台后,面临一大堆功能技术各异的系统都非常的不happy,于是整合在所难免,如何重用已有的系统来实现一个新的,大一统的新产品成了重中之重。然而这并不比找到宇宙中的终极大一统理论更简单。最终的整合结果往往并不能有效的重用已有的系统,当老板因为各种原因离开时,我们会发现,对新的老板来说,整合的任务变得更加艰巨了,因为,又有一个新的系统需要整合了。
提高可重用性的一个最主要的原则就是避免重复,“Don't repeat yourself!”我想大家应该非常熟悉了,这里就不多说了。
在成熟度不高的开发团队中(很不幸,我们大多数人都处在这样的团队中),对代码的重用很难,其实只有人才是最可靠的可重用组件,人离开了,所有的可重用性也就跟着离开了。

伸缩性(Scalability)
伸缩性要求软件系统能够跟着所需处理的工作量相应的伸缩。例如如果计算机是多CPU多核心的,软件是否能够相应的利用到这些计算资源。另一个方面就是软件是不是能够部署到分布式的网络,有效的利用网络中的每一个节点的资源。
有两个方向的伸缩,垂直和水平。
在垂直方向的伸缩(scale up)是指提高单节点的处理能力,比如提高CPU主频和内核数,增大内存,增大磁盘容量等等。SAP的HANA就是一个典型的垂直方向的伸缩。
在水平方向的伸缩(scale out)通常是指通过并发和分布的方式来增加节点以提高处理能力。Hadoop就是一个很好地水平伸缩的例子。
设计高伸缩性的软件时,我们可以考虑
  • 避免有状态的服务或组件
  • 使用配置文件决定组件的的部署和关系
  • 考虑支持数据的分区
  • 避免统一层的责任跨越不同的物理实体
在云时代,软件的伸缩性越发重要。

可测试性(Testability)
可测试性顾名思义就是指软件是否容易测试。
什么样的软件是不可测试的呢?举个例子来说,我们曾经开发过一个数据可视化的组件,就是把数据以图表的形式展现出来。有一种数据可视化的类型使用力导向的算法(force-directed)把数据以网络拓扑图的形式展现出来,该算法使用一些随机的参数来模拟节点的初始位置,并通过迭代计算生成最终layout的结果。也就是说每次的layout结果都是不一样的。测试团队对这样的算法很不满意,他们认为这样的实现是无法测试的,因为当时我们的测试主要以比对图形为基础,也就是生成一个正确的图形为基准,每次测试都会把输出的图形和基准图形进行比较,如果不一致则认为出错或者要修改基准。随机算法虽然从功能上讲并没有错误,但是在这样的测试方法下是无法满足可测试性的要求的。最后,开发团队修改了算法,使得每次的初始位置未固定位置来解决这个问题。
David Catlett提出了一个SOCK模型可以有效地帮助我们了解可测试性的要素
  • Simple
    代码越简单越容易测试。
  • Observable
    软件系统应该是可观测,无法观测也就无法衡量
  • Control
    软件系统应该是可以控制的,尽可能多的把控制权暴露给测试模块。
  • Knowledge
    测试人员或者模块需要更多地理解被测试模块,理解的越多也就越容易测试(白盒测试)
软件质量属性的每一个方面都有很多的内容,我们只能浅尝而止,而且仍然有许多重要的质量属性我们还没有涉及到,有时间的话,我们以后再说。

发帖者Unknown 时间: 23:28  

0 评论:

发表评论