J++ · 真实项目改写实测 · 数据截至 2026-09-26 16:30

84 个真实 JEV 项目,用 J++ 重写后逐字段比对

从 GitHub 上 3361 个用到 JEV 判断接口的开源仓库里,按用途和题型聚成 75 类,每类取一个代表。原项目的代码一行不改地跑,J++ 另写一遍,两边喂同一批判断读数,逐字段比较输出。结果:72 个完全一致,11 个部分一致(不一致处单列原因、不剔除),1 个因原项目自身缺陷无法比较;J++ 的判断核心代码中位数是原项目的约五分之二。调用判断接口的次数在 79 个项目上与原项目持平;另有 4 个要在候选之间互相比较的项目,J++ 目前得把每个候选拆成单独一次判断,调用次数高出很多。

72 / 84项目在同一份读数下逐字段完全一致(85.7%),另 11 个部分一致
2.5×判断核心代码量倍率中位数(按每 100 字符折行归一;四分位 1.8–3.6×)
1.44–1.66×把两边都要写的胶水代码也算进去之后的倍率(这一口径的上限)
0.99979 个项目上 J++ 与原项目调用判断接口次数之比(1111 次对 1112 次);4 个跨候选比较的项目是 174 次对 18 次

怎么比的

  1. 圈出原项目的判断核心:题怎么定义、怎么调判断接口、阈值怎么分流、多道题怎么组合。命令行、网络、日志这些不算。
  2. 写任何代码之前先提交预注册:预测行数比、调用数比、哪些字段比不了。
  3. 给原项目接一个同名同签名的假客户端,跑它未改动的代码,记下每次调用的题目和读数;输入覆盖每个阈值的两侧和模棱两可的中间带。
  4. 核对每条依赖读数的分支确实走到了;走不到的先分清是输入没造到还是原项目自己的缺陷。
  5. 把调用记录转成 J++ 的夹具,写 J++ 程序,用同一批读数跑。
  6. 逐字段比较输出,第一处不同原样打印;再比调用次数、数代码行数。部分一致的项目照样计入分母。

代码量落在哪一层

每个点是一个项目(判断核心口径,对数刻度)。底色是业界有出处的参考区间:同代通用语言之间(例如 C 对 C++)约 1.4–3 倍;领域专用语言连同它需要的生成器和胶水代码约 3.5–3.9 倍,只算专用语言自身的文本可到 2.7–17 倍。

完全一致部分一致竖线:中位数 2.5× 虚线:1×(行数相同)

省得最多的项目,原本手写了大量重试、校验、分批和拿不准时的分流,这些 J++ 语言本身就做了:推理力度路由 427 行变 39 行,机械臂控制 396 行变 43 行。省得最少、甚至更长的项目,核心本来就短,主要是题面文字和多道候选集不同的选择题,J++ 写法上每道题要各自带候选集。

用业界评价语言的框架评 J++

业界比较两门语言,从来不只看一个「好用多少倍」,而是分几个维度量。我们之前核实过这些框架的出处,下面逐项对照。

维度业界怎么量、参考数J++ 的结果
代码量功能点语言等级表(Jones)、同题多实现(Prechelt):C→C++ 约 2.4 倍;同代通用语言 1.4–3 倍;专用语言连胶水 3.5–3.9 倍判断核心中位数 2.5 倍、汇总 2.98 倍;计入胶水 1.44–1.66 倍。落在「同代通用语言」一层,和 C 对 C++ 同量级,不是 SQL 那种十倍量级
开发时间受控实验:专用语言快 1.45–2.3 倍;时间倍率通常低于代码量倍率没有测。实验设计已写:同一批任务,代理分别用 J++ 和 Python 独立实现,记墙钟时间与 token 消耗,多次取中位数
正确性Rust 的价值靠「一类错误写不出来」证明,Google 报告改写后工作量减少两倍以上,主要来自缺陷更少改写时在原项目未改的代码里查出 8 处真实缺陷(见下);J++ 版本自带原项目没有的保证:每次判断记账可重放、拿不准必须有去处、撤不回的动作过线才执行、判断线来历可见
运行成本传统框架没有这一项:C 或 Rust 的执行不按次付费79 个项目上与原项目持平(0.999);4 个要在候选之间互相比较的项目,J++ 目前把每个候选拆成单独一次判断,合计 174 次对 18 次,这是已登记的缺口(请求形状与重排器)。同一处同样的请求只发一次,结果可缓存复用

