对抗软件复杂度的战争(2)

简介: 对抗软件复杂度的战争

07

软件道德观


在微观层面控制软件复杂度,认真编写单元测试以保障代码编写的质量反馈,对于研发效率来说是至关重要的,但同时也是耗时耗力的。而且由于这种投入对商业的价值需要很长时间才能体现出来,因此容易被研发主管所忽视。


开发者都是在生产代码、文档、API 服务等软件中间产物,这些中间产物被逐渐组装起来成为产品,产生商业价值。软件中间产物的质量对于研发组织的整体效率是至关重要的,而复杂度得到很好控制的代码和系统,就是高质量的软件中间产物;良好的软件研发道德,或者有时候也会认为这是良好的工程师文化,就是大家形成一种以交付高质量软件中间产物为荣,以交付低质量软件中间产物为耻的共识文化。


软件研发的核心职责之一是关注软件复杂度,通过开放代码、文档,Code Review 等方式让软件复杂度的信息透明,并且让所有在增加/降低复杂度的行为透明,并且持续激励那些消除复杂度的行为。唯有如此,在微观层面的控制复杂度的方法才能得到落实。


08

系统架构对复杂度的影响


介于宏观的技术战略和微观的工程师文化之间,存在着一块重要的决策区域,也对软件复杂度有着关键的影响,我称之为系统架构。在面对需求的时候,缺乏经验的工程师会直接想着在自己熟悉的模块中直接解决,而经验丰富的工程师会先思考一下系统上下文。在《Design Docs at Google》这篇优秀的技术文档写作指导中,就重点提到了,设计文档应当写清楚系统上下文图(sysmte-context-diagram),这背后的原因是什么呢?


我近期对一个遗留系统做了一个依赖链路的梳理分析,这个系统是负责生产环境中各类资源的管理的,包括资源的规格,版本,依赖关系等等,梳理完成后,整体的结构吓了我一跳,这个图大致是这样的:

图中蓝色的部分是控制和执行的子系统(System X,Y,Z),例如控制容器的调度,控制镜像变更的执行等等,是比较清晰的。但是其余部分就不是这样了(A1, A2, A3, C1, C2, S, E),它们都是在管理一个资源的运行态版本,包括镜像的版本,容器的规格,是否有 GPU,容器的数量,关联的网络资源等等,但却演进出了七个子系统,这实际上是非常高的偶然复杂度。当一个领域的概念被分散到这么多子系统之后,就会产生一系列问题:


  • 不同子系统对于同一个概念有不同的名称,交互的时候会涉及各种翻译。

  • 不同子系统承担了同一个实体的部分概念,导致修改的时候需要大范围一起修改,且容易出错。

  • 更高的运维成本。


仔细去分析这一复杂度形成的因素,我发现这既不是技术战略的问题,也不是微观层面工程师生产低质量代码导致,而是有其他更深层次的问题。其中的最核心的因素是,这些子系统在不同时期是归属于不同的团队的,有的甚至是不同部门的,具体来说,当各个部门各个团队目标不一致的时候,而这个系统又不幸地被拆到各个团队,那么就不会有人会对系统整体的复杂度控制负责。当有的团队在负责把这套系统商业化对外输出,有的团队在负责把这套系统从虚拟机模式演进到容器模式,有的团队在负责资源的成本控制,有的团队在思考全局高可用架构,而没有一个全局的架构师从整体控制概念,控制边界的时候,系统就自然而然地腐化成这样的一个状态了。


当一个问题域没有系统架构,或者其系统架构是错误的时候,你就会发现不同的人在发明不同的语言,这就好比相隔几十公里的两个村子,常常对同一个概念有不同的用词或者发音。日常生活中语言的不精确不是问题,因为日常的沟通是充满上下文的(表情,气氛,环境等),但在计算机的世界,语言的不精确就意味着需要写代码翻译,一旦翻译错误软件就会执行出错。这也就是为什么领域驱动设计那么强调统一语言,强调限定上下文。但领域驱动设计是方法论,而知道方法并不能取代系统架构角色的缺位。


这个复杂系统是康威定律的绝佳例证,康威定律说:“任何系统设计的系统,其系统结构会复制组织的沟通结构。”这句话其实还是有些抽象的,更具体的一些阐述是:


“康威定律 … 是一个合理的社会学观察。… 除非模块 A 和模块 B 的设计及实现者能有效沟通,否则这两个软件模块是无法正确对接的。因此软件系统的接口结构,就必然会和生产软件系统的社会结构及组织相对应。”


康威定律所揭示的事实,就是软件架构在很大程度上是由组织的结构和协作模式决定的,这实际上已经不再是一个软件技术问题了,而是一个组织管理问题。因此,解决系统架构层面的软件复杂度问题,就必须面对组织管理的挑战。关键问题域是否有唯一的负责人?当不同的团队在同一个问题域重复建设系统的时候,如何整合团队?当已有团队为了自己的生存,不断夸大其负责系统的重要性和特殊性,如何识别这种问题?组织如何给予大家充分的安全感,让工程师愿意为了架构的合理性,放弃自己辛苦耕作的系统模块?


