当你第一次写出能跑通的 CRUD(Create、Read、Update、Delete)接口时,那一刻你觉得,"我就是后端之神"。
直到某天,产品经理说:
"能不能加个流程审批?再加个缓存?要不再加个多租户?"
你皱眉,翻开一堆 service 和路由文件,发现逻辑像好几个螺旋藻打成的奶昔。
这时,你需要的不只是多打几行代码,而是迈向工程师的下一个台阶:架构思维。
一、从"能跑"到"能扩展"
写 CRUD,关键是接口能对数据库"有回应";做架构,重心变成人和机器的可维护性。
著名原则一句话总结:
"代码是写给人看的,只是恰好能被机器执行。"
于是我们要开始塑造结构,而非堆叠逻辑。
在企业级或中大型 Web 项目里,一种常见又高效的分层方式是:
- 控制层 Controller:接收请求、输出响应。
- 服务层 Service:业务逻辑的核心。
- 数据层 Repository:直接操作数据库或存储系统。
这三层的协作,像建筑工程里分工精细的施工队:
- Controller 是门面接待员;
- Service 是工头组织施工;
- Repository 是工地上的搬砖队。
二、控制层(Controller)------优雅的门面
Controller 层的职责是"接前端的请求,回前端的结果"。
它不做决定,只传递和协调。
Controller 的哲学
"不思考,不计算,只转发。"
它要保证输入验证、安全过滤、访问授权三座防线,然后把决策权交给业务层。
示例
javascript
// controllers/userController.js
import userService from "../services/userService.js";
export async function createUser(req, res) {
try {
const result = await userService.registerUser(req.body);
res.status(201).json(result);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
🌟 要点 :Controller 不要直接碰数据库,也不要藏着逻辑判断。
否则你很快会写出一份"逻辑蛋糕":每层都糊成一坨。
三、服务层(Service)------架构的灵魂
Service 层才是业务大脑,它决定了"流程规则、权限逻辑、系统行为"。
Controller 只是短暂的接待,真正的故事都在这里讲。
Service 的职责
- 组合不同仓储逻辑(Repository)
- 执行业务规则或计算
- 调用外部接口或其他服务
示例
javascript
// services/userService.js
import userRepository from "../repositories/userRepository.js";
async function registerUser(data) {
if (!data.email.includes("@")) {
throw new Error("Invalid email");
}
// 检查重复用户
const existing = await userRepository.findByEmail(data.email);
if (existing) {
throw new Error("User already exists");
}
// 业务逻辑:注册用户并发欢迎邮件
const newUser = await userRepository.create(data);
sendWelcomeEmail(newUser.email);
return newUser;
}
export default { registerUser };
🎩 架构师语录:
"Service 里定义的是知识,不是操作。"
四、数据层(Repository)------与数据库交心的搬运工
Repository 层是最接近真实世界(数据库、文件、缓存、第三方 API)的部分。
它不关心业务,只关心如何存 和怎么取。
示例
javascript
// repositories/userRepository.js
import db from "../utils/database.js";
async function findByEmail(email) {
return db.query("SELECT * FROM users WHERE email = ?", [email]);
}
async function create(user) {
return db.query("INSERT INTO users SET ?", user);
}
export default { findByEmail, create };
🧠 底层哲理 :
一旦 Repository 功能清晰,你就可以自由切换底层实现------从 MySQL 到 MongoDB,甚至是区块链存储,而不侵入业务逻辑。
五、数据流的优雅之舞
让我们把三层放到一幅简化流程图中感受下:
scss
(HTTP Request)
│
▼
┌─────────────────┐
│ Controller │ → 接受请求,验证输入
└─────────────────┘
│
▼
┌─────────────────┐
│ Service │ → 执行业务逻辑
└─────────────────┘
│
▼
┌─────────────────┐
│ Repository │ → 操作数据库/外部资源
└─────────────────┘
│
▼
(HTTP Response)
整个调用链像一场芭蕾舞:每层只做自己该做的动作,互不拥挤,节奏流畅。
六、从底层原理看分层的必要性
为什么一定要分层?
因为计算机世界讲究职责分离 与复杂度控制。
- 缓存局部复杂度:每一层内部可以做得很复杂,但暴露的接口简单。
- 解耦依赖:Controller 不依赖数据库,Service 可独立测试。
- 可替换性:Repository 可按环境替换不同存储实现。
底层原理很像操作系统的多层抽象:
- 应用(Controller)调用系统 API(Service),
- 系统 API 再调底层驱动(Repository)。
分层本身就是"软件工程的物理定律"。
七、文学视角下的分层之美
倘若程序是一出戏,Controller 是舞台门童,Service 是导演,Repository 是道具师。
三者分工:
- 门童迎宾,不参与剧情;
- 导演执导,不背道具;
- 道具师默默支撑,不抢镜头。
只有清晰分工,整场戏才可长演不衰。
八、扩展思考
当你真正习惯这种结构后,会自然衍生出更多层次:
- DTO 层(Data Transfer Object):解决数据输入输出的不确定性;
- Middleware 层:通用请求处理,如日志、鉴权、限流;
- Domain 层:引入领域驱动设计(DDD),让业务像对象一样自组织。
架构,就像打磨一把工程之剑:
- CRUD 是铁坯;
- 分层是锋刃;
- 可扩展性,是它真正的光。
🧭 总结:从工程手艺人,到系统建筑师
层级 | 职责 | 代表代码 | 设计哲学 |
---|---|---|---|
Controller | 接请求、发响应 | userController.js | "我只传达,不思考" |
Service | 执行业务逻辑 | userService.js | "我才是规则之脑" |
Repository | 操作数据存储 | userRepository.js | "我忠于原始事实" |
当你真正理解这个层次的分工,你的代码不再只是程序,而是一座可生长的系统。
🧩 彩蛋式感悟:
CRUD 程序员写逻辑,架构师写系统。
程序员想"跑起来",架构师想"活得久"。
真正的大工程师,不止写代码,而是造出能让人心安的秩序。