前言

软件设计上我们寄希望于能够让软件更简单、更容易维护,但是一面是害怕墨菲定律的应验,一方面又害怕遵循纯粹原则导致出现更多的缺陷。我们可以认为简单和复杂分别是跷跷板的两端,而它的支点就是复杂度守恒原则。只有充分了解并预见了项目的复杂度,不过分高估也不过分低估才能把握好项目进展。

简记

整体复杂度不会消失也不会凭空产生,只会在不同模块和代码间分布。完成一个固定复杂度的工作时,在每一个局部尽可能用有限的依赖、产生有限的描述。

阐述

当你的程序拥有更多的行数、方法、类、包、依赖库、可执行程序时,你的程序一定会非常复杂。我们要做的解决方案一般而言复杂度是固定的,一定能找到某种让方法、类、依赖数量合适的临界点。比如我们降低了代码行数,那么一定会意味着我们所使用的依赖库会更多;反之如果我们将依赖降低,势必需要写大量的工具类来完成同样的事情,从而提升代码行数。再比如我们将一个大类分成几个更小的类来实现同样的功能,意味着架构复杂度、文档字数、学习成本会上升;反之如果我们将小类聚合成一个大类,意味着边界控制、可用性控制的代码会上升。没有能够既做到不降低复杂度,也能保证产品高质量的方案,如果你认为有,那么只有两种情况:1、可能你忽略了某些导致BUG的场景;2、你把高复杂度的代码进行了封装并假设它永远不会有人改动。

实际软件工程项目中,模块切分的太大则会产生模块化不足的现象,模块切分的太小则会陷入过度模块化陷阱。模块化不足会让你的项目失去灵活性,并且与业务高度耦合,相同的代码不得不写多次才能实现同样的功能;而过度模块化则会让程序员记忆成本增加,并可能出现只有在特定情形下多个模块组合才能达成某个目的的“魔法组合方式”,不利于维护。

图1、一个典型的拆分模块的例子

人脑的记忆力是有限的,如果需要记住大量的模块或者API,那么这个模块一定是很难理解的。而且一个模块如果很大,需要很长时间才能完成学习,对于新人引入也是不利的。如果有很多的模块和API,寻找一个特定的组合来完成工作需要很长的时间,而且当检索的时间越长,程序员就越容易忘记之前用过的组合,这便导致引入更加复杂的代码。我们不能寄希望于后来者能够像参加高考一样刻苦认真的研究你的项目和架构,更有可能的情况是后来者会用自己的方式在他所能理解的范围内试图“降低复杂度”,结果是整体复杂度就会变得更高。

比如说一个项目原本用fastjson,但是被高度封装过几十层之后,新来的程序员就会以为这部分工作没做,于是引入了gson框架,再过几个月,来个人引入了jackson框架,谁看了都觉得一团糟。不要认为从管理角度出发可以杜绝这个现象,因为即使你把这种复杂度甩到制度上,仍然会有人认为制度的复杂度过高而忽视它,毕竟趋利避害是人共同的天性。

那么我们有什么策略能够使各个模块、类的复杂度保持在一个平衡位置呢?

首先,我们要正确而且正确的评估需求落地实现的复杂度。用UML序列图反复推演各个模块间的通信,所有的模块我们都做“拟人化”思考,很容易就可以判断出它忙不忙、闲不闲、是否混乱、要的数据是否真的拿到了、谁应当做数据准备。此时我们可以发现如果所有模块都很内聚,只有少数的几个模块边缘化,那么就要考虑是否整合成一个新模块或去掉这几个边缘化的模块;如果所有模块都很零散,只有少数的几个模块高度内聚,就要考虑是否将高内聚模块的部分职能放给其他的小模块。当传递的数据不确定的时候,可以考虑用对象做参数;当信息传递的时机不确定的时候,可以考虑用事件驱动和消息总线的方式来解决共同的复杂度。

图2、平衡复杂度的方法对比

其次,当我们无法对项目进行大规模重构的时候,可以从一些细节出发,比如一个代码文件里行数超过了200行,就可以考虑是否再建一个类分担一下。如果我们在面向对象的程序设计里,让一连串的类产生的过多的继承结构,这也就意味着超高的复杂度被封装在了某个基类或抽象类里,除非你确认再也不动它,否则当一个新业务来临时,你不得不平行的再造一连串的类来适应业务,而其恐怖之处在于未来有一天你的接口、策略要写两套,维护成本直接x2。

这也就是为什么架构设计里要融入大量的设计模式。因为既然复杂度我们是无法消灭的,我们就只能从“设计模式”这一个统一规范上达成一种共识,来降低维护成本。实际上世界上的设计模式有数千种之多,我们甚至可以认为一个前所未有的小技巧就可以成为一种新的设计模式,但技巧用多了,便是系统不可被他人理解的根源,从而导致无法维护,所以一个公司范围内固定的用20-30种设计模式便可以基本覆盖所有应用场景,也利于培训和推广。

总结


图3、天平和砝码加在一起的重量是恒定的

