软件系统持续不断地受到变化力量的作用。其中一些力量直接而明显:修复缺陷、响应客户反馈、添加新能力、开发新版本——这些都是驱动软件产品开发的基本变更力量。
还有一些力量不那么显眼却同样产生影响。你的系统运行在一个或多个平台(软硬件)之上,而这些平台本身也在变化。随着它们演进,它们可能限制或移除你的系统所依赖的能力,迫使你的系统适应;也可能提供新的或扩展的能力,你的系统可以加以利用。如果竞品采用了这些新能力,你这边也可能承受采用压力。
更宏观的软件技术生态也会诱发变化。新的平台、技术与标准不断出现、流行、乏味、过时。这些变化会重塑客户与用户的期望,甚至影响我们自己对“想构建何种系统、想使用何种技术”的判断。软件行业中的**“潮流因素”**远超我们愿意承认的程度。
如果没有变化,我们只需为每个产品设计—交付—转向下一项挑战即可。但几乎没有软件系统真能如此运作。今天的软件开发,与其说是在生产离散产品,不如说是在管理对一个在运行中的系统的持续变更——其中一些变更横跨数百万客户端与数千台服务器。每一次变更都会修改某个组件子集,而这些组件必须同时与其他组件的当前与旧版本兼容,甚至要与它们自身的旧版本兼容。其他变更也在并行发生;变更本身就是系统的稳态。
正因为变化,软件开发需要软件架构。正是这种持续变化迫使我们从“只做一次设计”走向“随时间演进的设计”。如第 1 章所述,系统的架构是一个用于随时间迭代地创建设计的模板。每次迭代都区别于前一次——同时又与其相关且受其约束。换言之,每一种架构都描述了一组与之相容的可能设计。
如上所述,变化已成为软件开发的核心,而理解并管理变化是有效的软件架构实践的标志。本章将探讨并分类变化,并深入驱动与约束变化的要素。这些讨论为全书其余部分关于流程、实践及其他变更管理方面的内容奠定基础。
变更的阶段(Stages of Change)
一个有用的变更模型包含三阶段:
- 动机阶段(Motivational) :我们为何要做这次变更?也许为解决具体问题、满足某种需求、采用新技术等。动机促使我们行动。
- 概念阶段(Conceptual) :我们打算改变什么?在概念阶段,我们选择路径:替换一种技术、优化代码或配置、采用新算法,等等。
- 细化阶段(Detailed) :我们将如何实施这次变更?此时我们敲定细节,尤其包括从旧态过渡到新态的方式。可能只是部署新代码,也可能复杂到把数据迁移到新数据库。
图 3.1 变更的阶段。名义上每次变更从动机出发,进入概念,再进入细化;随着变更推进,我们在向前。
现实当然更混乱。讨论常常从概念开始——直接宣告“要改什么”。但若不理解动机,很难评估概念方案,于是讨论可能**“倒回去”**以取得更充分理解。
在细化阶段也会出现类似情况:更深入的理解会促使我们重新审视概念方案。因此,尽管一次变更最终会经过这三阶段,但不必线性前进。事实上,愿意在获得更深理解时回到前一阶段,是避免因沉没成本谬误而做出糟糕变更的关键。
变更的类型(Types of Change)
从一开始我们就区分了架构与设计:架构是“随时间的基础组织”,而设计描述的是“某一时点的组织”。架构描述随时间的演化;设计捕捉某个时间点。换句话说:架构 = 随时间的设计。
每个设计进一步又描述了一组可能的实现。因此,有些变更可以在不做架构工作(即不引入新设计)的情况下完成——它们可以在当前设计之内实现。
反过来,某项变更可能提出一个不再符合既有架构的新设计。此时就需要演化架构——从而改变可用设计集合。因此,架构、设计与实现的区分虽重要,却常常模糊。
是否需要改变架构以容纳某需求,有时本身就是一个抉择。第 2 章讨论的与架构相关的关键需求(ASR) ,恰是那类必须在架构层面应对的需求;若原架构未容纳它们,就会强制引发架构变更。这是个有用标签,但只有在理解需求影响之后我们才知道如何应用它。
由于这些权衡,我们往往要推进到一定程度才知道某次变更是否需要架构变更。破解这难题的办法,是聚焦管理变更本身,而暂不纠结架构与设计的边界。因此,后文的实践会聚焦变更的范围(scope)而非类型:它们虽为“管理架构变更”而写,也同样适用于“设计变更”。变更越重大,越需要更高严谨度,架构团队越应严格遵循这些实践;对较小的变更(不论属架构还是设计),则可相应下调投入。
面向产品的变更(Product-Driven Change)
产品需求的演进是软件系统两大主要变更来源之一。产品会因不同原因、以不同方式演进:寻求市场匹配的新产品,也许要探索概念层面的变更;而成熟产品团队则更关注小、渐进改进。为响应这些压力,架构师不仅要知道下一条新需求,更要为**能力随时间的轨迹(trajectory)**形成判断。
能力的轨迹是关于我们预期其需求如何随时间演进的断言。见图 3.2,可把轨迹看作在两维上绘制:一轴是预期变更速率(从 0=已完成,到很大=高投入能力);另一轴是不确定性/变更范围(0=演化路径明确,数值越大=越不确定)。
图 3.2 能力的演化与轨迹。 横轴:变更速率;纵轴:变更范围/不确定性。不同象限暗示团队应对产品演进的策略。
当轨迹在两轴都很高,意味着你可预期大量新需求,却尚不清楚它们是什么!你需要与产品团队深入讨论把这些信息梳理出来,因为轨迹向量与架构工作量直接相关。
回想设计(时点)与架构(随时间)的区别:这恰好对应需求与轨迹的区别。系统的当前设计必须满足当前需求;而系统的架构致力于应对并前瞻这些能力的轨迹。如果你不清楚下一步需求,就很难构建支持这些运动的架构。
例如,你在考虑实现“另存为 PDF”能力。产品团队给出的当前需求不包含加密、表单字段等特性,你也确认未来版本不打算加入。也就是说,这个能力的轨迹落在图 3.2 的**“一次性工作”象限(左下)**:这轮做完就不再动。
在这种信息下,你可以采用简单直接的设计。团队目标很明确:尽快完成并转向别处。在此区域为未来功能扩展预铺过多基础会是过度投入,不是资源的最佳用法。
相反,若你得知该能力的轨迹在两轴都很高(右上) ,你就处在相反情境:当前设计只是众多设计中的第一个。挑战在于:既然处于“高不确定性”象限,你知道会有新需求,但还不知道是什么。
这正是架构的要害:你面对的不仅是需要一个设计的能力,更是需要一个能支撑该能力随时间迭代的架构。也就是说,你既要定义实现该能力的组件与关系,也要定义当该能力演化时将支配这些组件与关系的原则。简而言之,这就是软件架构的核心挑战。
技术驱动的变更(Technology-Driven Change)
所有软件系统都嵌入在某个技术版图之中,而该版图的变化构成了另一大类变更来源。实时控制系统也许需要适配更新、更优的传感器;云端系统也许希望利用性能更好或成本更低的新服务。在这一切之下,编程语言、设计与架构风格也在持续演进,因为工程师与架构师对“系统可以、也应当如何构建”的看法在不断演化。
产品驱动与技术驱动的力量有时会同向。例如,机器学习拓展了技术层面的可能性,同时也改变了用户对产品“能做什么”的预期。因此,在许多系统中,采用机器学习既是新需求推动,也是新技术选项推动,两者共同作用的结果。
在另一些时候,这两种力量可能相互牵制。例如,“NoSQL 数据库”的发展是重大的技术变革。然而,除非你的产品本身就是数据库,否则仅仅因技术演进而切换数据库,未必是对产品演进的直接且有用响应。相反,若你的系统已在使用 SQL 数据库,切换成本可能使净收益为负:消耗研发资源,却没有带来新的或更好的功能。
与产品演进类似,架构师必须理解这些技术变化的轨迹(trajectory) 。当技术驱动的变更轨迹与能力/产品的变更轨迹并不对齐时,应当冷静评估。要放下对“新奇技术”的炒作并不容易——毕竟,正是这些“新奇”把很多人吸引进软件行业。但我们也不难列举技术驱动变更导致不良结果的路径:
- 新技术可能失败:名不副实,相较既有技术没有实质改进,甚至更差。
- 新技术可能仅有温和改进:这对新建系统也许合理;但对既有系统,必须把切换成本纳入分析。若收益不够大,多数情况下过不了理性成本—收益评估。
反过来,即便与产品驱动的变更未对齐,某些技术驱动的变更仍值得投入:
- 新技术可能在效率、性能、开发速度或其他关键指标上带来显著提升。
- 使用新技术可能是招募/留住愿意维护该系统的人才的必要条件——尤其当旧技术逐渐失宠、具备相关经验的人越来越少时。
大多数系统依赖多项底层技术。为每一项都识别变更轨迹既不现实也没必要。更可取的是聚焦以下两类:
- 行业内快速演进的技术:为抓住新能力或保持竞争力,你可能希望或必须容纳变更。
- 当前满足度偏低的技术:一旦出现替代方案,你能更好地顺势而为。比如,你在用 SQL 数据库却与数据模型不匹配,你可以将其标记为观察点——当 NoSQL 技术出现时便能把握良机。
并非所有技术变更都可预判,新技术也并不总如预期。拿不准时,回到原则:尽可能保持系统简单。
简单性(Simplicity)
系统越简单,越能从容应对任何变更。因此,架构团队必须始终追求简单。以我的经验来看,系统寿命与其架构、设计与实现的简单程度呈最强正相关。
简单并不等于弱。相反,简单的架构强大:它以最小机制实现最大效果。它们之所以“简单而有力”,是因为内部只有少量强大且通用的抽象。这类系统可以拥有很多组件,但这些组件及其连接关系只落在少数几类模式中。
简单的反面是复杂。复杂可有多种衡量方式,但其根源在于系统包含大量特化的组件与关系。复杂系统难以被系统化描述,因为它们缺乏基本组织:只是拼凑的部件与关系。
当你发现自己总在谈具体组件与具体连线而非模式时,就是正在面对一个复杂系统。简单系统受模式约束,例如“A 类组件通过B 类关系相连”。而在复杂系统中,就算这些模式存在,也会被无穷例外不断侵蚀。
若听之任之,复杂性终将渗透并淹没任何系统。即便一开始拥有简单架构,也会在缺乏自律的情况下走样。例外会出现——出于赶工或无知都一样;没有维护,熵只会增加。不追求简单的系统,实际上已在自己的重量下走向衰亡。
复杂性会拉低质量。当系统只是零件拼盘,很容易把零件以错误方式拼在一起;也很难测试,因为缺少结构阻碍系统化评估。最终,唯有把整个系统在所有变体上都测一遍才能知道是否可用。对任何像样规模的系统,这种成本难以持续。
复杂性也会降低开发速度。变更系统时,我们必须能正确、准确、快速推断其影响。简单系统只有少数模式,因此容易达成;复杂系统里,推断一次变更的影响在极限情况下意味着要对所有现有组件与关系做影响评估。与质量测试的负担一样,多数团队吃不消。结果就是:变更缓慢或停滞,且一旦发生就容易出故障。
复杂性增长的另一个信号,是开始用站不住脚的不变式(tenuous invariants)来为设计变更辩护。比如你要给服务加缓存。你“知道”实体 A 的所有改动(存于另一服务)“目前只由你的客户端发起”,因此你实现直写缓存(write-through) 。但系统的组织并未阻止其他客户端直接更新实体 A,只是当下没人这么做而已。这就是脆弱不变式。迟早,其他客户端会绕过你的缓存读写实体 A,从而冲破这个不变式,弄坏系统。
更糟的是,复杂性会自我滋生。一旦系统的基本组织失效,每个新补丁或新功能都在引入随机的变化。每个改动都得与以往所有改动逐一比对。轻则新增一个孤立组件,重则引入一整套跨平台的新关系。若不加遏制,复杂性一定增长——区别只在快与慢。
有时,复杂性打着“面向未来(future proofing) ”的旗号被引入。其思路是:通过预先为未来变更铺路,降低未来成本。挑战在于:预测很难,尤其是关于未来的预测。若预测错误、变更不来,系统就白白背上额外复杂度;更糟的是,今天的铺垫可能挡住未来真正需要的变更。以我的经验,面对未知的未来,系统最佳姿态始终是追求简单,从而让任何可能的未来工作都更容易。
要达成并维持简单,需要持续投入:
- 需要一个以强约束原则为基础组织的系统;
- 需要把每一次变更都放到这一基本组织下审视。
维护或强化这些基本面的变更,会守住系统的简单;依赖脆弱不变式(当前成立、但并非根本)的变更,应当拒绝。
当然,这并不意味着系统的基本组织不能演化。恰恰相反,它必须演化。某种意义上,坚持“让变更是根本性的,而非脆弱性的” ,正是维护简单的方式。这样的变更让系统持续立于坚实地基之上。
化繁为简并不容易。工程师的天然反应是:遇到新挑战/需求就新建点东西。简单要求我们在整个系统的上下文中寻找解法。
有时,更简单的解法反而工作量更小:也许可以复用一个现有组件/关系,或对其做适度泛化来提供新功能。比如,若最初对实体 A 的缓存是只读且带新鲜度校验,那么新增客户端也不会把它搞坏。看见并评估这种路径可能比“撸一个全新组件”更花时间,但好处是:新行为不增加系统整体复杂度。
另一些时候,追求简单确实需要更多努力。比如,若每次读取都做新鲜度校验太慢,则缓存需要通过事件(实体更新时派发)来保持同步。构建这一通知机制可能投入不小,但一旦完成,它或许成为通用的缓存机制,可供所有实体与客户端复用。作为通用解,它以一种“一次辛苦、处处受益”的方式维护了系统整体的简单性。是否值得,则取决于具体情境、预期的变更轨迹等。
即便尽力,大多数系统仍会随时间增长复杂度。因此,架构团队在“简单性”上还有一项最终职责:推动持续简化。最好的做法往往是识别系统中的潜在模式;一旦识别出来,就构建更通用的能力,把一次性的实现迁移过去并淘汰。完成后,系统新增了一项基本能力,同时去除了若干特例。当然,若你发现某些东西纯属多余、直接删掉更好。
实现并维持简单需要投入。架构团队必须时刻警惕复杂性蔓延,主动寻找简化机会,并愿意为此在短期与长期投入。最终,这些时间与精力都会物有所值。
投资心态(Investment Mindset)
人们总爱二分法,软件项目也常被当作只有两种极端选项:短期、超战术的一把梭,或长期、为一切可能预构的“大而全”。但在工程中应当避免极端;架构团队应努力寻找务实的中间道路——用投资心态来看待每一次变更。
纯战术路径的诱因几乎都与截止日期相关。事实上,“又快又脏”的变更往往唯一的理由就是赶进度。若大家一致同意某设计除了更快之外处处糟糕,那几乎可以断定你正走向战术死胡同。
短期做法的问题在于:唯一短期的只是前期投入。其余部分——测试、修复、维护以及“与之共处”——都将像项目里的其他决策一样长期存在。从某种意义上说,“短期”这个标签本身就不诚实:它们不是短期,而是在短塞项目。
短期做法会制造无数长期问题。这些问题不仅限于架构,甚至主要还不是架构问题。没有人应该为损害产品完整性的改动辩护。所有参与者都应该期望产品能长期成功,哪怕他们不持“长期视角”,至少也要跨越下个死线去看问题。
许多软件开发角色倾向短期,但架构并无此奢侈。架构不仅是系统的组件及其关系,也包含这些组件与关系随时间的演化。忽视演化的架构团队,严格说不在从事架构。
在架构中,没有任何变更可以与其长期影响割裂。理想状态下,变更会改善系统架构。例如,通过移除两个组件间不必要的依赖来简化系统——这无疑是好事。无论该变更是否解决了下个版本的紧急问题,架构团队都应该支持。
在任意结构尚可的系统里,多数变更都发生在既有架构之内:既不会更糟(不会新增无谓的组件/关系导致更复杂),也未必更好(未明显简化),而是在当前边界与行为、遵循当前原则下新增或演进能力。
这类变更同样应当得到架构团队的支持。事实上,凡是位于当前架构边界内的变更,默认应被视为合理;若要提出异议,举证责任在团队。而一旦提出异议,指向的也不应是这次变更本身,而应是当前架构中的某个缺陷,需要更广泛地修复。
真正麻烦的是那些披着“短期”外衣却在侵蚀架构的变更。所谓“对架构的短期改动”是神话:每新增的组件与关系都会一直存在,直到未来某次变更把它们移除。
现实是,这类欠账通常不会被补。项目一旦被短期修修补补驱动,往往就难以回头;甚至会变本加厉:依赖累积→工作更难→进度压力更大→更多“短期”补丁……恶性循环。短期修复的讽刺在于,它们从长期上扼杀项目。
因此,架构团队的职责之一,是点名那些伪“短期”却非短期的变更。一个好办法是把“短期补丁”转写成架构语言:看似只是让组件 A 多调用一下 B,但在此之前,A 从未与 B 通信。
其影响何在?经验法则:每一个新关系都会增加测试成本(引入新状态组合),会因耦合上升而增加维护成本、降低开发速度,并且降低可信赖性:此前 A 可独立运行,现在不行了。B 的可靠性是否足以不降低 A 的既有可靠性保证?也许可以,但至少必须提出问题并评估。
用这些问题把讨论重心转向“选项与权衡”而非“人” 。避免把争论描述为“架构 vs. 工程”“架构 vs. 产品”或“架构 vs. 任何角色”。一旦把选项绑定到人/角色,决策者就被逼在应当合作的同事间选输赢。更好的做法是假定所有人都想为产品做正确的事,并就选项本身展开辩论。
当你列出了选项,就请团队以投资心态看待每个提议:每次变更都是一笔投资。我们要讨论的是好投资还是坏投资。好投资带来超额回报;坏投资则会在时间里吞噬成本。
回报可沿多个维度度量:性能、运维成本、可信赖性、质量等。架构的任务是把变更放回上下文,并据此评估预期回报。记住:每个变更都会留在系统里,直到另一个变更把它移除。
权力与问责(Authority versus Accountability)
本应就“方案优劣”展开的争论,太容易滑向“谁说了算” 。我职业早期清楚记得两次糟糕场景:架构师挫败地摊手:“我不懂你们为什么不听我的——我是架构师!”其中一位甚至拂袖离场。这都是反面教材。
他们把权力(authority)与问责(accountability)混为一谈。他们坚信自己掌握“正确做法”,不愿浪费时间讨论选项;在他们看来,架构师身份赋予了拍板权,并准备动用它。显然,合作伙伴们不这么看。
正确的做法是聚焦问责。架构师在软件开发中确有独特角色:因为他们要治理系统的长期演化,所以更适合评估并理解任何提议在短期与长期的影响。对某些变更而言,架构师也许是唯一能看清技术全貌的人。
若这些人承担起问责,他们会以不同方式参与争论:不是宣示权威,而是贡献洞见;聚焦更优结果而非“赢”,也就更愿意接纳他人问题与见解,帮助团队共同收敛到更好的答案。
软件开发是团队运动。每个人都应对成功为自己的那一份负责。如果你因“以为架构师拥有权力”而渴望这个头衔,最终你多半会失望。
增量交付(Incremental Delivery)
若每个提议的变更都演变成“五年重构”,要保持投资心态就很难。大的变更有时必要,但在健康系统里应当少而又少。多数变更应当更聚焦、务实、执行更快——以增量方式交付是最佳途径。
任何大变更都需要带来超额回报才算好投资。麻烦在于,变更越大,我们越倾向低估成本、夸大收益,导致评估失真。
如果你做过大型软件,多半经历过这样的对话:从一个小改动起步,随着设计推进,雪球效应让投资迅速变大。“这块本来就一团糟,不如趁机重做吧。”
随后范围继续外溢:你本来只重做 A 组件,它又与 B 相连——正好把 B 的接口也改了吧?自然这又波及 B,再到 C/D……要不一并搞了?
作为思想实验,我喜欢这类练习:一方面,它强调维护系统描述(文档/模型)准确、及时的价值——你若事先知道改 B 会影响 C/D,显然比半途发现“拼不回去”强得多(这就是文档投资的回报,后文详述)。另一方面,它们也催生新想法:有的好、该采纳;有的糟、该舍弃。产出选项并择优总比束手无策强(第 4 章还会谈“开发选项”的价值)。
此时,一些项目管理团队会一头扎进:范围在扩、边界未明,但新东西刺激、这些变更看起来必要,再加上一点一厢情愿,仿佛一切都会顺利……而事实是:什么也没交付。这种尝试鲜有善终,是不成熟团队的典型特征。
另一些团队会在意识到范围后急刹车。最糟糕的版本,是退回到**“短期”补丁上:绕开当前问题,但以产品净损为代价。这同样是坏投资**:既没有推动大变更前进,反而增加了阻力。
要避免在两极之间来回跷跷板,项目团队需要学会平衡当下与长期愿景。如同个人目标设定,要区分“长远所求”与“当下可行的下一步”。你想当《财富》500 强 CEO,但毕业就去投 CEO 职位并不现实。
为此,架构团队应把思考组织为三类:
- 长期愿景:不必、也不宜写得过细。应当阐明期望的基本组织及其理由,并与现状区分开来。(详见第 4 章)
- 通往目标状态的潜在变更清单(backlog) :之所以称“潜在”,是因为未必会做。它用来承载在设想目标状态时迸发的点子,而不等于承诺具体计划。(详见第 7 章)
- 当前工作:正在做的变更。它们应推动项目靠近愿景;若不是,十有八九是坏投资。但“当前工作”并不等于愿景所需全部工作——本来也不可能一次做完。
有时,“当前工作”会膨胀——典型的“既然来了,不如顺便重构一下”。此时,借助愿景来引导讨论,把结果分拣:放入backlog(以后再议)或保留在当前工作(较小且当下应做的子集)。
这看似麻烦,要做些“账目分类”。但以我的经验,这其实是解压:不必把所有变更都塞进当下,因为任何变更都可以先入 backlog等待评估;同时也避免了因忙于当下而丢掉长期视野,因为两者是分账管理的。
许多项目都立志随时间完成大变更。实现它的最佳方式,是在一致愿景的指引下,持续交付一串稳健的增量变更。
架构的演化(Architectural Evolution)
有时,产品会被定位为进行激进式变革。这类变革通常发生在技术与市场同时驱动之下——也就是说,它们既是产品驱动的,也是技术驱动的变更。比如,iPhone 与移动计算的出现,不仅催生了全新的产品,也推动许多现有产品改造升级,以便在新设备上运行并加以利用。
这等级别的变化,通常需要对产品架构做出相应规模的重大调整。以移动计算为例,它并非仅仅促使既有产品整体迁移到新设备上;许多产品被重新构想为同时运行在桌面与移动设备上,由此在平台、数据、连接性等方面引入了全新的挑战。
正如刚讨论的,架构团队应当以增量方式朝长期愿景迈进,并对“重构整个架构”之类的行动保持警惕。那当架构愿景本身发生改变时怎么办?
首先,要明确:这应是罕见情形。若一个系统的架构愿景每六个月就变一次,那多半哪里出了问题。目标经常移动的结果是:即便每一步都对准目标,整体仍会成一场随机游走——无论过程管理多好,最终产出都将是混乱且缺乏组织的系统。
同样,架构团队要警惕仅由技术演进驱动、却缺乏相应市场影响的变化。移动计算的兴起不仅是技术现象,它直接影响用户并创造了新市场。对移动计算作出架构响应是必需的,并且最终为客户带来了新价值。
相比之下,一些技术演进对客户与市场的影响要有限得多。微服务、NoSQL、区块链等技术也许新颖好玩,但对许多产品而言,它们未必能转化为新的客户价值。如果一种新技术不能为客户带来新价值,就很难证明花大力气演化架构去适配它是合理的。
当一项技术相关但来得太晚时,抉择更棘手。比如,NoSQL 也许非常契合你的系统——如果当初建架构时它已成熟,你可能就会选它。但当你的系统已经基于 SQL 数据库且运行良好时,为什么还要更换?
记住:切换成本可能巨大。当你在生产中使用一种技术、而另一个还停留在方案里时,团队往往已在现有技术上投入了数百人年:理解其理论与真实世界行为,熟悉其 API、调试、部署与运维。
你在评估的“最新最棒”的替代方案也许更好;但切换意味着要在新技术上对上述每件事重新投入。这不仅必然丢弃既有投资,还存在新技术不达预期的风险。故而切换门槛必须设得足够高,把这些因素统统算清。
尽管如此,对任何长寿系统而言,架构迟早需要演化。这恰是系统成功的迹象——已超越初始使命,被要求承担更多。我们应认识到:每种架构都有边界;当触及边界,就需要有能力调整并演化它,让系统延续生命。
因此,我们的目标并非避免演化,而是避免过于频繁地演化。为此,每当重访架构时,都必须投入足够的时间与注意力。更大的单次投资应当延长下一次升级到来的时间;充分的投资能形成正反馈,让目标更久保持稳定。
好消息是:架构的变更不必过于艰难,在某种程度上甚至可以预作准备。事实上,为演化做准备的最强手段就是一开始就拥有良好的架构。你的系统越有组织、越清晰,你就越能更有把握地提出、评估并实施变更。相反,若当前架构复杂、认知不清或文档不全,就需要先补课;这些努力在架构演化时都会回本。
有些团队会定期进行架构评审,这对管理变更也很有帮助。首先,它提示我们停下来看:系统的架构是否仍服务得当?也许答案是是,那就暂不变更,等下个周期再议;更好的是,它能在危机前暴露出需要变更的信号。
定期评审也可作为日常工作的减压阀:有了评审节奏,更容易坚守当前选择、避免不必要的干扰。新点子当然欢迎——“也许我们真的该上区块链?”——但这类讨论可以延后到评审周期。评审周期本身将成为收集新想法、调研与原型的催化器。
大型组织往往有年度节奏来推动规划与预算。若你运行定期的架构评审流程,请让其与组织流程对齐:若架构需要资源推动重大变更,应在规划启动时就心中有数;反之,若架构还能稳过一年,也可帮组织把资源投向更紧迫的地方。
总结(Summary)
软件系统处于持续变更之中;这些变更可能由产品驱动、由技术驱动,或二者兼而有之。通过刻画变更轨迹,我们能更好地理解其当下与未来影响。作为架构师,如何容纳、应对并利用变更,与如何设计系统本身同样重要。
简单性是为变更做准备的最根本方法,因此它必须成为架构工作的重点。在其他条件相同的情况下,更简单的架构更易于应用、维护与演化。
保持简单并不容易。为守住简单,请以投资心态来做设计:每次变更都是对平台的投资,问题只是好投资还是坏投资。努力做好投资,在战术与战略变更之间取得平衡。
最后别忘了:架构所处的上下文本身也在演变。市场在变,愿景在变,技术在变。你既要起步于,也要持续保持对上下文的清醒认知。一方面,不应让架构随潮流起舞——那只会制造大量工作而收效甚微;另一方面,从不改变的架构也难以跟上不断发展的需求。成熟的架构实践承认架构演化的必要性,并把它纳入流程、深思熟虑地执行。