比特衰减也被称为软件腐蚀、代码腐蚀、软件侵蚀、软件衰变或软件熵,是指随时间的推移软件的质量缓慢下降,或其响应性逐渐降低,最终导致软件失效。
长期以来,团队一直在设法构建高质量的软件,使其随着时间的推移仍然能够维持高质量,同时还需要和反映这种困难的“自然规律”抗争,比如上述各种意义上的比特衰减。促成这种对峙局面的因素不止一个:管理复杂软件中各种持续变化组件带来的问题,以及软件开发生态系统的动态本质。
现代软件由成千上万个独立组件组成,每个组件都可以在某些维度上发生变化。这些变化中的每一个都会产生可预测的或不可预测的影响。试图手工治理架构的团队最终不可避免地会被组件的庞大数量和组合副作用所淹没。
即使在相对静态的情况下管理软件的无数交互也已足够困难,然而现实世界连这样的情况都不存在。软件开发生态系统由所有工具、框架、库和最佳实践组成——在任何给定时间点软件开发最新技术的状态叠加。这个生态系统形成一种平衡(很像生物系统),开发人员可以理解并在其中构建事物。然而,这种平衡是动态的——新的事物不断涌现,先是破坏平衡再达到新的平衡。想象一个抱着箱子骑独轮车的人:动态是因为骑独轮车的人需要不断调整重心以保持平衡,其稳定状态就是持续地保持平衡。在软件开发生态系统中,每个创新或新的实践都有可能破坏现状,迫使大家去建立一种新的平衡状态。形象点来说,就如同不停地给骑独轮车的人抛箱子,迫使他重新达到平衡。
从许多方面看,架构师就像那个可怜的骑独轮车的人,必须不断地去平衡以适应环境的变化。持续交付的工程实践代表了平衡状态的一次重大变革:将以前独立的职能(如运维)整合到软件开发生命周期中,让人们对“变化”有了新的理解。企业架构师不能再依赖静态的五年计划,因为在这么长的时间内,整个软件开发生态系统会不断演进,这可能使每一个长期决策失去意义。
即使对见多识广的从业者来说颠覆性的变化也难以预测。像Docker( https://www.docker.com )等工具促成的容器技术的兴起,就是一个无法预见的行业转变的例子。然而,我们可以通过一系列小的渐进步骤来回溯容器技术的兴起。很久以前,操作系统、应用服务器和其他基础设施都是商业产品,需要获得使用许可并支付高昂的费用。那个时代设计的许多架构都着眼于高效利用共享资源。随着时间的推移,Linux对许多企业来说已经足够好了,将操作系统的“货币”成本降为零。随后,诸如Puppet( https://puppet.com )和Chef( https://www.chef.io )这样的DevOps实践,通过自动化的服务器配置使Linux在“运维”上实现了免费。一旦生态系统免费并得到广泛应用,通用可移植格式的出现便水到渠成了,如同Docker的横空出世那样。但是,没有过程中的每一步演进,容器化是不可能发生的。
软件开发生态系统不断演进,带来了新的架构方法。虽然许多开发人员怀疑架构师在闭门造车,在象牙塔里决定下一件大事会是什么,但这个过程实际上比想象重要。生态系统不断产生新的功能,也附带整合现有功能和新功能产生更多新功能的新方式。例如,考虑最近兴起的微服务架构。开源操作系统的流行,加上持续交付驱动的工程实践,使得机智的架构师思考如何构建更加可扩展的系统,他们最终将这样的系统命名为微服务。
设想一名有时间机器的架构师通过时间旅行回到2000年,向运维主管提出了一个新的想法。
“我有一个很棒的新架构概念,可以在每个功能之间实现绝佳的隔离——我叫它微服务。我们可以围绕业务功能设计每一个服务,使它们保持高度解耦。”
“太好了,”运营主管说,“你需要什么?”
“嗯,我需要大约50台新计算机,当然还需要50个新的操作系统许可证,以及另外20台计算机作为隔离数据库及这些数据库的许可证。你觉得我什么时候能拿到这些?”
“请离开我的办公室。”
即使在那个时候微服务听起来似乎也是个不错的想法,但当时的生态系统还不够成熟,不足以支持它。
架构师的一部分工作就是用结构化的设计解决特定问题——针对某一个问题决定用软件来解决它。在考虑结构设计时,可以将它分为两个部分:业务域(或需求)和架构特征,如图1-1所示。
图1-1:整个软件架构范畴包括需求和架构特征(即软件的“特性”)
图1-1所示的需求代表软件解决方案解决的任意业务问题域。其他几项则可以被统称为架构特征(我们倾向的叫法)、非功能性需求、系统质量属性、横切需求等。无论叫法是什么,它们代表的都是项目成功的关键能力,也同样适用于初次发布和长期可维护性。例如,可伸缩性和性能等架构特征可以作为市场的成功标准,而模块性等属性有助于实现可维护性和可演进性。
在本书中,我们使用术语“架构特征”(architecture characteristics)来指代非领域设计考量因素。然而,许多组织和机构使用不同的名字来表示同样的概念,例如非功能性需求、系统质量属性和横切需求等。我们对具体使用哪个术语没有强烈的倾向——在书中遇到这个术语的任何地方,你都可以根据自己的需要进行替换。这些术语所表达的概念没有本质区别。
软件从来都不是静态的,随着团队引入新的功能、集成点和其他常见变更,它会持续演进。架构师需要的不是单元测试那样的防御机制,而是针对架构特征的保护机制。架构特征的变化速率不同,有时还会受到领域解决方案以外的因素的影响。例如,公司内部的技术决策可能会驱动独立于领域解决方案的数据库变更。
本书将描述为软件架构治理提供持续保障的机制和设计技巧,就像高效软件开发团队目前在软件开发过程的其他环节所采用的措施一样。
架构决策中的每个选择都要深思熟虑、斟酌利弊。在本书中,当提到“架构师”这个角色时,我们指的是任何作出架构决策的人,无论其在组织中的职称是什么。并且,重要的架构决策总是需要其他角色的协作。
这个问题常常来自那些已经应用了敏捷工程实践一段时间的团队。要知道,敏捷性的目标是消除无用的浪费,而不是必要的步骤,比如设计。在架构的许多方面,规模决定架构的级别。用建筑物打比方,如果要做的是一个狗窝,那么我们不需要进行详细设计,只给出材料即可,而当我们要建一座50层的写字楼时,设计就是必要的。同样,如果我们需要搭建一个网站来追踪简单的数据库,那么我们不需要用到架构,找一些素材拼凑一下就可以了。然而,对于可扩展和高可用性的网站(比如高流量的演唱会票务网站),则必须慎重考虑许多权衡取舍来做架构设计。
问题不是敏捷项目是否需要架构,对于架构师来说,问题在于他们能负担得起多少不必要的设计,同时建立迭代早期设计以寻求更合适的解决方案的能力。