Ohhnews

分类导航

$ cd ..
Jetbrains Blog原文

基于IDE遥测数据的Java与Kotlin开发周期速度对比分析

#软件开发#java#kotlin#生产力#ide遥测

引言

编程语言的选择是否会影响开发者的代码交付速度?对于评估技术栈的工程团队而言,这是一个至关重要的问题,但却难以回答。基于自我报告的调查容易产生回忆偏差,代码行数对比往往混淆了简洁性与生产力,而受控实验又很难扩展到少数参与者之外。

2024 年,Meta 推出了差异编写时间(Diff Authoring Time, DAT)——即从开发者开始处理代码变更到提交审核所需的实际时间——作为一种可扩展的、基于遥测的生产力指标。受此启发,我们将该概念应用于 IntelliJ IDEA 的内置使用遥测(功能使用统计),构建了 IDE-DAT:直接在 IDE 内部测量从首次代码编辑到推送(push)的时间。

本文展示了一项大规模观察性研究,对比了 Java 和 Kotlin 的开发周期速度。我们分析了约 32 万名 IntelliJ IDEA 开发者在 20 个月内(2023 年 11 月至 2025 年 6 月)的遥测数据,涵盖了约 2800 万个开发周期。

在控制了用户、项目、总体时间趋势和任务规模等变量后,我们发现 Kotlin 项目的开发周期通常比 Java 项目中类似的开发周期更短——对于日常的小型、中型和大型任务,周期缩短了约 15%–20%。在实践中,主要模式并非戏剧性的一次性加速,而是较慢的性能退化:随着项目的成熟,未迁移的 Java 环境中周期时间往往会增加,而 Kotlin 环境的退化程度则较小。

关于透明度的说明:JetBrains 是 Kotlin 的创造者,我们意识到任何将 Kotlin 与 Java 进行对比并得出有利结论的研究都可能被视为有偏见。因此,我们采用了严谨的统计框架——基于对数转换结果的纵向双重差分法(longitudinal difference-in-differences),并辅以多个对照组和有效性检查。我们完整地呈现了方法论、数据、局限性和悬而未决的问题,以便读者能够独立评估证据的力度。

在接下来的章节中,我们将介绍该指标(第 1 节),展示核心发现及其具体量级(第 2 节),梳理详细结果(第 3 节),探讨有效性威胁与悬而未决的问题(第 4 节),并记录完整的方法论(第 5 节)。

1. 开发速度的衡量:IDE-DAT 指标

1.1 “首次编辑 → 推送”周期

**IDE-DAT(IDE 差异编写时间)**是Meta 的 DAT 针对 IntelliJ IDE 遥测的适配版本。

我们测量单个开发周期的持续时间

推送₁ → [首次编辑, ..., 编辑, ..., 提交] → 推送₂

  • 周期开始 = 上一次推送后,首次编辑 Java/Kotlin 文件的时刻。
  • 周期结束 = 下一次推送的时刻。
  • IDE-DAT = 两者之间的实际墙上时钟时间。

这作为“处理单个变更所花费时间”的代理指标——从开发者开始编写代码到推送结果的时刻。

1.2 任务规模的确定方式

在每个周期内,我们统计编辑事件的数量——即 IDE 报告的文件编辑实例,并设有 1 分钟的冷却时间(每次报告后,系统会静默 1 分钟,即使开发者继续输入)。编辑事件的数量是任务规模的代理:粗略地说,这反映了开发者在周期内切换阅读和编写代码的频率。我们承认,编辑次数也可能取决于所研究开发者的资历水平。

周期被划分为规模桶(Size Buckets)

编辑次数典型周期时长(中位数,Java)任务类型
S1–5~10 分钟小型修复,单文件变更
M6–15~30 分钟小型功能,Bug 修复
L16–40~1.5–2 小时跨多文件的功能开发
XL41+~10 小时大型功能或重构

1.3 周期语言的确定方式

对于每个周期,编辑事件按文件类型进行统计。如果 Java 编辑次数多于 Kotlin 编辑次数,则该周期被归类为 Java 周期;反之则归类为 Kotlin 周期。编辑次数相等的周期被排除在外。

