【软件架构】跨越界线
你看到系统多少的真相,决定了你用怎样的影像去表现它,并进而推进与实现这种影像,亦即是架构。
更新历史
- 2022.07.24:完成初稿
读后感
这本书虽然比较老了,但是很多内容放到今天都不过时,这可能就是看老书的好处,时间已经天然做了一次次的考验。只要按照规范写一下软件指南,基本上就能避免 90% 的坑了。
读书笔记
架构思考
架构师需要超越自己与别人的所见,因为你观察与架构的对象称为“系统”,你看到系统多少的真相,决定了你用怎样的影像去表现它,并进而推进与实现这种影像,亦即是架构。我们既已知道的、理解的、明白的,形成了我们的知识与行为的一切,却也正是阻碍着我们前进的东西。
这些障碍正是你以为你最珍视的、最不可放弃的、最鲜血淅沥体验过的那些经验与成就。在这些所得与所碍中挣扎与决策,就是架构师的全部职责。因此作为架构师,你需要能够超越自已对系统的既有认识,看到你在光明中——显而易见之处——所未见的,这是你驱动系统架构进化的主要动力。
所以架构中最难超越的并不是某个大师或前辈,而是你以及你为自己所作的设定。当你设定了“架构师”这个目标,便设定了这个目标所表达的某种影像(角色),你最终可能变得跟这个影像完全一致——成为所谓的“真正的架构师”,但你仍不过是困囿于对这个“角色”的一个假设/设定而已。唯一破局的方法是:超越别人对某个角色的定义,将自己做成这个角色。
软件架构在一个成功的软件交付中扮演关键角色,然而令人沮丧的是,很多团队都忽视了这一点。即使在最敏捷的团队中,软件构架这一角色也都是必需的,不管是由一个人还是整个团队共同扮演,但要寻求到预先和演化两种构架理念的平衡,往往还只是人们美好的意愿而并没有变为现实。
换句话说,从代码结构和基础到将代码成功部署到生产环境,与一个软件系统重要元素相关的所有东西就是软件架构。从开发者的角度考虑软件开发,关注点多数会放在代码上。在这里,我们考虑的是有助于构架更好软件的东西,比如面向对象的原则、类、接口、控制反转、重构、自动化单元测试、代码整洁和其他不胜枚举的技术实践。如果你团队里的人都只考虑这些,那么谁来考虑其他事情?
- 横切关注点,比如登录和异常处理;
- 安全性,包括认证、授权和敏感数据保密;
- 性能、可伸缩性、可用性和其他质量属性;
- 审计及其他监管需求;
- 客观环境的约束;
- 互操作性、与其他软件系统的集成;
- 运营、支持和维护的需求;
- 结构和整个代码库解决问题、实现特性的方法的一致性;
- 评估正在构建的基础有助于交付按计划进行。
思考软件架构能带来哪些好处?总结如下:
- 让团队跟随一个清晰的愿景和路线图,无论这个愿景是一人所有还是整个团队共有;
- 技术领导力和更好的协调;
- 与人交流的刺激因素,以便回答与重要决策、非功能需求、限制和其他横切关注点相关的问题;
- 识别和减轻风险的框架;
- 方法和标准的一致性,随之而来的结构良好的代码库;
- 正在构建的产品的坚实基础;
- 对不同的听众,以不同层次的抽象来交流解决方案的结构。
人们承担的软件架构角色可能千差万别。比如下面这些。
- 架构驱动力 :捕捉和挑战一套复杂的非功能需求,还是简单地假设它们的存在。
- 设计软件 :从零开始设计一个软件系统,还是扩展已有的。
- 技术风险 :证明你的架构能够工作,还是盲目乐观。
- 架构演化 :持续参与和演化你的架构,还是把它交给“实现团队”。
- 编写代码 :参与交付的实践部分,还是袖手旁观。
- 质量保证 :保证质量并选择标准,还是反其道而行之或无所作为。
其中大部分可以归结为是承担寻找方案的责任还是推诿问题。
跨越界线是我们的责任:给一个软件系统的架构出力和为之负责之间,有一个很大的差异,那就是构成软件架构角色所需的,跨越不同领域融会贯通的技能、知识和经验。能否跨越软件开发者和架构师的界线,取决于我们自己。作为个人,我们要清楚自己的经验水平,以及为了提升它我们需要关注什么。
知识能力
为什么技术知识面宽对软件构架师来说也很重要。当然,他们可能是Java或者Oracle专家,但软件构架角色的要求更高。例如,他们要能够回答以下类型的问题。
- 和其他可选技术相比,我们所选的是否最合适?
- 对该系统的设计和构建,还有哪些选择?
- 是否应该采用一种通用的架构模式?
- 我们是否明白所做决策的利弊?
- 我们照顾到了品质属性 的需求吗?
- 如何证明这种架构行之有效 ?
本书主要讨论软件架构角色 跟技术深度和广度 有关的部分。但这只是一部分,我们本质上谈论的是领导的角色,“软技能”或“交际能力”也极其重要。
- 领导力 :简单来说,领导力就是创造共有的愿景,并带领人们向着共同目标前行的能力。
- 沟通 :你有世界上最好的想法和愿景,但如果不能有效地传达给其他人,也是死路一条。这包括了软件开发团队内外的人,要使用适合受众的语言和细节水平。
- 影响力 :这是重要的领导技能,从毫不掩饰的劝说到神经语言编程1 或绝地控心术2 ,它能够以多种途径实现。通过妥协和谈判也可以达到这样的目的。每个人都有自己的想法和计划,你在处理时还得让他们都不反感,并主动地去追求你需要的结果。好的影响力也要求好的倾听和探索能力。
- 信心 :信心很重要,是有效的领导力、影响力和沟通的基础。但信心不代表傲慢。
- 合作 :软件架构角色不应该被孤立,(与其他人)合作想出更好的方案是一项值得实践的技能。这意味着倾听、谦虚和响应反馈。
- 指导 :不是每个人都对你正尝试做的事情有经验,你需要对他们进行角色、技术等方面的指导。
- 辅导 :辅导是对人进行学习方面的指引,而非告诉他们怎么做一件事。作为领导,你可能会被要求去辅导团队中的其他人。
- 动力 :这说的是保持团队愉快、开朗和积极。团队要有积极性,才会跟随你这个软件架构师所创建的任何愿景。你还要面对团队中一些人不买账的局面。
- 润滑剂 :你经常需要退后一步,促进讨论,特别是团队内有不同意见时。这需要探索、客观,帮助团队达成共识。
- 政治 :每个组织都少不了政治。我的咒语是,离得越远越好,但你至少应该明白周围发生了什么,这样才能做出更可靠的决策。
- 责任感 :你不能因为失败就责备软件开发团队中的其他人,有责任感对你而言很重要。如果软件架构不能满足业务目标,无法交付非功能性需求或技术品质很差,那都是你的问题。
- 授权 :授权对任何领导角色来说都是一个重要部分,作壁上观和事必躬亲之间有一条模糊的界线。你应该学会在适当的时候授权,但请记住,你授权的可不是责任。
设计常识
为了设计软件,你需要了解要满足的目标。如果这听起来天经地义,那是因为确实如此。话虽如此,但有的团队对软件应该向最终用户提供的特性还没有高层次理解,就设计甚至构建软件。有人可能会称之为敏捷,但我说这叫愚蠢。特性或用户故事清单,即使粗糙短小,也是必不可少的。需求驱动架构。
非功能需求代表的质量属性 反映了服务等级,如性能、可伸缩性、可用性、安全性等。这些属性主要是技术方面的,可以对最终的架构产生巨大影响,特别是如果你正在构建“高性能”系统,或者你想达到“谷歌级”的运行规模。实现非功能需求的技术解决方案通常是交叉的,因此需要合并到你所构建系统的基础中。向已有的代码库加入高性能、可伸缩性、安全性、可用性等通常极其困难且耗时。
我们生活在有约束 的现实世界中。例如,你任职的组织可能对技术选型、部署平台等有一系列细致的约束,能做什么,不能做什么。
约束通常是强加于你的,而原则 是你为了将一致性和清晰度引入最终代码库而想采用的原则(例如编码规范、自动化测试的使用等)或架构的原则(如分层策略,架构模式等)。
非功能性需求
非功能性需求通常被看作是“能力”,主要跟服务质量有关。按理说,比非功能性需求更好的说法是“系统特征”或“质量属性”,但不太常用。下面大致列出了常见的质量属性。
- 性能:就是一个东西有多快,通常指响应时间或延迟。
- 响应时间:从发出请求到收到响应所用的时间,比如用户点击网页中的超链接或桌面应用程序中的按钮。
- 延迟:消息从A点到B点,通过你的系统所用的时间
- 可伸缩性:可伸缩性基本上就是软件处理更多用户、请求、数据、消息等的能力。可伸缩性和并发机制密不可分,因此能在相同的时间内处理更多的东西(比如每秒的请求)。
- 可用性:可用性是软件对服务请求的可操作和可见程度。你常会看到用“9”来衡量或指代可用性,如99.99%(“四个9”)或99.999%(“五个9”)。这些数字指的是正常运行时间的百分比。硬币的另一面是可以容忍的停机时间。99.9%(“三个9”)的正常运行时间意味着留给计划维护、升级和意外故障的时间每天只有1分多钟。
- 安全性:安全性涵盖了从认证和授权到数据在运输和储存中的机密性的所有事情。和性能一样,安全性很有可能在一定程度上对你很重要。对于部署到互联网的Web应用程序,安全性应该被视为最基础的东西
- 灾难恢复:如果失去一个运行了你的软件的硬盘、服务器或数据中心,会发生什么?灾难恢复处理的就是这些。如果你的软件系统至关重要,就会经常听到人们谈论业务连续性过程,也就是发生灾难事件时,应该做什么才能保持持续运行的状态。
- 可访问性:可访问性通常是指像W3C的可访问性标准2 这样的东西,指的是如何让视觉障碍之类的残疾人也能使用你的软件。
- 监测:有些组织对于应该如何监测软件系统才能确保它们正常运行和满足服务请求,有特定的需求。这可能包括将软件与平台特定的监测功能(比如Java平台的JMX)集成,或发生故障时向集中监测仪表发送警报(比如通过SNMP)。
- 管理监测通常提供一个软件系统的只读视图,有时会有运行时管理需求。例如,有必要的话,暴露一些功能,使得操作人员能够修改系统运行时的拓扑结构或配置元素,刷新只读缓存等。
- 审计:人们往往需要一个引起软件系统中数据或行为变化的事件的日志(即审计日志),特别是涉及钱的时候。通常这些日志需要捕获与变动由谁做出、什么时候做出以及为什么做出相关的信息。变动本身(即变动前后的值)往往也需要记录。
- 灵活性:灵活性是一个有点滥用和含混的术语,指的是软件执行多个任务,或以不同方式执行单个任务的“灵活性”。一个很好的灵活性需求的例子是非技术人员修改软件内部使用的业务规则的能力。
- 可扩展性:可扩展性也是滥用和模糊的,但它指的是扩展软件使其可以做一些现在还不能做的事的能力,也许是通过使用插件和API。一些市面上的产品(如微软Dynamics CRM)允许非技术用户扩展存储的数据和改变其他用户与数据交互的方式。
- 可维护性:可维护性往往被认为是一个需求,但这到底是什么意思?作为软件开发者,我们通常会努力打造“可维护”的软件,但值得我们思考的是,代码库以后将由谁来维护。可维护性很难量化,所以我宁愿思考我们可以遵循的架构和开发原则 ,因为这些是编写可维护的代码的驱动力。
- 法律法规:有些行业受到当地法律或监管机构的严格管理,导致了与数据保留或审计日志等相关的额外需求。举个例子,大多数金融机构(投资银行、零售银行、信托公司等)为了保持在市场中的运作能力,必须遵守一些规则(如反洗钱)。
- 国际化(i18n):很多软件系统,特别是部署在互联网上的,不再以单一的语言交付。国际化是指以多种语言交付软件中用户可见元素的能力。这看似简单,当你试图将其加入已有软件时,才会意识到有些语言是从右向左书写的。
- 本地化(l10n)
原则
说到原则,很多软件开发者立刻想到的都是关于软件应该如何开发。比如下面这些。
- 编码标准和规范 :“我们将采用内部的[Java|C#|其他]语言编码规范,这可以在我们公司wiki找到。”
- 自动化单元测试 :“我们的目标是核心库的自动化单元测试达到80%的代码覆盖率,无论代码开发是先测试还是后测试。”
- 静态分析工具 :“所有的生产和测试代码在提交到源代码管理之前,必须通过[Checkstyle|FxCop|其他]定义的规则。”
还有一些原则是关于软件结构应该如何安排的。比如下面这些。
- 分层策略 :因为每一层都独立于周围,分层架构通常出现在有高度灵活性的软件系统中。比如,你可以把软件系统解构为UI(User Interface,用户界面)层,业务层和数据访问层。使业务层完全独立于数据访问层意味着(通常)可以实现在不影响业务或UI层的情况下切换数据访问。能这样做是因为数据访问层向业务层呈现了抽象,而不是业务层自己直接处理数据存储机制。如果想以这种方式安排软件结构,你就应当确保开发团队里每个人都明白这个原则。“UI组件或域对象里没有数据访问逻辑”是该原则在实践中的一个具体例子。
- 业务逻辑的位置 :有时候,出于性能或可维护性的原因,你要确保业务逻辑总是驻留在一个地方。对于连接互联网的移动应用程序,你可能想要确保服务器尽可能多地处理发生的请求。或者如果你在整合一个已经包含了大量业务逻辑的遗留后端系统,可能想要确保团队里没有人打算复制它。
- 高内聚、低耦合 、SOLID 1 等:有很多关注点分离相关的原则,专注于构建不需要太多依赖就能完成工作的高内聚的小结构单元。
- 无状态组件 :如果你在构建一个需要很强可伸缩性的软件,那么尽可能把组件设计得无状态,就是一种确保可以通过复制组件来对系统进行横向扩展从而分担负载的方式。如果这是你的可伸缩性策略,每个人都需要明白他们必须使用相同的模式来构建组件。这有助于避免将来出现任何讨厌的意外和可伸缩性瓶颈。
- 存储过程 :关系型数据库的存储过程就像马麦酱2 ——你对它们不是爱就是恨。用不用存储过程都各有优缺点,但当团队只是选择一种数据访问的方法并坚持,我还是倾向于存储过程。然而,每条原则都有例外。
- 域模型:丰富与贫瘠 :有些团队喜欢在自己的代码中有很丰富的域模型,构建本质上非常面向对象的系统。另一些则倾向于更贫瘠的域模型,对象只是被粗粒度组件和服务使用的数据结构。方法的一致性有很长的路要走。
- HTTP会话的使用 :如果你在构建一个网站,可能想或者不想用HTTP会话来存储请求间的临时信息。这通常取决于很多事情,包括你的伸缩策略是什么,会话支持对象到底存储在哪里,服务器出现故障时会发生什么,你是否使用粘性会话,会话复制的成本,等等。再次,开发团队的每个人都应该明白想要的方法,并坚持下去。
- 始终一致与最终一致 :很多团队都发现,他们往往需要为满足复杂非功能需求做出权衡。比如:有些团队用数据一致性换取性能或可伸缩性。我们能看到所有的Facebook3 状态更新,但是否都能立即看到真的重要吗?你的语境将决定立即或延迟的一致性是否妥当,但一致的方法很重要。
交互
进一步深入代码会帮助验证你最初的假设正确与否,但也可能留给你一大堆问题。也许你在较高层次明白系统做的事情,但不明白像下面这样的事。
- 软件系统如何融入已有的系统形态;
- 为什么会选择正在使用的技术;
- 软件系统的整体结构;
- 各个组件在运行时部署在哪里,如何相互沟通;
- Web层如何“知道”在哪里找到中间层;
- 日志/配置/错误的处理/其他采用了什么方法,在代码库中是否一致;
- 代码库中是否使用了通用的模式和原则;
- 如何添加新功能,在哪里添加;
- 栈的安全性是如何实现的;
- 如何实现可伸缩性;
- 与其他系统的接口如何工作;
我曾被要求评审和参与开发没有文档的系统。你当然可以从代码的角度评估大部分问题的答案,但这会很繁重。阅读代码的作用始终有限,但某些时候你可能需要向团队的其他人请教一些问题。如果没有问对问题,你就得不到正确的答案:你不知道你未知的。
软件指南
以下标题描述了你可能想要包含在软件指南中的事情:
- 语境;
- 功能性概览;
- 质量属性;
- 约束;
- 原则;
- 软件架构;
- 外部接口;
- 代码;
- 数据;
- 基础设施架构;
- 部署;
- 运营和支持;
- 决策日志。
语境
语境应该是一份软件指南最开始的部分之一,用来为文档的其余部分设置好场景。语境部分应该回答下面几类问题。
- 这个软件项目/产品/系统是关于什么的?
- 构建的是什么?
- 它如何融入现有环境?(比如,系统、业务流程等)
- 谁在使用?(用户、角色、参与者、人物等)
功能性概览
功能性概览让你总结系统的关键功能是什么。如果它们对架构很重要,还能解释为什么,就让你可以在系统的功能切片(用例、用户故事等)之间建立明确的链接。功能性概览应该回答下面几类问题。
- 系统实际上做什么是否清楚?
- 哪些特性、功能、用例、用户故事等对架构是重要的,原因是否清楚?
- 重要的用户是谁(角色、参与者、人物等)以及系统如何满足他们的需求是否清楚?
- 上述已用于塑造和定义架构是否清楚?
另外,如果你的软件自动化了业务流程或工作流,功能试图应该回答如下问题。
- 从流程的角度系统做什么是否清楚?
- 系统的主要流程和信息流是什么?
质量属性
质量属性总结了主要的质量属性,应该回答下面几类问题。
- 对于架构必须满足的质量属性是否有清晰的认识?
- 质量属性是否满足SMART原则 (具体、可衡量、可达成、相关、及时)?
- 如果通常理所当然的质量属性并无必要,是否会明确标示为超出范围(比如,“用户界面元素只用英语呈现”就表明并没有明确考虑多语言支持)?
- 有没有不切实际的质量属性(比如,在很多组织中,实现真正的全天候往往很昂贵)?
直接列出每个质量属性是一个很好的起点。例子包括:
- 性能(比如延迟和吞吐);
- 可伸缩性(比如数据和流量);
- 可用性(比如运行时间、停机时间、定期维护、全天候、99.9%等);
- 安全性(比如认证、授权、数据保密性等);
- 可扩展性;
- 灵活性;
- 审计;
- 监测和管理;
- 可依赖性;
- 故障转移/灾难恢复的目标(比如手工还是自动化,要花多长时间);
- 业务连续性;
- 互操作性;
- 遵守法律法规(比如数据保护法);
- 国际化(i18n)和本地化(l10n);
- 可访问性;
- 易用性;
- 等等。
约束
约束就像质量属性,直接列出并简要总结已知的约束就行了。约束的例子包括:
- 时间、预算和资源;
- 允许使用的技术清单和技术约束;
- 目标部属平台;
- 已有系统和继承标准;
- 局部标准(比如开发、编码等);
- 公共标准(比如,HTTP、SOAP、XML、XML结构、WSDL等);
- 标准协议;
- 标准消息格式;
- 软件开发团队的规模;
- 软件开发团队的技能配置;
- 所构建软件的本质(比如战术或战略);
- 政治约束;
- 内部知识产权的使用;
- 等等
如果约束确实有影响,就值得总结(比如,它们是什么、为什么要强加它们,是谁强加的),说明它们对你的架构有多重要。
原则
原则:如果你已经有一套软件开发原则(比如在开发wiki上),那就直接参考。否则,就列出你遵循的原则,为每一条都加上简短的解释或进一步信息的链接。原则的例子包括:
- 架构分层策略;
- 视图中没有业务逻辑;
- 视图中没有数据访问;
- 接口的使用;
- 始终使用ORM;
- 依赖注入;
- 好莱坞原则(不要给我们打电话,我们会给你打电话);
- 高内聚,低耦合;
- 遵循SOLID (单一职责原则、开闭原则、里氏代换原则、接口隔离原则、依赖倒置原则);
- DRY(don’t repeat yourself,不要重复自己);
- 确保所有组件都是无状态的(比如,让伸缩更容易);
- 选择一个富域模型;
- 先择一个贫血域模型;
- 始终选择存储过程;
- 绝不使用存储过程;
- 不要重新发明轮子;
- 错误处理、日志等的通用方法;
- 购买而非构建;
- 等等。
软件架构
软件架构:这个部分的目的是总结你的软件系统的软件架构,这样就能回答以下问题。
- “大局”看起来是什么样?
- 是否有清晰的结构?
- 从“30000英尺视图”看系统如何工作是否清楚?
- 它展示了主要的容器和技术选择吗?
- 它展示了主要的组件及其交互吗?
- 关键的内部接口是哪些?(比如,你的Web层和业务层之间的Web服务。)
外部接口
外部接口 这个部分的目的是回答下面几类问题。
- 关键的外部接口是哪些?
- 比如,你的系统和其他系统之间的(不管它们在你的环境内部还是外部)。
- 比如,暴露出来用于消费的API。
- 比如,从你的系统导出的文件。
- 每个接口都从技术角度考虑过了吗?
- 接口的技术定义是什么?
- 如果使用了消息,哪些队列(点对点)和话题(发布-订阅)是用于通信的组件?
- 消息的格式是什么(比如,纯文本或DTD/Schema定义的XML)?
- 同步还是异步?
- 异步消息的连接有保障吗?
- 如果必要,人们会长期订阅吗?
- 消息能否打乱顺序接收,这是一个问题吗?
- 接口是否幂等?
- 接口是否总是可用,或者比如说你是否需要在本地缓存数据?
- 性能/可伸缩性/安全性/其他是如何满足的?
- 每个接口都从非技术角度考虑过了吗?
- 接口所有权属谁?
- 接口多久会有变化,版本怎么处理?
- 是否有服务级别的协议?
数据
数据部分的目的是记录任何从数据的角度来看重要的东西,回答下面几类问题。
- 数据模型看起来是什么样?
- 数据存储在哪里?
- 谁拥有数据?
- 数据需要多少存储空间?(比如,特别是如果你在处理“大数据”。)
- 归档和备份策略是什么?
- 业务数据的长期归档是否有法规要求?
- 日志文件和审计跟踪是否有类似的要求?
- 是否用简单文件来存储?如果是,用的是哪种格式?
基础设施
基础设施 这个部分描述软件将会部署到的物理/虚拟硬件和网络。虽然作为一个软件架构师,你可以不参与基础设施的设计,但还是需要了解,让你有能力满足目标就够了。这个部分的目的是回答下面几类问题。
- 是否有清晰的物理架构?
- 在所有的层中,什么硬件(虚拟或物理)做了这件事?
- 如果适用,它是否满足冗余、故障转移和灾难恢复?
- 选择的硬件组件如何改变大小和被选中是否清楚?
- 如果使用了多个服务器和网站,它们之间的网络联系是什么?
- 谁负责基础设施的支持和维护?
- 有照管通用基础架构(比如,数据库、消息总线、应用程序服务器、网络、路由器、交换机、负载均衡器、反向代理、互联网连接等)的中心团队吗?
- 谁拥有资源?
- 开发、测试、验收、试制、生产等是否有合适的环境?
部署
部署 这个部分是用来描述软件(比如容器 )和基础设施之间的映射。有时候这是简单的一对一映射(比如,把一个Web应用程序部署到单个Web服务器上),其他时候会更复杂(比如,把一个Web应用程序部署到服务器集群的多个服务器上)。这个部分回答下面几类问题。
- 软件安装和配置软件在哪里,怎么做?
- 软件如何部署到基础设施架构部分 描述的基础设施元素上是否清楚?(比如,一对一映射、每个服务器多个容器等。)
- 如果这仍待决定,有哪些选项,是否做了文档?
- 内存和CPU在运行于单块基础设施上的进程间如何分配是否清楚?
- 有容器 或组件 以主动-主动、主动-被动、热备用、冷备用等形态运行吗?
- 部署和回滚策略是否已经定义?
- 软件或基础设施出现故障时会发生什么?
- 跨站点的数据如何复制是否清楚?
运营和支持
运营和支持:大多数系统都会受到所支持的运营需求的限制,特别是关于如何进行监测、管理和执行。在软件指南中包含一个专门的部分可以让你明确你的软件如何支持那些需求。这个部分应该处理下面几类问题。
- 软件如何为运营/支持团队提供监测和管理系统的能力是否清楚?
- 在架构的各个分层中这是如何实现的?
- 运营人员要如何诊断问题?
- 错误和信息记录在哪里?(比如,日志文件、Windows事件日志、SNMP、JMX、WMI、自定义诊断等。)
- 更改配置是否需要重新启动?
- 有需要定期执行的手动管理任务吗?
- 旧数据需要定期归档吗?
技术决策
技术决策 这个部分的目的是简单记录所做的重要决策,包括技术选择(比如,产品、框架等)和整体架构(比如,软件的结构、架构风格、分解、模式等)。
- 你为什么选择技术或框架X,而不是Y和Z?
- 你是怎么做的?产品评估还是概念证明?
- 你是否根据公司政策或企业架构战略而被迫做出关于X的决策?
- 你为什么选择所采用的软件架构?你考虑过其他哪些选项?
- 你怎么知道解决方案满足主要的非功能性需求?
- 等等。
写在最后
多少预先设计是太少
- 不了解系统边界是什么,在哪里。
- 团队中对“大局”没有形成共识。
- 无法交流整体愿景。
- 团队成员对需要做的事情不清楚或感到不适。
- 没有考虑非功能需求/质量属性。
- 没有考虑(现实的)环境约束如何影响软件(比如部署环境)。
- 没有考虑主要的风险,比如非功能需求、外部接口等。
- 尚未确认重大问题及其答案。
- 没有考虑关注点分离、适当的抽象层次、分层、可修改性,拐点等。
- 对架构师要扮演的角色没有共识。
- 解决问题的方法不一致。
- 团队缺乏控制和指导。
- 项目生命周期中本应预先考虑到的重大架构变化。
- 过多的设计选择和选项,往往伴以团队成员对解决方案或前进方向的反对。
- 对于设计是否管用的不确定(比如,设计过程中没有执行原型的部分)。
- 缺乏技术选择(即不必要的延迟)。
多少预先设计是太多
- 太多信息(即很长的文档或信息超载)。
- 在太多抽象层次都过于详细。
- 太多图表。
- 在文档中编写代码或伪代码。
- 过于死板,缺乏灵活性的架构。
- 所有抽象层次的所有决策都已做出。
- 有着众多展示了所有可能交互的序列图的类层次设计。
- 详细的实体关系模型和数据库的设计(比如,表、视图、存储过程和索引)。
- 分析瘫痪和纠缠于次要细节的团队。
- 编码成了对团队来说无聊而消极的设计文物到代码的简单变换。
- 一个无节制的“设计阶段”(即时间和预算)。
- 还未进行任何编码就已到达最后期限。