一、背景

前面两篇已经大体讨论了整个软件系统中的复杂度相关的衡量指标,但是如何相对客观的通过复杂度模型来构建出来并输出相关复杂度数据,就需要对不同的衡量指标和影响因素做量化,同时需要仔细考量不同复杂度因素之间的相关性和其在真实业务场景下的权重。本篇文章将通过一些分析思维和建模方法来构建一个软件复杂度评估模型。
当然,评估模型可能确实不够准确,或者有些粗糙,需要理论研究的话还要继续优化,可以参考下。

二、复杂度向量列表

2.1 向量分类

根据前面的分类我们这里将整个向量分成三种,就是时间,空间和钱。我们对每一种的向量单位做一些说明。

2.1.1 时间

这里我们根据不同的软件周期和需求交付时间可以把,小时,天和周,月来当作复杂度在时间上的衡量单位。

2.1.2 空间

前面说的一些复杂度因素在空间上可能指的比较广泛,所以这里的衡量单位可以是个数,和大小等计量单位。

2.1.3 钱

在成本复杂度方面,我们最直观的感受就是钱,如果一个系统能够带来的利润预期上可以覆盖成本,那么对这个系统的投入是值得的。所以钱方面,在RMB上,我们可以以千元和万元为基本单位。

2.2 复杂度因素表格

这里为了方便统计和构建模型我用了一张表格来构建关于软件系统复杂度的影响因素。
表1-1:复杂度因素表格

复杂度分类 复杂度因素(单位) 说明
时间复杂度 需求收集的时间(天) 包括需求调研沟通相关的时间
时间复杂度 需求文档编写时间(天) 需求相对确定可以做的时候,落地到文档的时间,上面和下面可以分开也可以合并计时。
时间复杂度 需求技术方案文档编写时间(天) 可能也包括前期的技术调研和方案设计讨论这里可以分开也可以合并计时。
时间复杂度 需求技术方案评审时间(天/周) 一般情况下如果技术评了多轮无法确定则单独计时。
时间复杂度 软件开发时间(天/周/月/年)
时间复杂度 软件测试时间(天/周/月) 开发完成到验证的时间。
时间复杂度 软件验收时间(天/周)
时间复杂度 软件发布时间(天/周)
时间复杂度 问题排查时间(天/周/月) 这里需要指自己负责系统范围内排查问题的时间
时间复杂度 文档熟悉时间(天/周/月)
空间复杂度 系统数量(个) 指单独可运行的系统数量,如mysql,单独的微服务,或者单体服务。
空间复杂度 系统模块数量(个) 模块之间有子模块,这里可以按一定维度做模块数量的衡量。尽量覆盖全。
空间复杂度 系统模块文件数(个) 软件系统运行涉及到的全部文件数量
空间复杂度 系统模块方法数量(个) 也包括对外API
空间复杂度 系统依赖的外部系统数量(个)
空间复杂度 系统依赖的外部系统模块数量(个)
空间复杂度 系统给外部系统提供服务的数量(个)
空间复杂度 系统接口被调用的数量(次)
空间复杂度 软件服务运行所需要的机器数量(台)
空间复杂度 软件数据存储所需要的内存磁盘数量(TB/GB/PB)
空间复杂度 软件提供服务所需要的带宽量(TB/GB/PB)
空间复杂度 软件使用的用户数量(人)
空间复杂度 软件开发和运维相关的人员数量包括涉及到的产品测试UI(人)
空间复杂度 软件依赖的其他技术或者组件或者开发环境软件的数量 这里将软件开发和运行依赖的一些偏底层和工具相关的数量划为一类,如果有特定情况可以分开计数。
空间复杂度 软件开发运行维护相关的组织部门数量 这里涉及到跨部门系统或者组织与系统相关的关联关系,类似于康威定律的一个统计因素。
成本复杂度 软件开发依赖的人力资源成本 这里我们只统计了人相关的成本,当然与复杂度关联比较弱或者没有什么直接关系的成本则不在此范围内。
成本复杂度 软件开发依赖的专利采购成本
成本复杂度 软件开发依赖的特定软件环境成本
成本复杂度 软件运行依赖的硬件成本(网络,机器,内存,磁盘) 这里也可以拆开来统计成本
成本复杂度 政策变化导致的需求变更调整成本 这里对特定行业和场景有一定成本,当然也可以不计入分析

