
这个模型由 Philippe Kruchten 在 1995 年提出。它的本质含义是:没有一种单一的视图能够涵盖系统的方方面面。不同的利益相关者(Stakeholders)关心的是不同的东西。
-
业务方关心功能(能不能用?)。
-
开发关心代码结构(好不好写?)。
-
运维关心部署和硬件(稳不稳定?)。
-
用户关心操作流程(顺不顺畅?)。
架构师的职责,就是通过这 5 个视角,把这些“鸡同鸭讲”的需求统一成一个完整的系统设计。
为了让你更好理解,我将这个经典的后端/通用架构概念,完整“翻译”成前端架构师的视角。
1. 场景视图 (Scenarios / Use Cases View) —— “+1” 的那个核心
本质:系统的灵魂,它驱动了其他 4 个视图。 这是架构设计的起点。如果不知道系统要干什么,设计就无从谈起。
graph LR
%% 样式定义
classDef icon fill:#fff9c4,stroke:#fbc02d,stroke-width:3px,color:#333,rx:50,ry:50;
classDef step fill:#fff,stroke:#fbc02d,stroke-width:2px,color:#333,rx:10,ry:10;
classDef note fill:#fffde7,stroke:none,color:#666;
%% 左侧:核心概念
User((用户<br/>User)):::icon
%% 右侧:关键链路 (Critical Journey)
subgraph Journey [关键链路: 秒杀场景]
direction LR
Step1[进入详情页]:::step --> Step2[抢购点击]:::step
Step2 --> Step3[排队等待]:::step
Step3 --> Step4[创建订单]:::step
Step4 --> Step5[支付成功]:::step
end
User ==> Step1
%% 架构决策点
Note1(架构决策点:<br/>CDN缓存, 骨架屏):::note -.-> Step1
Note2(架构决策点:<br/>高并发防抖, 乐观UI):::note -.-> Step2
2. 逻辑视图 (Logical View) —— “功能是怎么组织的?”
本质:系统的抽象模型。 这是最接近业务逻辑的一层,忽略具体的代码文件,只看概念。
-
关注点:系统有哪些“部件”?它们之间是什么关系?
-
谁看:开发人员、业务分析师。
-
前端架构视角:
-
组件模型:原子组件 vs 业务组件。
-
领域模型:User, Product, Order 等实体定义(TypeScript Interface 定义)。
-
状态管理设计:全局状态(Redux/Pinia)存什么?局部状态存什么?模块间如何通信?
-
例子:画一张图,展示
OrderList 组件依赖 UserStore 和 API Service,而不关心它们具体写在哪个文件里。
graph LR
%% 样式定义
classDef icon fill:#e1f5fe,stroke:#039be5,stroke-width:3px,color:#333,rx:50,ry:50;
classDef layer fill:#fff,stroke:#039be5,stroke-width:2px,color:#333,rx:5,ry:5;
classDef rel stroke:#90caf9,stroke-width:2px,stroke-dasharray: 5 5;
%% 左侧
Logic((抽象<br/>逻辑)):::icon
%% 右侧:分层架构
subgraph LayerSystem [前端逻辑分层]
direction TB
UI[<b>表现层 UI Layer</b><br/>Button, Layout, Page]:::layer
Adapter[<b>适配层 Adapter</b><br/>Hooks, Presenters]:::layer
Domain[<b>领域层 Domain</b><br/>UserEntity, CartModel]:::layer
Infra[<b>基础层 Infra</b><br/>Axios, Storage, Logger]:::layer
end
Logic ==> UI
%% 依赖关系 (单向依赖是架构的关键)
UI --> Adapter
Adapter --> Domain
Adapter --> Infra
3. 开发视图 (Development / Implementation View) —— “代码是怎么写的?”
本质:系统的静态组织结构。 这是程序员每天面对的 IDE 里的样子。
-
关注点:文件目录怎么分?用什么框架?依赖怎么管?
-
谁看:开发人员、构建工程师。
-
前端架构视角:
-
工程化结构:Monorepo (Nx/Turborepo) 还是 Multirepo?
-
目录规范:
src/components, src/hooks, src/utils 怎么归类?
-
依赖管理:
package.json 里的依赖,公共库(Shared Library)如何抽取?
-
构建工具:Vite/Webpack 配置,分包策略(Chunking)。
-
例子:决定把所有的 API 请求封装在
@api 目录下,并禁止组件直接调用 axios,这就是开发视图的约束。
graph LR
%% 样式定义
classDef icon fill:#f3e5f5,stroke:#8e24aa,stroke-width:3px,color:#333,rx:50,ry:50;
classDef file fill:#fff,stroke:#8e24aa,stroke-width:2px,color:#333,rx:2,ry:2;
classDef tool fill:#f3e5f5,stroke:#8e24aa,stroke-width:1px,color:#333,stroke-dasharray: 5 5;
%% 左侧
Dev((工程<br/>代码)):::icon
%% 右侧:目录与工具
subgraph ProjectStructure [工程化与目录规范]
direction TB
subgraph Mono [Monorepo 仓库]
Pkg1[packages/ui-lib]:::file
Pkg2[apps/web-client]:::file
Config[tsconfig.json]:::file
end
subgraph Toolchain [构建工具链]
Vite(Vite / Webpack):::tool
Lint(ESLint / Prettier):::tool
end
end
Dev ==> Mono
Mono -.-> Toolchain
4. 处理视图 (Process View) —— “系统是怎么运行的?”
本质:系统的动态行为、并发与性能。 对于前端来说,这是最容易被忽视,但最考验功底的一层。
-
关注点:性能、并发、同步/异步、时序。
-
谁看:系统集成人员、高级开发。
-
前端架构视角:
-
异步流控:接口竞态问题(Race Condition)怎么处理?Promise 并发限制。
-
生命周期:SSR(服务端渲染)的数据注水(Hydration)流程是怎样的?
-
性能优化:Web Worker 处理复杂计算,避免阻塞主线程(UI 线程)。
-
通信机制:WebSocket 怎么保持心跳?跨 Tab 通信(SharedWorker/LocalStorage)怎么做?
-
例子:设计一个“大文件分片上传”的功能,你需要画出切片、上传、暂停、续传的时序图,这属于处理视图。
graph LR
%% 样式定义
classDef icon fill:#e8f5e9,stroke:#43a047,stroke-width:3px,color:#333,rx:50,ry:50;
classDef action fill:#fff,stroke:#43a047,stroke-width:2px,color:#333,rx:10,ry:10;
classDef async fill:#c8e6c9,stroke:none,color:#333,rx:5,ry:5;
%% 左侧
Run((运行<br/>时序)):::icon
%% 右侧:大文件上传时序
subgraph AsyncProcess [大文件分片上传流程]
direction TB
Start[开始上传]:::action --> Check{检查文件}:::action
Check -->|太大| Slice[Web Worker<br/>进行切片计算]:::async
Slice --> Upload[并发上传切片<br/>Promise.all]:::action
Upload --> Pause{网络中断?}:::action
Pause -->|是| Wait[暂停 & 记录断点]:::async
Pause -->|否| Finish[合并请求]:::action
end
Run ==> Start
5. 物理视图 (Physical / Deployment View) —— “代码跑在哪里?”
本质:软件到硬件的映射。 前端代码最终是要通过网络传输并运行在用户设备上的。
-
关注点:部署、网络拓扑、硬件限制。
-
谁看:运维工程师 (DevOps)、系统管理员。
-
前端架构视角:
-
部署策略:静态资源上 CDN,Nginx 反向代理配置。
-
运行环境:BFF 层运行在 Docker 容器里;前端代码运行在用户的 Chrome/Safari 里(考虑兼容性)。
-
网络环境:弱网情况下如何降级?离线包(PWA)策略。
-
多端适配:同一套代码是跑在 PC 浏览器,还是内嵌在 App 的 WebView 里?
-
例子:决定使用“灰度发布”系统,将新版本的 JS 文件只推给 10% 的用户,这属于物理视图的范畴。
graph LR
%% 样式定义
classDef icon fill:#fff3e0,stroke:#fb8c00,stroke-width:3px,color:#333,rx:50,ry:50;
classDef device fill:#fff,stroke:#fb8c00,stroke-width:2px,color:#333,rx:5,ry:5;
classDef net fill:#ffe0b2,stroke:none,color:#333,rx:20,ry:20;
%% 左侧
Deploy((部署<br/>环境)):::icon
%% 右侧:部署拓扑
subgraph NetworkTopology [资源分发与运行环境]
direction LR
subgraph Cloud [云端设施]
CICD[CI/CD 构建产物]:::device --> OSS[对象存储]:::device
OSS --> CDN((CDN 边缘节点)):::net
end
subgraph Client [用户终端]
CDN --> Browser[PC 浏览器]:::device
CDN --> Mobile[手机 WebView]:::device
CDN --> Hybrid[小程序]:::device
end
end
Deploy ==> Cloud
总结:软件开发的本质是什么?
通过 4+1 视图,我们可以得出软件开发的本质:
-
控制复杂度 (Managing Complexity) : 如果没有分层和视图,系统就是一团乱麻。4+1 试图把复杂问题拆解成 5 个维度分别解决。
-
沟通与妥协 (Communication & Trade-offs) : 架构不是追求“完美的代码”,而是平衡各方利益。
- 为了物理视图的加载速度(上 CDN),可能要牺牲开发视图的便利性(复杂的构建流程)。
- 为了处理视图的流畅度(虚拟列表),可能要增加逻辑视图的复杂度。
此时此刻,你可以做的 Next Step
作为想转型的架构师,不要只写代码,开始写文档。
你可以挑选你当前负责的一个复杂模块,尝试写一份简易版的技术设计文档 (TDD) ,强制自己包含以下三点:
-
逻辑图:用方块图画出组件和数据流。
-
处理图:用时序图画出关键的用户交互流程。
-
部署说明:说明代码构建后怎么发布,有没有缓存策略。