当前位置:首页>java>从代码补全到工程约束:AI编程不是摆姿势

从代码补全到工程约束:AI编程不是摆姿势

  • 2026-10-12 21:50:39
从代码补全到工程约束:AI编程不是摆姿势
我一直觉得“AI编程革命”这个词,很像PPT里那种会自动变大的箭头:动效做得很足,方向感却很弱。至于所谓的Vibe Coding,翻成“氛围编程”之后反而让人更清醒——如果一个概念需要靠“氛围”来成立,那它大概率不适合拿来维护一个活了十几年的工程。老系统要的不是感觉对不对,而是这一步会不会炸。尤其当你维护的是一个从2013年长出来的iOS工程:Objective‑C和Swift深度混编,XIB、纯代码、历史宏、Category、条件编译一起上桌,任何一个“看起来很合理”的重构,都可能在下一个版本把线上用户送去看白屏。这个时候你再听人说“让AI帮你重构”,会有一种奇妙的感觉:像在加油站里抽烟的人对你说“别怕,我很熟”。
过去两年我最大的焦虑,不是“AI会不会取代我”,而是AI 正在极其高效地制造一种新的屎山,而且看起来还很高级。它写出来的代码往往并不“错”,只是完全不理解你工程里那些不能动的历史约束:为什么这个BaseVC不能继承、为什么这里还在手算frame、为什么这个XIB只能“半用”、为什么一个看似无害的布局调整会牵扯到三条登录路径、两套皮肤和一堆埋在角落的监听。
所以这篇文章不准备鼓吹任何工具,也不打算给你画“未来所有人都AI编程”的大饼。它只回答一个老工程负责人最关心的问题:怎么把AI从“漂亮但危险的代码生成器”,驯化成“遵守工程纪律的合作者”,并且在高风险改动里不翻车。

一、第一阶段(2024):代码补全时代,AI只是个超级实习生

2024年我们最早的用法非常朴素:把Copilot/GPT当作高级补全,写写重复性代码,比如UITableViewDataSource、Swift模型映射、一些模板化View/VM结构。这阶段的价值是真的,省体力也省情绪,尤其在你已经写了第200次同款列表页之后。
问题也同样真实:它只能看到光标附近的上下文,跨模块、跨历史时期的逻辑,它只能靠“合理猜测”。而在老工程里,“猜测”几乎等价于“埋雷”。你让它补一段通知收银台刷新状态的链路,它会编出一个看起来很像你们风格的 API,甚至命名也对味,但那个API在工程里根本不存在。更麻烦的是,这种“幻觉”不是那种一眼就错的低级错误,而是那种能让你review时也差点点头的错。
这阶段的结论很直接:AI只适合做局部加速器,不适合当工程方向盘。它能让你写得快,但写得快不等于改得对。

二、第二阶段(2025 上半年):Rules先立规矩,MCP再给权限(同一阶段)

