解决 XY 问题:重新构建问题以解决真正的问题。
译自 Devs Need System Design Tools, Not Diagramming Tools,作者 Thomas Johnson。
当工程团队选择工具来管理他们的软件系统时,特别是用于设计和可视化,他们经常遇到XY问题。
XY问题是指当有人试图用解决方案Y来解决问题X时,却遇到了挑战。他们没有寻求解决问题X的帮助,而是请求对解决方案Y的支持,掩盖了根本原因,导致沟通不畅和次优解决方案。
以下是从XY问题网站中摘取的一个具体例子:
代码语言:javascript复制<bob> 如何回显文件名中的最后三个字符?
<feline> 如果它们在变量中:echo ${foo: -3}
<feline> 为什么是3个字符?你真正想要的是什么?
<feline> 你想要扩展名吗?
<bob> 是的。
<feline> 不能保证每个文件名都有一个三个字母的扩展名,
<feline> 所以盲目地获取三个字符并不能解决问题。
<feline> echo ${foo##*.}
在他们的系统架构或可视化其组件时,他们经常会问:
- 我们应该使用哪个绘图工具来映射我们的系统架构?
- 我们如何共享和存储架构决策记录?
- 我们在哪里可以列出系统中的所有API?
这些问题虽然有效,但关注的是Y——提出的解决方案——而不是X——团队想要解决的实际痛点。为了找出根本原因,这些问题应该重新表述如下:
- 我们需要按计划交付功能性软件,因此我们需要一种简单的方法来可视化和访问有关我们系统架构的最新信息。
- 我们需要毫不费力地达成系统设计共识,并拥有决策记录的单一来源。
- 我们需要了解系统行为,并在发生故障更改之前将其捕获。
不幸的是,许多团队没有意识到他们正在关注Y而不是X。这导致他们采用一种支离破碎的系统设计方法,为单个任务实施各种解决方案。他们可能会使用一个工具进行草图绘制,另一个工具用于系统架构,另一个工具用于序列图。系统需求和设计决策散布在Google Docs、Jira、Linear、Slack、电子邮件、Confluence等中。API可能列在电子表格或专门的工具中。
这种方法导致在维护这些资源、搜索相关信息和不必要的上下文切换方面花费了大量时间和精力。
系统设计与系统架构图
系统设计通常被错误地等同于仅仅绘制软件架构图。另一个误解是将其仅仅与BDUF(前期大设计)、UML(统一建模语言)、TOGAF等特定架构框架或各种文档类型(如HLD(高级设计)、SAD(软件架构文档)、KDD(关键设计决策)、ARD(架构需求文档)、LLD(低级设计)和ADR(架构决策记录))相一致。
系统设计超越了任何特定的工具或文档;它是一个持续的过程,概述了复杂系统(系统架构)的高级概念结构,并定义了其重要组件和交互。它涵盖了系统的各个方面(即软件、硬件、数据、接口和用户交互),以确保它们协同工作,有效且高效地满足应用程序的要求。
此过程的输出可能包括:
- 系统需求文档(即详细说明功能和非功能需求。)
- 系统架构文档(即描述所选架构的目标、约束和基本原理。)
- 系统架构图(即提供组件、服务、它们的交互和关系的视觉表示。)
但是,系统设计应该侧重于前期和持续的系统设计评审,这些评审不断记录和重新审视系统需求、决策、权衡和折衷方案。它是软件开发中必不可少的一步,用于评估系统的技术可行性、功能和性能,并识别依赖关系和风险,以便做出明智的决策。
将系统设计仅仅降级为制作图表或文档,可能会忽略关键信息,并在工程团队中培养低效的实践。这最终会导致积累架构技术债务,并给团队带来手动任务和无效资源的负担。
如今,图表已不足够
开发人员经常使用图表来解决一个基本沟通挑战:清晰有效地向分布式团队传达分布式软件系统的复杂性,包括其组件、依赖关系和 API。
软件开发本质上是协作性的,需要对系统构建、约束和未来演进的共同理解。这种一致性对于消除歧义和实现团队的协同进展至关重要。
视觉插图是实现这种一致性的强大工具,因为它们有助于绕过书面和口头沟通中固有的潜在误解和延迟,确保团队成员的思维模型保持一致。然而,绘图工具存在重大局限性。有效的图表旨在向特定受众讲述特定故事,提供软件系统的静态快照,以解决特定利益相关者的关注(例如,后端团队、前端团队、QA、PM、DevOps、高管)。
过去,当软件系统更小、更简单时,一个图表可以(可能)捕获所有必要的信息。如今,随着 SaaS、API、可组合平台和遗留系统的激增,软件系统的复杂性呈指数级增长。
“当今的软件技术栈更像热带雨林——动物和植物共存、竞争、生存、死亡、生长、以非计划的方式相互作用——而不是像一个规划好的花园。” — Jean Yang
我们都见过试图将这些现代软件系统的整个架构塞进一张图中的图表。具有讽刺意味的是,这些系统最需要有效地传达其复杂性。
微服务“死亡之星”在《微服务指南》中讨论。
随着系统规模的扩大和团队需求的演变,传统绘图工具的局限性变得更加明显:
- 缺乏实时更新: 图表提供静态表示,无法自动反映现代系统的动态特性。
- 笨拙的用户界面: 更新图表可能很麻烦,需要花费大量时间格式化和排列组件。
- 版本控制问题: 在团队之间维护更新的版本具有挑战性。
- 有限的协作功能: 实时协作和反馈通常需要更好的支持。
- 没有单一的事实来源: 图表很少包含有关需求、权衡、设计决策等的信息。设计文档通常用于此目的。
- 无法管理云资源: 图表无法控制或生成基础设施代码(例如,CloudFormation、Terraform)。
这些局限性表明,绘图工具并非为处理现代软件系统及其架构演变的复杂性而设计的。
当今的工程团队需要能够拥抱复杂性并支持动态系统设计的工具,超越传统绘图工具的功能。虽然开发人员可以借助所有可用的新技术构建更大的系统,但他们现在面临着管理和协调这些快速变化、不断演变、拼凑而成的系统的难题。在大多数这些现实世界中混乱的技术栈中,开发人员必须将新代码与遗留代码集成,同时不断评估何时以及如何对现有组件进行现代化改造。
缺乏对软件系统的可见性和理解会导致团队瓶颈,减缓开发速度,并导致系统脆弱且缺乏灵活性。管理这种复杂性的典型反应是寻求更高层次的抽象。然而,简化事物并非总是最佳解决方案。
有些问题无法自动化,开发人员必须收集适当的信息,以提供针对性的输入,说明如何解决这些问题。例如,考虑调试:软件系统的高级静态抽象无法为工程师提供有效解决问题的详细理解。此外,问题可能需要不同的抽象,这意味着没有一个抽象可以满足所有需求。
这类似于了解你的汽车是如何工作的:你不需要了解每一个细节,但你应该能够检查引擎盖下以诊断问题,尤其是在不需要每次都将汽车送回经销商的情况下。因此,我们需要拥抱复杂性的工具,将抽象与深入技术栈的能力相结合。这些工具应该提供有关任何组件、结构或关系的最新信息,并促进协作解决问题。
与通用图表和白板工具不同,我们需要能够区分组织结构图中元素关系和平台架构中元素关系的工具。增强的系统可观察性和理解工具至关重要,它们使开发人员能够有效地探索、发现和管理复杂性。
最后的想法
许多工程团队坚持使用图表工具,原因是多种因素的综合作用,包括沉没成本谬误(“我们已经投入了 30 个小时来创建和更新此图表,所以我们不妨继续,不要浪费时间”)、抵制变化(“切换工具需要时间和培训,我们现在有其他优先事项”)以及问题定义不明确(“我们需要更新图表” 与 “我们需要对系统有实时了解”)。
沉没成本谬误是指人们倾向于继续一项努力或行动,即使放弃它会更有益。
随着现代软件系统复杂性的不断增长,越来越多的团队将遇到传统图表工具的局限性。这些工具曾经是说明想法和设计的必备工具,但它们仍然需要改进才能捕捉到系统的全部复杂性,阻碍开发人员全面理解、设计、开发和管理系统。
图表工具必须不断发展,以支持系统设计过程中所需的全面活动,并使团队能够轻松地回答有关其软件架构的更深入问题。
如今,我们拥有技术和知识来创建工具,防止开发人员浪费宝贵的开发时间来解读静态的、过时的图表,手动更新文档或从分散的来源收集信息。相反,我们可以使团队能够专注于有意义的讨论,推动解决复杂问题并为系统的演变做出明智的设计决策。