1.4 指标的局限性

  • 不包含代码审查、规划、讨论或 CI/CD 所花费的时间。
  • 不包含代码质量(Bug 和回滚)。
  • 不区分推送到功能分支还是主分支(不报告分支名称)。
  • 不代表代码行数(编辑事件 ≠ 代码行数)。

2. 核心发现:Kotlin 周期更短

2.1 在同类任务中,Kotlin 的开发周期更短

使用针对用户-项目 × 任务规模环境的主要纵向 log-DiD(对数双重差分) 估计器,“首次编辑 → 推送”周期在迁移到 Kotlin 后,比未迁移的 Java 环境中更短:

任务规模典型周期 (Java)*主要估计值95% 置信区间绝对值差异
S: 小型修复~10 分钟−15.7%[−24.4%, −6.0%]快约 1–2 分钟
M: 小型功能~30 分钟−20.3%[−31.3%, −7.6%]快约 6 分钟
L: 多文件功能~1.5–2 小时−15.1%[−26.8%, −1.6%]快约 15–20 分钟
XL: 大型功能~10 小时−11.0%[−23.5%, +3.5%]趋向于快约 1 小时,但不精确

* Kotlin 迁移者在 Java 阶段该任务规模桶中的近似周期中位数。精确的桶中位数见第 3.3 节。 ** 该主要百分比估计值转换为该桶中典型 Java 周期所需分钟数或小时数的近似值。

如何阅读表格: “小型功能”(M 桶)是指开发者在推送前进行了 6–15 次编辑会话的周期。在 Java 中,此类典型周期从首次编辑到推送大约持续 30 分钟。根据主要估计器,迁移后的 Kotlin 环境周期缩短了 20.3%,即从 30 分钟缩短至约 24 分钟。

该效应是通过纵向 log(DAT) 的双重差分法得出的:对于每个用户-项目和任务规模桶,我们比较 Java→Kotlin 迁移者的前→后变化,并与未迁移的 Java 对照组的相应变化进行对比。这剔除了总体时间趋势,从而隔离了与转换到 Kotlin 相关的效应。

重要提示: 在更严格的估计器中,大部分效应仍是由对照组的退化所解释,而非迁移者产生了剧烈的加速。详细信息见第 2.3 节。

2.2 保守估计的理由

我们通过编辑事件数量来控制任务规模。同时,Kotlin 包含许多语言特性(数据类、默认参数、属性、扩展函数、智能转换等),使代码更加简洁。因此,同一个逻辑任务(跟踪系统中的一个工单)在 Java 中可能需要 20 次编辑,而在 Kotlin 中仅需 15 次。这会导致它们落入不同的规模桶中。

因此,在上述假设成立的情况下,直接对比“同一个工单”会使 Kotlin 迁移者与 Java 对照组之间的差距变得更大。

2.3 效应的表现方式

更严格的 DiD 估计由两个部分组成(通过桶控制任务规模):

  1. Java→Kotlin 迁移者在小型和中型任务上有适度改善:在主要的对数尺度模型中,S 和 M 桶的前→后变化约为 −8%,L 和 XL 桶则基本持平。
  2. 未迁移的 Java 环境在所有桶中均出现退化:在同一模型中,前→后变化约为 +9% 到 +17%

换句话说,迁移到 Kotlin 的项目在周期时间增长方面的表现明显优于仍停留在 Java 上的项目。

这一点也得到了补充性对比的印证(在不进行任务规模归一化的情况下对比绝对 DAT):持续停留在 Kotlin 上的项目(从未迁移)在绝对 DAT 的 p90 处退化了 +14.5%,而未迁移的 Java 项目退化了 +23.1%(详情见第 3.4 节)。两组项目都在退化(项目随时间推移变得更加复杂),但 Kotlin 项目在 p90 处的退化速度大约只有 Java 项目的一半。

2.4 实际量级

从实际角度看,核心估计值意味着小型修复节省约 1–2 分钟,小型功能节省 ~6 分钟,多文件功能节省 ~15–20 分钟。对于 XL 任务,点估计值也为负,但区间太宽,无法得出确切结论。与早期的描述性中位数对比相比,更严格的估计器不再支持“任务越大,效应越明显”的单调叙事;稳定且更窄的结论是:在同类任务中,Kotlin 环境的周期时间增长明显低于未迁移的 Java 对照组。## 3. 证据详情

