编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

软件设计开发经验分享(三)—软件结构性

wxchong 2024-06-14 13:38:40 开源技术 12 ℃ 0 评论

在上篇文章里,我们讨论了调研和两大设计特性:功能性、易用性。在本篇,我们会主要讨论结构性。

链接:http://www.ideadata.com.cn/wisdomAction/readWisdom.do?id=83

链接:http://www.ideadata.com.cn/wisdomAction/readWisdom.do?id=98

结构性主要是从软件组织结构的角度来衡量,它包含或关联了一些更详细的特性:结构的一致性、稳定性、可维护性。其中可维护性还包含了可读性,可扩展性等等。可能有些地方把这些详细特性独立出来作为并列于功能性、易用性,而且各个子特性之间也可能有互相的交叉。但行无妨,这里的分法是为了概念组织方便。

1、先来看下结构的一致性,正如其他主要特性,我们在结构上也需要保持一致,这是概念完整性在软件生命周期的统一体现。结构上的一致性主要表现在软件的各种组成部分(组件、模块)采用的技术、设计方法、功能划分的标准要尽量保持一致,而他价值的体现主要在开发效率,产品质量以及可维护性上。保持该特性的好处在于可让软件开发维护成本更低,质量更好,生命周期更长。

比方说我们可能选择XML文件作为配置的存储格式,那么我们整个软件在类似的地方都应该如此;又或者说选择使用TinyXML作为了读取XML配置的开发库,那么其他读取XML的地方也要使用该库。这听起来理所应当,但软件规模扩大以及后续维护更新时,不同部分的负责人可能就有不同于最初设计者的理由来使用其他的技术或者方法。

比如某些新增组件的设计者使用JSON格式来传递网络协议,它可能为了方便就用JSON格式存储了一些本应该用XML的配置文件;又或者有些开发者在维护过程中发现TinyXML太简陋,而新增了LibXML库读写某些配置文件。这样相关的业务代码必须使用新的方法实现一次,再经过层层测试,最终堆砌在旧的代码上。长此以往类似的冗余部分就会日渐增长,维护和改进需要修改的地方也会愈来愈多。会导致产品更新变慢,维护成本升高等问题,当问题积累到一定程度甚至会导致牵一发而动全身,软件无法有效更新和维护。

要避免或者解决这些问题的方法有三种。

其一就是在设计或者维护时,架构师贯彻结构一致性,能用既有组件解决问题就尽量不要引入新的技术(避免违反概念完整性);

其二要多花一些功夫,在必要引入新东西时把旧的可替代的部分统一更新(更新概念完整性),使软件只依赖于该新技术;

其三,就是花更大代价重构甚至重写来恢复其一致性(大范围恢复概念完整性)。要问我有没有简单快速的PLAN-D,这个可以有:结束其生命周期,该软件的所有技术问题可立刻解决。

2、再说稳定性,在建筑工程界有个著名的例子,旧塔科马海峡大桥(图1),坐落于美国西海岸的华盛顿州,由著名桥梁设计专家莫伊塞夫(金门大桥设计师)制定设计方案,1940年7月1日建成通车,但仅仅四个月过后,就以垮塌而告终。

图1:旧塔科马海峡大桥

经调查大桥的材料和施工都符合要求,但设计时未考虑到海峡风的影响。在风作用下,这座大桥会以桥的中心线为对称轴扭曲变形,再加上大桥的弹性作用扭曲变为震动,震动的出现使得风对大桥的作用更为明显,最终风能战胜了大桥的刚性,导致垮塌。从此之后空气动力学和共振实验成为了建筑工程学的必修课,所有的桥梁设计方案都必须通过严格的数学分析和风洞测试。

这个案例对我们软件工程也有启示作用,针对意外的设计方案是保证产品稳定性的第一道关。风之于大桥可能就像内存空间之于软件,有些软件没有考虑到内存用尽的情况,导致一旦内存空间不足就会崩溃,这是设计缺陷。除了内存我们还可能遇到硬盘空间不足,网络中断,网络数据异常,CPU占用过高导致线程无法及时调度,甚至机房空调失效导致过热死机等等问题。倘若设计一个需要在机房长期运行的服务软件,这些问题在设计方案中必须有处理方式。例如监控CPU、内存和硬盘的使用状态,内存分配异常的捕获和上下文恢复,网络超时和协议异常处理机制,意外宕机的业务恢复机制等等,都是应对这些意外问题的有效手段。综上,这些都是靠在业务流程上增加意外处理的结构来保证稳定性。

还有从另一种角度上增加产品的稳定性的方法,那就是在软件的模块接口处做出隔离,只要不是关键模块故障,软件就可以带病运行。这样做虽然可以让整个软件持续运行,但还可能会导致部分服务的中断,所以还必须要有故障警报和恢复方案来保证服务正常,甚至用热备这种方法来提供不间断服务。这种增加稳定性的思想在业内非常常见,传统的例如磁盘阵列(图2),把每块磁盘作为一个可隔离和备份的模块,新潮例子是现在流行的大数据服务集群,在宏观上每台计算机和运行在其上的软件都是一个模块。

图2:存储服务器上的磁盘的阵列

另外还有减少bug,提升软件质量来保证来稳定性的方法,会放到质量相关的章节中去。

