Lazy loaded image
对于新人古法编程的思考
Words 2741Read Time 7 min
2026-4-8
type
Post
status
Published
date
Apr 8, 2026
slug
thought1
summary
tags
成长
category
icon
password
起因:开源社区committers一致要求新同学做前几个需求时必须古法编程。
我做的背景是Dubbo-go Issue #3259:Java 泛化调用 dubbo-go 时,Go 方法如果是 args ...string 这种可变参数,应该怎么传。我发现是框架不支持,那就补上这个特殊情况,让框架支持就好了.我也是这么做的,首版 commit 只改了 4 个文件,新增只有138 行,测试跑通了,本地看问题解决了,我就提交了 PR #3284
但是PR 交上去以后,committer review 出了 2个P0、5个P1、5个P2 问题。跟他交流之后,我才发现这个修复不能只是在 generic filter 里补一段参数处理,还会牵扯到 proxy/invoker、Triple reflection、server reflection 和多层测试,没考虑到我的这个小修改会影响这么多地方。这个看起来很小的 special case,进框架以后变成了调用语义问题,可是我连往这方面想的意识都没有。很明显我当时看问题的思维太差了,对链路的理解不够,也没有从不同角度去看,比如说从全局视角、owner视角看问题。
所以,对刚入行新手时,写前几个需求的时候,我非常推荐先古法编程:自己读调用链,自己复现问题,自己改代码,自己跑测试,再把 PR 交给社区 review。虽然AI可以很快生成一版答案,但真正自己去做,去发现问题,再去改正,能让你更好理解编程。最重要的是你看问题的意识变了,你开始成为一个能解决问题的人。
对新人来说,AI 时代最危险的不是“不会用 AI”,而是“只会把 AI 当代写器”。你是否有能力给 AI 提对问题、设对边界、看出它哪里错”。这一层不会,你是能用AI完成任务,但AI跑偏了怎么办?
古法编程输出倒逼输入,有了古法编程的经验,之后能更好review AI写的代码。
那我从这次2个P0、5个P1、5个P2问题经历中学到了什么?

第一课:外形相似不等于语义相同

我一开始就是在这里想简单了:看到参数像 slice,就想把它当成 variadic 尾参处理。
我首版的想法很直接:既然目标方法是 variadic,最后一个参数又是 slice 或者能整理成 slice,那我就在泛化调用路径里把它整理好,后面反射调用时配合 CallSlice。这个思路在本地能跑,所以我觉得合理。结果……
notion image
review 提醒我,普通 []interface{} 参数和 ...interface{} 在泛化调用里可能长得很像。如果我只靠“最后一个参数像 slice”判断,就可能把普通调用误判成 variadic 调用,进而包错参数、拆错参数,甚至走错反射路径。
改的时候,我把思路放到了 marker 上:generic filter 明确识别并整理过 variadic 参数后,写入 GenericVariadicCallSliceKey;后续 proxy、Triple、server 反射路径看到这个 marker,才继续判断是否允许 CallSlice特殊逻辑必须有来源标记,不能靠“看起来像”触发。
以后我再写类似逻辑会想:这个分支为什么知道自己是特殊路径?如果是“参数形态看起来符合”,我会去检查特殊逻辑有没有明确 marker。

第二课:reflect.Set 前必须先做类型门禁

一开始把反射写得太像普通赋值了,但反射没有编译期兜底。
我首版在 generic filter 里重塑 variadic slice 时,思路是把传进来的值转成目标 slice 里的元素,再用 reflect.Set 塞进去。当时我关注的是“能不能构造出目标参数”,没有把每一次 Set 可能 panic 的情况拆开看。我当时只关注构造成功,没有先检查构造过程是否安全。结果……
notion image
review指出来,不能直接 Set(reflect.ValueOf(x))。nil 能不能被目标类型接住,值能不能 AssignableTo,不能 assign 时能不能 ConvertibleTo,这些都要在 Set 前确认。我错把类型不匹配留给运行时 panic了。
改完以后,这块逻辑变成了先做类型门禁:nil 按目标类型处理;能 assign 就直接用;不能 assign 但能 convert,就转换;都不满足,就返回清晰错误。array、slice、zero value 这些边角形态,也不能凭感觉混在一起处理。反射代码要先确认值能安全进入目标类型,再谈调用。
以后我看到 reflect.Setreflect.Call 会自然多想一步:这里有没有 nil、assign、convert 的保护?错误是能返回出来,还是会直接 panic?以后要检查反射前的类型门禁。

