3. 数据契约定义:字段命名规范、数据类型约定、约束条件定义
好,咱们进入数据契约最核心的部分——怎么把契约写清楚。说白了,就是让数据提供方和消费方对「字段长什么样、能装什么值、有什么限制」达成共识。我见过太多项目,契约写得模棱两可,结果上线后数据对不上,排查起来比重新写一遍还痛苦。
3.1 字段命名规范:一眼看懂,别猜
命名这件事,看起来简单,但坑最多。我个人习惯用 snake_case,全小写加下划线。为什么?因为大多数数据库和数仓工具对大小写敏感,混用 CamelCase 容易出幺蛾子。
核心原则:字段名要自解释,不要缩写到只有自己能看懂。
举个例子:
# 不推荐
usr_id, ord_dt, prd_nm, cst_amt
# 推荐
user_id, order_date, product_name, customer_amount
我曾经接手过一个项目,字段名叫 f_01、f_02…… 你猜猜是什么?后来翻了三层文档才搞清楚,原来是「首次下单金额」和「复购率」。这种命名,契约签了等于没签。
3.1.1 命名规范清单
| 规范项 | 要求 | 示例 |
|---|---|---|
| 字符集 | 仅允许小写字母、数字、下划线 | order_status |
| 长度限制 | 不超过 64 个字符 | customer_registration_channel |
| 前缀约定 | 业务域缩写 + 下划线 | ord_ 表示订单域 |
| 禁止关键字 | 避免 SQL/编程语言保留字 | 不用 date、name、type |
| 语义清晰 | 动词+名词,或名词+形容词 | is_active、total_amount |
小技巧:我建议在契约里加一个「字段命名词典」,把每个业务域常用的词根列出来。比如订单域用 ord_,用户域用 usr_。这样新同学上手,看字段名就能猜个八九不离十。
3.2 数据类型约定:别让类型成为隐患
数据类型选不对,后面全是坑。你想想看,一个金额字段用 FLOAT 存,算到小数点后几位就开始飘了。我遇到过最离谱的,是把手机号用 INT 存,结果前导 0 全丢了,用户投诉电话打爆。
3.2.1 常见数据类型选择指南
| 业务含义 | 推荐类型 | 避坑说明 |
|---|---|---|
| 金额 | DECIMAL(18,2) |
别用 FLOAT,精度会丢 |
| 手机号 | VARCHAR(20) |
前导 0 和 +86 需要保留 |
| 时间戳 | TIMESTAMP |
统一 UTC,别用本地时间 |
| 状态码 | VARCHAR(10) 或 INT |
枚举值要写在约束里 |
| 布尔值 | BOOLEAN 或 TINYINT(1) |
明确 0/1 含义 |
注意:数据类型一旦定下来,改起来成本极高。我建议在契约里明确写上「类型变更必须走审批流程」,别让开发同学随手改。
3.3 约束条件定义:把规则写进契约
约束条件,就是告诉数据「你不能乱来」。没有约束的数据,就像没有交通规则的路口,早晚出事故。
3.3.1 常见约束类型
- 非空约束:关键字段不能为 NULL。比如订单 ID、用户 ID。
- 唯一约束:业务主键必须唯一。比如订单号、身份证号。
- 取值范围:枚举值或数值范围。比如状态字段只能取 'A'、'B'、'C'。
- 外键约束:引用其他表的数据必须存在。比如订单中的用户 ID 必须在用户表存在。
- 业务规则:比如「结束时间必须大于开始时间」。
我曾经踩过一个坑:一个「用户等级」字段,文档里写的是 1-5 级,但代码里偷偷加了 6 级。消费方按 1-5 做逻辑,结果 6 级用户全被当成异常数据过滤掉了。嗯,这就是约束没写进契约的后果。
3.3.2 约束定义示例
-- 数据契约:订单表
CREATE TABLE orders (
order_id VARCHAR(32) NOT NULL,
user_id VARCHAR(32) NOT NULL,
order_amount DECIMAL(18,2) NOT NULL,
order_status VARCHAR(10) NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL,
-- 约束条件
CONSTRAINT pk_order PRIMARY KEY (order_id),
CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(user_id),
CONSTRAINT chk_status CHECK (order_status IN ('PENDING', 'PAID', 'SHIPPED', 'CANCELLED')),
CONSTRAINT chk_amount CHECK (order_amount >= 0),
CONSTRAINT chk_time CHECK (updated_at >= created_at)
);
关键点:约束条件要写在契约里,而不是只写在代码注释里。代码会变,注释会过期,但契约是双方签字的,改起来有流程。
3.4 知识体系总览
下面这张图,把字段命名、数据类型、约束条件的关系串起来了。你可以把它当成数据契约定义的「检查清单」。
3.5 实战避坑指南
最后,分享几个我亲身踩过的坑,希望能帮你省点时间。
坑1:我曾经在契约里只写了字段名和类型,没写约束。结果上游把 NULL 值传过来了,下游消费方直接报错。后来我强制要求:每个字段必须标注是否可为 NULL,枚举值必须列出所有选项。
坑2:数据类型用 VARCHAR(255) 一把梭。看起来省事,但实际存储和索引效率都很差。我建议根据业务实际长度来定,比如手机号用 VARCHAR(20),邮箱用 VARCHAR(100)。
我的习惯:每次定义新字段,我都会问自己三个问题:
- 这个字段名,新同学能一眼看懂吗?
- 这个类型,能覆盖所有业务场景吗?
- 这个约束,能防止脏数据进来吗?
三个问题都回答「是」,再往下走。
嗯,数据契约的定义,说白了就是「把话说清楚」。命名规范、数据类型、约束条件,这三样东西写明白了,后面数据流转的 80% 问题都能提前规避。别嫌麻烦,前期多花 10 分钟,后期省 10 个小时。