3、随着软件业的趋势从项目化到产品化再到服务化的日益发展,运维作为其生命周期中最长的一个阶段,该阶段的状况直接关系到软件价值的体现,故也越来越被大家所重视。用户需求和软件的环境是经常变化的,而人的思维和代码则是有限的、固定的。所以再好的软件也免不了在运行时出现一些问题,我们需要一些手段来发现这些问题以及更方便的修复和增加功能。而软件的可维护性就是衡量运维阶段难易程度的一个标准,高可维护性可以显著降低软件运维阶段的资源投入,降低成本投入的“长尾效应”。

保证软件可维护性的方式有很多,但主要切入点有:稳定保障、问题监控、问题定位、软件更新这四个方面。稳定性和可维护性的关系显而易见,上面也有描述,在此不多说。

1)对于问题监控就要求我们在设计时,对软件内部状态和外部环境要有一系列的监视措施。内部状态经常用程序日志的方式进行记录,外部则可监视软件进程、系统参数以及使用诊断协议(如心跳)等。通过这些参数的记录和临界值比对,选择发出不同等级的报告来通知运维人员。我们iAMS团队在某银行部署产品时接触过他们使用的监控系统,该监控系统可以把其数据中心所有业务系统通过监控客户端和接口接入进来。在一个大屏幕上能看到业务系统运行状态;还可以通过日志、邮件、短信、电话甚至警报器的方式来执行不同等级的告警任务。

图3:长征五号指控大厅

长征五号首发之所以能化险为夷,监控系统提供的实时关键信息功不可没。

2)对于问题定位。要想定位到问题精确所在,首先是要根据已有信息来复现问题,从而获得更多的问题相关信息;然后则是根据这些信息找到问题产生的根本原因。如果问题监控做的足够细致或问题足够明显,使得信息获取足够充分,则可以直接跨到第二步。问题复现难点在于有些问题是偶发的,难以复现。这时候我们需要这种问题的更多更详细的记录,从中找到共性;或者直接在生产环境通过不影响业务的方式详细监控,例如对偶发网络超时问题进行双端的抓包监视,这样可以准确定位出是某一端或者网络设施导致。

图4:Wireshark抓包软件界面

当问题能够复现出现但不好定位具体位置时,可以采取“二分法”的方式加快工作效率。该“二分法”和算法中二分法的含义一致,就是把组件以某个关键节点一分为二,如果前半段没有出问题那么必然是在后半段,然后在剩下的部分继续使用二分法,直到发现问题所在点。这样可避免撒网式定位的低效。

还有一点对于问题定位非常重要,我们知道绝大多数故障产生的原因就是软件bug,那么我们大部分问题定位的时间则花在了阅读和理解代码上。所以代码的可读性非常重要,这点放在下一段讲。

3)可维护性的最后一个切入点是软件更新。当我们找到的软件存在的问题或者发现新需求的时候会更新软件来处理这些情况。这免不了要修改或者新增代码,首先就要同可读性以及可扩展性打交道,在设计阶段保证可读和可扩展性的重要方法就是模块化。

模块化即高内聚低耦合,这个大家都很熟,但很多人对模块化的具体实践认知往往就是函数写的小,函数小是模块化的一个展现,而不是其充分条件。模块化的函数不但要足够小,而且要复用,那就意味着函数处理的问题是足够单一的,这样才能做到复用。即要在模块之间做到信息的隔绝:每个模块/函数只需要依赖和返回尽量少的信息。另外在宏观上看,模块之间要有层次结构(主模块和子模块),而不是杂乱无章的组合,主模块把大的问题分解成小问题交给子模块处理。这样能让模块的使用者和维护者非常高效的理解模块,提升了可读性以及可维护性。但如果只是把模块拆分了,但子模块涉及的信息相比主模块丝毫没有减少,那就是徒劳无功。

在维护软件时,我们往往会引入一些新的需求,可能某些新的需求和原来的设计结构不相符导致软件大面积的修改,开发和测试人员都要投入很多,并且更新速度和产品质量会下降,这是需要避免的问题。那么如何避免这种问题,就要求我们的设计面向变动。良好的模块化是面向变动的,但仅仅这点还不够。在设计时的无论是整个方案还是单一模块都不能设定的只恰好满足要求,要留有余量,以便于后续功能加入。当然,我们也知道不是所有的功能都要求变动,而且面向变动的设计也是有额外成本。所以需要按照用户的主要需求做一些可扩展性,可变更的操作。

例如在视频播放类软件中,我们有很多种播放器可以选择,MPC-HC/MPC-BE、Potplayer、以及一些国产软件等等,除此之外还有很多解码器、滤镜用来的处理不同格式视频和播放效果的第三方组件。这类软件中的优秀个体比如MPC-HC,为了给用户更大的灵活性,对解码器和滤镜做了扩展接口,这样用户可以各取所需的选择自己喜欢的解码器和滤镜(图5)。

图5:MPC-HC扩展滤镜界面

MPC-HC在设计时了解用户有变更滤镜的需要,并且自己无法提供全部滤镜(那样做代价太大),所以作出了面向变更的设计。这样以较小花费来取代未来可能发生的大变更的代价,并增加了用户满意度。

在本篇主要谈了一些软件结构上的知识和经验,在下篇我们会讨论剩余的其他特性和调研决策方法。

-----------------------------------------------------------------------------------------------------------------------------------------------------------

文章为原创,欢迎点赞或收藏。如有大数据爱好者,欢迎共同探讨。

关于IDEADATA:IDEADATA专注于从数据到信息的有效管理与应用,是领先的商业信息服务技术提供商,是数据仓库及大数据技术和应用的先行实践者。

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表