真正的转折点,不是模型突然变强,而是我们终于正视了一个事实:在没有工程约束之前,讨论AI能力毫无意义。
我们先做了一件很不性感但很关键的事:把团队十多年形成的“部落知识”写成规则,放进.cursorrules(或等价的规则体系)里。比如布局必须用Masonry、禁止新增 XIB 混编ViewModel必须实现统一协议;哪些基础类禁止乱继承;哪些宏属于历史包袱但暂时不能动。你可以把这理解成给AI发员工手册:先告诉它哪些事情会被扣绩效。
Rules能解决一个问题:让 AI 不再随心所欲。但它解决不了另一个更致命的问题:AI仍然不知道工程的真实状态。它依然是被动的、静态的,只是一个更听话的实习生。
于是MCP(Model Context Protocol)进入视野。这里有必要把话说清楚:MCP 本身并不等同于“AI 会查工程”,它解决的是规范化访问外部数据与工具接口的问题——也就是说,AI 终于有了一套受控、可审计的方式,去调用文件系统、工程索引、依赖分析器等外部能力。它提供的是“通道”和“协议”,而不是具体的工程规则。
而Rules则完全是另一层东西。Rules来自工程自身,往往就是一些约定好的markdown、规范文档,或者已经固化在模块边界里的隐性约束,它们回答的是“什么能做、什么不能做”。没有Rules,MCP只是一把权限很大的钥匙;没有MCP,Rules就只能停留在文本层面,最多约束AI别乱写,却无法让它基于真实工程状态做判断。正因为二者分工不同、又彼此依赖,我们才把它们放在同一阶段讨论:一个负责规范通路,一个负责工程边界,缺一不可。
到这里,AI终于开始从“只会说”向“能做事”靠近,但它离真正可控还差一段关键拼图:Skills。
三、第三阶段(2025 下半年):Skills单独拆开,才是让AI真的能干活的部分
如果Rules是员工手册,MCP是门禁系统,那么Skills就是你发给AI的工具箱。它不是“提示词技巧”,而是基于MCP封装出来的可执行能力:读取工程文件、分析依赖、解析 XIB、追溯宏定义、做语义检索。更重要的是,Skills 带来的并不是“一次性把上下文全喂给模型”,而是两种在老工程里极其关键的能力:动态获取(Dynamic Context Retrieval) 与 渐进式披露(Progressive Disclosure)。
所谓动态获取,指的是AI在需要判断时,才通过Skill去拉取当下最相关的工程事实,而不是依赖训练记忆或静态上下文;而渐进式披露,则意味着上下文不是一次性暴露给模型,而是随着问题推进、决策收敛,按需、分层地展开。这两点叠加在一起,才让AI在老工程中具备一种接近“谨慎工程师”的行为模式:不知道就查,没必要就不看,避免在信息过载中做出自信但危险的判断。你不需要把几百个文件贴进聊天窗口,AI可以按需检索;你也不需要祈祷它记得你们项目里到底用的是哪个约束写法,它可以直接去看仓库先例。
我们在iOS工程里给AI封装的Skills不是越多越好,而是越克制越好,核心目标只有两个:动态获取真相,以及把上下文限制变成按需查询。举几个典型场景(均为脱敏抽象):
第一类是工程状态查询与解释。以前遇到Pod冲突,最常见的操作是“先升级试试”,本质上是在用经验赌结果。现在AI并不是“自动判断该怎么升级”,而是通过Skill按需读取Podfile.lock、Podfile、workspace等确定性的工程输入,把当前依赖图、版本约束和传递关系摊开给你看,并明确指出哪些组合在当前状态下存在冲突风险、哪些变更会扩大影响面。这里Skill提供的不是“升级建议”,而是可验证的工程事实,最终是否升级、如何升级,仍然由人来决策。
第二类是UI结构与约束来源的可视化披露。老XIB的真正风险不在于“不好改”,而在于“你不知道当前布局到底由谁控制”。Skill 并不是替你修改布局,而是解析XIB与关联代码,按需披露视图层级、约束来源(IB / 代码 / 运行时调整)、Safe Area绑定关系以及关键IBOutlet的作用范围,让你明确回答一个问题:这次改动会触碰哪几条事实来源。它解决的是“看清楚现状”,而不是“帮你动手改”。
第三类是符号级定义与引用关系的追溯。在老工程里,宏、全局常量、条件编译往往比业务代码更难追责。Skill在这里做的不是语义推理,而是符号级检索:某个#define或配置项定义在哪里、被哪些文件引用、引用发生在什么编译或运行语境下。它把“我记得好像有这么个东西”还原为明确的定义点与引用集合,至于是否替换、如何迁移,同样交还给工程负责人判断。
Skills 的价值不在于“AI 很强”,而在于它让 AI 开始遵守一种工程事实:不知道就去查,不要猜。对老工程来说,这是从“会写代码”到“不会乱写代码”的质变。

四、第四阶段(2025 年末):SDD不是流程崇拜,而是高风险重构的安全带

