学习指南: 第22部分。实践考核

模块「第22部分。实践考核」中第 3 / 5 节课
您正在未登录状态下查看课程。 请登录,以保存进度并参加测试。

主题: 第 22 部分。实践考核:从规范到审阅者报告的 SDD Data 完整周期

难度等级: 中级

预计学习时间: 3–4 小时独立工作(包括编写规范、实现模型以及准备审阅者报告)

前置要求: 熟练掌握 SQL(聚合、窗口函数、JOIN)

了解 dbt 基础知识(模型、测试、sources、schema.yml)

理解 data contracts 和 SDD Data(Specification-Driven Development for Data,规格驱动数据开发)的概念

了解 PII(Personally Identifiable Information,个人可识别信息)处理原则

具备 git 和命令行使用经验

理解 staging、intermediate 和 mart 层之间的区别

学习目标: 批判性地评估数据规范,并在开始 SQL 实现前发现其中至少 10 个薄弱之处

将薄弱的需求文档(ТЗ)改写为完整的 SDD Data 规范,包含 grain、PII、contract、验收事实等章节

设计 dbt mart 层模型,保证 grain 为「每个键对应一行」并覆盖必需的测试

区分作者和审阅者角色,生成审阅者报告,将事实、假设和待确认事项分开

开展 SDD Data 回顾,并确定下一项功能(feature)的哪个阶段需要缩小或更详细地描述

概述: 课程的最终部分考查的不是对 dbt 语法的记忆,而是从规范到审阅者报告全程坚守数据产品承诺的能力。考核特意从一个糟糕的规范(例如「做一个有用的数据表」)开始,以检验学生是否能在编写 SQL 之前阻止这种薄弱的任务。考核由四个模块组成:12 个关于 SDD Data 术语理解的快速书面问题;在刻意薄弱规范中找出问题的任务;将其重写为正确的 SDD Data 格式;最后,使用完整证据包——SQL 之前的规范、测试、对 contract 的影响、审阅者报告和回顾——在 dbt 中实现 mart_customer_risk_summary 数据表。考核可以单独完成,也可以结对(作者 + 审阅者)完成——结对形式说明审阅是积极的工程角色,而不是被动阅读 SQL。工作按 25 分评分量表进行评估:21 分以上表示流程已准备好可迁移到真实的数据产品。

关键概念: Grain(粒度):grain 的真相来源是模型规范或数据产品的 contract,而不是 SQL。Grain 规定输出数据表的每一行恰好对应一个业务对象(例如 customer_id)。grain 的任何变更都需要人工确认,即使 SQL 能够「干净」地执行。

Odps vs odcs:ODPS(Open Data Product Specification)描述产品及其消费者:数据表的目的、读者、回答的问题。ODCS(Open Data Contract Standard)是技术 contract:schema、SLA、格式、所有者、版本管理。SDD Data 同时使用两者:ODPS 用于产品语义,ODCS 用于技术承诺。

Dbt 测试与数据 contract 的区别:dbt 测试(not_null、unique、accepted_values、relationships)仅检查部分形式和部分数据属性。它们不能证明规范的完整性、指标计算方法的正确性,也不能替代产品 contract。dbt build 全绿只是卫生指标,不是承诺。

PII 政策与禁用字段:禁止的直接 PII 列表(姓名、email、电话、护照数据)必须记录在模型规范、AGENTS.md 和审阅者检查清单中。尽可能将其转换为 singular 测试或扫描最终 schema 的宏。这可以将政策从口号转变为可验证的产物。

Contract drift(合同漂移):contract/规范与实际实现的模型之间的偏差。当进行「小改进」的作者悄悄更改 grain、添加字段、削弱测试或重命名实体时,就会出现漂移。在发布前捕获漂移是审阅者的首要任务。

破坏性变更:更改 grain、重命名或删除 contract 字段、更改指标语义、修改 PII 政策、修改 SLA。添加 nullable 列通常不是破坏性的,但如果下游系统将其解读为新的业务指标或它改变了 grain,则可能成为破坏性的。

