软件架构导论
从设计模式到软件架构
过去十节课,我们走完了 GoF 二十多种设计模式——策略、工厂、状态、观察者、桥接、装饰、代理……每一种都是把「具体类」之间的关系拧到刚好的工艺。复合模式那一节,我们让五种模式在「鸭子模拟器」里协作起来,已经隐约触及了系统级的设计。
但当系统从「几十个类」扩展到「几百个模块、几千名工程师、十几年的演化」时,仅仅会用模式是不够的。你需要回答的不再是「这个类该不该实现这个接口」,而是:
- 这个系统由哪些大块组成?它们怎么通信?
- 哪些设计决策一旦定下来就改不动了?
- 性能、可用性、安全性这些「非功能」需求,在哪里落地?
- 八十名工程师怎么并行协作而不互相踩脚?
这些问题的答案,住在一个比设计模式更高的抽象层——软件架构(Software Architecture)。设计模式是单体建筑里的雕花门窗,软件架构是整个城市的规划图。本节是 SysArch 板块的开篇,我们先建立起架构的概念框架:什么是架构、为什么重要、架构师做什么、后续会学什么。
软件工程是什么样的工程
讨论架构之前,先退一步看「软件工程」本身。
人类与世界互动的两条路径,一条是科学(Science),一条是工程(Engineering)。科学研究既存事物——天文学研究恒星,生物学研究生命,化学研究物质——靠的是观察、测量、实验。工程创造从未存在之物——金字塔、轮船、汽车、电话——靠的是构造(Construction)和评估(Evaluation)。
flowchart TD
H[人类与世界的互动]
H --> S[科学之路]
H --> E[工程之路]
S --> SO[研究既存之物<br>天文/生物/化学]
SO --> SM[观察 / 测量 / 实验]
E --> EO[创造新生之物<br>金字塔/轮船/汽车]
EO --> EM[构造 / 评估]
SM -.相互滋养.-> T[更好的工具与认知]
EM -.相互滋养.-> T
classDef human fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
classDef science fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef engineering fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
classDef tool fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
class H human
class S,SO,SM science
class E,EO,EM engineering
class T tool
科学和工程不是对立的,而是相互滋养:科学提供更好的对材料和测量的认知,工程提供更好的工具反哺科学。软件工程站在工程一侧——它的核心活动是「设计与构造前所未有的系统」,并对其行为进行评估。
这个视角解释了为什么软件设计本质上是创造性的。它没有「正确答案」,只有「在给定约束下足够好的方案」。架构正是这种创造性活动中最为关键、影响最深远的部分。
什么是软件架构
「软件架构」是一个被反复定义的术语,业界有两个最常被引用的版本。
软件架构(SEI 定义)
The software architecture of a program or computing system is the structure or structures of the system, which comprise software elements, the externally visible properties of those elements, and the relationships among them.
程序或计算系统的软件架构是该系统的结构或结构集合,由软件元素、这些元素对外可见的性质,以及它们之间的关系所组成。 ——卡内基梅隆大学软件工程研究所(Software Engineering Institute, SEI)
软件架构(IEEE 1471-2000 定义)
The fundamental organization of a system, embodied in its components, their relationships to each other and the environment, and the principles governing its design and evolution.
系统的根本组织,体现在其组件、组件之间及组件与环境之间的关系,以及指导其设计与演化的原则中。 ——IEEE 1471-2000《软件密集型系统架构描述推荐实践》
把两段定义剥到骨头,会发现它们说的是同一件事——架构由三类要素构成:
- 元素 / 组件(Elements / Components):系统的「积木」,可以是模块、子系统、服务等
- 关系(Relationships):组件之间如何连接、通信、依赖
- 性质 / 原则(Properties / Principles):组件对外可见的行为约定,以及指导系统演化的规则
注意 SEI 定义中的限定词「对外可见」(externally visible)——架构关心的是组件的接口承诺,而不是组件内部如何实现。这是「黑盒」思维的早期体现,后面我们会反复回到这一点。
架构、设计与结构
「架构」「设计」「结构」三个词在日常使用中常被混用,但在课程语境下需要区分清楚。
架构 vs. 设计
软件架构和软件设计不是两件事,而是同一活动的两个层次:
- 所有架构都是软件设计,但并非所有设计都是软件架构
- 「架构」(Architecting)是设计过程的一部分,专指其中最早期、最高层、最难变更的那部分
可以把架构理解为「高层设计」(High-level Design)或「关键设计决策的集合」(A Set of Design Decisions)。一个常用的判别问题是:「如果这个决策错了,要修正它需要重写整个系统吗?」如果答案是「是」,那它属于架构层面的决策。
flowchart TD
SD[软件设计的全集]
SD --> A[架构<br>关键的、难改的决策]
SD --> D[详细设计<br>类、方法、算法]
SD --> I[实现细节<br>变量命名、代码风格]
A -.约束.-> D
D -.约束.-> I
classDef arch fill:#ffebee,stroke:#c62828,stroke-width:3px
classDef design fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
classDef impl fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
classDef root fill:#eee,stroke:#495057,stroke-width:2px
class SD root
class A arch
class D design
class I impl
架构 vs. 结构
「结构」是把系统分解成组件、模块、子系统这一过程的产物。架构在结构之上更进一步,它要回答关于这些组件的三个问题:
| 维度 | 问题 |
|---|---|
| 接口(Interface) | 这个组件能做什么? |
| 通信(Communication) | 组件之间如何对话?依赖谁? |
| 职责(Responsibility) | 当你请求它时,它具体做什么? |
光画一张分模块的方框图——「这是 UI 层、这是业务层、这是数据层」——还称不上架构。只有当你说清楚「UI 层通过 REST API 同步调用业务层」「业务层通过仓库接口读取数据层」「业务层不能直接访问数据库」时,才算把架构讲清楚了。
元素 + 关系 + 性质
架构的三要素也可以这样记:
- 元素(Elements):组件(components)和连接件(connectors)
- 关系(Relationships):静态关系(如依赖)和动态关系(如调用流)
- 性质(Properties):单个元素的、一组元素的、整个系统的对外属性
架构关注的两类内容
架构师的笔触落在两个地方:组件如何通信,以及系统满足哪些非功能需求。
通信机制
组件之间的对话有两个维度——数据怎么传和控制怎么走。
flowchart LR
C[组件通信]
C --> D[数据传递]
C --> F[控制流]
D --> D1[函数调用<br>Function Call]
D --> D2[远程方法调用<br>RMI]
D --> D3[异步消息<br>Message]
F --> F1[顺序执行<br>Sequential]
F --> F2[并发/并行<br>Concurrent]
F --> F3[同步<br>Synchronization]
classDef root fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef data fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
classDef flow fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
class C root
class D,D1,D2,D3 data
class F,F1,F2,F3 flow
数据传递可以是同进程的函数调用(轻、快、紧耦合),跨进程跨主机的远程方法调用(Remote Method Invocation, RMI),或基于消息队列的异步消息(松耦合、可扩展、但有延迟)。控制流则刻画消息在组件间流动的方式——顺序执行(一步接一步)、并发并行(多个组件同时工作)、同步(两个并发流的会合点)。
不同的通信选择对应着不同的架构风格。同样是「订单服务调用库存服务」,做成函数调用就是单体应用,做成远程调用就是微服务,做成异步消息就是事件驱动架构——三者的可扩展性、容错性、复杂度天差地别。
非功能需求
如果说功能需求回答「系统能做什么」,那么非功能需求(Non-Functional Requirements, NFRs)回答「系统做得有多好」。
非功能需求
非功能需求(NFRs)刻画系统的质量属性、约束条件等「做得多好」的维度,而非「能做什么」。
NFRs 很少出现在功能需求文档里,常被称为架构需求(Architecture Requirements),需要架构师主动去挖掘和确认。
NFRs 大致分三类:
- 技术约束(Technical Constraints):必须运行在 ARM 架构上、必须兼容 Java 8、必须使用公司既有的消息中间件
- 业务约束(Business Constraints):上线时间不能晚于六月、预算上限两百万、必须支持五年以内的硬件
- 质量属性(Quality Attributes):性能、可用性、安全性、可修改性、可测试性……
想想看
你能列出多少种质量属性?性能、可用性、安全性、可修改性、可移植性、可测试性、可用性(usability)、可扩展性……下一节课我们会系统讨论这些。
NFRs 之所以是架构师的核心关注点,是因为它们无法在某个组件内部「局部解决」——你没法靠优化一段代码让整个系统变得「高可用」。可用性、性能、安全性这些属性是从架构层面渗透到每个组件的全局性质。
设计是一种抽象
架构对设计的另一个核心贡献是抽象(Abstraction)。
架构提供一个比详细设计更高的抽象视角:
- 隐藏具体设计的复杂度和实现细节
- 架构元素与软件元素之间,不一定存在直接的一一映射——一个架构组件可能对应几十个类,一个类也可能跨多个架构组件
抽象有两种风格:
- 黑盒设计(Blackbox Design):只描述组件做什么、对外有哪些接口,不关心内部如何实现
- 白盒设计(Whitebox Design):除了对外行为,还描述内部结构和实现思路
架构层面通常更偏黑盒——它给出系统的结构和交互的非正式描绘,体现架构所蕴含的设计哲学,但不规定每个组件的内部实现。
为什么设计需要抽象?
一个架构师的脑容量是有限的,一个项目相关方的耐心也是有限的。如果一上来就把整个系统铺开到代码细节,没人能看清整体。抽象让我们能在不同层次上谈论系统:和老板谈业务模块、和架构师谈接口契约、和工程师谈类设计。每一层都只暴露当前对话需要的复杂度。
多视图:架构的「平面图」
一栋建筑有楼层平面图、立面图、电气图、给排水图、暖通图——每张图回答不同问题,没有哪张图能独自描述整栋建筑。软件架构是同样复杂的产物,需要多张「图」从不同视角共同描绘。
flowchart TD
B[一栋建筑的图纸]
B --> B1[平面图]
B --> B2[立面图]
B --> B3[电气图]
B --> B4[给排水图]
B --> B5[暖通图]
A[一个软件架构]
A --> A1[逻辑视图<br>Logical]
A --> A2[过程视图<br>Process]
A --> A3[物理视图<br>Physical]
A --> A4[开发视图<br>Development]
A --> A5[用例视图<br>+1]
classDef building fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
classDef software fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
class B,B1,B2,B3,B4,B5 building
class A,A1,A2,A3,A4,A5 software
最经典的多视图建模框架,是 Philippe Kruchten 在 1995 年提出的 4+1 视图模型(4+1 View Model)。
Kruchten 的 4+1 视图模型
一个软件架构可以从五个互补的视角描述,每个视角回答不同的问题:
- 逻辑视图(Logical View):刻画架构上重要的元素及其关系——回答「系统由哪些功能模块组成」
- 过程视图(Process View):刻画并发与通信元素——回答「运行时有哪些进程/线程,如何交互」
- 物理视图(Physical View):刻画主要进程和组件如何映射到硬件——回答「部署在哪些机器上」
- 开发视图(Development View):刻画软件组件的内部组织(如配置管理工具中的结构)——回答「代码仓库怎么组织、模块怎么打包」
- 架构用例(Use Cases):捕获架构需要满足的需求场景,是贯穿其他四个视图的「+1」
为什么需要多个视图?因为不同的相关方(Stakeholder)关心不同的问题。运维关心物理视图,开发关心开发视图,业务方关心用例视图。一个完整的架构文档需要覆盖所有这些维度。
后续课程会反复用到 4+1 视图——画一张架构图时要先问自己「这是哪个视图」,否则容易把所有信息塞进一张乱糟糟的图,谁都看不懂。
怎么开展设计
当面对一个新系统时,架构师手里有一组通用的设计策略可以反复使用:
| 策略 | 直觉 |
|---|---|
| 分解(Decomposition) | 把大问题切成多个小问题 |
| 抽象(Abstraction) | 忽略当前层次不关心的细节 |
| 逐步求精(Stepwise Refinement) | 「分而治之」,每一步只解决一个层次 |
| 生成与测试(Generate and Test) | 先草稿出方案,再用质量场景验证 |
| 迭代(Iteration) | 增量式精化,承认第一稿一定不完美 |
| 复用(Reusable Elements) | 借用既有的组件、模式、框架 |
这些策略不是互斥的——一个架构通常先分解再抽象,逐步求精中迭代,并积极复用。复用是其中最具杠杆效应的一项,模式(Patterns)和战术(Tactics)就是为复用而存在的成熟方案,后续几节课会重点讲。
通用设计模型
把前面的策略形式化,可以画出软件设计的通用流程:
flowchart TD
R[需求规格<br>Requirements Specification]
C[约束<br>资源/组织/经验/已有软件复用]
P[设计过程<br>Design Process]
D[设计师的决策<br>Designer's Decisions]
PD[程序描述<br>Program Description]
R --> P
C --> P
P --> D
D --> PD
classDef input fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef process fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
classDef output fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
class R,C input
class P process
class D,PD output
设计的输入有两类:显式的需求规格(需要做什么),和隐式的约束(资源限制、组织结构、团队经验、可复用的既有软件)。设计过程把这些输入加工成「设计师的决策」,再具体化为「程序描述」。
注意:约束往往比需求更隐蔽,也更容易被忽略。「我们团队没人会 Rust」这样的现实约束,对架构选型的影响可能比「需要支持每秒一万次查询」更大。
软件设计本身可以拆成更细的过程:
flowchart LR
R0[需求]
R1[需求规格]
A[分析需求<br>构造黑盒模型]
L[逻辑设计细节]
R0 --> R1
R1 --> A
A --> L
classDef req fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef ana fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
classDef des fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
class R0,R1 req
class A ana
class L des
第一步先把模糊的需求精化成可写下来的规格;第二步分析需求并构建系统的「黑盒模型」——只关心系统对外的行为;第三步才是把黑盒拆成内部的逻辑组件。这个流程刻意把「做什么」和「怎么做」分开,避免一上来就钻到实现细节里。
架构活动:架构师的工作清单
把上面的过程具体到架构层面,架构师要做的事情大致是:
- 为系统建立商业理由(Business Case)——为什么要做?谁出钱?给谁用?
- 理解需求——功能需求 + 非功能需求 + 约束
- 创建并选择架构——多个候选方案,从中权衡选择
- 沟通架构——向利益相关方(包括开发者)传达架构
- 分析或评估架构
- 整体方法学(如 ATAM 等综合评估方法)
- 质量属性专项技术
- 实现架构——把决策落实到代码
- 保证架构一致性(Conformance)——确保实现没有偏离架构
flowchart TD
B[商业理由]
R[理解需求]
C[创建/选择架构]
Co[沟通架构]
E[分析/评估架构]
I[实现架构]
Cf[保证一致性]
B --> R --> C --> Co --> E --> I --> Cf
Cf -.反馈.-> C
classDef early fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef mid fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
classDef late fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
class B,R early
class C,Co,E mid
class I,Cf late
最后一步「保证一致性」常被忽略,但极其关键——再好的架构图,如果代码实际上没遵守它,等于没有架构。这就是为什么后续会专门讨论架构评审、静态分析、ADL(Architecture Description Language)等工具:它们让「图」和「代码」可以被机械地对比。
架构过程的高层视角
把上面的活动拼成一张大图,整个软件架构过程长这样:
flowchart LR
SH[利益相关方<br>Stakeholders]
RC[需求与约束<br>Requirements,<br>Constraints]
QA[优先级化的质量属性场景<br>Prioritized Quality<br>Attribute Scenarios]
ASR[规约 ASR<br>Architecturally<br>Significant Requirements]
PT[模式与战术<br>Patterns & Tactics]
AV[候选视图的草图<br>选择并组合]
AE[架构评估<br>Architecture Evaluation]
SH --> RC
RC --> QA
QA --> ASR
ASR --> PT
PT --> AV
AV --> AE
AE -.迭代.-> ASR
classDef stake fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
classDef req fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef pat fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
classDef view fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
classDef eval fill:#ffebee,stroke:#c62828,stroke-width:2px
class SH stake
class RC,QA,ASR req
class PT pat
class AV view
class AE eval
几个关键术语先记住,后面几节会系统展开:
- ASR(Architecturally Significant Requirements,架构上显著的需求):那些会决定架构走向的需求,往往不是功能需求
- 质量属性场景(Quality Attribute Scenarios):把抽象的质量属性写成可验证的具体场景,例如「在峰值负载下,95% 请求的响应时间小于 200 毫秒」
- 战术(Tactics):实现某个质量属性的可复用设计技巧,比单个模式更细粒度
整个过程不是线性的,评估的结果会反馈回 ASR 的修订,迭代多轮才能收敛。
架构生命周期
把过程压缩成最简版本,就是三个阶段循环:
flowchart LR
D[架构设计<br>Architectural Design]
E[架构评估<br>Architectural Evaluation]
I[架构实现<br>Architectural Implementation]
D --> E --> I -.演化.-> D
classDef stage fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
class D,E,I stage
每一轮迭代都包括设计、评估、实现三步——这是架构持续演化的基本节律。
架构师:从建筑师到软件架构师
「架构师」(Architect)这个职业最早属于建筑业。1972 年,建筑历史学家 James Marston Fitch 留下一句话:
Architects design structures to meet human needs.(架构师设计结构以满足人类的需求。)
软件架构师与建筑架构师的角色高度类似——只是把「钢筋混凝土」换成了「类、组件、协议」:
- 倾听客户,理解他们的全部需求(不只是嘴上说的那些)
- 审视可行性——技术可行、预算可行、时间可行
- 形成实用的愿景,画出蓝图
- 监督建造过程,确保实施符合蓝图
- 在设计变更、危机和模糊性的「风暴」中保持愿景
软件架构师监督的「建造工人」是程序员、工程师、设计师。
历史上几位著名的软件架构师:
| 名字 | 身份 |
|---|---|
| Bill Gates | 微软首席软件架构师 |
| Tim Berners-Lee | 万维网(WWW)发明人和首席架构师 |
| Roy Fielding | REST(Representational State Transfer)的提出者 |
架构师每天在做什么
理论上的角色描述容易让人觉得架构师就是「画图的」,但实际工作要复杂得多:
- 联络人(Liaison)
- 在客户、技术团队、业务/需求分析师之间传话
- 与管理层、市场部门对接
- 软件工程
- 推行软件工程的最佳实践
- 技术专家
- 对所在技术领域有深入理解
- 风险管理
- 识别设计、技术选型上的风险并提前应对
简而言之,架构师既是技术专家,也是组织里的「翻译官」和「风险预警员」。光懂技术做不好架构师——你还得懂业务、懂人。
架构为什么重要
这是本节最重要的部分——理解架构的价值,是后面所有内容的动机。
架构的角色
软件架构在系统的整个生命周期中扮演四个核心角色:
- 早期决策的固化:架构是第一批表达「需求如何被满足」的产物。它体现的是项目最早期的设计决策,而最早期的决策也是最难变更的——它们值得最仔细的考虑。
- 产品线工程的基石:成功的产品线工程(Product Line Engineering)依赖于一个统一的架构——用更小的成本、更短的时间、更低的风险开发一系列相似的系统。一个架构对应许多系统。
- 新人理解系统的入口:当某人开始接手一个系统时,他最先要看的就是架构。
- 维护与修改的参照框架:架构是后续做维护决策时的判断依据。
架构的重要性
进一步展开,架构在六个维度上具有不可替代的价值。
1. 沟通的载体
架构是各方识别和谈判利益冲突的参照框架:
- 与用户协商需求时
- 让客户了解进展、成本时
- 实施管理决策和资源分配时
没有架构图,开会就只能靠「想象」——每个人脑子里的系统都不一样,争论起来像盲人摸象。
2. 早期设计决策的载体
架构约束实现和开发者:
- 实现必须符合架构
- 资源分配决策约束着各组件的实现方式
这种约束不是限制,而是保证一致性的脚手架。
3. 决定组织结构
架构反过来决定开发与维护的组织结构。康威定律(Conway's Law)的另一面:
| 用途 | 说明 |
|---|---|
| 团队划分 | 一个组件一支团队 |
| 预算与计划 | 按组件分配资源 |
| 工作分解结构(WBS) | Work Breakdown Structure 的基础 |
| 文档组织 | 文档按架构层次组织 |
| 配置管理(CM)库 | 代码仓库按组件划分 |
| 集成与测试 | 测试边界沿组件边界划分 |
| 维护 | 维护团队按组件分工 |
4. 推动或阻碍质量属性
架构促进或阻碍可修改性、安全性、可用性等质量属性的实现:
- 架构影响质量,但不保证质量——还有很多其他因素在起作用
- 这是架构「能做到什么、做不到什么」的关键边界
5. 关于变更的讨论平台
架构引发「未来可能怎么变」的讨论。这条尤其重要,因为:
80% 的成本来自部署后
一个系统大约有 80% 的工作量发生在部署之后——维护、修改、扩展、迁移。如果架构没有为这些变化预留空间,后期的成本会以指数级膨胀。
架构把变更分为三类,从局部到全局:
flowchart LR
L[局部变更<br>Local]
NL[非局部变更<br>Non-local]
A[架构性变更<br>Architectural]
L -->|影响范围扩大| NL
NL -->|影响范围扩大| A
classDef local fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
classDef nonlocal fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
classDef arch fill:#ffebee,stroke:#c62828,stroke-width:3px
class L local
class NL nonlocal
class A arch
| 类型 | 含义 | 成本 |
|---|---|---|
| 局部变更(Local) | 单个组件的修改 | 低 |
| 非局部变更(Non-local) | 多个组件的修改 | 中 |
| 架构变更(Architectural) | 系统的基本结构、通信、协调机制的修改 | 极高 |
一个好的架构能让大多数变更停留在「局部」层级,避免轻易触发架构变更。这就是「为变化而设计」的具体含义。
6. 可迁移、可复用的抽象
最后,架构本身就是一种一对多映射的资产:
- 一个架构可以被多个系统复用——架构是可迁移的
- 整个产品线可以共享同一个架构——架构是产品共性的基石
- 系统可以通过整合独立开发的组件来构建——这就是 CBSE(Component-Based Software Engineering,基于组件的软件工程)
flowchart TD
A[一个架构]
A --> S1[系统 1]
A --> S2[系统 2]
A --> S3[系统 3]
A --> S4[系统 4]
S1 -.同款架构.-> P[产品线]
S2 -.同款架构.-> P
S3 -.同款架构.-> P
S4 -.同款架构.-> P
classDef arch fill:#ffebee,stroke:#c62828,stroke-width:3px
classDef sys fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef line fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
class A arch
class S1,S2,S3,S4 sys
class P line
架构的现实样貌
抽象概念终归要落到具体例子。课件里给了几个示意性的例子,我们简单看一下它们的形状。
移动电话系统
移动电话系统的架构涉及资源管理(Resource Management)、切换决策(Handoff Decision)、切换失败处理(Handoff Failure Actions)等组件,以及它们之间的协作关系。这是一个典型的实时控制系统架构——核心关注点是资源调度和故障容错。
洗衣机系统
洗衣机的嵌入式系统也有架构——传感器、控制器、电机驱动、用户界面之间的关系。这个例子说明架构存在于一切「软件密集型系统」中,不只是云端服务器。
AI 护栏架构
最具时代特色的例子——AI 系统的护栏架构(Guardrail Architecture):
flowchart TD
I[输入护栏<br>Input Guardrails]
R[RAG 护栏<br>RAG Guardrails]
EX[执行护栏<br>Execution Guardrails]
M[多模态护栏<br>Multimodal Guardrails]
O[输出护栏<br>Output Guardrails]
F[基础模型<br>Foundation Models]
N[窄域 AI 模型<br>Narrow AI Models]
I --> F
R --> F
F --> EX
F --> M
F --> O
F <--> N
classDef guard fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
classDef foundation fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef narrow fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
class I,R,EX,M,O guard
class F foundation
class N narrow
输入端有输入护栏和 RAG 护栏(Retrieval-Augmented Generation,检索增强生成的护栏),中间是基础模型与窄域 AI 模型的协作,输出端有执行护栏、多模态护栏和输出护栏。这种架构正是为应对大模型的安全、合规、可靠性这些「质量属性」而生——和洗衣机的故障容错本质上是同一类问题,只是放在了 AI 的语境下。
这些例子告诉我们:架构不是某个特定领域的专属概念,任何复杂的软件密集型系统都需要架构,从 IC 卡到航天器,从单机游戏到 ChatGPT。
知识地图:本课程会教什么
架构是一个庞大的话题,本课程会按以下知识区域展开。
软件设计与架构知识体系
flowchart TD
SDA[软件设计与架构]
SDA --> BC[设计基本概念]
BC --> BC1[通用设计概念]
BC --> BC2[软件生命周期上下文]
BC --> BC3[设计过程:策略/角色/活动]
SDA --> KI[关键技术议题]
KI --> KI1[并发]
KI --> KI2[控制与事件处理]
KI --> KI3[分布]
KI --> KI4[异常处理]
KI --> KI5[交互系统]
KI --> KI6[持久化]
SDA --> SA[结构与架构]
SA --> SA1[架构结构与视点]
SA --> SA2[架构风格与模式<br>宏观架构]
SA --> SA3[设计模式<br>微观架构]
SDA --> DM[设计方法]
DM --> DM1[架构方法<br>如 ADD]
DM --> DM2[设计方法<br>如 DDD]
SDA --> QE[质量分析与评估]
QE --> QE1[质量属性]
QE --> QE2[评估方法<br>如 ATAM]
QE --> QE3[静态/动态分析]
QE --> QE4[仿真与原型]
QE --> QE5[度量与指标]
SDA --> MR[建模与表示]
MR --> MR1[ADL]
MR --> MR2[UML]
MR --> MR3[Views & Beyond]
MR --> MR4[ACME / Rapide 等]
classDef root fill:#ffebee,stroke:#c62828,stroke-width:3px
classDef level1 fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef level2 fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
class SDA root
class BC,KI,SA,DM,QE,MR level1
class BC1,BC2,BC3,KI1,KI2,KI3,KI4,KI5,KI6,SA1,SA2,SA3,DM1,DM2,QE1,QE2,QE3,QE4,QE5,MR1,MR2,MR3,MR4 level2
注意「架构风格与模式」是宏观架构(macro-architecture),而前十节学的「设计模式」是微观架构(micro-architecture)——两者都是「模式」,但作用层次不同。
几个关键术语先建立印象:
- ADD(Attribute-Driven Design):属性驱动设计,一种面向质量属性的架构设计方法
- DDD(Domain-Driven Design):领域驱动设计,一种面向业务领域建模的设计方法
- ATAM(Architecture Trade-off Analysis Method):架构权衡分析方法,SEI 提出的架构评估方法学
- ADL(Architecture Description Language):架构描述语言,用形式化语言描述架构(如 ACME、Rapide)
后续课程预告
| 课程 | 主题 |
|---|---|
| 本节(Lecture 1) | 软件架构概念导论 |
| Lecture 1/2 | 质量属性与架构战术 |
| Lecture 3 | 架构模式 |
| Lecture 4/5 | 架构设计方法(ADD) |
| Lecture 6 | 微服务架构 |
| Lecture 7 | 软件架构课程复习 |
每一节都会回到本节建立的概念框架——架构由元素、关系、性质组成;架构关注通信、NFRs、抽象;架构活动是设计、评估、实现的循环;架构的价值在于沟通、约束、组织、质量、变更、复用。这些都是后续讨论的脚手架。
小结
本节是 SysArch 板块的开篇,我们从「设计模式之外」迈入了更高层次的软件设计。核心要点:
- 软件工程是「创造新事物」的工程活动,架构是其中最早期、最关键、最难变的部分
- 软件架构 = 元素(组件) + 关系 + 性质,且只关心对外可见的接口承诺
- 架构 ⊂ 设计,但不等于详细设计;架构关注结构、通信、非功能需求、抽象
- 架构是多视图的——4+1 视图(逻辑/过程/物理/开发 + 用例)刻画不同维度
- 架构师既是技术专家,也是联络人和风险管理者
- 架构的价值贯穿系统生命周期:沟通载体、决策固化、组织依据、质量推动、变更框架、复用基础
下一节我们会深入讨论质量属性(Quality Attributes)——把「系统做得有多好」从抽象概念变成可写下来、可验证的场景。这是架构设计真正落地的入口。