3.1 Java 转 Kotlin 的开发者:分阶段数据

1,501 名用户,1,664 个用户项目,约 7.6 万个周期。 对于迁移者活动的每个月,根据其 Kotlin 编辑占比确定一个阶段:Java 阶段(<10%)、过渡阶段(10%–50%)和 Kotlin 阶段(>50%)。

指标Java 阶段 (N=29,554)过渡阶段 (N=11,657)Kotlin 阶段 (N=35,406)Δ Java→Kotlin
p25 DAT6.3 分钟5.6 分钟5.8 分钟−8.7%
中位数 DAT34.7 分钟32.2 分钟32.1 分钟−7.5%
p75 DAT4.51 小时4.13 小时4.02 小时−10.9%
p90 DAT39.2 小时36.7 小时34.2 小时−12.7%
平均 DAT14.5 小时14.0 小时13.6 小时−6.4%
每个周期编辑数22.519.824.3+8.0%

所有百分位数的 DAT 均呈单调下降趋势,并在过渡阶段平稳过渡。值得注意的是,每个周期的编辑次数有所增加——这意味着在 Kotlin 阶段任务规模更大,但周期时间反而更短。

3.2 对照组:未迁移的 Java 用户

320,248 名用户,665,154 个用户项目,约 2800 万个周期。 指在开始和结束时 Kotlin 代码占比均 <10%,且活跃时长 ≥4 个月的用户。其历史记录按时间等分为三个阶段。

指标前期 (Early)中期 (Middle)后期 (Late)Δ 前期→后期
p25 DAT6.6 分钟6.2 分钟6.0 分钟−8.4%
中位数 DAT38.9 分钟37.7 分钟35.7 分钟−8.2%
p75 DAT5.25 小时5.45 小时5.35 小时+2.0%
p90 DAT31.7 小时35.5 小时39.0 小时+23.1%
平均 DAT12.7 小时13.7 小时14.5 小时+14.1%
每个周期编辑数21.219.617.9−15.4%

未迁移的 Java 组表现出退化趋势:中位数略有下降,但长尾部分(p75、p90)和平均值大幅上升。项目变得更加复杂,长周期变得更长,且每个周期的编辑次数在下降。

3.3 主要纵向 log-DiD 分析(含任务规模控制)

我们比较了迁移者(Java 阶段 vs. Kotlin 阶段)和对照组(前期 vs. 后期)中相同规模周期的 DAT。下方的分桶中位数表仅供描述性参考。主要效应规模是基于“用户-项目 × 任务规模桶”层面上 log(DAT) 的前后变化估算的。

Java 转 Kotlin 迁移者 —— 按分桶和阶段划分的中位数 DAT:

分桶Java 阶段Kotlin 阶段Δ
S: 1–5 次编辑10.4 分钟9.6 分钟−7.5%
M: 6–15 次编辑33.9 分钟31.9 分钟−5.8%
L: 16–40 次编辑1.82 小时1.70 小时−6.3%
XL: 41+ 次编辑11.4 小时12.2 小时+6.7%

未迁移 Java 对照组:按分桶划分的中位数 DAT:

分桶前期后期Δ
S: 1–5 次编辑10.5 分钟11.0 分钟+4.7%
M: 6–15 次编辑35.2 分钟38.8 分钟+10.3%
L: 16–40 次编辑1.93 小时2.27 小时+17.7%
XL: 41+ 次编辑12.1 小时15.3 小时+26.3%

主要估计量:基于“用户-项目 × 任务规模桶”上下文的 log-DAT 双重差分法 (DiD)

面板规模:978 个迁移者上下文400,425 个对照组上下文,每个上下文在前后周期中均包含 ≥3 个周期。标准误按 machine_id 进行聚类。

任务规模迁移者 前→后未迁移 Java 前→后主要 log-DiD 效应95% 置信区间
S: 小型修复 (~10 分钟)−8.1%+9.0%−15.7%[−24.4%, −6.0%]
M: 小型功能 (~30 分钟)−7.3%+16.4%−20.3%[−31.3%, −7.6%]
L: 多文件功能 (~1.5–2 小时)−0.3%+17.5%−15.1%[−26.8%, −1.6%]
XL: 大型功能 (~10 小时)−0.1%+12.2%−11.0%[−23.5%, +3.5%]