即使有了Rules、MCP、Skills,我们也不会把所有需求都丢给AI编程。因为老工程真正要命的活,往往不是“写一段代码”,而是“动一次结构”。比如我们这次做的实战:把登录页的布局约束从Interface Builder迁移为代码维护,目标是提升可维护性、减少合并冲突、提高可审查性,同时保证不引入任何可见回归。
这类任务,一句话总结就是:你可以不加新功能,但你不能把入口页面搞歪。于是我们用了SDD(Spec‑Driven Development)+ GitHub Spec Kit的工作流,让AI在写代码之前先写清楚“什么叫做对”。这不是文档洁癖,这是事故预防。
下面是脱敏后的真实文档结构与要点(来自附件中的spec kit实战记录,路径已替换为):
1)Specify:先把“验收”写到代码出现之前
分支名采用明确可追踪的形式:[001-migrate-login-constraints],规格说明 spec.md 的输入是“将登录页面的布局约束迁移为代码维护,以改进可维护性”。文档里把需求写成可测试的用户故事,并且按优先级划分:
P1:维护人员希望登录页布局由代码统一定义与维护,不依赖可视化编辑器也能调整间距并通过验收;
P2:测试/验收人员希望此次改动不改变交互与信息结构,横竖屏切换与键盘弹出等场景下不出现遮挡、跳动、错位;
P3:评审者希望布局改动可通过文本diff审查,不需要打开可视化编辑器才能理解改动。
规格里还把边界条件写死:横竖屏/分屏、键盘弹出、文案长度变化、系统字体大小变化,这些都是老工程UI迁移最爱翻车的地方。然后把它们固化成FR与AC,比如 FR‑003 明确“布局约束以代码形式集中定义”,AC‑004明确“键盘弹出/收起与横竖屏切换后布局稳定且可完成操作”。你会发现这里的关键不是写得“全面”,而是写得“可判定”,每条都能用客观标准验收。
2)Research:技术决策不是拍脑袋,要对齐仓库先例
research.md 做了三件关键决策:
第一,约束放在initUI里由Controller驱动,并使用Masonry,理由是仓库已有先例(例如另一个登录相关 Controller在initUI中定义Masonry约束),避免为单页引入新范式,同时保证diff可审查;
第二,保留XIB作为视图层级与outlets,移除/失效化其中Auto Layout约束,让代码成为布局单一事实源,这样回归风险最小;
第三,用代码维护的约束更新/重建流程替换原先由IB管理的jobViewLayoutConstraint,避免“单一事实源”被一个遗留outlet破坏。
注意,这里所有决策都写了备选方案与拒绝理由,比如把约束放updateViewConstraints更标准,但容易重复添加且与仓库模式不一致;完全代码重建页面风险更高。这种“写明为什么不选”的部分,往往比“选了什么”更能救命。
3)Plan:把边界、约束、验证方式提前锁死
plan.md明确范围:仅 UI 改动、不引入新依赖、不动业务逻辑、尽量减少.pbxproj噪音;明确工程背景:Objective‑C + wift、UIKit、Masonry、ReactiveObjC;明确验证方式:手动UI回归 + 增量 xcodebuild编译。
它还把“单一事实源”写得很直白:触碰范围内的布局约束事实源应集中在UserLoginController。这句话本质是在对未来的自己说:别再让布局散落在XIB、Category、宏和多个方法里。
4)Tasks:把大手术拆成可并行、可回滚的原子任务
tasks.md 的组织方式按用户故事分组,并且把准备、实施、回归、收尾拆成阶段。关键任务点非常工程化:先基线增量构建,再检查现有IB约束与outlet连接,再对齐仓库Masonry写法,然后进入迁移。
核心迁移任务里最关键的是一组连贯动作:在 .m 中实现顶层组件 Masonry 约束(T010),在 .xib 中移除/失效化冲突顶层 IB 约束(T011),用代码约束更新/重建替换 jobViewLayoutConstraint(T012),最后移除该outlet 连接及引用(T013),再做一次增量构建验证(T014)。这组任务最大的价值在于它把风险压到可控粒度:你每一步都能编译、能回滚、能定位问题。
5)Quickstart + QA:把“怎么验”写成最短路径,不靠口头传承
quickstart.md 给出推荐的增量构建命令(workspace、scheme、derived data路径等都写清楚),并把手动验证步骤列成顺序:启动进入登录页,覆盖多设备尺寸与横竖屏组合,切换登录模式(账号登录 && 账号+工号登录),分别验证各输入框键盘弹出/收起,最后做一次登录尝试确认行为不变。qa.md 则把设备/方向矩阵做成可填写的checklist,并把关键场景固定下来:模式切换、键盘弹出、长文本与字体变化、登录流程。这套东西看起来“文档多”,但它解决的是老工程最常见的事故来源:测试依赖记忆,验收依赖口头。
SDD 的真实收益不是“AI写得更好”,而是:在代码出现之前,你就已经把翻车的方式写在纸上,然后逐条封死。

五、第五阶段(2026 至今):GPT‑5.2 让AI编程终于可以用,但它依然需要刹车