作者与审阅者角色分离:审阅者应核查作者的假设,而不是为它们辩护。因此,作者和审阅者是不同的角色(在结对考核中为两个不同的学生)。审阅者不编辑作者的文件,而是准备一份对 contract、SQL、测试和流程分别给出意见的报告。

dbt build 能证明什么:dbt build 只能证明 DAG 的可执行性以及已声明的测试在当前数据上通过。它不能证明规范的完整性、方法的正确性、测试的充分性以及对消费者 contract 的符合性。

Schema manifest 与模型规范的区别:Schema Manifest(或 schema.yml)描述可观察的来源:实际的列、类型、测试。模型规范描述承诺的数据表:grain、消费者、方法、PII 政策、验收事实。它们相关,但不能互换。

Raw 数据与为绿色 build 而「修补」:Raw 层保留输入原样,不会为了 dbt build 全绿而「修补」。空值和 null 的语义在 staging 层解决,或在规范中明确说明。否则你只是把糟糕的数据质量隐藏在看似有效的模型背后。

验收事实(acceptance fact):这是一个产物,必须包含四个要素:命令(SQL/dbt/手动步骤)、预期结果、执行状态以及确认人。没有这四个要素,「检查」就只是注释而已。

人工确认(human confirmation):在更改 grain、PII 政策、SLA、contract 字段或风险指标计算方法时需要人工确认。这是 AI 助手不应自行决策、而应停下来请求确认的场景列表。

重要日期: 阶段 1 — SQL 之前的规范:在任何代码变更之前创建 specs/models/mart_customer_risk_summary.md 和验收事实

阶段 2 — 关于 contract 影响的备注:在实现之前确定该数据表是新产品还是对现有产品的扩展

阶段 3 — 实现与验证:编写 dbt 模型,更新 models/schema.yml,运行 dbt build --profiles-dir .

阶段 4 — 审阅者报告:结对审阅者运行 data-contract-review,并生成将事实、假设和确认分开的报告

阶段 5 — 回顾:填写回顾模板,评估规范的哪些部分描述得好以及哪些部分在 SQL 之后才需要澄清

练习题: 名称: 模块 1。关于 12 个 SDD Data 快速问题的书面回答

问题: 不借助 AI 助手书面回答以下 12 个问题:(1)grain 的真相来源是什么?(2)ODPS 与 ODCS 有什么区别?(3)为什么 dbt 测试不能替代数据 contract?(4)禁用 PII 列表应在哪里描述?(5)什么是合同漂移(contract drift)?(6)什么时候添加 nullable 列会成为破坏性变更?(7)为什么作者和审阅者应该是不同的角色?(8)dbt build 能证明什么,不能证明什么?(9)Schema Manifest 与模型规范有什么区别?(10)为什么不需要为了 dbt build 全绿而「修补」原始数据?(11)验收事实应包含什么内容?(12)什么时候需要人工确认?

解决方案: 参考答案:(1)模型规范或数据产品 contract,而不是 SQL。(2)ODPS 描述产品和消费者;ODCS 是技术 contract。(3)dbt 测试检查部分形式/数据,但不覆盖完整的产品语义。(4)记录在规范、AGENTS.md、审阅者检查清单中,尽可能记录在 singular 测试中。(5)contract/规范与实际模型之间的偏差。(6)如果它表现为新的业务指标、改变 grain 或影响下游 API。(7)审阅者应核查作者的假设,而不是为它们辩护。(8)dbt build 证明 DAG/测试的可执行性,但不证明规范的完整性。(9)manifest 描述可观察的来源;模型规范描述承诺的数据表。(10)raw 保留输入;空值和 null 的语义在 staging 层/规范中解决。(11)命令、SQL 或审阅者手动步骤、预期和状态。(12)更改 grain、PII 政策、SLA、contract 字段或风险方法时。

难度: 中级

名称: 模块 2。在薄弱规范中找出 10+ 个问题

问题: 给出一个刻意薄弱的规范。请分析它并找出所有薄弱之处。规范文本:「# 客户风险汇总。做一个有用的客户风险数据表。## 数据。使用 customer_360 和支付数据。添加所需的风险字段。## 验证。检查数据是否正确,且不含个人数据。」

