系统困境与软件复杂度:为什么我们的系统会如此复杂?

本文探讨了软件复杂性及其在系统中的表现,指出变更放大、认知负荷和未知的未知是复杂性的特征。文章强调了复杂性产生的原因,包括不合理的内容治理、认知负荷增加和技术能力不足等。作者引用了《A Philosophy of Software Design》中的观点,提倡战略编程以对抗战术编程导致的系统腐化,并讨论了架构设计中的误区,主张在面对复杂性时寻找平衡,避免过度优化。
摘要由CSDN通过智能技术生成

| 读 A Philosophy of Software Design 有感,软件设计与架构复杂度,你是战术龙卷风吗?

前言

有一天,一个医生和一个土木工程师在一起争论“谁是世界上最古老的职业”。医生说:“上帝用亚当的肋骨造出了夏娃,这是历史上第一次外科手术,所以最古老的职业应该是医生”,土木工程师说:“在创世纪之前,上帝从混沌中创造了天堂与人间,这是更早之前的一次土木作业,所以最古老的职业应该是土木工程”。这时软件工程师拖着键盘走出来说,“那你认为,是谁创造了那片混沌?”

建筑师不会轻易给 100 层的高楼增加一个地下室,但我们却经常在干这样的事,并且总有人会对你说,“这个需求很简单”。到土里埋个地雷,这确实不复杂,但我们往往面临的真实场景其实是:“在这片雷区里加一个雷”,而雷区里哪里有雷,任何人都不知道。

什么是复杂性

我们一直在说系统很复杂,那到底什么是复杂性?关于复杂的定义有很多种,其中比较有代表的是 Thomas J. McCabe 在 1976 提出的理性派的复杂性度量,与 John Ousterhout 教授提出的感性派的复杂性认知。

理性度量

复杂性并不是什么新概念,早在上世纪 70 年代,软件就已经极其复杂,开发与维护的成本都非常高。1976 年 McCabe&Associates 公司开始对软件进行结构测试,并提出了 McCabe Cyclomatic Complexity Metric,我们也称之为 McCabe 圈复杂度。它通过多个维度来度量软件的复杂度,从而判断软件当前的开发/维护成本。

圈复杂度 代码状况 测性成本 维护成本
圈复杂度1 - 10 清晰/结构化 可测性高 维护成本低
圈复杂度10 - 20 复杂 可测性中 维护成本中
圈复杂度20 - 30 非常复杂 可测性低 维护成本高
圈复杂度30 不可读 不可测 维护成本非常高

感性认知

复杂度高的代码一定不是好代码,但复杂度低的也不一定就是好代码。John Ousterhout 教授认为软件的复杂性相对理性的分析,可能更偏感性的认知。

Complexity is anything that makes software hard to understand or to modify
译:所谓复杂性,就是任何使得软件难于理解和修改的因素。
John Ousterhout 《A Philosophy of Software Design》

50 年后的今天,John Ousterhout 教授在《A Philosophy of Software Design》书中提到了一个非常主观的见解:复杂性就是任何使得软件难于理解和修改的因素

模糊性与依赖性是引起复杂性的2个主要因素,模糊性产生了最直接的复杂度,让我们很难读懂代码真正想表达的含义,无法读懂这些代码,也就意味着我们更难去改变它。而依赖性又导致了复杂性不断传递,不断外溢的复杂性最终导致系统的无限腐化,一旦代码变成意大利面条,几乎不可能修复,成本将成指数倍增长。

复杂性的表现形式

复杂的系统往往也有一些非常明显的特征,John 教授将它抽象为变更放大(Change amplification)、认知负荷(Cognitive load)与未知的未知(Unknown unknowns)这 3 类。当我们的系统出现这 3 个特征,说明我们的系统已经开始逐渐变得复杂了。

症状 1-变更放大

Change amplification: a seemingly simple change requires code modifications in many different places.
译:看似简单的变更需要在许多不同地方进行代码修改。
John Ousterhout 《A Philosophy of Software Design》

变更放大(Change amplification)指得是看似简单的变更需要在许多不同地方进行代码修改。比较典型的代表是 Ctrl-CV 式代码开发,领域模型缺少内聚与收拢,当需要对某段业务进行调整时,需要改动多个模块以适应业务的发展。

/**
 * 销售捡入客户
 */
public void pick(String salesId, String customerId) {
  // 查询客户总数
  long customerCnt = customerDao.findCustomerCount(salesId);
  // 查询销售库容
  long capacity = capacityDao.findSalesCapacity(salesId);
  // 判断是否超额
  if(customerCnt >= capacity) {
    throws new BizException("capacity over limit");
  }
  // 代码省略 do customer pick
}

在 CRM 领域,销售捡入客户时需要进行库容判断,这段代码也确实可以满足需求。但随着业务的发展,签约的客户要调整为不占库容。而客户除了销售捡入,还包括主管分发、leads 分发、手工录入、数据采买等多个场景,如果没对库容域做模型的收拢,一个简单的逻辑调整,就需要我们在多个场景做适配才能满足诉求。

症状 2-认知负荷

Cognitive load: how much a developer needs to know in order to complete a task.
译:开发人员需要多少知识才能完成一项任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值