2.3 复杂度因素相关性说明

上面的复杂度其实有些可能是重叠的有些则具有一些正相关和负相关的关系。所以这里我们需要对一些明显的复杂度因素之间的相关性和复杂度本身与因素相关的关系做一些阐述。比较明显的一个例子就是生孩子,一个人10个月可以生1一个孩子,但是10个人一个月一个人也生不出来。对一个因素进行特定的投入可能会因为客观规律和其他因素导致产生混乱,就是其他复杂度因素会变的很高或者很坏。

2.3.1 软件开发时间和开发人数的相关性

2.3.2 软件开发时间与成本的相关性

2.3.3 其他相关性

这里因为篇幅问题不再一一详细介绍所有存在相关性的复杂度因素,感兴趣的可以根据自己的实际情况评估下还有哪些因素之间有相关性,可以加我好友一起讨论哈。

  1. 软件开发时间与软件依赖的开发技术栈
  2. 软件发布时间与依赖的发布技术栈(工具集,平台,中间件等)

2.4 复杂度因素权重说明

在实际情况中,复杂度因素其实不能按上面的进行单一维度计算,比如计算代码行数或者方法数,这里可能让指标统计产生一定偏差,所以我们可以按数学向量或者多项式的方式对每个复杂度因素进行合理的权重评估。
这里我们应用权重的时候其实有以下几点作用:

  1. 突出某方面复杂度,其权重会比较大,这样在整体上该复杂度对于软件系统的痛点则更明显。
  2. 客观与主观并存,权重在不同的时间阶段,不同的角色职责下取值区间不太一样。所以定权重系数的时候一定需要一个合适的评估值。
  3. 存在相关性的复杂度因素其权重之间的相关性也会跟着变化。比如有些指标之间存在正相关或者负相关,则可以用权重系数来表达。

三、复杂度模型

3.1 构建模型

3.1 模型公式

这里用上面提到的向量分类来做模型的公式因素,用代数表达一下。假设如下:
  1. 时间方面的复杂度值代表T(Time)
  2. 空间方面的复杂度值代表S(Space)
  3. 钱方面的复杂度值代表M(Money)

由于整个系列的精华可能就在这些数学公式了,可能确实功底不够,所以这里我们用一个比较浅显也比较low的多项式公式来表达不同方面的复杂度:
T=X1W1 + X2W2 + X3W3+…+XnWn.
S=Y1W1 + Y2W2 + Y3W3+…+YnWn.
M=Z1W1 + Z2W2 + Z3W3+…+ZnWn.
总体复杂度可以认为是三者之和,这里我把复杂度的值用C(Complexity)来表示。
那这样的话整体复杂度可以表示为C = T + S + M.

3.2 权重评估

上述公式中的X,Y,Z基本都比较容易评估出来,但是对于W来说不同的人在软件开发阶段看到的复杂度不一样,所以其权重评估值也会不一样,所以有些很明显的导致软件复杂的问题其权重都会比较高,也就是说在某几个复杂度因素中,其权重评估值会得到共识。另外一方面在软件需求到交付的整个生命周期中我们关注的效率问题,软件需求交付问题都将从权重上得到一些衡量。
在应用权重评估的时候可以根据自己的实际情况以及团队所处的情况进行合理评估,实际上答案不止一个,可能是一个区间。

3.3 复杂度模型建模

3.2 模型输入

这里以时间方面的复杂度来模拟计算一下,代码如下:

package com.coderman.complexity;import com.coderman.complexity.enums.ComplexityTypeEnum;
import com.coderman.complexity.enums.TimeComplexityEleTypeEnum;
import com.coderman.complexity.model.CalculateResultBO;
import com.coderman.complexity.model.ComplexityEleBO;
import com.coderman.complexity.model.MeasuringUnitBO;
import com.coderman.complexity.service.CalculateService;
import com.coderman.complexity.service.impl.TimeCalculateServiceImpl;import java.util.ArrayList;
import java.util.List;/*** Hello world!**/
public class App
{public static void main( String[] args ){CalculateService calculateService = new TimeCalculateServiceImpl();List<ComplexityEleBO> complexityEleBOList = buildTimeComplexityEleBOList();//这里以天为时间方面的复杂度的衡量标准CalculateResultBO calculateResultBO = calculateService.calculate(complexityEleBOList, MeasuringUnitBO.getInstanceDay());System.out.println(calculateResultBO);}/*** 模拟时间方面的复杂度因素* @return*/private static List<ComplexityEleBO> buildTimeComplexityEleBOList(){List<ComplexityEleBO> complexityEleBOList = new ArrayList<>();complexityEleBOList.add(new ComplexityEleBO(ComplexityTypeEnum.TIME.getCode(), TimeComplexityEleTypeEnum.REQUIREMENT_COLLECTION,1.0d,2.0d,MeasuringUnitBO.getInstanceDay()));complexityEleBOList.add(new ComplexityEleBO(ComplexityTypeEnum.TIME.getCode(),TimeComplexityEleTypeEnum.REQUIREMENT_DEVELOP,1.5d,8.0d,MeasuringUnitBO.getInstanceDay()));complexityEleBOList.add(new ComplexityEleBO(ComplexityTypeEnum.TIME.getCode(),TimeComplexityEleTypeEnum.REQUIREMENT_DEVELOP_TEST,1d,2.0d,MeasuringUnitBO.getInstanceDay()));return complexityEleBOList;}
}

3.3 模型输出

模型的输出则相对简单,这里仅输出复杂度的衡量单位,复杂度类型和复杂度的值。

四、衡量系统

这里我们用一些实际的例子来看一下如何基于上面的复杂度模型来计算复杂度值。为了比较方便的抽取复杂度信息,我们将上面的表格稍微调整下,如下:

复杂度分类 复杂度因素(单位) 复杂度值(区间范围) 复杂度权重值(区间范围) 复杂度因素计算结果(区间范围) 说明
时间复杂度 需求收集的时间(天) 包括需求调研沟通相关的时间
时间复杂度 需求文档编写时间(天) 需求相对确定可以做的时候,落地到文档的时间,上面和下面可以分开也可以合并计时。
时间复杂度 需求技术方案文档编写时间(天) 可能也包括前期的技术调研和方案设计讨论这里可以分开也可以合并计时。
时间复杂度 需求技术方案评审时间(天/周) 一般情况下如果技术评了多轮无法确定则单独计时。
时间复杂度 软件开发时间(天/周/月/年)
时间复杂度 软件测试时间(天/周/月) 开发完成到验证的时间。
时间复杂度 软件验收时间(天/周)
时间复杂度 软件发布时间(天/周)
时间复杂度 问题排查时间(天/周/月) 这里需要指自己负责系统范围内排查问题的时间
时间复杂度 文档熟悉时间(天/周/月)
空间复杂度 系统数量(个) 指单独可运行的系统数量,如mysql,单独的微服务,或者单体服务。
空间复杂度 系统模块数量(个) 模块之间有子模块,这里可以按一定维度做模块数量的衡量。尽量覆盖全。
空间复杂度 系统模块文件数(个) 软件系统运行涉及到的全部文件数量
空间复杂度 系统模块方法数量(个) 也包括对外API
空间复杂度 系统依赖的外部系统数量(个)
空间复杂度 系统依赖的外部系统模块数量(个)
空间复杂度 系统给外部系统提供服务的数量(个)
空间复杂度 系统接口被调用的数量(次)
空间复杂度 软件服务运行所需要的机器数量(台)
空间复杂度 软件数据存储所需要的内存磁盘数量(TB/GB/PB)
空间复杂度 软件提供服务所需要的带宽量(TB/GB/PB)
空间复杂度 软件使用的用户数量(人)
空间复杂度 软件开发和运维相关的人员数量包括涉及到的产品测试UI(人)
空间复杂度 软件依赖的其他技术或者组件或者开发环境软件的数量 这里将软件开发和运行依赖的一些偏底层和工具相关的数量划为一类,如果有特定情况可以分开计数。
空间复杂度 软件开发运行维护相关的组织部门数量 这里涉及到跨部门系统或者组织与系统相关的关联关系,类似于康威定律的一个统计因素。
成本复杂度 软件开发依赖的人力资源成本 这里我们只统计了人相关的成本,当然与复杂度关联比较弱或者没有什么直接关系的成本则不在此范围内。
成本复杂度 软件开发依赖的专利采购成本
成本复杂度 软件开发依赖的特定软件环境成本
成本复杂度 软件运行依赖的硬件成本(网络,机器,内存,磁盘) 这里也可以拆开来统计成本
成本复杂度 政策变化导致的需求变更调整成本 这里对特定行业和场景有一定成本,当然也可以不计入分析

这里加了三列,按照上面的公式可以方便的计算出某个系统的复杂度,当然也可以通过计算机程序输入然后得到输出结果。前面说了,复杂度的计算结果可能是在某个区间,所以计算机程序仍然需要计算出复杂度结果所在的区间范围。

4.1 单体组件级别的系统

这里我们把单体组件级别的系统看作可以独立运行的一个Java进程或者一个微服务实例。或者一个大的单体服务。所以上面的表格中要填写的内容会简单一点。但是仍然要相对全面的从技术业务和人的角度评估。

4.2 分布式服务级别的系统

这里就是分布式微服务或者集群维度的系统衡量了,比如商品系统或者营销优惠系统,这些系统一般来说是一个团队去负责的,所以系统边界与团队边界是相互契合的,同时也符合康威定律。划定了系统范围则划定了系统个数和开发使用人员的大概范围。但是要注意的是需要评估人员变动,服务资源动态规划的相关内容,所以在范围上尽量做合理且真实的评估。

4.2 单体集成式系统

这里指的是表面上是一个系统,比如操作系统,但是还有很多子系统一起合并到一个可执行exe或者jar包里,或者安装文件里,通常这种模式下跟我所开发的微服务应用不太一样,但是仍然可以进行复杂度评估。

五、与复杂度相关的系统

5.1 工程效率平台

很多公司都会用到工程效率平台,或者自己开发维护一套,这么做的原因一方面是辅助记录各种信息,跟踪项目,同时帮助提高软件研发效率和交付能力。工程效率平台也涉及到方方面面,个人也觉得就是DevOps的外延。此时可能就是开发Owner全部了。在工程效率平台中不同角色的人可以更好的应对其职责范围内的复杂度。
当然其本身是否能更好的支持软件研发的生命周期,也需要做工具平台的人逐步去优化和改良,大多数情况下买来的工程效率平台可能都不太适应公司的实际情况。

5.2 研发效能平台

研发效能平台与上面的工程效率平台可能差别不大,或者就是叫法不一样,但是实际上研发效能平台可能范围更广,服务的业务线和场景也更多,同时会附带很多统计信息类似于把jira或者confluence的文档功能结合在一起了,但是很多时候研发效能会被一些开发人员抵制,或者心理上产生排斥心理。这块会在后面的文章专门讨论。
话说回来,研发效能与复杂度有什么关系,因为研发效能重在统计和衡量,所以简单来说研发效能就是复杂度衡量的一种简单方式。只是没有特别全,有些场景在研发效能里占比非常少,但并不能衡量系统的复杂度。

5.3 敏捷框架与方法论

关于软件复杂度和研发效率不同的人关注点也不一样,所以如何衡量复杂度看上去不是特别重要,但是应对复杂度的方法却层出不穷。这里从敏捷框架和方法论上简单介绍一下降低并控制复杂度的理论方法。

5.3.1 敏捷开发方法论

