架构设计的目的在于管理复杂度,以达到:
- 合理化依赖关系,依赖指向更稳定的方向
- 隔离变化,最小化每次变更的影响范围等等
最终达到用最小的人力成本,来满足构建和维护该系统的需求
复杂度来源
管理复杂度的同时,我们也应该认识复杂度,我们平时谈论的复杂度都来自哪里?关于复杂度的讨论,在《Unix 编程艺术》里有非常精辟的阐述,我们谈论的复杂度来源主要有:
- 本质复杂度:实现一个产品基础功能必然要引入的复杂度
- 选择复杂度:补充功能的取舍所引入的复杂度
- 偶然复杂度:功能实现不够简洁,功能划分不够正交所引入的复杂度
编辑器的例子
以编辑器为例,要实现一个编辑器,至少要支持单个或多个文件的内部缓冲区拷贝,否则无法称之为一个编辑器,这种复杂度属于本质复杂度,当然实现不善的话仍会引入偶然复杂度。
vi 编辑器选择加入命令模式,以支持方向移动:一旦 hjkl
键在编辑缓冲区中的意义依赖于模式,就容易陷入以专用方式增加新命令的习惯,模式的引入不是必然,是一个取舍的问题,增加模式而引入的复杂度属于选择复杂度,此外,无限撤销功能也会引入选择复杂度。
vi 编辑器支持上百条命令,而许多都是重复的。据推测,多数用户知道的命令集不超过 5%,多种命令的支持也会引入复杂度,而命令分解不够正交导致的复杂度属于偶然复杂度。
了解了复杂度的来源分类后,我们分析一个日常项目——多媒体点播服务,这里不展开分析底层设计,而是以基于云服务的云原生服务为例。
点播系统中的复杂度
在点播系统中,哪些属于本质复杂度呢?要搞清楚这个问题,我们要首先了解点播系统要解决的最根本问题是什么。
一个典型的点播文件生产消费过程:
一个点播系统要解决的最本质问题是:多媒体资源的存储、转码和分发问题,因为是点播系统而不是普通的文件存储,所以媒体资源的存储不仅要解决文件的物理存储,还要支持点播文件的内容解析,识别码率、分辨率、声道等基础信息,这样才算是将资源管理了起来
所以点播系统的本质复杂度包括:音视频文件的存储和解析、音视频媒体的转码、音视频文件的分发。
在此基础上,我们还想解决可用性问题,引入多副本机制、转码监控、融合 CDN 技术,这些技术带来了选择复杂度。
因此,偶然复杂度常常源于接口设计并非正交;本质复杂度通常无法去除,除非调整软件的基本功能需求;选择复杂度很难归纳出可能的复杂来源,他们往往依赖于值得为何种功能付出复杂度代价的精微判断。
总结
处理各种复杂度,必然更仰赖于见识而非方法。通过发现更简单的方法,可以去除偶然复杂度。依赖上下文环境判断哪些功能值得去做,可以去除选择复杂度。而要去除本质复杂度,就只能通过对现实真滴的洞察和顿悟,从根本上重新定义所需要的解决的问题。