页面打开了,按钮点了也没报错,说明刚才那条路径走通了。至于输出对不对、换一组输入会不会出错,还得接着验。
到了维护这一步,还要知道下一次需求该改哪里,改完会影响谁。一个函数看着只管价格筛选,调用完,旁边列表的顺序却变了,这就得有人顺着代码往回找。
AI 可以很快写出一段实现。审查如果只盯着眼前的效果,理解代码关系的工作就容易留给下一位。下一位可能是过两周的自己,到时候代码不认识你,你也不太认识代码,连甩锅都缺个合适的对象。
筛个价格,怎么把原数组也改了
假设需求很简单:给商品列表加价格区间筛选,保留原来的展示顺序,不改原始数组。
在这个简化示例里,价格和区间上下界都是有效数值。实现却写成了这样:
function filterProductsByPrice(products, minPrice, maxPrice) {
products.sort((a, b) => a.price - b.price);
return products.filter(
(product) => product.price >= minPrice && product.price <= maxPrice,
);
}
它能运行,也能筛出价格范围内的商品。如果测试只断言“返回的价格都在区间内”,这段实现可以通过。
麻烦出在排序。JavaScript 的 sort() 会原地修改数组,MDN 对这一点有明确说明。其他地方如果也持有这个数组,读到的顺序就可能跟着变。你让它装个筛网,它连货架也重新摆了一遍。
只做需求里的筛选,代码其实是这样:
function filterProductsByPrice(products, minPrice, maxPrice) {
return products.filter(
(product) => product.price >= minPrice && product.price <= maxPrice,
);
}
前一段违反了“不改原数组”和“保留顺序”的要求,已经有正确性问题。难维护的地方在于,函数名没告诉你它还负责排序。另一个列表出了问题,排查的人得追着调用链,才能找到这个藏起来的副作用。
类似的麻烦也会藏在模块之间。页面和公共层各请求一遍数据,组件里的状态又复制进全局 store;同一种业务状态,在不同页面还各有一套判断。每一处单独看都能工作,等规则要改时,得先把这些地方找齐。
为什么又多了一套请求封装
项目里往往已经有了约定:请求在哪里封装,权限由谁判断,状态归哪里,错误怎么处理。
只给 AI 当前页面和一句需求,它可能就在页面里补一个请求,再加一套错误提示。局部确实能跑,项目里却多出一条需要维护的路径。以后认证方式或者错误码变了,公共封装已经改好,这个页面还得单独照顾。
带检索和工具调用的 Agent 能查仓库,也能读项目规则。不过,这次到底有没有找到相关实现,要看它实际读了什么。工具有这个功能,不能直接当作这一步已经做完。把整个仓库塞进上下文,也不能替它挑出该复用的代码。
可以先让它找出已有的类似功能,再说明准备复用哪一层、改哪些文件,理由是什么。答不清楚就继续读。改完再发现用错了数据入口,还得退回这一步。
一个页面几千行,怎么还在往里塞
一个商品列表,把筛选区、表格、编辑抽屉都写在同一个文件里,请求、权限判断和样式也全住在这儿。写到几千行,功能确实齐了,滚动条也快瘦成一粒芝麻了。改个表单校验,得先在里面找半天。
如果任务只写“把功能做出来”,没交代分层和组件边界,AI 就可能继续往现有入口里添。再把“少改文件”理解成“最好只动一个文件”,连该新增的组件都一起省了。拆出几个有明确职责的组件,照样可以是一次小范围改动。
没有自定义 rules,它也会受工具默认指令、现有代码和当前上下文影响,也可能主动拆分。只是团队希望页面管到哪、哪些逻辑该独立,不能每次都靠它猜。
以 Vue 页面为例,先找已有公共组件和相似实现。确实需要新增时,可以按职责考虑这样的组织方式;这是示意,不必照着新建一套:
product-list/
index.vue 页面组装与区域协作
components/
ProductFilters.vue 筛选交互
ProductTable.vue 列表展示与行操作事件
ProductEditDrawer.vue 编辑抽屉与表单校验
composables/
useProductList.ts 列表加载、分页与刷新状态
独立交互区域可以抽成业务组件,有状态逻辑按职责封装,请求继续复用项目已有的 API 层。Vue 官方文档也说明,composable 除了复用有状态逻辑,还能按逻辑关注点组织复杂组件的代码。
拆完还得看状态和依赖。筛选条件保留一个来源,组件通过明确的输入和事件协作;把整份页面状态复制到每个子组件,照样会出同步问题。几千行全搬进一个巨大的逻辑文件,也只是给原来的大文件换了个门牌。
行数可以当预警,是否拆得合理,还得看职责能不能说清、相关修改能不能落在该去的地方。把文件切小以后,如果调用关系更绕了,这次拆分就得重新想。
rules 要写具体,也要确认它真在起作用
“注意模块化”“代码要优雅”给的余地太大。项目规则可以把长期有效的约束写得更具体,例如:
修改页面前,读取当前工具实际支持、且对当前目录生效的项目规则。
先查已有公共组件和相似实现,再列出拟新增或修改的文件及各自职责。
页面入口以组装为主,独立交互区域按职责评估组件拆分。
可独立维护的有状态逻辑按职责封装,请求复用已有 API 层。
状态保留单一来源,组件通过明确的输入和事件协作。
触及项目约定的文件或函数预警值,先说明拆分方案或保留理由。
不得仅为压行数随意切碎代码,或把所有逻辑搬进另一个大文件。
完成后运行适用检查,不得关闭规则或放宽门槛来消除告警。
规则放在哪里、对哪些目录生效,要按当前工具的文档确认。不能随手放一个叫 rules.md 的文件,就默认它一定会读。让它复述适用条目可以帮助核对,后续仍要检查 diff:文件到底建在哪一层,状态有没有复制,请求有没有绕开公共入口。
而且,写进规则不等于自动拦截。Claude Code 的文档说明,CLAUDE.md 等内容会作为上下文指令加载;需要强制阻止动作时,应使用相应的 hook 等执行机制。
能自动检查的要求,也可以接进实际门禁。比如用 ESLint 的 max-lines 规则检查文件长度,阈值和例外按项目约定;Vue 单文件组件还要配好适用文件和 parser,并在项目里实际跑通。需要阻止合并的检查,要设为失败条件、接入 CI,并确认脚本没有忽略失败退出码。
超过行数只是提醒你回来检查设计,lint 不会替你决定组件怎么分。规则文档、自动检查和代码审查各管一部分,光让 AI 在结尾保证一句“已遵循规范”,还得再看看它交了什么。
补丁加多了,得看看这个函数到底管什么
假设一个页面先加价格筛选,又加品牌筛选,之后补库存状态。每轮都往现有函数里添条件,后来这个函数还管起了数据转换、权限判断和错误提示。一个筛选函数,逐渐把门卫和售后的活也接了。
如果每次给 AI 的要求都是“这里再兼容一下”“测试别报错就行”,它就可能一直围着当前症状打补丁。每次改动都很小,合起来却越来越难说清这个函数负责什么。
小 diff 值得争取,但文件少、行数少,不能证明设计合理。某个分支反复被改,就该回头看看这些判断是否真的属于这里,有没有重复的业务规则。如果要重构,也得说清楚这次能解决什么问题。
同样,看到重复就抽通用框架,也未必划算。价格筛选还没交付,先收到一份插件系统设计书,这热情多少有点超出预算。
Google 的代码审查指南专门提醒评审者留意过度设计,包括没有现实需求的通用化和额外功能。先把当前问题解决清楚。未来需求真来了,再按它的具体样子决定怎么改。
测试全绿,也可能一起误会了需求
如果测试只检查返回商品的价格范围,刚才的排序副作用就不会暴露。再添几组同样思路的数据,也补不上“原数组有没有被修改”这个缺口。
让 AI 写实现,再让它写测试,可以节省工作。但两边如果沿用了同一个误解,就可能在错误答案上愉快会师,谁也不觉得有事。
验收条件最好在看实现之前定好。筛选结果要正确,区间两端的价格也要包含。返回顺序、原数组是否保持不变,以及没有匹配项时是否返回空结果,也都得检查。
Google 的同一份审查指南还要求检查测试本身是否有效:代码出错时,它真的会失败吗?断言有没有用?测试也需要维护,不能只数写了多少个。
功能没过,就让 AI 一直“修到测试通过”,也得看它到底修了什么。它可能改对实现,也可能改了断言、跳过用例,或者把需求悄悄改成当前代码能满足的样子。测试文件的 diff 不能漏看。
审查要看依赖关系,不能只看排版
类型名起得漂亮,目录整整齐齐,注释还把每一步都解释了,确实很容易让人放心。
轮到维护,就得问些不那么客气的问题。组装页面的函数为什么能改账户余额?两个模块各存一份相同状态,更新时由谁同步?异常被统一转成成功结果以后,调用方还能不能知道失败了?
格式化工具回答不了这些问题,补几段注释也修不好职责和数据流。
GitHub 关于 Copilot Agents 的说明明确列出了限制:代码审查可能漏掉问题,尤其是大型或复杂改动;生成的建议也可能不准确,需要人工审查和测试。再找一个 AI 看一遍,多了一次检查机会,合并前仍然得有人理解这次改动。
人写的代码也得这么查。AI 让代码更容易产出了,团队还得留出时间读它,不能把省下来的时间全排给下一个需求。
把维护要求写进任务
“写得优雅一点”“注意可维护性”听着都对,验收时却不好使。商品筛选这个任务,可以交代得具体些:
先阅读商品列表、相关数据入口,以及已有的类似筛选实现。
先说明准备复用哪里、预计改哪些文件,暂时不要修改代码。
确认方案后再实现价格区间筛选:
- 筛选基于现有数据,不新增一套请求。
- 不修改原数组,保留原来的展示顺序。
- 本次筛选状态只属于当前组件,不复制到全局 store。
- 不改公共组件接口,不升级依赖,不顺手重构其他模块。
- 覆盖边界价格、空结果、顺序保留和原数组不变的测试。
完成后说明数据怎么流转、状态放在哪里,以及实际执行了哪些检查。
如果发现需要扩大改动范围,先说明原因。
这里把筛选状态留在当前组件,是这个小任务的要求。换成需要跨页面共享的条件,就得重新判断状态放在哪里,别把示例里的约束当成所有项目的标准答案。
真要改公共接口或者重构,可以单独讨论影响范围和验收方式。功能必须改哪些、哪些只是额外建议,分开看比较清楚。
合并前,还可以提一个小的后续需求,例如“再加品牌筛选”。先不实现,让它说说准备改哪里、补哪些测试。如果这也要牵动权限、请求封装和全局状态,就值得先检查这些依赖是否必要。
最后让它交代清楚数据从哪来、状态归谁、哪些行为不能动,能一项项指到实际代码。至于“已全面优化,具有良好扩展性”,这句可以省了。真要查 bug,还得从文件和调用关系里找,交付感言帮不上忙。
本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。
The page is open, the button is not wrong, which means the path just went through. The output is wrong, the other type of input is wrong.
When this is done, it is important to know where the next needs should be changed and who will be affected. A function looks at price filters, calls are exhausted, and the order of the next list changes, so someone has to follow the code back.
AI can write a paragraph soon. If the review focuses only on immediate effects, the understanding of code relationships is easily left to the next. The next person may be himself in two weeks, and by the time the code doesn't know you, you don't know the code, you don't even have a suitable object for the dump pot.
Why did you change the original number?
Assumptions of demand are simple: the list of commodities is screened in price bands, the original display order is maintained and the original array is not changed.
In this simplified example, both the price and the inter-zone upper and lower bounds are valid values. This is what it says:
function filterProductsByPrice(products, minPrice, maxPrice) {
products.sort((a, b) => a.price - b.price);
return products.filter(
(product) => product.price >= minPrice && product.price <= maxPrice,
);
}
It works and it sifts out goods within the price range. This could be achieved if the test only asserted that “return prices are in the zone”.
Trouble out in the sort. JavaScript's sort() will modify the array in situ, and MDN has a clear indication of this. If the array is held elsewhere, the order of reading may change. You put it on a screen, and it even reset the shelf.
It's just a filter in demand. It's actually the code:
function filterProductsByPrice(products, minPrice, maxPrice) {
return products.filter(
(product) => product.price >= minPrice && product.price <= maxPrice,
);
}
The question of correctness already arises from the former paragraph, which violates the requirements of the “non-renewal series” and the “order of reservations”. It's hard to maintain that the function name doesn't tell you it's also responsible for sorting. There's a problem with the other list, and the searcher has to follow the call chain to find the side effects of this hiding.
Similar problems are hidden between modules. The data are requested over and over again on the pages and at the public level, and the status of the component is replicated in the global store; the same business situation has a set of judgements on different pages. Each place can work on its own, and when the rules are changed, they must first be located.
Why is there another request for sealing?
There is often agreement in the project where the request is sealed, who judges permission, where the status is and how the error is handled.
Only the current AI page and one sentence is required, which may fill the page with a request and a set of error tips. It is true that parts of the project can run and that there is an additional path to maintain. The form of authentication or the wrong code has changed, the public seal has been changed and this page has to be looked after separately.
Agent with search and tool call can check the warehouse and read the project rules. However, whether or not this time has been achieved depends on what it actually reads. The tool has this function and cannot be considered as having been done directly. The entire warehouse was plugged into context and it was not possible to pick out the duplicate code for it.
It could first identify similar functions already in place and then indicate which layers and which documents it was intended to reuse, for what reason. If you don't know what you're doing, keep reading. The change would have to be followed by the discovery of the wrong data entry.
It's thousands of lines in a page.
A list of goods, with screening areas, forms, editing drawers in the same document, is also available for request, permission judgement and style. It's a thousand lines, it's fully functional and it's almost thinner than a sesame. We'll have to check it out first.
If the mission simply writes "make the function work" and fails to refer to layers and components boundaries, AI may continue to add to the existing entrance. The word "reduced" was then interpreted as "preferably one document" and even the additional component was saved. Dismantling several components with clear responsibilities could be a small-scale change.
There is no custom rule, and it is also influenced by the tool default command, the current code and the current context, and may also be active split. It's just that the team wants to see where the page is and what logic should be independent, and it can't always be used to guess.
Take the example of the Vue page, looking for existing public components and similar achievements. When new additions are needed, such an organization can be considered on a functional basis; this is indicative of the need to create a new set:
product-list/
index.vue page assembly and regional collaboration
components/
ProjectFilters.vue Filter Interactive
ProjectTable. vue List Displays and Line Operations Events
ProjectEditDrawer.vue Edit drawers and forms
composables/
Use ProjectList.ts list to load, break and refresh
The stand-alone interactive area can be drawn into an operational component with a state-based, functional envelope requesting the continuation of the existing API layers of the project. The Vue official document also indicates that in addition to reusing the state logic, it can organize the code of complex components with a logical focus.
It depends on state and dependence. The filter condition retains a source where the component collaborates with the specified input and event; the entire page status is copied to each sub-component, and problems with synchronization arise. Thousands of lines were moved into a huge logical document, and only the original large document was replaced with a signboard.
The line numbers can be used as a warning, whether they are reasonable or not, depending on whether the duties are clear and whether the relevant modifications fall where they should be. When the documents are cut down, if the call is more convoluted, this time split has to think again.
You have to be specific. Make sure it works.
There is too much room for Modularization to be elegant. The project rules could be more specific in terms of long-standing constraints, such as:
Reads the rules of the item that is actually supported by the current tool and is valid for the current directory before changing the page.
The public components and similarities already exist are checked, and the documents and respective responsibilities proposed for addition or amendment are listed.
The page entrance is mainly organized and the independent interactive area assesses the component split on duty.
A state-based logic that can be maintained independently is functionally sealed, and a request is made to reuse an already existing API layer.
Status maintains a single source, with components collaborating through clear input and events.
The split scheme or the reason for retaining it is first specified by reference to the document or function warning value agreed upon for the project.
Codes may not be shredded at will for the mere number of rows, or all logic may be moved into another large file.
Upon completion, the applicable inspection must not close the rules or ease the threshold to eliminate the alarm.
Where the rules are placed, for which directories are valid, to be confirmed by the document of the current tool. A file called Rules.md cannot be put in hand, but it will be read. Recapturing the applicable entry will help to check, and follow up on the diff: which floor the document is built, whether it is duplicated, and whether the public entrance is requested to be bypassed.
Moreover, the inclusion of rules does not amount to automatic interception. Claude Code's document indicates that elements such as CLAUDE.md will be loaded as context command; where action needs to be stopped by force, the corresponding execution mechanism, such as Hook, should be used.
The requirement to automatically check can also be followed by a physical door ban. For example, check the length of files, thresholds and exceptions by project using the ESLint max-lines rule; Vue single file components are also equipped with applicable files and parser and actually run through the project. Merger checks need to be prevented, condition failure, access to CI and confirm that scripts do not ignore failed exit codes.
Just reminds you to come back and check the design, Lint doesn't decide how to split the components. The rules document, the automatic check and the code review each part of the tube, allowing AI to end with an assurance that it is “compliant”, and then see what it delivers.
We need to see what the function is.
Assuming that a page is priced and branded and then stocked. Each round adds conditions to the existing function, which then also handles data conversion, permission judgement and error tips. A filter function is gradually taking over the doorman and after the sale.
If each request to AI is to “compatible here” and “test not to miss”, it may always be patched around current symptoms. Each change is small, but it is increasingly difficult to explain what this function is responsible for.
Small diff is worth fighting for, but fewer documents and fewer lines cannot justify the design. When a branch is changed repeatedly, it is time to look back at whether these judgements really belong here and whether there are duplicate business rules. If it is to be reconstituted, it is also important to make clear what can be done this time.
Similarly, it is not necessarily cost-effective to draw a generic framework when duplication is seen. The price screening had not yet been delivered and a plug-in system design document had been received, which was somewhat over-budgeted.
Google's code review guide is dedicated to alerting reviewers to over-design, including interoperability and additional functionality without realistic needs. The solution to the current problem is clear. The needs of the future come true, and it will determine how.
It's all green. It's probably a misunderstanding.
If only the price range of the returned commodity is checked, the side effects of the sorting just taken will not be exposed. The addition of additional sets of data along the same lines does not fill the gap between “whether the original array has been modified”.
Let AI write it and then let it write the test and save the job. But if the same misunderstanding were to be followed on both sides, it might be pleasant to meet with the wrong answer, and nobody felt anything.
acceptance check conditions are best set before they are realized. The selection results should be correct and the price at both ends of the zone should be included. The order of return, whether the original array remains unchanged, and whether the empty result is returned when there is no match item, must also be checked.
The same Google review guide also requires that the test itself be checked for validity: does it really fail when the code is wrong? Does the assertion work? Tests also need to be maintained, not just a few.
It's not working, and it's going to let AI fix it until the test passes, and it depends on what it does. It may be achieved, or it may change the assertion, skip the use of examples, or quietly change the need to the current code. The diff of the test file cannot be missed.
The review depends on dependency, not just the layout.
It is easy to be reassured that the type of name is beautiful, that the catalogue is complete and that the notes explain every step.
It's up to the maintenance team to ask unkind questions. Why can the assembly page function change account balances? Each module will be stored in the same state and who will synchronize the update? When the anomaly is converted to a successful outcome, can the caller know that it failed?
The formatting tool does not answer these questions, and the additional notes do not fix duties and data flows.
GitHub ' s note on Copilot Agents clearly sets out the limitations: code reviews may omit problems, especially large or complex changes; the resulting recommendations may also be inaccurate and require manual review and testing. Look again, there's an opportunity to check, and someone still has to understand the change before the merger.
People write codes like this. AI has made the code easier to produce, and the team has to leave time to read it, and the time saved cannot be set aside for the next demand.
Write maintenance requests to task
acceptance check is not easy. The task of screening commodities is more specific:
Read the list of goods, the relevant data entry, and similar filters where they exist.
First, indicate where it is intended to be reused, which documents are expected to be changed, and not change the code for the time being.
Once the programme has been confirmed, the price interval screening will be achieved:
- Screening on the basis of existing data without adding a new set of requests.
- Keep the original display order without modifying the original array.
- This screening status belongs only to the current component and is not copied to global store.
- No changes to the interface of the public component, no upgrades of dependence, and no re-engineering of other modules.
- Tests to cover boundary prices, empty results, order retention and original arrays.
When completed, indicate how the data flowed, where the status was placed and what inspections were actually performed.
If it is found that the scope of the change needs to be expanded, the reasons are explained.
This is what this small task requires to leave the screening in its current component. Instead of the condition of sharing across the page, you have to re-judge where you put it, and do not treat the constraints in the example as a standard answer for all items.
The scope of impact and the acceptance check approach could be discussed separately if public interfaces were to be changed or re-engineered. It is clearer which functions must be modified and which are merely additional recommendations.
A small follow-up requirement, such as “branding” could also be raised before the merger. Not yet. Let it say where it's ready to change and what tests to add. If this also involves permission, requests for seals and general conditions, it is worth first checking whether these dependencies are necessary.
Finally, it makes clear where the data comes from, where they belong, what behaviour is not moving and can point to the actual code. The phrase “has been fully optimized and has been well expanded” could be omitted. It's hard to look for bugs, it's hard to find them in documents and calls.
Auto-fetched and translated by AI Atlas. All rights belong to the original author.