深入分析软件复杂度

作者:CQITer小编 时间:2018-12-18 16:36

字号

软件复杂度的成因

Eric Evans的经典著作《领域驱动设计》的副标题为“软件核心复杂性应对之道”,这说明了Eric对领域驱动设计的定位就是应对软件开发的复杂度。Eric甚至认为:“领域驱动设计只有应用在大型项目上才能产生最大的收益”。他通过Smart UI反模式逆向地说明了在软件设计与开发过程中如果出现了如下问题,就应该考虑运用领域驱动设计:

没有对行为的重用,也没有对业务问题的抽象。每当操作用到业务规则时,都必须重复这些规则。

快速的原型建立和迭代很快会达到其极限,因为抽象的缺乏限制了重构的选择。

复杂的功能很快会让你无所适从,所以程序的扩展只能是增加简单的应用模块,没有很好的办法来实现更丰富的功能。

因此,选择领域驱动设计,就是要与软件系统的复杂作一番殊死拼搏,以降低软件复杂度为己任。那么,什么才是复杂呢?

软件复杂度

什么是复杂?

即使是研究复杂系统的专家,如《复杂》一书的作者Melanie Mitchell,都认为复杂没有一个明确得到公认的定义。不过,Melanie Mitchell在接受Ubiquity杂志专访时,还是“勉为其难”地给出了一个通俗的复杂系统定义:由大量相互作用的部分组成的系统,与整个系统比起来,这些组成部分相对简单,没有中央控制,组成部分之间也没有全局性的通讯,并且组成部分的相互作用导致了复杂行为。

这个定义庶几可以表达软件复杂度的特征。定义中的组成部分对于软件系统,就是我所谓的“设计单元”,基于粒度的不同可以是函数、对象、模块、组件和服务。这些设计单元相对简单,然而彼此之间的相互作用却导致了软件系统的复杂行为。

Jurgen Appelo从理解力与预测能力两个维度分析了复杂系统理论,这两个维度又各自分为不同的复杂层次,其中,理解力维度分为simple与comlicated两个层次,预测能力维度则分为ordered,complex与chaotic三个层次,如下图所示:

深入分析软件复杂度

参考复杂的含义,complicated与simple(简单)相对,意指非常难以理解,而complex则介于ordered(有序的)与chaotic(混沌的)之间,认为在某种程度上可以预测,但会有很多出乎意料的事情发生。显然,对于大多数软件系统而言,系统的功能都是难以理解的;在对未来需求变化的把控上,虽然我们可以遵循一些设计原则来应对可能的变化,但未来的不可预测性使得软件系统的演进仍然存在不可预测的风险。因此,软件系统的所谓“复杂”其实覆盖了complicated与complex两个方面。要理解软件复杂度的成因,就应该结合理解力与预测能力这两个因素来帮助我们思考。

理解力

在软件系统中,是什么阻碍了开发人员对它的理解?想象团队招入一位新人,就像一位游客来到了一座陌生的城市,他是否会迷失在阡陌交错的城市交通体系中,不辨方向?倘若这座城市实则是乡野郊外的一座村落,不过只有房屋数间,一条街道连通城市的两头,还会生出迷失之感吗?

因而,影响理解力的第一要素是规模。

1. 规模

软件的需求决定了系统的规模。当需求呈现线性增长的趋势时,为了实现这些功能,软件规模也会以近似的速度增长。由于需求不可能做到完全独立,导致出现相互影响相互依赖的关系,修改一处就会牵一发而动全身。就好似城市的一条道路因为施工需要临时关闭,此路不通,通行的车辆只得改道绕行,这又导致了其他原本已经饱和的道路因为涌入更多车辆而超出道路的负载变得更加拥堵,这种拥堵现象又会顺势向这些道路的其他分叉道路蔓延,形成一种辐射效应的拥堵现象。

软件开发的拥堵现象或许更严重:

函数存在副作用,调用时可能对函数的结果作了隐含的假设;

类的职责繁多,不敢轻易修改,因为不知这种变化会影响到哪些模块;

热点代码被频繁变更,职责被包裹了一层又一层,没有清晰的边界;

在系统某个角落,隐藏着伺机而动的Bug,当诱发条件具备时,就会让整条调用链瘫痪;

不同的业务场景包含了不同的例外场景,每种例外场景的处理方式都各不相同;

同步处理与异步处理代码纠缠在一起,不可预知程序执行的顺序。

责任编辑:CQITer新闻报料:400-888-8888   本站原创,未经授权不得转载
继续阅读
热新闻
推荐
关于我们联系我们免责声明隐私政策 友情链接