我们发现的不一样

只看代码量,J++ 像 C 到 C++。倍率是几倍,不是几十倍。如果有人问「J++ 是不是像 SQL 那样把代码压缩了十倍」,如实的回答是「不是」。

更大的价值在正确性,这一点像 Rust。原项目里那种「浮点误差改了阈值边界」「拿不准的结果被悄悄丢进失败列表」「一个更严格的阈值因为逻辑覆盖从来没生效」的问题,在 J++ 的结构里更难写出来。这类价值不体现在行数上,要用「少出多少错、能不能审计重放」来量。

判断的调用成本是传统框架没有的维度。每一次判断都是一次真实的外部调用,有延迟和费用,需要单独测、单独报。

编码之外的工作变了形。Jones 的研究提醒过:编码只占大型项目工作量约三成,代码量倍率不能直接换算成开发效率。J++ 还把原来藏在几行 if/else 里的判断设计(问什么题、线划在哪、拿不准怎么办)变成必须写明的东西,这部分工作在传统工时统计里没有对应的科目。

在原项目里查出的真实缺陷

这些缺陷都在原项目未改一行的代码里,是真的跑起来、喂数据时暴露的,不是 J++ 或改写工具引入的。

分支永远走不到

onciopescini/botcraft:收判断结果的分支受线程执行顺序保证约束,两个条件永远不能同时成立。5000 次复现 0 次反例,真机 260 步一次也没触发。

更严的阈值从未生效

XMoyas/web_attack_detection_jev:先判 0.40 再判 0.70,宽的条件已经覆盖了严的,0.70 从不单独决定结果。

分档在边界上方向交替

behindthedash/worktrail:Python 的四舍五入在 0.5、1.5、2.5 上方向依次是下、上、下(「五取偶」规则),分档不单调。

浮点误差改了边界

meetr1912/jev-bracket:abs(p − 0.5) < 0.05 在 p = 0.45 时因双精度减法的舍入误差为真,本该在边界外的读数被划进了「拿不准」。

概率大于 0 就算「是」

sudeshkar/jev-corrective-rag:用 bool(ans.noul) 取是非题的真假,概率只要不是恰好 0 就为真,真机上几乎每个问题都会被升级给人工。

置信度门永远能过

sudeshkar/jev-corrective-rag:从是非题答案里取一个它根本没有的置信度字段,缺省为 1.0,「不低于 0.5」恒成立。

公开入口打不开的功能

adigulalkari/Jev_GC:ask_item_role 没有暴露给配置,走文档写的入口时永远关着。

「或」条件意外重叠

prantikmedhi/anchorlint:一条分支的条件里的「或」让它在标签不对时也会触发,造测试用例隔离分支时发现。

原项目自己让 JEV 判断代码就能定的事

JEV 的价值在复杂的语义判断。能不能运行、数值相等、坐标比较这类事,用普通代码判就行,不该花一次判断。改写要求效果一模一样,所以原项目这么问的,J++ 版照原样对照,但在这里标出来。

按题面扫了 84 个项目:明确属于这一类的有 1 个,siroccomask/snake-jev,贪吃蛇每一步问 JEV「会不会撞墙」「会不会撞到蛇身」「离食物是不是更近」,这些都是坐标运算。另有 9 个项目的题面里有一部分看起来能用代码算,要不要算取决于输入细节,没有逐题重读源码,暂列为拿不准。

边界与还没做的

逐项数据

编号仓库语言用途结果核心行J++ 行倍率调用 原 / J++