很多工程师在从"写代码"向"做架构"转型的过程中,往往会遇到一个瓶颈:面对一个复杂的项目,不知道从何下手分析,更不知道如何画出一张清晰的架构图。
随着 AI 时代的到来,具备架构分析能力往往会更重要。因为你会发现,在使用 AI Coding 的过程中,你不再只是一个 "搬砖"的程序员,你更多要做的是顶层的架构设计。
这篇文章将从"如何画一张架构图"这个具体的问题出发,带你一步步理解架构的本质,并梳理后端与大前端不同类型项目的方法论。
一、架构的意义:为什么我们需要架构图?
在讨论如何画图之前,我们需要先回答一个根本问题:架构的本质是什么?
著名面向对象专家 Ralph Johnson 曾给过一个非常精辟的定义:
"架构是那些难以改变的设计决策。"
架构并不是为了设计一个完美的系统,而是在当前资源的约束下,做出一系列高代价的决策,从而解决三类核心问题:复杂度管理 (划分边界,避免系统失控)、变化应对 (解耦模块,防止牵一发而动全身)以及团队协作(明确接口契约,避免多人开发互相踩踏)。
而架构图,本质上就是这些"架构决策"的可视化表达。我们画架构图,通常是为了达到三个目的:
- 强迫自己想清楚。画图的过程本身就是思考的过程。很多模糊的地带(如依赖方向、模块归属)在画图时都会暴露无遗。画不清楚,说明没想清楚。
- 对齐团队认知。代码是个人的,图是团队的。一张好的架构图能让新人在一小时内理解系统全貌,它是跨角色沟通的通用语言。
- 作为决策依据。当需要讨论是否引入消息队列、是否拆分微服务时,有架构图才能有效讨论,避免鸡同鸭讲。
二、C4 模型:通用的后端架构分析方法论
对于后端系统(单体应用或微服务),目前业界最主流的架构可视化方法是 C4 模型。它采用自顶向下的视角,将系统分为四个层次。
Level 1: System Context(系统上下文图)
目的:展示系统是什么?谁在用它?依赖哪些外部系统?主要用于与非技术人员沟通,明确系统边界。
graph TB
reader["👤 普通读者"]
admin["👤 管理员"]
subgraph system["📦 图书管理系统"]
api["🖥️ API 服务\n(NestJS)"]
end
smtp["📧 邮件服务\n(外部)"]
reader -- "查询图书 / 借书 / 还书" --> api
admin -- "管理图书 / 用户管理" --> api
api -- "发送到期提醒" --> smtp
style system fill:#dbeafe,stroke:#3b82f6
style api fill:#3b82f6,color:#fff,stroke:#2563eb
style reader fill:#1e3a5f,color:#fff,stroke:#1e3a5f
style admin fill:#1e3a5f,color:#fff,stroke:#1e3a5f
style smtp fill:#6b7280,color:#fff,stroke:#4b5563
Level 2: Container(容器图)
目的:展示系统由哪些可独立部署的技术单元组成,明确技术选型和部署方案。
graph LR
client["👤 用户 / 浏览器"]
subgraph system["图书管理系统"]
api["🖥️ NestJS API 服务\n处理所有业务逻辑"]
mysql[("🗄️ MySQL\n持久化存储")]
redis[("⚡ Redis\n缓存 + Token 白名单")]
end
smtp["📧 邮件服务"]
client -- "HTTP/HTTPS" --> api
api -- "TypeORM 读写" --> mysql
api -- "缓存 / Token 校验" --> redis
api -- "SMTP" --> smtp
style system fill:#dbeafe,stroke:#3b82f6,stroke-dasharray:6
style api fill:#3b82f6,color:#fff
style mysql fill:#f59e0b,color:#fff
style redis fill:#ef4444,color:#fff
style smtp fill:#6b7280,color:#fff
Level 3:Compoent(组件图)
目的:深入 NestJS API 服务内部,回答"它由哪些模块组成、模块间如何协作",是开发人员日常最常参考的图。
解读:API 服务内部分为两层:
公共层(Common) 是所有请求的必经之路,包含:
•JwtAuthGuard:双重验证(JWT 签名 + Redis 白名单)
•RolesGuard:基于角色的权限控制(admin / user)
•GlobalExceptionFilter:统一异常捕获和格式化
业务模块层 按领域划分为四个模块,每个模块内部均遵循 Controller → Service → Repository 三层结构,模块间通过依赖注入(DI)解耦。
Level 4: Code(时序图)
除了静态结构,我们通常还需要补充**时序图(Sequence Diagram)**来追踪关键业务场景下的动态数据流,例如下面这个带悲观锁的并发借书流程:
>G: 返回存储的 Token
G->>G: 比对 Token 是否一致
alt Token 无效
G-->>C: 401 Unauthorized
else Token 有效
G->>S: borrowBook(userId, bookId)
S->>R: GET user:{userId}:borrow_count
R-->>S: 当前借阅数量
alt 已达上限(>=5)
S-->>C: 400 已达最大借阅数量
else 未达上限
S->>D: BEGIN TRANSACTION
S->>D: SELECT * FROM books FOR UPDATE
D-->>S: 图书信息(加悲观写锁)
S->>D: UPDATE stock / INSERT borrow_record
S->>D: COMMIT
S->>R: 更新借阅计数 / 清除图书缓存
S-->>C: 201 借阅成功
end
end -->
三、大前端架构:为什么场景比后端更多?
当我们将目光转向前端时,会发现情况变得截然不同。后端的复杂度主要来自规模 (服务数量、数据量、并发量),架构模式相对收敛。而前端的复杂度主要来自维度的爆发。
后端的运行环境几乎是单一的服务器进程,而前端需要面对浏览器、iOS、Android、小程序、桌面端甚至服务端渲染(SSR)等多种环境。此外,前端的产物类型也更加多样化。这种多样性导致大前端领域不存在"一招鲜"的架构图画法,我们必须针对不同的项目类型采用不同的分析思路。
1. 前端/客户端应用:分层数据流图
对于传统的 SPA 或客户端应用,分析的核心是页面路由拓扑 和分层数据流。我们需要梳理从 UI 层(View)到状态层(Store),再到服务层(Service)和后端 API 的单向数据流链路。
flowchart TD
User["👤 用户操作\n(点击、输入)"]
subgraph view["UI 层 (View)"]
Page["Pages / Components\nBookListPage · BorrowPage"]
end
subgraph store["状态层 (Store)"]
BookStore["bookStore\nbooks / pagination"]
BorrowStore["borrowStore\nborrowRecords / count"]
AuthStore["authStore\nuser / token"]
end
subgraph service["服务层 (Service)"]
HTTP["HTTP Client (Axios)\n统一注入 Token · 处理 401"]
end
API["🌐 后端 REST API"]
User --> Page
Page -- "useBookStore()" --> BookStore
Page -- "useBorrowStore()" --> BorrowStore
BookStore -- "fetchBooks()" --> HTTP
BorrowStore -- "borrowBook()" --> HTTP
AuthStore -- "login()" --> HTTP
HTTP -- "HTTP 请求" --> API
API -- "JSON 响应" --> HTTP
HTTP -- "更新状态" --> BookStore
HTTP -- "更新状态" --> BorrowStore
BookStore -- "响应式重渲染" --> Page
style view fill:#dbeafe,stroke:#3b82f6
style store fill:#f3e8ff,stroke:#9333ea
style service fill:#fef3c7,stroke:#f59e0b
style Page fill:#3b82f6,color:#fff
style BookStore fill:#9333ea,color:#fff
style BorrowStore fill:#9333ea,color:#fff
style AuthStore fill:#9333ea,color:#fff
style HTTP fill:#f59e0b,color:#fff
style API fill:#374151,color:#fff
2. UI 组件库:分层依赖图
组件库没有页面和路由,其架构分析的核心是组件的分层与依赖隔离。一个优秀的组件库必须是严格自下而上依赖的。
flowchart BT
subgraph L0["🎨 设计 Token 层(无任何依赖)"]
T1["Colors"]
T2["Spacing"]
T3["Typography"]
end
subgraph L1["🪝 基础 Hooks 层"]
H1["useTheme"]
H2["useControllable"]
H3["useClickOutside"]
end
subgraph L2["⚛️ 原子组件层"]
A1["Button"]
A2["Input"]
A3["Icon"]
A4["Tag"]
end
subgraph L3["🧩 复合组件层"]
C1["Modal"]
C2["Form / FormItem"]
C3["Select"]
C4["Table"]
end
subgraph L4["🏢 业务组件层"]
B1["SearchBar"]
B2["DataTable"]
B3["BookCard"]
end
L0 --> L1
L0 --> L2
L1 --> L2
L2 --> L3
L3 --> L4
style L0 fill:#f3e8ff,stroke:#9333ea
style L1 fill:#dbeafe,stroke:#3b82f6
style L2 fill:#dcfce7,stroke:#16a34a
style L3 fill:#fef3c7,stroke:#f59e0b
style L4 fill:#fee2e2,stroke:#ef4444
3. Monorepo 多包项目:包依赖拓扑图
对于大型前端项目,分析的核心是包与包之间的依赖拓扑(Apps 层依赖 Packages 层)以及基于依赖树的构建流水线编排。
graph BT
subgraph apps["Apps 层(可部署应用)"]
Web["apps/web\nReact + Vite"]
Admin["apps/admin\nReact + Vite"]
Mobile["apps/mobile\nReact Native"]
end
subgraph packages["Packages 层(共享包)"]
UI["@book/ui\nUI 组件库"]
API["@book/api-client\nHTTP 请求封装"]
Utils["@book/utils\n工具函数"]
Config["@book/config\n共享配置"]
end
Web --> UI
Web --> API
Admin --> UI
Admin --> API
Mobile --> API
UI --> Utils
API --> Utils
Utils --> Config
UI --> Config
API --> Config
style apps fill:#dbeafe,stroke:#3b82f6
style packages fill:#f3e8ff,stroke:#9333ea
style Web fill:#3b82f6,color:#fff
style Admin fill:#3b82f6,color:#fff
style Mobile fill:#3b82f6,color:#fff
style UI fill:#9333ea,color:#fff
style API fill:#9333ea,color:#fff
style Utils fill:#9333ea,color:#fff
style Config fill:#9333ea,color:#fff
四、如何系统性地学习架构?
架构能力的提升无法一蹴而就,它需要理论知识的武装,更需要真实项目的历练。以下是我推荐的进阶路径和学习资料:
1. 建立通用架构思维(必读经典)
这些书籍虽然成书较早,但讲述的底层原则(SOLID、高内聚低耦合)至今依然适用:
- 《架构整洁之道》(Clean Architecture) - Robert C. Martin 著。入门必读,讲透了组件原则和架构边界。
- 《设计模式》(Design Patterns) - GoF。解决对象级别复用与扩展的圣经。
- 《领域驱动设计》(Domain-Driven Design) - Eric Evans 著。进阶读物,教你如何用业务语言为复杂系统建模。
2. 掌握现代架构模式
- 《软件架构:架构模式、特征及实践指南》 - 深入剖析了微服务、事件驱动、微内核等现代架构风格。
- Martin Fowler 的个人博客 (martinfowler.com) - 软件架构领域的风向标,微前端、BFF、CQRS 等模式的权威定义都来源于此。
3. 前端领域特定资源
- Patterns.dev - 一本极好的开源在线电子书,图文并茂地讲解了现代前端的设计模式和渲染模式(SSR/SSG/ISR 等)。
- 《前端架构:从入门到微前端》 - 黄峰达 著。国内少有的系统性梳理前端架构演进的书籍。
4. 最有效的方法:阅读顶级开源项目的架构文档
除了读书,阅读知名开源项目的源码和架构文档是提升最快的方式。
- 看看 React 是如何设计 Fiber 架构来解决渲染中断问题的;
- 看看 Vite 是如何通过插件化架构(微内核模式)实现极高扩展性的;
- 看看 NestJS 是如何将后端的依赖注入(DI)和控制反转(IoC)完美落地到 Node.js 中的。
结语:因地制宜的架构眼光
架构没有银弹。把复杂的领域驱动设计(DDD)用在一个简单的 CRUD 项目上,不仅不能解决问题,反而会带来灾难性的过度设计。
架构的核心原则是:架构要匹配项目的核心复杂度所在。CRUD 后台的核心是数据模型,高并发后台的核心是可用性,前端 SPA 的核心是状态管理,组件库的核心是复用性。
当你面对一个新项目时,能够准确识别出它的核心复杂度,并选择合适的架构思路和分析方法去拆解它------这种"因地制宜"的能力,正是区分"会写代码的工程师"和"优秀架构师"的核心所在。