第三课:CallSlice 会改变语义,不能宽松触发

我一开始把 CallSlice 当成解决 variadic 的工具,却没有先确认它会不会改掉普通调用,对反射分发里的语义切换不太熟悉。
我首版的方案是:方法是 variadic,最后一个参数是 slice,那就走 CallSlice。因为 Go 反射里调用 variadic 方法确实经常会想到 CallSlice我当时的问题是只看到了目标 case,没有考虑普通调用也可能满足同样条件。结果……
notion image
review提醒我,这个条件太宽。普通本地调用也可能传入一个 slice,如果这时因为方法是 variadic 就切到 CallSlice,原有调用语义就被改掉了。我做错的点,是让特殊修复有机会影响普通路径。
改的时候,我把 CallSlice 的触发条件收紧了:方法必须是 variadic,调用必须带有 generic variadic marker,参数数量要匹配,最后一个参数还要能匹配声明的 variadic slice 类型。只有这些条件同时成立,才说明这是 generic filter 明确准备好的 variadic 调用。语义切换不能靠单个宽松条件触发。
以后我再写框架分发逻辑会想:这个特殊分支会不会被普通调用误进来?如果会,就说明门禁还不够。以后我要检查特殊路径会不会误伤普通路径。

第四课:测试要封住语义影响面

我一开始更像是在测“issue 复现路径好了没”,review 要求我测“相关语义有没有被改坏
首版里,我主要关注 Java generic call 调 Go args ...string 这个主 case。它能跑通,我就觉得核心问题已经解决了。结果……
review 里的 P1 回归测试不足评论 要求补离散参数、packed array、...interface{} 不要二次包装、固定参数加 variadic、nil、零个 variadic 参数、单个参数、多类型参数等场景。看到这些要求以后,我才意识到:reviewer 关心的不是“我遇到的 case 能不能过”,而是“这个改动可能影响的语义有没有被圈住”。我做错的点,居然是按复现步骤测,而不是按影响面测。
改完以后,测试不只补在 generic filter,还覆盖到了 proxy/invoker、Triple reflection、server reflection。这个跨度让我明白,一个参数整理问题在框架里会穿过多层调用路径,测试也要跟着调用链往下铺。框架修复的测试要覆盖它实际经过的路径。
以后我写测试会想:普通路径测了吗?特殊路径测了吗?最容易混淆的参数形态测了吗?跨层传递的 marker 或上下文测了吗?以后我要检查测试有没有封住语义影响面。

剩下的 review,让我补上社区习惯

能合并的 PR 不只要核心逻辑对,还要让维护者读起来、查起来、合起来都顺。
一开始我会天然觉得,命名、错误信息、重复 reflect.ValueOf、target branch、Codecov、SonarQube 这些事情没有 P0 那么关键,可以等核心逻辑差不多了再处理。review 之后我才发现,这些“小问题”会一起影响 PR 的维护成本。我当时低估了社区项目里一致性的价值。
改的过程中,我开始对齐项目里的命名习惯,比如 ivkURL 这类缩写风格;错误信息也要贴近项目已有格式;反射路径里明显重复的操作要顺手收掉;target branch、CI、覆盖率、质量门禁也要自己提前核对。社区规范决定你的代码能不能自然长进项目。
以后我再提 PR 会注意这些规范,而不是等 maintainer 或 bot 来提醒。提前处理能省掉很多来回沟通,减少返工。要主动检查代码的规范性问题和可维护性问题

总结

如果这次我从头到尾都交给 AI,能更快完成任务。但我亲手读链路、亲手提交、亲手被 P0/P1/P2 review 打回来,再一条条修掉问题,才有了 marker、类型门禁、CallSlice 语义、测试影响面和社区规范这些意识。
PR #3284 之后,我再写框架类改动,会先想:这个特殊修复有没有来源标记?会不会误伤普通调用?反射前会不会 panic?测试有没有封住语义?风格和流程是否符合社区要求?尽量不出问题,减少返工。
新人阶段的古法编程,让你从一个只会写玩具项目、只会死背八股的人,变成一个有解决实际问题思维的人高级程序员大多拥有好的编程思维,如果一直Vibe coding,一直做prompt工程师,不自己去思考,如何提升?等着被取代吗?
 
回到首页