解决方案: 逐步分析:1) 未指定数据表名称——无法在 contract 中引用该产物。2) 未指定消费者——无法验证其有用性。3) 未指定粒度(grain)——无法证明行的唯一性。4) 「有用的」——这个词不可验证,不是验收标准。5) 「所需字段」未定义——消费者无法理解他们将得到什么。6) 没有强制指标——无法测试。7) PII 政策未转化为基于禁用字段列表的测试——这只是口号,而不是检查。8) 未描述对 contract 的影响——无法理解这是扩展还是新产品。9) 没有以 source 形式列出输入模型——在 DAG 中无法验证。10) 没有 dbt 命令——没有可复现的检查。11) 没有供审阅者使用的手动事实——没有证据基础。12) 未说明这是新产品还是扩展——无法评估变更风险。

难度: 中级

名称: 模块 3。将规范重写为 SDD Data 格式

问题: 将模块 2 中的薄弱规范重写为完整的 SDD Data 格式,包含以下章节:目的、消费者、Grain、输入、输出字段、PII 政策、对 contract 的影响、验收事实、待确认事项。约束:grain 为每个 customer_id 一行;输入为 mart_customer_360 和 mart_payment_risk_signals;字段为 customer_id、risk_event_count、large_amount_event_count、last_risk_event_date;不含直接 PII;检查包括 customer_id not_null/unique,风险计数器 not_null;不修改 mart_customer_360 的现有 contract。

解决方案: 重写后的规范示例:

# Спецификация модели: mart_customer_risk_summary

## Назначение
Витрина агрегированных риск-сигналов по клиенту для команд скоринга и антифрода. Не используется для маркетинга.

## Потребитель
Команда риск-моделирования, downstream-дашборд в BI; вторичный потребитель — антифрод-алерты.

## Grain
Одна строка на customer_id. Изменение grain запрещено без подтверждения владельца продукта.

## Входы
- mart_customer_360 — справочник клиентов, контракт зафиксирован, не меняется.
- mart_payment_risk_signals — события риск-признаков платежей.

## Выходные поля
- customer_id (PK, BIGINT, NOT NULL, UNIQUE)
- risk_event_count (INT, NOT NULL) — общее число риск-событий за 90 дней.
- large_amount_event_count (INT, NOT NULL) — число событий с суммой выше порога.
- last_risk_event_date (DATE, NULLABLE) — дата последнего события; NULL допустим, если событий нет.

## Политика PII
Запрещены прямые PII: ФИО, email, телефон, паспорт, адрес. Используется только customer_id как квазиидентификатор. Список запрещённых полей проверяется singular-тестом no_pii_columns на схему итоговой модели.

## Влияние на контракт
Новый дата-продукт, не расширение существующего. Контракт mart_customer_360 не меняется. Зависимости downstream: BI-дашборд риска начинает читать mart_customer_risk_summary вместо ad-hoc SQL.

## Приёмочные факты
1. dbt run на модели mart_customer_risk_summary — успех.
2. dbt test на not_null + unique customer_id — успех.
3. dbt test на not_null риск-счётчиков — успех.
4. singular-тест no_pii_columns — успех.
5. Ручной факт ревьюера: визуальная проверка 5 случайных customer_id через BI — соответствие.

## Открытые подтверждения
- Порог large_amount: требует подтверждения владельца риск-модели.
- Окно 90 дней: требует подтверждения потребителя BI-дашборда.

难度: 中级

名称: 模块 4。最终项目——实现 mart_customer_risk_summary

问题: 在 dbt 项目中添加新的 mart_customer_risk_summary 数据表。要求:grain 为「每个 customer_id 一行」;输入为 mart_customer_360 和 mart_payment_risk_signals;字段为 customer_id、risk_event_count、large_amount_event_count、last_risk_event_date;不含直接 PII;dbt 测试;模型规范和验收事实;关于 contract 影响的备注;审阅者报告。遵循 10 步流程:从工作树到回顾。