讨论管理工作似乎已经超出了这篇论述软件复杂度的文章的范畴,但很多工程师或者隐隐感觉,或者思来想去最终领悟,这是我们的软件系统或优雅健壮或千疮百孔的根本因素。


小结


我曾经的大老板郭东白曾在一次 QCon 的演讲中讨论优秀架构师的特质,除了大家都很好理解的有眼光、善于思考、能感召等几个特质外,还特别强调了“有良知”,他说:

有良知,这是一个架构师随着时间的流逝,沉淀在身上最重要的品质。什么是有良知?为人正直,选择做正确的事情。很多人是非常聪明的,业务理解能力强,技术实践丰富,但他不一定为公司或为组织做最正确的事情。有良知是非常重要的一个事情,如果架构师没有素质,他会让一家公司的损失很惨重。


软件复杂度是人的行为引起的,无论是微观层面的重视质量和工程师文化,在系统架构层面让组织结构和沟通符合客观问题域,还是在技术战略层面做符合公司利益的决策,这里都存在客观无法改变的规律。如何认识到这些规律,并基于这些规律制定决策(可改变可影响),努力为公司创造价值,努力让每个工程师被尊重,是每个工程师、架构师、技术管理者所应当秉承的基本态度。本文讨论软件复杂度的初衷,就是尽量去揭示复杂度背后的客观规律,希望帮助大家认清现实,用更务实的态度去思考和决策,创造更有价值,也更让自己满足的软件系统。


参考阅读

  1. Why choose Domain-Driven Design?  这篇文章清晰地解释了本质复杂度和领域驱动设计的关系。
  2. 《人月神话》-「没有银弹」一篇阐述了本质复杂度和偶然复杂度的概念。
  3. 《The Lean Product Playbook》- 本书的第2章清晰地解释了 Problem Space 和 Solution Space。
  4. Wardley Map  - 分析技术战略的绝佳工具,合理地选取商业产品可以帮助降低系统复杂度。
  5. Grokking Simplicity  - 在微观层面,使用函数式的思维降低软件复杂度。
  6. Design Docs at Google
  7. Conway’s Law
  8. 警惕复杂度困局:关于软件复杂度的思考
相关文章
|
网络协议
Diameter协议
【本文转载于Diameter协议】 Diameter是计算机网络中使用的一个认证、授权和审计协议。它从功能更少的RADIUS协议进化而来,并且取代之。        Dimater应用通过添加新的命令或属性扩展基础协议,例如使用扩展认证 协议(EAP)。 与RADIUS协议比较        名字是一个单词游戏(从RADIUS,半径到DIAMETER,直径),从
6479 0
|
机器学习/深度学习 人工智能 算法
如何将Yolov5 模型部署到OpenVINO上
OpenVINO是英特尔推出的一款AI工具套件,可以用于快速部署AI应用和解决方案,支持计算机视觉的CNN网络结构超过150余种。它可以兼容多种主流的开源框架如PyTorch,Tensorflow,Keras,mxnet、Caffe和ONNX,并可以将上述开源框架训练好的模型,轻松的通过工具转换到OpenVINO框架上,并支持将预训练模型部署到英特尔的CPU、GPU和VPU上。
2479 0
如何将Yolov5 模型部署到OpenVINO上
|
算法 测试技术 程序员
硬核教程:五步掌握用VSCode进行高效Python开发
硬核教程:五步掌握用VSCode进行高效Python开发
1342 0
硬核教程:五步掌握用VSCode进行高效Python开发
|
Web App开发 缓存 前端开发
Spring Boot devtool的使用
Spring Boot devtool的使用
Spring Boot devtool的使用
|
存储 安全 程序员
Libra教程之:move语言的特点和例子
Libra教程之:move语言的特点和例子
Libra教程之:move语言的特点和例子
|
Web App开发 API
效率神器 | 一款节省时间和标签页的浏览器插件
记得曾经看过一份文档写作规范,其中提到一点让我印象深刻--避免套娃式文档。
效率神器 | 一款节省时间和标签页的浏览器插件
|
Java Android开发 对象存储
如何基于OSS和MPS,快速搭建音视频文件上传服务?
背景 本文主要介绍如何基于OSS服务和MTS的上传SDK,快速搭建一个音视频文件上传服务。 优势 使用MTS的上传SDK上传音视频文件,具有以下优势: 增加文件列表管理功能。 增加STS Token 超时更新功能。
14297 0
|
搜索推荐 固态存储 双11
|
存储 Kubernetes 数据安全/隐私保护
如何在Kubernetes集群中把Vault用起来
## 1 Vault是什么? 如何在云上应用中管理和保护用户的敏感信息是一个经常令开发者头疼的问题,用户的密码口令,证书秘钥等私密信息时常未经加密被随意的放置在配置文件,代码仓库或是共享存储里,而对于普通的开发者来说,设计和实现一套完整的秘钥管理系统是一个很大的挑战。且不论令人生畏的加解密算法,很多的云应用仍然将一些敏感配置信息仅仅经过base64等一些简单的hash运算就放置在某个公共的配
3762 0