先读题:四个 TODO、三处埋雷、十个测试Read the task first: four TODOs, three planted bugs, ten tests
在写第一行 resolver 之前,把要改什么、别人给了什么、判卷标准是什么全摸清。Before writing the first line of a resolver, find out what to change, what is already given, and how it will be graded.
这一页有什么On this page8
- 01 题面原文The task text, as given
- 02 四个 TODO:README 只列了三个,代码里有四个Four TODOs: the README lists three, the code has four
- 03 写代码前先抄这张表Copy this table before you write code
- 04 跑基线:6 failed / 4 passedRun the baseline: 6 failed / 4 passed
- 05 4 个通过里有 3 个是假通过3 of the 4 passing tests are not real passes
- 06 只改一个文件Change one file only
- 练习 · 动手做Practice
- 迁移模式Transfer
- 复述四个 TODO 各自的要求Restate what each of the four TODOs asks for
- 抄出一张「数据源方法名 + context 键名」的对照表Copy out one reference table of data source method names and context key names
- 跑出基线测试并读懂那 6 个失败Run the baseline tests and read the 6 failures
- 认出「4 个通过里有 3 个是假通过」这件事See that 3 of the 4 passing tests are not real passes
这一节本身就是考点。README 有一句「The starter code also contains related TODOs and integration issues that may need attention」—— 那三处埋雷不会有人告诉你在哪,只能靠核对。This lesson is itself part of the exam. The README says: The starter code also contains related TODOs and integration issues that may need attention. Nobody tells you where the three planted bugs are; you find them by checking names one by one.
graphql-federation-practice/README.md任务清单与 EDIT THIS / PROVIDED 标注The task list and the EDIT THIS / PROVIDED markers
graphql-federation-practice/README.mdgraphql-federation-practice/node-subgraph/src/resolvers/orderResolvers.js唯一要改的文件The only file you change
提醒:源项目在磁盘上是做完的版本 —— 下面就是答案。想自己先写一遍的话,现在关上。Heads up: on disk this project is the finished version — what follows is the answer. Close this if you want to write it yourself first.
graphql-federation-practice/node-subgraph/src/resolvers/orderResolvers.jsgraphql-federation-practice/node-subgraph/__tests__/resolvers.test.js10 个判卷测试The ten tests that decide the marks
graphql-federation-practice/node-subgraph/__tests__/resolvers.test.js只显示前 120 行,整个文件共 144 行 —— 其余在本机打开看。First 120 of 144 lines — open the file locally for the rest.
题面原文The task text, as given
README 里 Task 1 的部分,一个字没改:
注意最后那句 integration issues —— 这是在暗示「starter 代码里有本来就坏掉的地方」。 它没说有几个、在哪。
The Task 1 section of the README, not a word changed:
Look at that last sentence, integration issues — it is hinting that parts of the starter code are broken to begin with. It does not say how many, or where.
graphql-federation-practice/README.md四个 TODO:README 只列了三个,代码里有四个Four TODOs: the README lists three, the code has four
这是第一个需要自己发现的地方。This is the first thing you have to notice on your own.
README 列了三条(User.orders、Order.shippingInfo、Query.orders), 但打开代码会发现还有一个:Query.order(单个订单)也是 TODO。
| 位置 | TODO 原文里的关键词 | README 提到了吗 | 有测试吗 |
|---|---|---|---|
User.orders | proper error handling + correlation ID tracing | ✅ | ✅ 2 条 |
Order.shippingInfo | using DataLoader to prevent N+1 queries | ✅ | ✅ 2 条 |
Query.order | using DataLoader with structured error handling | ❌ 没提 | ❌ 没有 |
Query.orders | error handling + correlation ID logging | ✅ | ✅ 2 条 |
Query.order 既没在 README 里被提到, 也没有测试。但代码里的 TODO 明确要求实现它。不实现它不会有任何测试变红 —— 但人工 review 会看到一个没做的 TODO。照代码里的 TODO 做,别只照 README。
The README lists three (User.orders, Order.shippingInfo, Query.orders), but open the code and there is a fourth one: Query.order (a single order) is a TODO too.
| Where | Key words in the TODO itself | Named in the README? | Any tests? |
|---|---|---|---|
User.orders | proper error handling + correlation ID tracing | ✅ | ✅ 2 of them |
Order.shippingInfo | using DataLoader to prevent N+1 queries | ✅ | ✅ 2 of them |
Query.order | using DataLoader with structured error handling | ❌ never mentioned | ❌ none |
Query.orders | error handling + correlation ID logging | ✅ | ✅ 2 of them |
Query.order is neither named in the README nor covered by a test. But the TODO in the code asks for it in plain words. Skipping it turns no test red — a human reviewer, though, sees an unfinished TODO. Work from the TODOs in the code, not only from the README.
graphql-federation-practice/node-subgraph/src/resolvers/orderResolvers.js写代码前先抄这张表Copy this table before you write code
三个埋雷里有两个就是「名字对不上」。抄一遍表,两个都能避掉。Two of the three planted bugs are just names that do not match. Copy the table once and you avoid both.
context 的结构(来自 index.js):
数据源的方法(来自dataSources/orderDataSource.js):
这张表值得在开始写之前真的抄一遍。 审计发现 starter 代码里有两处名字是错的 (orderAPI、getOrderById), 而它们都是「听起来非常合理」的名字 —— 靠直觉写就会中招,靠核对就不会。
The shape of context (from index.js):
The methods on the data sources (from dataSources/orderDataSource.js):
This table is worth actually copying out before you write anything. The audit found two wrong names in the starter code (orderAPI and getOrderById), and both of them sound entirely reasonable — write on instinct and you walk right into them, check the names and you never do.
graphql-federation-practice/node-subgraph/src/index.jsgraphql-federation-practice/node-subgraph/src/dataSources/orderDataSource.js跑基线:6 failed / 4 passedRun the baseline: 6 failed / 4 passed
改代码之前先知道起点。而且这个起点本身就在教你东西。Know your starting point before you change anything. The starting point already teaches you something.
node-subgraph 目录里原本没有node_modules,所以第一步必须npm install。然后 npm test(这个项目有 test script,和 React 那个不同)。
审计实测结果:
The node-subgraph directory ships with no node_modules, so step one has to be npm install. Then npm test (this project does have a test script, unlike the React one).
What the audit actually measured:
graphql-federation-practice/node-subgraph4 个通过里有 3 个是假通过3 of the 4 passing tests are not real passes
这是这门考试最重要的一课。This is the most important lesson in this exam.
逐条对照那 10 个测试:
| 测试 | 基线 | 为什么 |
|---|---|---|
| User.orders 返回用户订单 | ✕ | TODO 返回 [] |
| User.orders 无订单用户返回 [] | ✓ | 假通过:TODO 恰好返回 [] |
| Order.shippingInfo 返回物流 | ✕ | TODO 返回 null |
| Order.shippingInfo 无物流返回 null | ✓ | 假通过 |
| Query.orders 返回指定用户订单 | ✕ | TODO 返回 [] |
| Query.orders 无订单返回 [] | ✓ | 假通过 |
| Mutation.createOrder 成功 | ✕ | 埋雷 2(orderAPI 不存在) |
| DataLoader 批量取 order | ✕ | 埋雷 1(getOrderById 不存在) |
| DataLoader 批量取 shipping | ✓ | 这个 loader 本来就是对的 |
| 校验失败返回结构化错误 | ✕ | 埋雷 3(catch 把 INVALID_INPUT 吞成 SERVICE_ERROR) |
三个「假通过」的共同点:断言的都是「返回空」。而空实现正好就返回空。所以这三条测试对你的实现完全没有约束力 —— 它们从第一秒就是绿的,改完之后还是绿的, 但中间你可能写出了完全错误的代码。
怎么办?把注意力放在那 6 个红的上, 以及那些「测试没覆盖」的要求(correlation id 日志、Query.order、DataLoader 的使用)。红转绿是及格线,测试之外的要求才是分差。
Go through the ten tests one by one:
| Test | Baseline | Why |
|---|---|---|
| User.orders returns a user’s orders | ✕ | the TODO returns [] |
| User.orders returns [] for a user with none | ✓ | fake pass: the TODO happens to return [] |
| Order.shippingInfo returns shipping info | ✕ | the TODO returns null |
| Order.shippingInfo returns null when there is none | ✓ | fake pass |
| Query.orders returns one user’s orders | ✕ | the TODO returns [] |
| Query.orders returns [] when there are none | ✓ | fake pass |
| Mutation.createOrder succeeds | ✕ | planted bug 2 (orderAPI does not exist) |
| DataLoader batches order requests | ✕ | planted bug 1 (getOrderById does not exist) |
| DataLoader batches shipping requests | ✓ | this loader was correct all along |
| validation failure returns a structured error | ✕ | planted bug 3 (the catch swallows INVALID_INPUT into SERVICE_ERROR) |
What the three fake passes have in common: every one of them asserts “returns nothing”. And an empty implementation returns exactly nothing. So those three tests put no constraint at all on your implementation — green from the first second, still green when you are done, and in between you could have written completely wrong code.
So what do you do? Put your attention on the six red ones, and on the requirements no test covers at all (correlation id logging, Query.order, using DataLoader). Turning red to green is the pass mark; the requirements outside the tests are where the points differ.
只改一个文件Change one file only
README 的文件结构图标得很清楚。node-subgraph 下面:
src/resolvers/orderResolvers.js——EDIT THISsrc/dataSources/orderDataSource.js—— PROVIDEDsrc/schema.graphql—— PROVIDEDsrc/index.js—— PROVIDED__tests__/resolvers.test.js—— PROVIDED
PROVIDED 的意思是「别动」。判卷时这些文件很可能被替换回原版 —— 你改了 orderDataSource.js 加一个getOrderById 方法,判卷时那个方法就消失了, 你的 loader 又挂了。
所以埋雷 1 的正确修法是改 loader 里的调用, 不是给数据源加方法。这个判断在考场上值好几分。
The file tree in the README is explicit about this. Under node-subgraph:
src/resolvers/orderResolvers.js— EDIT THISsrc/dataSources/orderDataSource.js— PROVIDEDsrc/schema.graphql— PROVIDEDsrc/index.js— PROVIDED__tests__/resolvers.test.js— PROVIDED
PROVIDED means hands off. When your submission is graded, those files are quite likely swapped back to the originals — add a getOrderById method to orderDataSource.js and the method vanishes at grading time, breaking your loader all over again.
So the right fix for planted bug 1 is to change the call inside the loader, not to add a method to the data source. That judgement is worth several points in the exam.
动手做Get your hands on it
填空只是过渡。真正掌握的标准,是在没有答案的时候从头写出来 —— 所以做完 L2 之后一定要往 L3、L4 走。Filling blanks is a stepping stone. The real bar is writing it from nothing, so once L2 is comfortable, push on to L3 and L4.
四个 TODO 全都只写了 return [] 或return null,为什么还有 4 个测试通过?
All four TODOs contain nothing but return [] or return null. So why do 4 tests still pass?
createOrderLoader 调了不存在的orderDataSource.getOrderById(id)。 正确的修法是?
createOrderLoader calls orderDataSource.getOrderById(id), which does not exist. What is the right fix?
拿到 node-subgraph,最合理的动作顺序?
You have just opened node-subgraph. What is the most sensible order to work in?
换一道题也能用Works on other problems too
考试不会原题重考。真正能带走的是「看到这种信号 → 伸手去拿这个解法」。The exam will not reuse the same question. What you take away is the reflex: see this signal, reach for that solution.
- 四个 TODO,README 只列了三个 —— Query.order 既没被提到也没有测试,但代码里要求实现。There are four TODOs but the README lists three. Query.order is neither mentioned nor tested, yet the code asks you to implement it.
- 开始写之前抄两张表:context 的键名、三个数据源的方法名。Before you start writing, copy two tables: the key names in context, and the method names on the three data sources.
- 基线是 6 failed / 4 passed,其中 3 个通过是「空实现恰好满足断言」的假通过。The baseline is 6 failed / 4 passed, and 3 of those passes only happen because an empty implementation satisfies the assertion.
- 只改 orderResolvers.js;其余文件 PROVIDED,判卷时可能被换回原版。Change only orderResolvers.js. The other files are marked PROVIDED and may be replaced with the originals during grading.
- 先修埋雷再写 TODO,否则埋雷的报错会干扰你判断自己的代码对不对。Fix the planted bugs before writing the TODOs, otherwise their errors make it hard to tell whether your own code is right.