解决方案: 按流程的逐步解决方案:

  1. 创建一个干净的 git 分支:git checkout -b feat/mart-customer-risk-summary。
  1. 在任何 SQL 之前,使用模块 3 中的规范创建文件 specs/models/mart_customer_risk_summary.md。
  1. 在 SQL 之前描述验收事实:dbt 命令列表、手动步骤和预期。例如:「在 mart_customer_risk_summary 上运行 dbt test -m 期望 4 个绿色测试」。
  1. 描述对 contract 的影响:「新产品,没有扩展 mart_customer_360,下游 BI 仪表板切换到新的数据表」。
  1. 实现模型 models/marts/mart_customer_risk_summary.sql。SQL 示例:
{{ config(materialized='table') }}

with payments as (
  select customer_id, event_date, amount, is_risk_event
  from {{ ref('mart_payment_risk_signals') }}
),
agg as (
  select
    customer_id,
    count(*) filter (where is_risk_event) as risk_event_count,
    count(*) filter (where is_risk_event and amount > 100000) as large_amount_event_count,
    max(event_date) filter (where is_risk_event) as last_risk_event_date
  from payments
  group by 1
)
select c.customer_id, a.risk_event_count, a.large_amount_event_count, a.last_risk_event_date
from {{ ref('mart_customer_360') }} c
left join agg a using (customer_id)
  1. 更新 models/schema.yml:添加模型、描述、customer_id 上的 not_null 和 unique 测试、风险计数器上的 not_null 测试。
  1. 运行 dbt build --profiles-dir . — 所有测试都应为绿色。
  1. 准备审阅者报告(结对考核的伙伴):将意见分为事实(已检查的内容)、假设(默认接受的内容)和待确认事项(需要产品负责人的内容)。
  1. 在 specs 中记录:该数据表是否修改了现有的 contract(在这种情况下——没有修改,mart_customer_360 保持不变)。
  1. 如果审阅者发现了漂移(例如,last_risk_event_date 变成了 NOT NULL 而不是 NULLABLE)——在合并前修复规范或 SQL。

难度: 中级

案例研究: 名称: 案例 1:客户风险数据表——从零开始的新数据产品

场景: 一家金融科技公司的风险建模团队请求数据工程师构建按客户聚合的风险信号数据表。在此之前,BI 仪表板直接通过 ad-hoc SQL 在 mart_customer_360 和原始支付数据之上收集数据。该数据表应取代 ad-hoc 查询,并成为反欺诈告警的数据源。

挑战: 分析师最初提出的规范只是「做一个有用的客户风险数据表」。未指明:数据表名称、消费者、grain、必需字段、PII 政策、对现有 mart_customer_360 contract 的影响、验收标准。风险:数据工程师做出一个技术上能跑通的「方便」join 模型,但不回答风险团队的问题并破坏了 BI 仪表板。

解决方案: 工程师在编写 SQL 之前停止了工作。与产品负责人和分析师共同确定:grain = 每个 customer_id 一行;三个必需字段(risk_event_count、large_amount_event_count、last_risk_event_date);禁用 PII 列表(姓名、email、电话、护照、地址)已转化为 singular 测试 no_pii_columns;对 contract 的影响——新产品,mart_customer_360 不变;验收事实包括 dbt 测试以及在 BI 中手动检查 5 个随机 customer_id。在规范获批后,编写了模型,运行了 dbt build,审阅者准备了将事实与假设分开的报告。

结果: 数据表在一个 sprint 内投入生产。BI 仪表板切换到了新的数据表,ad-hoc SQL 脚本已删除。由于消除了 ad-hoc 查询的差异,反欺诈告警变得更加稳定。按评分量表考核:23/25 分——在「验收事实」部分丢了 2 分(在第一轮迭代中审阅者的手动步骤未描述)。

经验教训: 薄弱的规范是正常的起点;工程师的任务是在 SQL 之前阻止它,并将其转化为完整的 SDD Data 产物

禁用 PII 列表应转化为可执行的 singular 测试,而不是聊天中的口号

手动的验收事实(在 BI 中的可视化检查)是必需的——dbt 测试不能覆盖产品语义

「新产品」与「现有产品的扩展」的区分是一个 contract 决策,而不是技术决策