  1. Scrum
  2. XP
  3. 精益开发

5.3.2 Cynefin框架

这里放一张Cynefin的官网图:

官网链接如下:https://thecynefin.co/。
总体上是将复杂度因素按不同维度进行划分和归类,这样对于人来说更容易理解和管控。

六、经常关注的系统复杂度

上面的一些复杂度维度是偏理论的,实际上作为开发者,互联网架构上面会从下面的几个方面去看系统复杂度,这里我也简单介绍一下。

6.0 思维导图

6.1 代码复杂度

代码方面的复杂度其实在需求设计阶段是看不出来的,在方案上可能会有些体现,这里重点还是在开发阶段,代码上的不同评估因素都在影响整体复杂度。比如模块,接口设计,实现链路等。

6.2 组织复杂度

从管理者的角度来说组织上的复杂度其实也需要考虑,尤其是互联网行业,在互联网行业组织变动是非常频繁的。组织变动也会带着系统复杂度出现动态波动。

6.3 架构复杂度

现阶段的互联网技术其实已经趋于稳定了,分布式应用也已经发展了很多年,个人觉得快到瓶颈了,在刚发展的几年里部分工程代码还有拷贝的可能,但是架构却不一定有人能给你正确的参考。但是现在不一样了,很多大厂探索出的架构应用。

6.4 工程效能与软件复杂度相关文章

如何从容应对复杂性:https://mp.weixin.qq.com/s/8YD9sqTuZGJEpVZPYY-aBQ
系统困境与软件复杂度:https://mp.weixin.qq.com/s/npTzzZiJ_pvbXgFOTGmZ0Q
研发效能度量核心方法与实践系列文章:https://www.infoq.cn/article/kINcaQBBC0uyvFmVlvzx

七、总结

在整个衡量过程中我们可以得到一些想要的信息,或许结果并不重要,但是我们依然可以通过上述复杂度模型来更好的帮助我们找到应对复杂度的方法。

如何衡量软件系统的复杂度(三)相关推荐