GPT‑5.2‑codex 出现后,我们的日常迭代确实进入了更顺滑的状态:一句话描述意图,AI在Rules下输出符合项目风格的代码,再通过Skills拉取真实上下文,少走弯路。但我越来越坚定一个判断:AI编程的前提不是“模型够强”,而是“工程刹车在”。
我们现在的做法非常现实:日常小改动走轻量流程(Rules + Skills + 模型),核心重构必须走SDD(Spec Kit五步法)。不是所有需求都值得跑一套文档,但只要任务具备高风险特征——入口页、支付链路、登录链路、历史包袱重、回归成本高——就不要省那点文档时间。省下来的不是时间,是事故。
归根到底,AI不是用来写更多代码的,而是用来少犯那些你已经犯不起的错误。老工程最怕的不是“你不会写”,而是“你写得太自信”。AI的自信尤其便宜,而且还会带格式。
如果你也在维护一个活了十几年的iOS工程,我的建议只有一句话:先把工程纪律立住,再让AI进场;在风险可控的地方可以充分利用AI编程提升效率,但别忘了,安全带从来不碍事,碍事的是事故。

六、再往下走一步:为什么Skills不能泛滥

写到这里,其实有个问题是刻意没展开的:既然Skills这么有用,为什么不把“能做的事”都做成Skill?
这是很多团队在MCP落地后很容易踩的第二个坑。
直觉上你会觉得:既然AI可以查依赖、扫XIB、追宏定义,那是不是也可以直接给它“改文件”“批量重构”“自动提交”?理论上当然可以,实际上在老工程里,这种“全能型AI”往往死得最快。
原因很简单:Skills一旦越过“只读 / 分析”边界,就会和工程纪律发生正面冲突。
老工程最怕的不是“你不知道怎么改”,而是“你不知道自己改了多大范围”。如果Skill本身具备强副作用,而Rules又无法精确约束它的调用时机,那AI很容易在“我只是顺手帮你优化一下”的过程中,完成一次你自己都不敢做的全局修改。
所以我们在Skills设计上的原则其实非常保守:
  • 优先只读,慎用写操作
  • 优先结构分析,而不是自动修复
  • 优先暴露事实,而不是给结论
AI可以告诉你“这里有3处约束来源”,但不替你删;可以告诉你“这个宏影响了17个文件”,但不替你改。让人承担最后的决策成本,是老工程里非常重要的一条底线。

七、为什么SDD看起来慢,但实际上更快

很多人第一次看到SDD流程,都会有一个本能反应:这也太重了吧?一个登录页改布局,居然要写spec、research、plan、tasks、qa,看起来比直接上手改还慢。
但这是典型的“只看写文档时间,不看事故时间”。
老工程里真正消耗时间的,从来不是写代码,而是:
  • 改完一周后才发现一个边缘场景
  • 测试说“我记得以前不是这样的”
  • 线上问题回溯不到变更意图
SDD的本质不是流程,而是把这些隐形时间,前移成显性时间。Spec让你在改之前就把“争议点”写出来;Research让你在动手前对齐历史决策;Tasks把一次大手术拆成可以随时止血的小步骤;QA把“靠经验测”变成“按清单测”。
很多时候,SDD并不是让AI写得更好,而是逼着人把想当然的地方想清楚。AI只是那个被迫跟着你一起慢下来的角色。

八、AI编程的真实边界

现在回头看,Vibe Coding这个词其实挺容易被误解的。它听起来像是一种放松、即兴、随感觉走的写法,但在老工程或者复杂工程语境下,真正成立的AI编程,前提恰恰是边界极其清晰。
我们内部对 AI 编程 有一个不太浪漫的定义:
在确定不会引发结构性风险的前提下,允许效率优先。
所以它只适合:
  • 局部功能增强
  • 逻辑清晰、影响面可控的修改
  • 有现成先例可以对齐的实现
一旦涉及:入口链路、支付、登录、权限、历史包袱密集区,AI编程就必须让位。不是因为模型不行,而是因为工程不允许你赌。

九、写在最后:AI最大的幻觉,是让人觉得“这次应该没事”

普通脚本、玩具代码,今天的大模型确实可以随便写,写得还不差。但复杂产品不是脚本集合,老工程也不是一次性作品。它们有历史、有边界、有隐性契约,也有不能失败的时刻。能把一段代码跑起来,不代表能把一个系统稳稳地维护下去。
正因如此,AI编程在复杂产品里的价值,不是“写得多快”,而是在工程约束下少犯错。当改动牵一发动全身,当回归成本高到不可承受,真正重要的不是模型能不能写,而是工程有没有把刹车、护栏和责任链条立住。
老工程最怕的不是不会写,而是写得太自信。AI的自信尤其便宜,而且还会带格式。把规则立清楚,把权限收紧,把流程写死,把高风险交给SDD,这样的AI,才配得上进场。

最新文章

随机文章