更严格的估计量比之前的描述性中位数对比更为稳健,且不支持随任务规模增加而单调增长的结论。结论更加明确:对于可比任务,Kotlin 导向的上下文显示出比未迁移 Java 对照组更小的周期时间增长,且在 SML 桶中具有统计学支持的负值估计,其中 SM 的精度最高。汇总 S/M/L 上下文得出的主要估计值约为 −17.1% (95% CI [−23.7%, −9.9%])

作为稳健性检查,采用用户而非用户-项目上下文进行等权处理,得出的 S (−18.8%) 和 M (−20.3%) 点估计相似,L (−13.7%) 的估计值较弱但仍为负,XL (−11.0%) 的估计值依然不够精确。因此,结果的正负方向是稳定的,而确切幅度取决于加权方式,尤其是对于大型任务。

3.4 来自稳定组的补充证据:未迁移 Kotlin vs. 未迁移 Java

在不涉及迁移者的情况下,比较稳定组的趋势:

指标未迁移 Java Δ 前→后未迁移 Kotlin Δ 前→后
中位数 DAT−8.2%−7.7%
p75 DAT+2.0%+0.8%
p90 DAT+23.1%+14.5%
平均 DAT+14.1%+9.9%
每个周期编辑数−15.4%−12.4%

未迁移的 Kotlin 项目在 p90 的退化速度大约慢了一半,平均而言慢了约 4 个百分点。这为稳定组提供了补充证据,并显示了与迁移者队列方向相似的模式。

3.5 横截面比较:月内对比

这是控制最严密的设计:同一用户、同一项目、同一月份、同一任务规模。共 1,801 名用户和 6,908 个上下文。

分桶Java (中位数 DAT)Kotlin (中位数 DAT)Δ
S: 1–5 次编辑10.1 分钟9.8 分钟−2.0%
M: 6–15 次编辑31.6 分钟31.6 分钟0%
L: 16–40 次编辑1.69 小时1.62 小时−3.9%
XL: 41+ 次编辑9.76 小时10.91 小时+11.8%

横截面效应(S/L 为 −2% 至 −4%,M 为 0%,XL 为反向)比主要纵向估计更为温和。这表明 Kotlin 的贡献并非主要是即时的月内加速,而是一种周期时间的渐进式缩短。## 4. 有效性检查、局限性与待研究问题

4.1 解决选择偏差:逐步混杂因素控制

在分析的每个阶段,我们逐步排除了混杂因素(可能扭曲比较结果的因素,例如 Kotlin 开发人员是否天生更有经验,或是否在处理更简单的项目):

设计Kotlin 与 Java 的差异
所有用户(朴素比较)−6%
用户内(同一个人)−3.5%
用户内 + 项目内 + 月份内+12% (!)
...+ 任务规模控制−2% 至 −4% (S/M/L)
纵向 log-DiD + 任务规模控制≈ −15% 至 −20% (S/M/L 点估计);XL 仅具方向性

每一步混杂因素控制都会改变分析结果。朴素比较夸大了效应(选择偏差)。在月份内且未进行任务规模控制时,得出了相反的结果(+12%,即 Kotlin 看起来更慢),这是因为在混合语言项目中,Kotlin 的开发周期包含约 15% 更多的编辑事件。我们的假设是:在此类项目中,新功能倾向于用 Kotlin 编写(周期更长),而旧代码维护则使用 Java(周期更短);若不进行归一化处理,就会产生这种偏差。只有在控制了任务规模并采用纵向设计后,稳定的负向差距才会显现。在更严格的估计器中,SML 均保持负值,其中 SM 的精度最高,而 XL 因精度不足,无法下定论。

4.2 额外的稳健性检查

4.2.1 月度稳定性

针对混合语言项目(同一用户、同一项目)中 Java 与 Kotlin 在六个月内的横截面比较:

月份Java 中位数Kotlin 中位数ΔKotlin 更快?
2025-0131.8 分钟29.6 分钟−6.9%
2025-0235.1 分钟32.5 分钟−7.5%
2025-0327.3 分钟28.3 分钟+3.7%
2025-0427.0 分钟29.0 分钟+7.4%
2025-0530.0 分钟28.5 分钟−5.2%
2025-0631.7 分钟31.1 分钟−2.1%

