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 知识体系总览

下面这张图,把字段命名、数据类型、约束条件的关系串起来了。你可以把它当成数据契约定义的「检查清单」。

数据契约定义核心要素 数据契约定义 字段命名规范 数据类型约定 约束条件定义 snake_case 自解释 DECIMAL VARCHAR 非空约束 取值范围 核心原则 命名要自解释 · 类型要精确 · 约束要明确 三者缺一不可,共同构成可执行的数据契约

3.5 实战避坑指南

最后,分享几个我亲身踩过的坑,希望能帮你省点时间。

坑1:我曾经在契约里只写了字段名和类型,没写约束。结果上游把 NULL 值传过来了,下游消费方直接报错。后来我强制要求:每个字段必须标注是否可为 NULL,枚举值必须列出所有选项。

坑2:数据类型用 VARCHAR(255) 一把梭。看起来省事,但实际存储和索引效率都很差。我建议根据业务实际长度来定,比如手机号用 VARCHAR(20),邮箱用 VARCHAR(100)。

我的习惯:每次定义新字段,我都会问自己三个问题:

  1. 这个字段名,新同学能一眼看懂吗?
  2. 这个类型,能覆盖所有业务场景吗?
  3. 这个约束,能防止脏数据进来吗?

三个问题都回答「是」,再往下走。

嗯,数据契约的定义,说白了就是「把话说清楚」。命名规范、数据类型、约束条件,这三样东西写明白了,后面数据流转的 80% 问题都能提前规避。别嫌麻烦,前期多花 10 分钟,后期省 10 个小时。