相关概念: Grain 作为真相来源

ODPS vs ODCS

PII 政策与 singular 测试

验收事实(命令 + 预期 + 状态 + 确认人)

对 contract 的影响:新产品 vs 扩展

名称: 案例 2:「小改进」导致的合同漂移

场景: 在现有的 mart_customer_360 数据表中,作者在「丰富客户档案用于流失分析」的任务中添加了一个 nullable 列 date_of_birth。作者没有停下来,也没有与产品负责人协商变更,因为该列是 nullable 且「不会破坏任何东西」。

挑战: 一周后,反欺诈团队构建了一个按 date_of_birth 筛选客户的仪表板。这违反了 PII 政策(公司禁止在 KYC 流程之外处理出生日期)。漂移未被捕获,因为:(a)规范中没有带检查的禁用 PII 列表;(b)审阅者只检查了 SQL 而没有检查 contract;(c)dbt 测试通过——形式上全是绿的。

解决方案: 事后处理:删除该列,在所有 mart 数据表中添加 singular 测试 no_pii_columns,使用禁用字段列表更新 AGENTS.md,并修订审阅流程,使审阅者在合并前对照规范和 PII 政策进行检查。在下一轮迭代中,类似「小改进」被审阅者在规范阶段捕获。

结果: 该事件导致正式禁止在未经产品负责人确认的情况下向现有数据表添加字段。审阅流程已扩展为强制对照 PII 政策和 ODCS contract。经过改进,在接下来的 3 个月中,所有类似的漂移尝试都在发布前被捕获。

经验教训: Nullable 列如果被下游用作业务指标或违反 PII 政策,可能是破坏性变更

dbt build 全绿 ≠ contract 完好

禁用 PII 列表应该是可执行的产物,而不是 Confluence 中的文档

审阅者检查作者的假设,而不是 SQL——这是一个积极的角色

相关概念: 合同漂移

破坏性变更

dbt build 能证明什么

作者与审阅者角色分离

PII 政策作为可执行测试

名称: 案例 3:结对考核——区分作者和审阅者角色的经验

场景: 两名初级工程师参加 SDD Data 的结对考核。学生 A 是 mart_marketing_attribution 数据表的作者;学生 Б 是审阅者。两人都刚刚完成课程,并首次在实践中应用该方法论。

挑战: 作者倾向于「用锉刀打磨」SQL 而不返回规范。审阅者倾向于批准「小修补」以免拖慢流程。两人都可能将考核简化为形式化的 dbt build 运行,而不对 contract 进行实际检查。

解决方案: 在考核开始前,结对双方约定了规则:审阅者不编辑作者的文件;所有意见写入报告,分为「Contract」、「SQL」、「测试」、「流程」等部分;第一个数据表完成后,作者与审阅者互换角色进行第二个数据表。审阅者使用 data-contract-review 检查清单:将实际 schema 与规范进行对照、运行 singular PII 测试、检查验收事实是否完成。作者在第一次迭代后从审阅者报告中发现了三处漂移:(1)未经协商添加了 region 列;(2)未描述 attribution_window 的计算方法;(3)测试仅覆盖 not_null,没有用于归因渠道的 accepted_values。

结果: 第一个数据表得了 18/25 分——未达到「可以迁移到生产」的标准,但为回顾提供了素材。交换角色后,第二个数据表得了 23/25 分——两个学生都注意到,审阅者角色比作者角色收获更大,因为它迫使你将自己的验收标准形式化。

经验教训: 结对形式消除了审阅是被动阅读 SQL 的错觉

作者↔审阅者角色互换有助于理解哪些验收标准真正有效

审阅者报告应区分事实、假设和待确认事项——否则只是注释

考核后的回顾不是走形式,而是下一阶段的输入:如果「SQL 之后才需要澄清的内容」超过 3 项,则应缩小该阶段

相关概念: 作者与审阅者角色分离

审阅者报告(事实、假设、确认)

SDD Data 回顾

25 分评分量表

考核的结对形式

学习建议: 不要试图「跳到」SQL——在编写代码之前严格编写规范和验收事实。这是评分量表低分最常见的原因。