方向不一致(6 个月中有 4 个月支持 Kotlin)。瞬时效应较小且存在噪声,稳健的效应仅在纵向设计中可见。

4.2.2 按项目规模细分

按项目总规模进行的描述性拆分显示了类似的模式。由于此检查基于 p90/平均趋势的聚合,而非主要的 log-DiD 估计器,因此应视为探索性分析。该模式在 L 类项目(整个期间内 500–2,000 次编辑)中最显著:

项目规模p90 的描述性差距平均值的描述性差距
XL (2,000+ 次编辑)−13.9%−11.7%
L (500–2,000 次编辑)−39.7%−23.9%

4.2.3 Java 版本作为工程文化的代理指标

“活跃团队效应”假设认为,Kotlin 项目退化速度较慢并非由于语言本身,而是由于团队特征。如果是这样,那么未迁移的 Java 组中具有更强工程文化的团队也应退化得更慢。

为验证此点,我们使用项目 JDK 版本作为工程文化的代理指标。IDE 遥测中的 MODULE_JDK_VERSION 事件包含主要的 Java 版本。未迁移的 Java 用户项目被分为:

  • old_java:最高 JDK 版本 ≤ 11(约 30.8 万个用户项目)。
  • modern_java:最高 JDK 版本 ≥ 17(约 34.8 万个用户项目)。

按桶划分的 DAT/编辑退化率(每次编辑的中位数分钟数,从早期到后期):

old_java Δmodern_java Δ所有未迁移 Java ΔJava→Kotlin 迁移 Δ
S: 1–5 次编辑+0.1%+4.0%+4.7%−7.5%
M: 6–15 次编辑+9.1%+10.5%+10.3%−5.8%
L: 16–40 次编辑+17.2%+16.6%+17.7%−6.3%
XL: 41+ 次编辑+28.9%+25.1%+26.3%+6.7%

Java 版本与退化率之间的关系是混合的:对于大型任务(XL),modern_java 的退化比 old_java 慢 3.8 个百分点,但对于小型任务(S),它反而快 3.9 个百分点。对于 M 和 L 桶,各段之间的差异极小(≤1.4 个百分点)。modern_java 并没有系统性优势。

以 modern_java 为对照组重新计算的描述性 DAT/编辑对比:

迁移者 Δ对照组: 所有未迁移 Java描述性对比 (原始)对照组: modern_java描述性对比 (调整后)
S−7.5%+4.7%−12.2%+4.0%−11.5%
M−5.8%+10.3%−16.1%+10.5%−16.3%
L−6.3%+17.7%−24.0%+16.6%−22.9%
XL+6.7%+26.3%−19.6%+25.1%−18.4%

当使用 modern_java 作为对照组时,描述性对比变化甚微(各桶偏差 ≤1.2 个百分点)。此检查仅在 DAT/编辑层面执行,而非主要 log-DiD 估计器,因此仅作为辅助证据。

解读: 在此描述性检查中,作为工程文化代理指标的 Java 版本与 DAT/编辑退化率的关联较弱,且替换对照组对描述性对比几乎没有影响。这削弱了“迁移者与对照组之间的差异完全由团队特征决定”这一假设——至少在 JDK 版本能反映这些特征的范围内是如此。然而,JDK 版本只是工程文化的一种代理指标。其他因素(代码审查实践、CI/CD 流水线、重构习惯)可能在迁移者和对照组之间存在差异,即便它们与所使用的 Java 版本无关。

4.3 置信度