  1. 如何衡量软件系统的复杂度(二)

    一.背景 上一篇重点讲述了软件复杂度的由来和现象,以及不同视角下的复杂度是怎么呈现的,本篇文章将从更细致的方面来阐述形成复杂度的一些指标数据,并按不同维度进行区分. 这么做的一个原因就是希望通过本篇文 ...

  2. 文本相似度的衡量之余弦相似度

    余弦计算相似度度量 相似度度量(Similarity),即计算个体间的相似程度,相似度度量的值越小,说明个体间相似度越小,相似度的值越大说明个体差异越大. 对于多个不同的文本或者短文本对话消息要来计算 ...

  3. python衡量数据分布的相似度/距离(KL/JS散度)

    背景 很多场景需要考虑数据分布的相似度/距离:比如确定一个正态分布是否能够很好的描述一个群体的身高(正态分布生成的样本分布应当与实际的抽样分布接近),或者一个分类算法是否能够很好地区分样本的特征(在两 ...

  4. perplexity 衡量指标_困惑度(perplexity)的基本概念及多种模型下的计算(N-gram, 主题模型, 神经网络)...

    让人困惑的困惑度 发现网络上流传的关于困惑度(perplexity)大多数都是利用了N-gram或者主题模型的例子来阐述的.但是现在这个年代来学习这个指标的人多半都是想研究神经网络的,而两者对困惑度 ...

  5. 衡量文章词汇复杂度Type Token Ratio (TTR)

    Type Token Ratio (TTR): 一种有用的衡量复杂性的方法,它记录词汇丰富程度或词汇的多样性. Token 形符:文章所用单词总数,包括标点的字数 Type 类符:文章中不重复单词的数 ...

  6. 衡量风控策略区分度的三步法

    作为一个风控策略从业者,在做风险管理的过程中一直都在做的是,不断的挖掘有效的变量特征来填充风控决策引擎,使决策引擎的功效变大变强,最终形成一套可变的稳定风险护盾. 虽然单一的变量特征即使有很强的区分度 ...

  7. ​​​​​​ 如何衡量完善度?

    DWD层完善度:衡量DWD层是否完善,最好看ODS层有多少表被DWS/ADS/DM层引⽤.因为DWD以上的层引⽤的越多,就说明越多的任务是基于原始数据进⾏深度聚合计算的,明细数据没有积累,⽆法被复⽤, ...

  8. Python-图-如何找出社交网络中的三度好友关系

    羁绊前行的,不是肆虐的狂风,而是内心的迷茫.-王争. 最近有些偷懒,距离上次更新也有两个星期了,原因我也很清楚,就是又开始有些迷茫了,购买了不少课程,仍不能减轻内心的焦虑.焦虑的原因还是想得太多,做得 ...

  9. 阿里研究员谷朴:警惕软件复杂度困局

    作者 | 张瓅玶(谷朴)  阿里巴巴研究员 **导读:**对于大型的软件系统如互联网分布式应用或企业级软件,为何我们常常会陷入复杂度陷阱?如何识别复杂度增长的因素?在代码开发以及演进的过程中需要遵循哪 ...

最新文章

  1. Mono源代码学习笔记:Console类(四)
  2. java锁的种类以及辨析(转载)
  3. 51CTO学院三周年,一起成长与奋斗的日子
  4. java邮箱设置密送_修改后可以发送附件、抄送、密送的javabean,吐血推荐~(javamail范例)...
  5. python保持登录状态_“保持登录状态”-最佳方法
  6. php 调用redfish,RedfishWhitePaperRedfish白皮书.pdf
  7. labview事件结构
  8. 移动互联网数据安全蓝皮报告(2021年)
  9. apache 编译报错:undefined reference to `apr_array_clear'
  10. linux mysql多实例启动_Mysql实例Linux下启动多个mysql服务器例子
  11. HTTP之Web服务器
  12. 关于Mac下mysql8.0的启动
  13. systemd 介绍
  14. Win10 / 11新电脑最简单跳过联网激活和使用本地账户登录方法
  15. 幽默感七个技巧_如何让自己变得幽默-16个聊天幽默技巧
  16. [AV1] DC Intra Prediction
  17. 【缺陷检测】基于形态学实现印刷电路板缺陷检测技术附matlab代码
  18. 字符串(如DNA序列,蛋白质序列)的编码和用于机器学习和神经网络
  19. 值得看三次的高干文_值得看三次的高干文12部
  20. 【数据结构】什么是拓扑排序—关于图的拓扑排序

热门文章

  1. kernel: swapper: page allocation failure. order:1, mode:0x20
  2. FP7195转模拟调光技术解决智能家居调光频闪和电感噪音的原理
  3. react受控组件、非受控组件以及高阶组件
  4. 一文看懂无代码平台为何能助力企业生产管理数字化转型
  5. Java异常机制的最佳实践
  6. hyperledger fabric chaincode 教程二
  7. 华为11ui有鸿蒙,与EMUI11界面相似?华为工作人员:鸿蒙OS正式版将采用全新UI
  8. 极光推送Jpush的“appKey and masterSecret format is incorrect”问题修复
  9. 使用proz来加速你的Freebsd ports安装
  10. 加密数字货币的 7 个致命悖论