系统架构:前端架构的本质与演进
核心要点(TL;DR)
- 前端架构的本质是组织代码、应对变化与平衡性能/效率/可维护性,框架只是工具而非架构本身。
- MVC/MVP/MVVM 的核心都是分离界面与业务逻辑,MVVM 通过响应式系统实现 View 与 ViewModel 自动同步。
- BFF 在前后端之间提供面向前端的适配层,负责接口聚合、数据适配、鉴权与缓存。
- DDD 思想可帮助前端按领域拆分模块、定义领域模型并通过防腐层隔离后端 DTO 变化。
- 分层架构、模块化、依赖倒置与架构决策记录(ADR)是控制复杂度与可维护性的关键实践。
- 现代前端架构模式包括:微内核、插件化、低代码/搭建、Server-Driven UI、事件驱动/CQRS、六边形/整洁架构等。
- 架构模式选型应基于业务场景、团队能力、可维护性和演进成本,使用决策树和 ADR 记录决策过程。
学习时长与前置知识
- 建议学习时长:4-6 周(每周投入 6-8 小时)
- 前置知识:前端工程化、框架原理、BFF、设计模式基础
一、前端架构到底是什么?
如果把一个 Web 应用比作一座城市,那么 HTML/CSS/JavaScript 就是砖瓦和钢筋,而前端架构则是这座城市的规划图:道路如何连接、区域如何划分、水电如何布线、未来如何扩建。没有好的架构,城市会陷入“摊大饼”式的混乱;没有好的前端架构,项目会在需求迭代中逐渐失控。
前端架构的本质,可以概括为三句话:
- 组织代码的结构:让代码有清晰的边界,便于多人协作和长期维护。
- 应对变化的策略:业务在变、技术在变、团队在变,好的架构让变化成本最低。
- 平衡的艺术:在性能、可维护性、开发效率、可扩展性之间找到最佳平衡点。
很多初学者把“会用 Vue/React/Angular”等同于“懂前端架构”,这是一个巨大误区。框架只是工具,架构是思想和组织方式。就像会用 Photoshop 不等于会设计建筑。
二、前端架构的演进:从“脚本时代”到“工程化时代”
1. 混沌期:jQuery 一统天下(2006-2013)
这个时代的前端代码通常长这样:
$(document).ready(function () {
$('#btn').click(function () {
$.ajax('/api/user', {
success: function (data) {
$('#name').text(data.name);
}
});
});
});代码按页面组织,业务逻辑、DOM 操作、网络请求混在一起。项目小的时候很爽,大了之后就是“意大利面条”。
痛点:全局变量污染、代码复用困难、测试困难、协作困难。
2. 模块化时代:RequireJS / SeaJS / AMD / CommonJS
为了解决代码组织问题,社区提出了模块化规范。代码被拆成一个个模块:
// utils.js
define(function () {
return {
formatDate: function (date) { /* ... */ }
};
});这相当于把城市从“大院混杂”改成了“小区制”,每个小区有明确边界。
3. 组件化时代:MV* 框架兴起
React、Vue、Angular 把界面拆成组件。一个组件包含自己的结构、样式、逻辑:
function UserCard({ user }) {
return (
<div className="user-card">
<img src={user.avatar} />
<h3>{user.name}</h3>
</div>
);
}组件化让 UI 开发从“雕刻整幅画”变成“拼装乐高积木”。
4. 工程化与架构化时代
现代前端不仅要写代码,还要考虑:
- 构建与部署:Webpack/Vite/Rollup
- 状态管理:Redux/Vuex/Pinia/Zustand
- 路由与导航:React Router/Vue Router
- 测试与质量:Jest/Vitest/Cypress
- 性能与体验:代码分割、懒加载、SSR/SSG
- 跨团队协作:微前端、Monorepo
前端架构已经从一个“写页面的岗位”演变为“复杂客户端系统的架构设计”。
三、MVC / MVP / MVVM 在前端的体现
这三种模式的核心目标一致:把界面(View)和业务逻辑(Model)分开,只是分法不同。
1. MVC:Model-View-Controller
经典分层:
用户操作 → Controller → 更新 Model → View 刷新在前端早期,Backbone.js 是 MVC 的代表:
// Model
var User = Backbone.Model.extend({
defaults: { name: '' }
});
// View
var UserView = Backbone.View.extend({
render: function () {
this.$el.html('<p>' + this.model.get('name') + '</p>');
return this;
}
});
// Controller 通常由路由承担
var Router = Backbone.Router.extend({
routes: { 'user/:id': 'showUser' },
showUser: function (id) { /* ... */ }
});生活化比喻:MVC 像餐厅。Model 是后厨(数据和业务),View 是菜单和摆盘(界面),Controller 是服务员(接收顾客指令并协调后厨与摆盘)。
常见误区:很多人把 React + Redux 叫 MVC,其实 Redux 更像 Flux 架构,不是严格 MVC。
2. MVP:Model-View-Presenter
Presenter 是 View 和 Model 之间的中间人。View 只负责显示,所有逻辑都在 Presenter:
View ↔ Presenter ↔ Model在前端,MVP 常见于需要高度测试隔离的场景,比如原生 Android 开发转前端的团队。
优点:View 极其单薄,容易单元测试。 缺点:Presenter 容易变成“上帝类”。
3. MVVM:Model-View-ViewModel
MVVM 是前端最流行的模式。Vue 和 Angular 都是典型代表:
View <-> ViewModel <-> Model
(双向绑定)<!-- View -->
<div id="app">
<p>{{ message }}</p>
<button @click="reverseMessage">反转</button>
</div>// ViewModel
new Vue({
el: '#app',
data: {
message: 'Hello MVVM'
},
methods: {
reverseMessage() {
this.message = this.message.split('').reverse().join('');
}
}
});本质:通过响应式系统或脏检查,让 View 和 ViewModel 自动同步。
生活化比喻:MVVM 像智能音箱。你对音箱说“播放音乐”(View 层操作),音箱自己调用音乐服务(ViewModel),播放歌曲(Model 更新),整个过程你不需要知道背后调用了哪些 API。
对比总结
| 模式 | 核心思想 | 前端代表 | 适合场景 |
|---|---|---|---|
| MVC | Controller 协调 M 和 V | Backbone | 中小型项目 |
| MVP | Presenter 承担所有逻辑 | 自定义框架 | 需要强测试隔离 |
| MVVM | 双向绑定自动同步 | Vue、Angular | 数据驱动 UI |
React 严格来说不是 MVVM,它是“函数式 UI = f(state)”,但通过 useState/useEffect 也能模拟出类似 MVVM 的开发体验。
四、BFF:Backend for Frontend 架构
1. 为什么需要 BFF?
假设后端有一个“订单服务”,返回的数据结构是通用的:
{
"orderId": "123",
"userId": "456",
"items": [...],
"createdAt": "2023-01-01T00:00:00Z",
"statusCode": 1
}但前端需要:
- PC 端:展示完整订单详情
- H5 端:只展示关键信息
- 小程序:需要额外字段适配其组件规范
如果所有端都直接调用同一个后端 API,后端会被迫为不同端定制接口,导致耦合严重。
2. BFF 的解决方案
在前后端之间加一层“面向前端的后端”:
PC Web → PC-BFF →
H5 → H5-BFF → 通用后端服务(订单/用户/支付)
小程序 → 小程序-BFF →BFF 层负责:
- 接口聚合:一次请求聚合多个后端服务
- 数据适配:把后端数据转成前端需要的格式
- 鉴权与限流:统一处理登录态、权限、流控
- 缓存:针对前端场景做缓存策略
// H5-BFF /api/order-summary
app.get('/api/order-summary', async (req, res) => {
const order = await orderService.get(req.query.id);
const user = await userService.get(order.userId);
res.json({
title: `${user.name} 的订单`,
totalCount: order.items.length,
totalPrice: order.items.reduce((sum, item) => sum + item.price, 0),
statusText: STATUS_MAP[order.statusCode]
});
});3. BFF 的常见误区
- 误区 1:BFF 只是“API 转发”。错,它的价值在于聚合和适配。
- 误区 2:一个前端团队一个 BFF。错,应该按业务领域或端来划分。
- 误区 3:所有请求都走 BFF。错,通用、稳定的接口可以直接调用。
生活化比喻:BFF 像餐厅的点餐台。后厨(通用后端)只负责做菜,顾客(不同端)需求不同,点餐台(BFF)负责把顾客需求汇总、翻译成后厨能理解的订单。
五、DDD:领域驱动设计在前端的应用
DDD(Domain-Driven Design)原本用于后端复杂业务系统,但前端同样可以借鉴其思想。
1. DDD 的核心理念
- 领域(Domain):业务问题空间,比如电商中的“订单领域”“库存领域”。
- 实体(Entity):有唯一标识的对象,如
Order、User。 - 值对象(Value Object):无唯一标识,如
Money、Address。 - 聚合(Aggregate):一组相关对象的集合,由聚合根统一对外。
- 限界上下文(Bounded Context):明确业务边界,不同上下文用不同模型。
2. DDD 在前端的落地
前端通常不是业务逻辑的核心载体,但可以在以下方面应用 DDD:
(1)按领域拆分模块
不要按技术类型拆分(components/services/utils),而是按业务领域拆分:
src/
order/
components/
services/
stores/
types/
utils/
product/
components/
services/
stores/
types/
utils/
user/
...这种结构让“订单相关的所有东西”都在 order/ 目录下,便于定位和维护。
(2)定义领域模型
// domain/order.ts
export class Order {
constructor(
public id: string,
public items: OrderItem[],
public status: OrderStatus
) {}
get totalPrice(): number {
return this.items.reduce((sum, item) => sum + item.subtotal, 0);
}
canCancel(): boolean {
return this.status === OrderStatus.PENDING;
}
}
export class OrderItem {
constructor(
public productId: string,
public quantity: number,
public unitPrice: number
) {}
get subtotal(): number {
return this.quantity * this.unitPrice;
}
}(3)防腐层(Anti-Corruption Layer)
当后端接口设计不符合前端领域模型时,用防腐层做转换:
// adapters/orderAdapter.ts
export function adaptOrderFromDTO(dto: OrderDTO): Order {
return new Order(
dto.order_id,
dto.items.map(item => new OrderItem(item.product_id, item.qty, item.price)),
STATUS_MAP[dto.status_code]
);
}这样,业务代码只依赖 Order 领域模型,不依赖后端 DTO 结构。当后端接口变化时,只需改防腐层。
生活化比喻:DDD 像医院的分科室。内科、外科、儿科各自有专业术语和流程(限界上下文),但对外提供统一的挂号入口(防腐层)。患者不需要懂医学术语,只需要按症状挂号。
3. 前端 DDD 的边界
前端不要过度设计。DDD 适合复杂业务系统,简单 CRUD 项目用 DDD 反而增加成本。判断标准是:业务规则是否复杂?是否有多个团队在同一代码库协作?模型是否频繁变化?
六、分层架构、模块化、依赖管理与可扩展性
1. 分层架构
经典分层:
表现层(Presentation Layer)
↓
业务逻辑层(Business Logic Layer)
↓
数据访问层(Data Access Layer)
↓
外部服务(API / Storage)在前端中,可以对应为:
UI 组件层
↓
状态/业务逻辑层(Store / Services)
↓
数据访问层(API Client / Adapter)
↓
后端 API关键原则:上层可以依赖下层,下层不能依赖上层。
2. 模块化
模块化的目标:高内聚、低耦合。
- 高内聚:相关代码放在一起。
- 低耦合:模块之间通过明确接口交互,不依赖内部实现。
// 好的接口:只暴露必要的东西
export function useOrder() { /* ... */ }
export type { Order } from './types';
// 坏的接口:暴露内部实现细节
export { internalFetchOrder } from './api';
export { orderReducer } from './reducer';3. 依赖管理
前端依赖管理不仅是 npm 包,还包括模块之间的依赖关系。
依赖倒置原则(DIP):高层模块不应该依赖低层模块的具体实现,而应该依赖抽象。
// 抽象接口
interface Logger {
log(message: string): void;
}
// 具体实现可以替换
class ConsoleLogger implements Logger { /* ... */ }
class SentryLogger implements Logger { /* ... */ }
// 业务代码依赖 Logger 接口,不依赖具体实现
class OrderService {
constructor(private logger: Logger) {}
}生活化比喻:依赖倒置像插头插座。电器(高层模块)依赖插座标准(抽象接口),不依赖发电厂(具体实现)。你可以换发电厂、换电池,只要插座标准不变。
4. 可扩展性设计
可扩展性不是“预留一切”,而是“在不修改现有代码的前提下增加新功能”。这通常依赖:
- 插件化架构:通过约定接口让功能可插拔
- 策略模式:把变化的行为封装成策略
- 事件总线 / 发布订阅:解耦模块间通信
// 插件化示例
const plugins = [];
export function registerPlugin(plugin) {
plugins.push(plugin);
}
export function onRouteChange(route) {
plugins.forEach(plugin => plugin.onRouteChange?.(route));
}七、现代前端架构模式
传统 MVC/MVVM、BFF、DDD 是前端架构的基础,但随着业务复杂度提升,更多现代架构模式涌现。掌握这些模式,能让我们在特定场景下做出更优的架构决策。
1. 微内核架构(Microkernel / Plugin Architecture)
核心思想
将系统拆分为一个最小核心(Kernel)和一组可插拔的插件(Plugins)。核心负责生命周期管理、模块通信和基础服务;插件负责具体业务功能。
┌─────────────────────────────────────┐
│ Application │
├─────────────────────────────────────┤
│ Plugin A │ Plugin B │ Plugin C │
├─────────────────────────────────────┤
│ Plugin Manager │
├─────────────────────────────────────┤
│ Kernel(生命周期、事件总线、依赖注入)│
└─────────────────────────────────────┘前端应用场景
- IDE / 低代码平台:VS Code、Figma 插件生态。
- 企业级中台:不同业务线以插件形式接入统一基座。
- 微前端的一种实现方式:基座作为 Kernel,子应用作为 Plugin。
简单实现示例
// kernel.ts
class Kernel {
private plugins = new Map<string, Plugin>();
private eventBus = new EventTarget();
register(name: string, plugin: Plugin) {
this.plugins.set(name, plugin);
plugin.activate(this.eventBus);
}
unregister(name: string) {
const plugin = this.plugins.get(name);
plugin?.deactivate();
this.plugins.delete(name);
}
}
interface Plugin {
activate(eventBus: EventTarget): void;
deactivate(): void;
}优缺点
| 优点 | 缺点 |
|---|---|
| 功能可独立开发、部署、卸载 | 插件接口设计难度大 |
| 系统核心稳定,扩展灵活 | 插件间通信和依赖管理复杂 |
| 适合多团队协作 | 需要完善的安全隔离机制 |
2. 插件化架构的进阶:模块联邦与动态加载
除了自己实现插件系统,现代前端还可以借助:
- Module Federation:运行时共享和加载远程模块。
- ESM Dynamic Import:按需加载业务模块。
- Web Components:用标准组件封装插件 UI。
// 动态加载远程模块作为插件
async function loadPlugin(url: string) {
const module = await import(/* @vite-ignore */ url);
return module.default;
}3. 低代码 / 搭建体系(Low-Code / Schema-Driven UI)
核心思想
用配置(Schema)描述界面,而不是直接写代码。渲染引擎解析 Schema 并生成真实 UI。
用户拖拽/自然语言 → 生成 Schema → 渲染引擎 → 真实页面典型 Schema 示例
{
"type": "Page",
"props": { "title": "销售数据看板" },
"children": [
{
"type": "Chart",
"props": { "chartType": "line", "dataSource": "salesTrend" }
},
{
"type": "Table",
"props": { "columns": ["商品", "销量", "金额"], "dataSource": "topProducts" }
}
]
}前端架构要点
| 层面 | 职责 | 关键技术 |
|---|---|---|
| 物料层 | 组件库、图表库、模板 | React/Vue 组件 |
| 协议层 | Schema 定义、版本管理 | JSON Schema、Proprietary DSL |
| 渲染层 | 解析 Schema 并渲染 | 递归渲染器、动态组件映射 |
| 数据层 | 数据源绑定、状态管理 | 变量引擎、API 编排 |
| 权限层 | 组件级/字段级权限 | 权限表达式 |
适用场景
- 运营后台、数据看板、活动页搭建。
- 表单、列表、报表等高度模式化的页面。
- 需要业务人员自助配置的场景。
4. Server-Driven UI(SDUI)
核心思想
服务端不仅提供数据,还提供界面结构。客户端根据服务端下发的 UI 描述动态渲染。
传统方式:服务端返回数据,前端决定如何展示。
SDUI:服务端返回“数据 + 界面结构”,前端只负责渲染。典型应用场景
- 电商首页:不同活动、不同用户看到不同模块组合。
- 金融 App:合规要求下,页面结构需服务端动态控制。
- A/B 测试:服务端下发不同 UI 版本,无需发版即可实验。
与低代码的关系
| 维度 | 低代码平台 | SDUI |
|---|---|---|
| 控制方 | 运营/产品经理通过编辑器配置 | 服务端根据业务逻辑动态下发 |
| 灵活性 | 高(可拖拽设计) | 中(受限于预定义组件) |
| 实时性 | 配置后发布生效 | 请求时即时生效 |
| 适用 | 后台系统、活动页 | C 端动态页面、首页、卡片流 |
前端实现要点
- 组件映射表:将服务端组件类型映射到本地组件。
- 版本兼容:服务端 Schema 升级时,旧版本客户端能兼容。
- 降级策略:未知组件类型时展示占位或跳过。
- 性能优化:对常用 Schema 做缓存和预编译。
5. 事件驱动架构(Event-Driven Architecture)
核心思想
模块之间不直接调用,而是通过事件总线发布和订阅事件来通信。
// 发布事件
eventBus.emit('order:created', { orderId: '123' });
// 订阅事件
eventBus.on('order:created', ({ orderId }) => {
analytics.track('purchase', { orderId });
});前端应用场景
- 跨模块通信:订单模块创建订单后,通知购物车、优惠券、埋点模块。
- Undo/Redo:用事件溯源实现操作历史。
- 复杂 UI 流程:表单校验、审批流、多步骤向导。
与 CQRS / 事件溯源的关系
| 模式 | 核心思想 | 前端应用 |
|---|---|---|
| 事件驱动 | 通过事件解耦模块 | 跨模块通信、埋点 |
| CQRS | 读模型和写模型分离 | 复杂列表/详情页的状态优化 |
| 事件溯源 | 用事件序列表示状态 | Undo/Redo、操作回放 |
// 事件溯源示例:用命令和事件管理状态
interface Command {
type: 'ADD_TODO' | 'REMOVE_TODO';
payload: any;
}
interface Event {
type: 'TODO_ADDED' | 'TODO_REMOVED';
payload: any;
}
function reducer(events: Event[], command: Command): Event[] {
switch (command.type) {
case 'ADD_TODO':
return [...events, { type: 'TODO_ADDED', payload: command.payload }];
// ...
}
}6. 六边形架构 / 整洁架构在前端
核心思想
业务逻辑独立于框架、UI 和外部服务。通过端口(Port)和适配器(Adapter)与外部交互。
┌─────────────┐
│ UI │
└──────┬──────┘
│ 适配器
┌──────▼──────┐
│ 应用层/业务 │
│ 逻辑 │
└──────┬──────┘
│ 适配器
┌──────▼──────┐
│ 外部服务 │
│ (API/Storage)│
└─────────────┘前端落地示例
// domain/todo.ts —— 核心业务逻辑,不依赖任何框架
export class Todo {
constructor(public id: string, public title: string, public completed = false) {}
toggle() {
this.completed = !this.completed;
}
}
// ports/todoRepository.ts —— 抽象端口
export interface TodoRepository {
findAll(): Promise<Todo[]>;
save(todo: Todo): Promise<void>;
}
// adapters/apiTodoRepository.ts —— 具体适配器
export class ApiTodoRepository implements TodoRepository {
async findAll() {
const dtos = await fetch('/api/todos').then(r => r.json());
return dtos.map(dto => new Todo(dto.id, dto.title, dto.completed));
}
// ...
}
// UI 层只依赖应用层和端口,不依赖具体适配器
function TodoList({ repository }: { repository: TodoRepository }) {
// ...
}价值
- 可测试性:业务逻辑可以脱离浏览器和 API 单独测试。
- 可替换性:今天用 REST API,明天可以换成 GraphQL 或本地缓存,业务逻辑不变。
- 长期可维护:框架更新换代时,领域层代码可以复用。
7. Monorepo 组织方案
Monorepo 不仅是代码托管方式,也是一种架构组织方式。不同组织方式对应不同的团队协作模式:
| 组织方式 | 结构 | 适用场景 |
|---|---|---|
| 按领域划分 | packages/order、packages/product | 业务复杂、团队按领域负责 |
| 按产品划分 | apps/web、apps/admin、apps/mobile | 多端产品、团队按产品负责 |
| 按技术栈划分 | packages/ui、packages/utils、packages/api | 技术平台型团队 |
| 混合划分 | apps/ + packages/ | 中大型团队,兼顾产品和技术复用 |
选择依据
- 团队规模与组织结构(康威定律)。
- 代码复用需求。
- 构建和部署复杂度。
- 发布节奏是否一致。
8. 架构模式选型决策树
面对一个具体业务场景,如何快速选择合适的架构模式?可以按以下问题逐步判断:
1. 业务是否高度模式化、需要频繁配置?
├─ 是 → 低代码/搭建体系
└─ 否 → 继续判断
2. 页面结构是否需要服务端动态控制、无需发版即可调整?
├─ 是 → Server-Driven UI
└─ 否 → 继续判断
3. 是否需要多个独立团队/业务线在一个系统中并行开发?
├─ 是 → 微内核/插件化 或 微前端
└─ 否 → 继续判断
4. 业务规则是否复杂、需要长期演进和大量测试?
├─ 是 → DDD + 六边形/整洁架构
└─ 否 → 继续判断
5. 模块间通信是否复杂、需要解耦和可追溯?
├─ 是 → 事件驱动/CQRS/事件溯源
└─ 否 → 经典分层架构 + 模块化架构选型评分卡
| 维度 | 权重 | 说明 |
|---|---|---|
| 业务契合度 | 30% | 是否能自然表达业务结构 |
| 团队能力 | 20% | 团队是否具备实施和维护能力 |
| 可维护性 | 20% | 长期迭代成本 |
| 性能影响 | 15% | 对首屏、交互性能的影响 |
| 生态成熟度 | 15% | 工具链、社区、案例丰富度 |
建议将选型过程和评分结果记录到 ADR 中,便于后续回顾。
八、常见误区与最佳实践
误区 1:架构越复杂越好
很多团队看到大厂的架构就照搬。其实,架构应该匹配团队规模和业务复杂度。小团队用微服务、微前端,就像骑自行车开 NASCAR,反而拖累效率。
误区 2:只关注技术,不关注组织
康威定律说:“设计系统的组织,其产生的设计等价于组织间的沟通结构。” 好的架构必须匹配团队结构。如果团队按业务领域划分,代码也应该按领域划分。
误区 3:过度抽象
抽象是为了应对变化,但过度抽象会增加理解成本。原则是:先简单,后复杂;先复制,后抽象。不要一开始就为“未来可能的变化”写一堆接口。
最佳实践
- 单一职责原则:一个模块只做一件事。
- 开闭原则:对扩展开放,对修改关闭。
- 依赖倒置:依赖抽象,不依赖具体实现。
- 显式优于隐式:配置和约定要清晰可追踪。
- 可测试性驱动设计:如果一个模块难以测试,通常意味着架构有问题。
- 持续重构:架构不是一次性设计出来的,是演进出来的。
- 用决策树和评分卡辅助架构选型:避免盲目跟风,把选型过程记录为 ADR。
- 根据业务场景选择现代架构模式:低代码、SDUI、微内核、事件驱动、整洁架构各有适用场景。
九、架构决策记录与可维护性
1. 为什么需要记录架构决策?
很多团队在架构演进中会遇到一个经典问题:新加入的同事问“为什么当初要这样设计?”时,没有人能回答清楚。 architecture decision record(ADR)就是用来解决这个问题的。
ADR 是一份简短文档,记录某个重要的架构决策:
- 当时面临什么问题?
- 有哪些备选方案?
- 为什么选择了当前方案?
- 带来了哪些 trade-off?
# ADR-001:采用 BFF 架构
## 背景
前后端直接交互导致多端接口耦合严重。
## 备选方案
1. 后端为每端单独提供接口:加重后端负担。
2. 前端自行聚合:逻辑分散,重复请求多。
3. 引入 BFF:统一适配层。
## 决策
采用方案 3,按端建立 BFF 服务。
## Trade-off
增加了服务维护成本,但降低了前后端耦合。记录 ADR 不是为了形式,而是让架构决策可追溯、可讨论、可改进。
2. 架构的可维护性如何度量?
可维护性没有统一公式,但可以通过以下指标观察:
- 变更成本:新增一个功能需要改多少文件?
- Bug 回归率:改 A 功能是否经常影响 B 功能?
- 新人上手时间:新成员多久能独立开发?
- 测试覆盖率:核心路径是否有测试保护?
- 代码耦合度:模块间依赖是否清晰?
一个可维护的系统,应该让“小改动”真的只需要“小改动”。
十、前端与后端的协作边界
前端架构不是孤立的,它必须与后端架构协同。常见的协作边界问题包括:
- 接口设计:谁定义接口?RESTful 还是 GraphQL?是否需要 BFF?
- 数据模型:前后端是否使用同一套领域语言?
- 错误处理:后端返回什么状态码?错误信息如何展示?
- 鉴权与权限:登录态由谁维护?权限如何下发?
- 缓存策略:哪些数据可以缓存?缓存多久?
解决这些问题的关键是:早期对齐、文档化、契约化。
推荐做法:
- 前后端共同维护 API 文档(如 Swagger、OpenAPI)。
- 关键接口做契约测试。
- 建立联合评审机制,重大变更需双方确认。
- 使用 BFF 或防腐层隔离变化。
生活化比喻:前后端像餐厅的前厅和后厨。前厅(前端)负责接待顾客、展示菜品,后厨(后端)负责做菜。双方需要通过菜单(API)和点单系统(BFF)协作,否则上错菜、等太久都会让顾客不满。
十一、总结
前端架构不是炫技,而是为了解决复杂系统在多人协作、快速迭代、长期演进中的问题。从 MVC 到 MVVM,从模块化到组件化,从 BFF 到 DDD,背后贯穿的是同一个思想:把变化隔离、把职责分离、把复杂度控制在可理解的范围内。
作为前端架构师,你需要同时具备三种视角:
- 工程师视角:代码如何组织、如何测试、如何部署。
- 产品经理视角:业务如何拆分、需求如何落地、用户体验如何保障。
- 组织视角:团队如何协作、边界如何划分、知识如何传承。
只有这三种视角结合,才能设计出既优雅又实用的前端架构。
领域编号:A01 系统架构设计
最后更新:2026-06-24