方面状态注释
用户控制用户内比较(同一人)
项目控制项目内比较(同一项目)
时间趋势控制以未迁移 Java 为对照的初步 log-DiD;稳定组比较提供补充证据
估计器形式主要结果基于用户-项目 × 任务规模层面的 log-DAT 变化
项目规模稳健性按项目总规模进行的描述性拆分在各分段显示出方向一致的模式
任务规模控制按每个周期编辑次数进行分桶
二级对照组未迁移 Kotlin 提供额外对照,显示方向一致的模式
样本量1,501 名迁移者,约 7.6 万个迁移周期,约 2,800 万个对照周期
时间稳定性⚠️横截面月度比较不稳定;效应仅在纵向设计中可见
加权敏感性⚠️效应幅度在上下文加权与周期加权聚合之间存在差异
大任务精度⚠️XL 区间包含零;L 在用户级稳健性检查中较弱
分支信息⚠️无法区分推送到功能分支还是推送到主分支
周期定义⚠️单次推送可能包含多个任务
因果关系⚠️观察性研究,非实验

4.4 有效性威胁

什么会削弱结果?

  1. 未观察到的团队特征: 对未迁移 Java 项目按 JDK 版本细分显示,即便这种粗略的工程文化代理指标也仅能轻微缩小描述性对比。可能存在其他系统性差异,会进一步缩小差距。
  2. 未观察到的混杂因素: 无法测量且持续存在的因素:并发重构、流程变更、依赖升级。
  3. 加权敏感性: 等权重用户-项目上下文比周期加权变体产生了更强的幅度。符号保持为负,但确切效应大小取决于加权,特别是在大任务中。
  4. 大任务精度: XL 桶在方向上为负,但 95% 置信区间包含零。L 桶在主模型中为负,但在用户级稳健性检查中较弱。
  5. 推送 ≠ PR: 推送是交付的代理。PR 可能稍后创建或通过网页界面创建。
  6. 日历时间: DAT 包含夜晚、周末和午休。这增加了噪声,但对两组影响相同。
  7. 周期定义: 周期 = 推送之间的时间间隔;单次推送可能包含多个逻辑任务。

什么会加强结果?

  1. 分桶可能对 Java 有利: 如果 Kotlin 代码更简洁,那么同样的逻辑任务在 Kotlin 中可能比 Java 需要更少的编辑。在这种情况下,每个桶内的 Kotlin 任务客观上会更大。这是一个我们无法直接验证的假设(我们不知道每个周期背后的“逻辑任务”),但如果成立,真实效应比测量的更强。

4.5 待研究问题

  1. 预趋势/事件研究: 在迁移到 Kotlin 之前,迁移者和对照组的趋势是否平行?
  2. 主要估计器中的替代对照: 仅使用 modern_java 或匹配对照组时,log-DiD 结果是否成立?
  3. 阈值稳健性检查: 在不同的迁移定义(如 5/20% 代替 10%,40/60% 代替 50%)下,效应是否成立?
  4. 带有任务规模控制的反向迁移 DAT: 离开 Kotlin 时周期持续时间是否会变差?
  5. 长期动态: 使用 Kotlin 12 个月以上后,效应是继续增长还是趋于平稳?
  6. 其他生产力指标: 哪些开发过程指标(如编译错误、构建时间、重建频率)能更好地阐明收集到的数据?
  7. Android Studio: Android 开发人员群体的差异是否相同?
  8. 倾向评分匹配: 将每位迁移者与对照组中具有相似基准特征(项目规模、初始速度、活跃度)的“双胞胎”进行匹配,是否会得出更精确的 DiD 估计?

5. 方法论

5.1 IDE 遥测事件

事件group_idevent_id关键字段
文件编辑file.types.usageeditfile_type = "JAVA" / "Kotlin"
推送actionsaction.finishedaction_id = "Vcs.Push" / "Git.Commit.And.Push.Executor"

关于编辑事件的性质: 编辑事件具有 1 分钟的冷却时间——发送后,系统在一分钟内不会记录新的编辑,即使开发人员继续输入。在编辑事件之间,开发人员还会阅读代码、导航项目、运行测试并与同事讨论问题——所有这些都是包含在 DAT 中的工作周期的一部分,但不会产生编辑事件。因此,编辑次数是任务规模的代理,而非所花时间的度量。DAT 衡量的是周期的完整挂钟时间。

5.2 过滤条件

  • DAT > 36 秒且 < 14 天
  • 仅限 product_code = 'IU' (IntelliJ IDEA)
  • 仅限 recorder_code = 'FUS'
  • machine_id 和 project_id 不为空

5.3 迁移组定义