把模块 1 中的 12 个快速问题检查清单做成卡片,在每个功能前过一遍——这只需要 5 分钟,可以节省数小时的返工。

在 specs/models/ 中建立规范模板,不要未经产品负责人确认就「小修补」。任何规范变更 = contract 变更。

将 PII 政策立即转化为 singular 测试 no_pii_columns,就在同一次迭代中。「我们没有 PII」没有检查 = 下周就会发生的漂移。

与同事/伙伴约定结对形式。如果没有伙伴,请 AI 通过 /clear + data-contract-review 场景扮演审阅者的角色,但最终报告仍要展示给真人。

在规范中维护「待确认事项」日志——这会降低 Qwen Code「猜测」方法论并做出不可逆假设的几率。

使用 --profiles-dir . 运行 dbt build 并将输出作为产物固定下来——这是你的第一个验收事实。截图/日志与规范一起保存。

考核后不要跳过回顾。如果在「SQL 之后才需要澄清的内容」部分超过 3 项,则下一功能应缩小或更详细地描述。

将推荐的 Qwen 场景(创建规范 → 实现 → 审阅)作为字面脚本使用:/clear + 上下文 + 在第一步明确禁止编写代码。

记住:评分量表 21 分以上意味着「可以迁移到真实的数据产品」。如果你得到 16–20 分——这不是失败,但在迁移到生产之前需要加强检查和审阅。

附加资源: Open data product specification (odps):用于描述数据产品及其消费者的规范——bitol.io/odps 或 bitol.io 网站上的最新版本。用作「目的」和「消费者」部分的模板。

Open data contract standard (odcs):数据产品的技术 contract——bitol.io/odcs。用作模型规范中「输出字段」和「对 contract 的影响」部分的模板。

Dbt documentation — tests:关于 dbt 测试的文档(not_null、unique、accepted_values、relationships、singular)。规范中「dbt 检查」部分的来源。

Dbt documentation — contracts:关于 dbt contracts 的文档——enforce_schema、enforce_not_null。对模型规范中「对 contract 的影响」部分有用。

项目根目录下的 Agents.md:记录 PII 政策、禁用字段、技术栈、约束的文件。AI 助手在任何代码建议之前都应阅读它。

Qwen code — data-contract-review 场景:Qwen Code 中的内部审阅场景。在实现之后运行,检查变更是否与规范、PII 政策、测试和验收事实相符,而不编辑作者的文件。

SDD Data 回顾模板:包含「规范描述良好的部分 / SQL 之后才需要澄清的内容 / 哪些检查捕获了错误 / Qwen Code 在哪里试图猜测语义 / 在迁移到生产环境之前需要加强什么」等部分的 Markdown 模板。每次考核和重大功能后应填写。

摘要: 第 22 部分「实践考核」是对从规范到审阅者报告全程坚守数据产品承诺能力的最终考查。核心思想:考核从一个刻意薄弱的规范(「做一个有用的数据表」)开始,优秀的工程师应该在 SQL 之前阻止它。考核由四个模块组成:12 个关于 SDD Data 术语的书面问题(grain、ODPS vs ODCS、合同漂移、PII、dbt build、验收事实、人工确认);在薄弱规范中找出 10+ 个问题的任务;将其重写为完整的 SDD Data 格式;使用完整证据包实现 mart_customer_risk_summary——SQL 之前的规范、dbt 测试、对 contract 的影响、审阅者报告、回顾。结对形式说明审阅是一个积极的角色。按 25 分评分量表评估:21 分以上——流程可以迁移到生产数据产品;16–20——结果对学习有用,但需要加强检查和审阅;低于 16——阶段太大或规范不能保持语义。主要实践结论:如果回顾中「SQL 之后才需要澄清的内容」超过 3 项,下一个功能应在实现之前缩小或更详细地描述。

我的笔记
0 / 10000

笔记保存在当前浏览器中。在其他设备上将不会显示。

课程菜单

课程

SDD Data. 使用 Qwen Code 和 dbt 构建银行数据平台
进度 0 / 110