一句话:在写任何代码之前,先想清楚你要存什么数据、数据之间是什么关系。
"If we can get this part right, the rest of the code practically writes itself."
(如果我们能把数据建模做对,剩下的代码几乎是自动写出来的。)
这句话在传统开发中就已经是真理。在 Coding Agent 时代,它的分量增加了十倍。
为什么?因为 AI 特别擅长根据数据结构来生成代码。你给 AI 一个清晰的数据模型——有哪些表、每张表有哪些字段、表之间是什么关系——AI 就能自动生成增删改查的接口、表单页面、数据校验逻辑。但如果你的数据模型是错的,AI 生成的一切都会建立在一个有裂缝的地基上。
一个正确的数据模型,是你能给 Coding Agent 的最高杠杆输入。
数据建模听起来很抽象,但方法非常简单:
- 列出你的应用里的核心名词 — 用户、文章、评论、订单、商品、标签……
- 每个名词 = 一张数据表 — User 表、Article 表、Comment 表……
- 每张表的列 = 这个名词的属性 — User 表有 name、email、password;Article 表有 title、body、published_at
就这样。数据建模的第一步不是画 ER 图、不是写 SQL,而是用日常语言列出你的应用里有哪些"东西"。
试一试:想想你日常用的任何一个应用——微信、淘宝、抖音。列出它的核心名词。你会发现,虽然界面天差地别,但底层的数据结构都是"名词 + 属性 + 关系"。
这是检验数据模型是否正确的最朴素方法:
- 在纸上画出你的每张表,像 Excel 那样,列头是字段名
- 填上几行示例数据(真实的、具体的数据,不是"xxx")
- 用手指模拟查询:"我想查张三发布的所有文章"——你能从这些表里找到吗?
- 再试:"我想看某篇文章的所有评论"——找得到吗?
- 如果找不到,说明你缺了某个字段或某个关系
如果你手动能查到想要的数据,说明数据模型是对的。如果查不到,问题一定出在表的设计上——要么缺了某张表,要么缺了某个关联字段。
这个测试看起来很"低技术",但它比任何建模工具都有效。因为它迫使你用真实数据去验证,而不是在抽象概念里打转。
数据之间的关系只有三种。记住这三种,你就能建模 95% 的应用:
一个用户有多篇文章,但每篇文章只属于一个用户。
怎么实现?在"多"的那一方加一个外键(Foreign Key)。文章表里加一个 user_id 列,指向用户表的 id。
用户表 (Users) 文章表 (Articles)
┌────┬──────┐ ┌────┬──────────┬─────────┐
│ id │ name │ │ id │ title │ user_id │
├────┼──────┤ ├────┼──────────┼─────────┤
│ 1 │ 张三 │ │ 1 │ 第一篇 │ 1 │
│ 2 │ 李四 │ │ 2 │ 第二篇 │ 1 │
└────┴──────┘ │ 3 │ 第三篇 │ 2 │
└────┴──────────┴─────────┘
张三(id=1)有两篇文章,李四(id=2)有一篇。通过 user_id 就能查到。
一个学生选多门课,一门课有多个学生。
这时候不能简单地在一方加外键。你需要一张中间表(Join Table),专门记录"谁选了哪门课":
学生表 选课表 (Enrollments) 课程表
┌────┬──────┐ ┌────┬────────────┬───────────┐ ┌────┬────────┐
│ id │ name │ │ id │ student_id │ course_id │ │ id │ name │
├────┼──────┤ ├────┼────────────┼───────────┤ ├────┼────────┤
│ 1 │ 张三 │ │ 1 │ 1 │ 1 │ │ 1 │ 数学 │
│ 2 │ 李四 │ │ 2 │ 1 │ 2 │ │ 2 │ 英语 │
└────┴──────┘ │ 3 │ 2 │ 1 │ └────┴────────┘
└────┴────────────┴───────────┘
张三选了数学和英语,李四选了数学。中间表就是那个"粘合剂"。
一个用户有一份个人档案。相对少见,但偶尔会用到。处理方式和一对多类似——在其中一方加外键,但必须加上唯一性约束(Unique Constraint),确保每个用户只能有一份档案。没有唯一性约束的话,它实际上就变成了一对多。
面对任意两个名词,问自己两个问题:
"一个 X 能有多个 Y 吗?一个 Y 能有多个 X 吗?"
| X → 多个 Y? | Y → 多个 X? | 关系类型 |
|---|---|---|
| 否 | 否 | 一对一 |
| 是 | 否 | 一对多(X 是"一",Y 是"多") |
| 否 | 是 | 一对多(Y 是"一",X 是"多") |
| 是 | 是 | 多对多 |
每次遇到新的名词关系,用这两个问题一测,答案立刻出来。
这是最常见的错误。很多人上来就让 AI 写页面、写功能,结果做到一半发现数据存不对,只好推翻重来。数据结构决定一切。先用 5 分钟想清楚名词、属性、关系,后面能省几个小时的返工。
表的数量不是目标,每个独立的名词一张表才是原则。不要把不同的东西硬塞进一张表(比如把"用户"和"订单"放在一起),也不要把一个东西拆成多张表(比如把用户的基本信息和联系方式分成两张表,除非有特殊理由)。
AI 可以建议数据模型,但只有你才理解你的业务领域。"一个老师能教多门课吗?"这种问题取决于你的业务规则,不取决于技术。如果你在教培机构,一个老师可能只教一门课;如果你在大学,一个老师通常教多门课。AI 不知道你的具体情况,你知道。
试着为一个读书笔记应用做数据建模:
第一步:列出名词
- 用户(User)
- 书(Book)
- 笔记(Note)
- 标签(Tag)
第二步:列出属性
- User:name、email、password
- Book:title、author、isbn
- Note:content、page_number、created_at
- Tag:name
第三步:用黄金问题判断关系
- 一个用户能有多本书吗?是。一本书能属于多个用户吗?是。→ 多对多(需要中间表,比如 UserBook)
- 一本书能有多条笔记吗?是。一条笔记能属于多本书吗?否。→ 一对多(Note 加 book_id)
- 一条笔记能有多个标签吗?是。一个标签能属于多条笔记吗?是。→ 多对多(需要中间表 NoteTag)
- 一个用户能有多条笔记吗?是。一条笔记能属于多个用户吗?否。→ 一对多(Note 加 user_id)
第四步:纸质表格测试
在纸上画出这些表,填上几行数据,试试能不能查到"张三在《思考,快与慢》这本书上写的所有笔记"。如果能查到,数据模型就是对的。
打开 SQLiteOnline — 浏览器里直接写 SQL,不需要安装任何东西:
- 建一张用户表(复制粘贴到左侧编辑器,点 Run):
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
email TEXT
);
INSERT INTO users VALUES (1, '张三', 'zhang@example.com');
INSERT INTO users VALUES (2, '李四', 'li@example.com');
SELECT * FROM users;- 建一张文章表,体验外键关联:
CREATE TABLE articles (
id INTEGER PRIMARY KEY,
title TEXT,
user_id INTEGER
);
INSERT INTO articles VALUES (1, '第一篇文章', 1);
INSERT INTO articles VALUES (2, '第二篇文章', 1);
INSERT INTO articles VALUES (3, '第三篇文章', 2);
SELECT * FROM articles WHERE user_id = 1;最后一行查询的意思是:"查找张三(id=1)的所有文章"。运行看看结果。
- 试试连表查询:
SELECT users.name, articles.title
FROM articles
JOIN users ON articles.user_id = users.id;这就是把两张表"连"起来,同时看到作者名字和文章标题。
这些 SQL 你不需要背。重要的是亲手跑一遍,体会"表"和"关系"在真实数据库中是怎么工作的。
数据建模是你与 Coding Agent 协作的起点。实际操作建议:
- 先描述数据模型,再描述功能 — 给 AI 的 prompt 中,第一段就应该是数据模型:"这个应用有四张表:User、Book、Note、Tag,关系如下……"。然后再说功能需求。这是最高效的沟通方式。
- 把数据模型写进 CLAUDE.md — 如果你用 Claude Code,在项目的 CLAUDE.md 文件中明确写出数据模型。这样 AI 在整个开发过程中都有一致的参照。(参见 Agentic Coding Week 4)
- 数据模型变了,所有代码都要跟着变 — 如果你中途发现某个关系类型判断错了(比如把一对多误判为一对一),要立刻修正。越早修正代价越小。