对于每个月度的 (machine_id, project_id),计算 kotlin_share = kotlin_edits / (java_edits + kotlin_edits)。要求每月至少有 ≥10 次 Java/Kotlin 编辑事件,且至少有 4 个活跃月份。

定义
A: Java→Kotlin 迁移者首月 kotlin_share < 10%,末月 > 50%
B: 未迁移 Java首月和末月 kotlin_share < 10%
C: 未迁移 Kotlin首月和末月 kotlin_share > 50%

迁移阶段按月确定:Java 阶段 (<10%)、过渡阶段 (10–50%) 和 Kotlin 阶段 (>50%)。 未迁移组阶段: 历史被划分为三个等长的时间段(早期/中期/晚期),类似于迁移者的阶段。

5.4 双重差分 (DiD)

主要估计器是针对用户-项目 × 任务规模桶上下文的纵向 log-DiD:

  1. 上下文定义为 (machine_id, project_id, size_bucket)。
  2. 仅保留前后周期中各有 ≥3 个周期的上下文。
  3. 对于每个上下文,计算 ΔlogDAT = mean(log(DAT))_post − mean(log(DAT))_pre
  4. 计算处理组与对照组的差距:主要 log-DiD 效应 = exp(mean(ΔlogDAT)_migrants − mean(ΔlogDAT)_control) − 1。 标准误按 machine_id 聚类,因为一个用户可能贡献多个项目或桶。为便于解释,我们还提供了桶级中位数 DAT 表格和简单百分比变化。这些描述性摘要并非主要估计器。

5.5 任务规模控制

原始 DAT 不适合比较:混合语言项目中的 Kotlin 周期包含约 15% 更多的编辑(我们假设新功能用 Kotlin 编写,旧代码维护用 Java)。 主要控制方法是分桶:我们仅比较相同规模的周期。我们还在选定的稳健性检查中使用 DAT/编辑作为辅助描述性归一化。 使用两种控制方法:

  • DAT/编辑:周期持续时间除以编辑次数。
  • 分桶:比较相同规模的周期:S (1–5), M (6–15), L (16–40), XL (41+ 编辑)。

5.6 数据

  • 期间: 2023 年 11 月至 2025 年 6 月(约 20 个月)。
  • 产品: IntelliJ IDEA (product_code = 'IU')。
  • 规模: 约 2,800 万个对照组周期,约 7.6 万个迁移周期,约 250 万个未迁移 Kotlin 周期。
  • 主要 log-DiD 面板: 978 个迁移上下文和 400,425 个对照上下文(前后均有 ≥3 个周期)。## 结论

本研究提供了大规模的观察性证据,表明以 Kotlin 为导向的项目开发周期比同类 Java 项目更短。在控制了用户、项目、时间趋势和任务规模等变量后,主要的纵向双重差分法(log-DiD)估计显示,对于日常任务(S、M 和 L 规模),Kotlin 带来的效率提升约为 15%–20%。对于 XL 规模的任务,点估计值同样为负,但在统计学上不够精确。

其主要特征并非在于切换到 Kotlin 后开发速度会突然加快,而在于两者轨迹的差异:未迁移的 Java 项目在观察期内周期时间往往出现显著增长(在主要模型中增长了 9% 至 17%),而进行迁移的项目则表现出适度的改善或保持平稳。这一结果在“未迁移的 Kotlin 项目”与“未迁移的 Java 项目”的对比中得到了印证,即 Kotlin 项目的性能衰减速度仅为 Java 项目的一半左右。

我们需要明确指出本研究未能证实的内容。这是一项观察性研究,而非随机实验,因此我们无法做出确切的因果推论。选择迁移到 Kotlin 的团队与坚持使用 Java 的团队之间可能存在我们无法完全观测到的差异——尽管我们的有效性检查(JDK 版本细分、多重对照组、逐步剔除混杂因素)表明,这些差异本身并不能完全解释两者之间的差距。我们建议读者在评估这些证据时,参考第 4.4 节中的局限性说明和第 4.5 节中提出的开放性问题。

未来的研究方向可以进一步加强或完善这些发现,例如:对预趋势进行事件研究分析、通过倾向评分匹配构建更精确的对照组,以及将研究范围扩展到以 Kotlin 为默认语言的 Android Studio 环境。我们计划在后续分析中开展这些工作。