复杂度守恒原则揭示了一种“宿命论”:小到类和类之间的关系、中至项目和制度之间的关系、大到行业新老技术交替的关系。我们为了制造一个超高复杂度的系统,只能从更高复杂度的解决方案库或经验丰富的架构师口中寻找答案。我们试图用低代码平台将超高复杂度转移至平台,让产品设计者能快速做出原型产品,但如果平台短期内无法完全覆盖全领域,产品设计者则需要有超高复杂度的行业知识储备才能灵活运用这一平台。因此确认项目复杂度和各模块的复杂度平衡是程序设计过程中需要考虑的重要原则。

高级程序员必会的程序设计原则 —— 复杂度守恒原则相关推荐

  1. 高级程序员必会的程序设计原则 —— 墨菲定律及防呆设计

    前言 如果你或你带领的团队经常会写出一些BUG,日常不是在解决BUG就是在解决BUG的路上,那么你的项目一定是应验了墨菲定律,并且在开发时并没有足够考虑防呆设计.团队越是疲于奔命,错的越是多. 简记 ...

  2. SqlServer注意事项总结,高级程序员必背。

    本篇文章主要介绍SqlServer使用时的注意事项. 想成为一个高级程序员,数据库的使用是必须要会的.而数据库的使用纯熟程度,也侧面反映了一个开发的水平. 下面介绍SqlServer在使用和设计的过程 ...

  3. 程序员必懂的程序设计原则

    来自:source: //bigjun2017.github.io/2018/11/24/ruan-jian-she-ji/ruan-jian-cheng-xu-she-ji-yuan-ze 一.前言 ...

  4. 成为高级程序员必学知识点!

    技术选型 网关:Nginx.Kong.Zuul 缓存:Redis.MemCached.OsCache.EhCache 搜索:ElasticSearch.Solr 熔断:Hystrix.resilien ...

  5. 程序设计考试大纲(高级程序员级)

    一.考试说明 1.考试要求: (1)熟练掌握面向对象编程技术,用C/C++语言熟练编制程序: (2)了解CASL汇编语言的程序编制: (3)掌握软件设计的方法和技术: (4)掌握数据结构.程序语言.操 ...

  6. 程序员必读书单1.0

    原文:http://lucida.me/blog/developer-reading-list/ 本文把程序员所需掌握的关键知识总结为三大类19个关键概念,然后给出了掌握每个关键概念所需的入门书籍,必 ...

  7. 程序员必看的书籍推荐

    程序员必看的书籍推荐: 推荐1:Python 网络数据采集 作者:Ryan Mitchell 译者:陶俊杰,陈小莉 原书4.6星好评,一本书搞定数据采集 涵盖数据抓取.数据挖掘和数据分析 提供详细代码 ...

  8. 【转】程序员必读书单

    作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://lucida.me/blog/developer-reading-list/ 关于 本文把程序员所需掌握 ...

  9. java书籍_Java程序员必看的 13 本 Java 书籍!

    原文:Java程序员必看的 13 本 Java 书籍! 作者: java技术栈 关乎于程序员,除了做项目来提高自身的技术,还有一种提升自己的专业技能就是:多!看!书! 毕竟,书是学习的海洋呢!So,J ...

最新文章

  1. 李茶:虎牙直播推荐系统架构详解
  2. redis详解(四)-- 高可用分布式集群
  3. 大学开设python课程吗_在大学为什么你一定要学会Python?
  4. 前端ajax封装对象数组,后台的取法
  5. 【C语言】while后接分号“ ;”的用法
  6. cfdiv2/c/找规律
  7. vmware给linux增加空间,vmware增加linux硬盘空间
  8. 一个类的java代码_求一段java代码,定义一个类
  9. 偶然的相遇【我与51CTO的故事】
  10. 微软商店无法连接网络的问题解决
  11. Linux中nvme驱动详解
  12. 阿里云官网购买云服务器完整版流程(图文教程)
  13. 超时空智慧办公白皮书(2023)
  14. UE5中置人利用iphone驱动虚拟人面部
  15. python最简单的语言_Python语言的简单实用小工具
  16. ssm基于微信小程序的校园跑腿系统——计算机毕业设计
  17. 什么是CPC认证,现在亚马逊那边都需要提供CPC认证怎么办
  18. 能画数据库E-R图的软件有哪些
  19. 如何将区块链技术运用到实际场景中?
  20. 【Python小竞赛】ARIMA算法预测三日后招商银行收盘价

热门文章

  1. React 路由 Switch 用法
  2. 谷雨了。且惜春光,且迎初夏。
  3. spring事务——try{...}catch{...}中事务不回滚的几种处理方式
  4. 关于c语言的打卡机思路与代码
  5. okcc呼叫中心的收费标准
  6. 飞思卡尔MC9S12XEP100 CAN学习总结(三) 滤波器配置
  7. progressive-generation-master代码记录【下载处理数据】(定义CNNDataset类)
  8. MySQL的DQL语言:4、常见函数
  9. 超声波测距系统的设计实现(基于STM32 )-软件部分
  10. 执法仪app音视频相关