软件架构(software architecture)之于软件的重要性,如同打地基和筑框架结构对于房屋建造的重要性。当地基不稳、建筑框架不合理时,所带来的隐患、不便和更高的成本在后续的装修和维护阶段都将面临。正因如此,建筑设计成为了一个学科专业,以科学、规范、体系化的方式去应对。与之不同的是,软件行业似乎并没有软件(架构)设计这一学科专业,但从很多软件开发工程师想成为软架构师可见其重要性和份量。这篇文章就来聊一聊软件架构,探讨我所理解的度量软件架构质量的核心指标。
维基百科(Wikipedia)对软件架构的定义是:
Software architecture refers to the fundamental structures of a software system and the discipline of creating such structures and systems. Each structure comprises software elements, relations among them, and properties of both elements and relations. The architecture of a software system is a metaphor, analogous to the architecture of a building. It functions as a blueprint for the system and the developing project, laying out the tasks necessary to be executed by the design teams.
此外,电气和电子工程师协会(IEEE)也对软件架构这一概念进行了定义,表述为:
The fundamental organization of a system embodied in its components, their relationships to each other and to the environment, and the principles guiding its design and evolution.
为了方便读者抓住这两个定义的重点,我用红色对其中的关键词进行了标识。
不过,对于软件架构我有自己的理解,原点可浓缩为软件架构元模型。用UML表达出来如下图所示。
这个模型只存在“简单”的三个元素:
概念是软件架构的核心。Brooks在《人月神话》中指出,软件开发的主要任务是构建复杂软件的概念,次要任务是在满足时间冗余度和空间冗余度的情况下用编程语言表达出来。前者我称之为“软件设计”,后者则称之为“编程”,两者合起来就是“软件开发”。软件设计的背后,隐含了个体的设计思想,设计思想进一步由设计原则构成,而原则又由设计模式组成。以思想、原则和模式逐次细化的方式去指导软件设计工作,才能最大程度地确保设计的一致性、连贯性和可复用性。
概念和概念之间的关系。当概念确定后,概念间的关系也随之确立。当然,概念间的关系我们希望是清晰的、干净的,以便做到“松耦合”。从软件实现的层面来看,关系通常用接口来表达,可以是函数、类或网络通讯等形式。
分别或共同作用于概念和关系上的约束。约束提出了对概念和(或)关系应当满足的要求,可以是性能、内存容量、实时性、可靠性等包罗万象的(非功能性)内容。
基于软件架构元模型可以衍生出逻辑架构、物理架构、数据架构、运行架构和开发架构,这些架构是根据不同的场景和关注点对元模型的具象化。比如,逻辑架构中的核心概念是“系统“、“子系统”、“平台”、“框架”和“模块”,而关系则有“层”、“协议”和“接口”。再比如,开发架构中的核心概念是“库”、“SDK”、“程序包”,关系则有“CI/CD”,而约束可以包含“配置管理”、“可维护”、“可扩展”、“可测试”等。
不难看出,软件架构是非常复杂的话题。这也一定程度可以解释,为何成为真正的软件架构师并不容易,以及有那么多软件工程师将成为架构师当作是自己职业发展的阶段性奋斗目标。那么,面对如此复杂的内容,又如何定义度量其质量的核心指标呢?或者我们可以问,应对类似Chromium、Fuchsia这样的超大规模软件的架构问题,其成功的核心关键是什么?
软件架构的元模型表明,高质量的软件架构一定是建立于所塑造的概念能有效率和效果地解决现实(业务)问题。看似简单的一句话,却时常让人感到困扰,而困扰源于个体能力和我们认识和解决问题背后的自然规律。
能力层面,个体的概念能力与软件架构能力正相关。概念能力是指个体面对问题时能否抓住主要矛盾,从主要矛盾入手塑造概念去解决问题。个体的概念能力水平,可以从其所掌握和使用概念的精确度看出(比如,类似于区分重构与重写的区别),越是精确则概念能力越强。概念能力差的人,不只是软件架构能力弱,编程水平也不会好到哪去。概念能力是需要时间才能提高的,背后不只是行业经验的积累,更需要个体乐于主动思考才行。
解决同样的问题,采用不同的概念切分所设计的架构解决问题的效率与效果极可能全然不同。糟糕的概念切分,会让解决问题的路径荆棘丛生、意外连连,概念间的逻辑转换拗口且低效。
自然规律角度,通过软件解决现实问题是一个逐渐深入和范围不断扩大的过程,且深入与扩大的程度永无止境。换句话说,请不要幻想一开始就设计出一个完美的软件架构。这个规律也告诉我们,不要一上来就过度考虑灵活性设计,在很多情形下那就是冠冕堂皇的浪费。
作者在判定是否当下采纳灵活性设计时通常会问自己两个问题。问题一,这个灵活性是需求中明确指出的吗?如果是,则考虑,否则问第二个问题再决定。问题二,这个灵活性设计如果当下采纳和未来采纳所付出的成本是否相当。如果相当则眼下完全不用考虑灵活性设计,否则应当考虑。
以上两方面告诉我们,好的软件架构是演进出来的,而不是一躇而就设计出来的。那些看似非常有经验和能力的架构师,是因为他们之前在别的地方反复经历了很多次的演进而比普通人有更强的概念能力。然而,经验是会不断过时的,业务也是不断发展的,这两大因素决定了不会有一劳永逸的高质量软件架构。
如果高质量软件架构是演进而来的,那么背后所隐含的意思是(随时)可变才是高质量软件架构的唯一核心指标。接下来的问题在于,如何才能“可变”?
就我参与Chromium项目的二次开发经验来看,这个恐龙级项目之所以能很好地应对架构演进问题,是因为随时确保整个项目具有重构的能力。当发现哪一个模块的设计不合理时,可以通过重构去做调整与完善。第一次看到先后发布的两个版本的代码变化之大时,我确实吃了一惊,也在那时才突然意识到,好的软件架构并非代码长时间一成不变,而是可以随时变。我们并不担心软件的不完美,但担心软件演进时因为泥泞而缓慢。
现实中,很多深陷焦油坑的软件并非当事人不知道问题所在和如何根治,而是苦于无力改变。为了彻底解决问题所引入的代码变更对于这些项目来说在人力和时间投入度上根本“不可接受”,只能迫于无奈地持续“贴狗皮膏药”。
重构与重写的区别在于,前者是基于单元测试去做代码变更保障的,确保改变接口内部的实现时不会出现功能衰退。不难猜到,Chomium项目是一个严重依赖单元测试做质量保证的项目,这是很多全球知名大型软件项目都具有的一个特点。然而,重视并落实单元测试的工程实践在国内并不普遍,鲜有人或公司将单元测试代码当作生产代码那样去重视与维护。
理论上,软件平台的优点在于:
提升软件开发质量与效率。通过抽象与复用避免同类产品的重复开发;将知识和经验沉淀于代码,避免同类产品重复犯同样的错误。
输出设计思想、规范和引导基于之上做定制开发的软件工程师的编程行为。
培养具有软件平台设计能力的工程师。软件平台通常需要通过抽象、解耦处理好通用性和针对性问题,这需要软件设计者具有更好的概念能力,借助软件平台的打造将有助于培养出具备这种能力的人。
在作者看来,互联网行业所鼓吹的软件中台本质就是软件平台,所谓两者概念的区别只是为了造概念的需要而硬加上的。
十多年前,当我还在通信行业工作时,曾经历了软件平台成为了其上产品开发的瓶颈这样的尴尬,与打造平台是为了提升开发效率的初衷背道而驰。背后的根源就在于,软件平台从工程角度没有解决好架构“可变”的问题,使得软件平台在发展的过程中不能很好地适应上层产品业务发展的需要及时做出改变,最终因为适应能力衰退而影响了上层产品的开发与演进。
基于作者在通信行业的经历,建议时下互联网行业正践行软件中台的公司需要特别重视解决软件平台的架构“可变”问题。否则多年以后,你还得面临分拆或抛弃软件平台的劳命伤财之事。
软件平台唯有处理好架构“可变”问题,才能在出现适应能力衰退时,通过重构而进入新一轮的、更高层次的生命周期。
软件架构设计是软件开发领域永恒的热门话题,喧嚣的背后,我们不能只停留于形式上的架构经验分享与学习,更要重视工程能力的建设让软件架构做到随时可变(本文所讲到的重构只是其中的一个组成部分)。唯有具备随时可变能力的软件架构,我们才能实践从他人那学习到的经验,否则只能纸上谈兵。
中国软件,从繁荣走向文明