三位 Java Champion 如何用 GitHub Copilot 提升生产力
How 3 Java Champions are using GitHub Copilot for increased productivity
AI 导读
三位拥有十余年 Java 经验的 Java Champion 分享了在生产与开源项目中使用 GitHub Copilot 的具体做法。
摘要与补充说明
Hypersistence 创始人 Vlad Mihalcea 用 Copilot 开发 Optimizer 事件历史 Web 应用,原本需数周的任务两天完成,并基于自己 65 篇已发表文章创建自定义技能,让生成文本贴近本人写作风格。42talents 的 Patrick Baumgartner 用 Copilot 将 15 份演示中约 900 张教学幻灯片从 Reveal.js 迁移到 Marp,通过截图对比和并排运行验证动画等细节。三人均强调开发者仍需提供上下文、审查生成代码并保障可维护性。
正文· AI 翻译
AI 编码工具可以快速生成代码,但仅有速度并不能解决最困难的软件工程问题。开发者仍然需要提供上下文、验证结果、保护可维护性,并对最终交付的成果负责。
为了了解经验丰富的开发者如何取得这种平衡,我们采访了三位 Java Champion,他们都有超过十年的 Java 使用经验。他们分享了在生产环境和开源项目中使用 GitHub Copilot 的具体案例,以及他们将 AI 生成的输出转化为可靠软件所采用的实践。
以下是他们与我们分享的技巧。
认识这些 Java Champion
- Vlad Mihalcea,Hypersistence 创始人,著有《High-Performance Java Persistence》一书
- Patrick Baumgartner,42talents 的软件工匠,拥有 20 多年 Java 经验
- Frank Delporte,Azul 高级技术文档撰写人,Foojay.io 维护者,拥有 15 年以上 Java 经验
Vlad Mihalcea
GitHub 个人资料:@vladmihalcea
GitHub Copilot 最近如何帮助了你?
我一直在用它来分析、设计和实现 Hypersistence Utils 和 Hypersistence Optimizer 中的各种功能。
例如,我很早就想开发一个 Web 应用,提供 Optimizer 事件历史记录,这样我们就能看到性能改进工作如何体现在应用性能上。在 AI 出现之前,我一直推迟这项任务,因为开发它需要花费数周时间。但使用 Copilot 就像多了一位新团队成员,所以我用它创建了一个应用,该应用将在下一版 Hypersistence Optimizer 中发布。这项任务只花了两天就实现,而不是数周。
你通常如何使用?是把 GitHub Copilot 作为 IDE 插件使用,还是使用 GitHub Copilot 应用?
我在 IntelliJ IDEA 中使用 GitHub Copilot,因为在审查源代码或调试会话期间运行它很方便。
它作为代码助手非常有用,能帮助我加快调查速度,并为需要验证的功能构建原型。
我仍然会审查 AI 生成的计划和代码,因为它的目标是提高我的生产力,而不是完全取代我。虽然 AI 在许多情况下能给出正确答案,但有时响应仍不令人满意,需要我介入。
你能分享一些技巧和最佳实践吗?例如,你使用了哪些技能?
我创建了自己的技能,让 Copilot 生成的任何文本看起来都像是我亲手写的。
这项技能从我发表的 65 篇文章中捕捉了我的语气,因此返回的草稿听起来像我的博客,而不是像语言模型。这在为该项目生成文档时非常有用,因为它让 LLM 从 12 年的博客写作中学习,并提供遵循相同原则的示例,例如表达力、可测试性和简洁性。
在我作为软件工程师的职业生涯中,我了解到我们在代码维护上花费的时间远远多于创建代码的时间。因此,由于维护和稳定性对现有产品至关重要,我开发了一些技能,帮助 AI 遵循最小惊讶原则来模仿现有代码实践。
一个建议是根据操作类型来更换模型。对于需要深入思考的任务,我会使用 Opus,搭配 100 万上下文窗口以及 Extra High 或 Max 推理级别。不过,对于更简单的任务,比如生成报告、发布说明或验证文档,我会使用消耗 token 更少的轻量模型。
Patrick Baumgartner
GitHub 个人资料:@patbaumgartner
你的工作涉及辅导团队。你的方法是什么?
我的很多工作都是在日常业务仍需照常运转的情况下进行的。你不能为了“转型”而让一切停摆六个月。我们通常先一起解决眼前的问题,了解团队目前所处的位置,明确我们想要达到的目标以及如何判断我们正在进步,然后一步步向那里推进。
视情况而定,这可能意味着采用 TDD、重构、持续交付和 XP 等软件工艺实践;使用 Spring Boot、Spring Modulith 进行架构与模块化;Spring Security;针对容器优化 Java 和 Spring Boot 应用;或者越来越多地涉及智能体工程。
对我来说,重要的是我与团队一起工作。我们一起做决定。我不希望团队变得依赖我。理想情况下,过一段时间后他们不再需要我,或许只把我当作切磋伙伴。
也许这解释了为什么我觉得这一代新的 AI 工具如此有趣:我喜欢与人合作、学习、实验和解决问题。AI 为我们提供了另一个非常强大的工具,正好可以用来做这些事。
你能分享一个关于 GitHub Copilot 最近如何帮助你的好故事吗?
实际上有三个非常不同的例子,改变了我对与 GitHub Copilot 协作方式的看法。
让我们从第一个开始。
其中一个是将 15 份演示文稿中约 900 张教学幻灯片从 Reveal.js 迁移到 Marp。这些不是简单的幻灯片。许多包含代码、动画,甚至还有我可以在授课时实时修改 JavaScript 的交互式示例。更重要的是,这些演示文稿已经经过学生的实战检验。流程是行得通的。丢失任何一个小片段都可能破坏我在课堂上使用的叙事。
手动完成这次迁移,我大概需要一周或更长时间——而且现实中,我可能干脆就避免去做,因为这是如此乏味的工作。
借助 Copilot,我采取了不同的方式。我们先分析现有材料,定义目标,制定迁移计划,确立约束条件,提供示例,并明确哪些内容必须保持原样。然后我们从大的结构性改动逐步深入到细节。
真正重要的部分是验证。
我们生成了 Reveal.js 和 Marp 版本的截图,并进行了视觉和算法上的比较。我们构建了一个小应用,可以在其中并排运行两套幻灯片,以手动验证动画。我们甚至比较了生成的 PDF。
这意味着智能体不只是说“迁移完成”。我们有证据。
整个迁移花了我大约八到十个小时。我仍然掌控内容、教学意图以及每一处有意义的改动。Copilot 可以自动修正拼写错误,但如果内容、版本、日期或含义发生变化,那是我们需要讨论的事情。
对我来说,这段经历强化了一个重要原则:委托执行,而非责任。结果由我负责。
你能分享第二个例子吗?
第二个例子来自用 Tamboui 构建一个终端 UI 应用。它最初在 WSL 下的 Linux 中运行完美,而我完全忘了有人可能会直接在 Windows CMD 或 PowerShell 中运行它。
然后真的有用户这么做了。
他们发现,在某些表单中 Enter 键被直接忽略了。这也是我坚信的另一条原则:尽早发布软件,因为你能从人们实际使用它的方式中学到东西。
我们用 Copilot 把那条反馈转化为可复现的 UI 测试。在 Linux 上,Copilot 通过 tmux 来操作这个应用。在与它协作的过程中,我了解到了 psmux,并能在 PowerShell 中执行类似的流程。我们复现了问题,创建了一个本地修复,把真正的问题追溯到 Tamboui 中,然后我提交了上游修复,并被合并了。
在这项工作中,测试描述本身变得太大,超出了可用的上下文。于是我请 Copilot 帮我重新设计测试的表示方式。它没有采用包含标识符、名称和重复描述的那种冗长表格,而是提出了一种紧凑得多的箭头记法:step → step → input,只在关键之处附加额外信息。
这让我感到惊讶。我们不只是用 AI 来执行信息;我们是在共同研究信息应当如何被表示以便执行。它不必对人类尽可能友好,而是要在保留语义的同时对智能体高效。
那第三个例子呢?
第三个例子又完全不同。
我身边有人需要练习数学,于是我想:为什么不做一个小的学习应用呢?
它涵盖一到四年级的加法、减法、乘法、除法以及带余数的除法。但我不想再做又一个简单的测验应用。我和 Copilot 一起研究了间隔重复、即时反馈、自适应难度、动机、合作学习以及不带暗黑模式的游戏化等学习方法。
有趣的是,在那次研究中,Copilot 挑战了我最初的一个假设。我最初希望这个应用能通用地面向各地的孩子。而研究引导我们去关注实际的学校课程。我意识到,主题引入的顺序、运算和数字范围差异足够大,以至于立刻把它做成“通用”的并无必要。
于是我们先聚焦瑞士,并据此对齐学习进阶。因为瑞士是多语言国家,这个应用提供德语、法语、意大利语和英语版本。
它还有合作与竞争两种双人模式,当有人答错时,应用会解释一种解题方法,并通过间隔重复把类似的问题带回来。
我刻意选择了无后端的架构。我没有理由在服务器上收集儿童的个人数据,所以数据留在设备上,应用可以直接托管在 GitHub Pages 上。
最初只是一个小实验,如今已在朋友之间使用和分享。它意外地成了一个小产品。
那段经历让我看到了 Copilot 的另一面:不要只把它用来实现你的方案。把它当作陪练,在开始构建之前扩展并挑战方案空间。
你通常如何使用 Copilot?
其实我已经不再使用经典的 Copilot 自动补全体验了。
我的工作几乎已经完全转向了智能体工作流。
当我需要紧密的视觉反馈循环时——当我想仔细查看文档、代码、演示文稿或中间结果,并随着进展调整流程时——我会使用 VS Code。
对于规模更大的、以执行为导向的任务,我经常在终端里使用编码智能体。在那里,我更愿意把一部分工作委派出去,让它执行,然后再检查完整的结果。我选择哪种界面,主要取决于我需要什么样的反馈循环。
在前往 JavaLand 的旅途中,我还通过 GitHub 使用编码智能体工作流,获得了一次非常有趣的体验。我当时已经开始探索一个 Maven 插件的想法,用于优化加载哪些 Spring Boot 自动配置。在大约四个小时的旅程中,我用手机指挥智能体:给它一个任务,审阅它做了什么,思考下一步,然后发出下一条指令。
等我到达时,我已经有了一个可用的 Maven 插件、一条 CI 流水线、针对一个示例应用的性能测试,以及能够证明优化是否真正生效的报告。
那是我第一次以这种方式工作,我很惊讶它居然真的行得通。我并不是在手机上写 Java。我是在智能体执行的同时进行审阅、决策和指挥。
当 MCP 服务器能提供有用的能力或上下文时,我也会使用它们。例如,我用过 Context7 来查文档,用过与我的 Logseq 知识库的集成,还试验过用于 Adobe Premiere Pro 的 MCP 集成。
但我不会仅仅因为能用就去用 MCP。如果存在一个好的 CLI,我通常更倾向于 CLI,因为对我来说它感觉更直接、更快。
在我的心智模型里,智能体也不是“初级开发者”。我更把它看作一个陪练伙伴。但就像任何加入项目的人一样,它首先需要被带到应有的水平。
上下文为王。
你能分享一些技巧和最佳实践吗?
我最大的建议是:不要再做一次性提示。
对于任何不简单的事情,我希望在执行开始之前先理解问题。我经常会明确要求智能体先来采访我。那次采访的目的是揭示那些仍然隐含的假设和期望。
一个好的智能体能以极快的速度执行一个错误的想法。这并不会让绕路变得更便宜。
我在开发自己的 Spring Boot 自动配置优化器时就亲身经历过这一点。起初我想同时支持 Spring Boot 3.5 和 4.x。由于存在架构差异,我们实现了两种方案。后来我意识到自己不再需要 3.5 那条路径,而移除它非常痛苦。
教训很简单:绕路代价高昂。在加速之前先把需求搞清楚。
一旦意图清晰,我就想要一个计划。当我审阅那个计划时,有四件事对我尤其重要:假设是否可见,验证关卡是否已定义,方案是否契合架构,以及是否避免了不必要的工作?
第二条原则是定义针对具体任务的验证关卡。
“完成”不应该意味着模型说它完成了。
对于一次重构,关卡可能包括测试通过、证明所有预期文件都已处理、更新文档,以及不留下任何 TODO。对于幻灯片迁移,关卡包括截图、视觉差异、动画、PDF 输出和内容完整性。
这些关卡取决于具体任务,但原则不变:智能体应当能够提供证据,证明工作满足“完成”的定义。
我最近看到一个名为unlazy的技能,它遵循类似的思路:设立明确的关卡,有条不紊地逐一通过,并证明它们已经完成,而不是走捷径。
第三条原则是把你的经验教训转化为可复用的技能。
我已经开始编写并维护自己的 Agent Skills。当我从一次执行中学到东西时——也许是智能体误解了某项约定、缺少了一项有用的检查,或者我找到了更好的任务处理方法——我就会更新这个技能。
下次我执行那项任务时,经验教训已经在那里了。
一个例子是我称之为maintainer-audit的技能,它受到开放智能体技能社区工作的启发。我在自己的多个代码库中使用它。它会检查并在适当的时候修复我期望一个持续维护的项目所应具备的内容:代码库文档、CI 流水线、Dependabot 配置、CodeQL、一致的清理以及其他项目标准。
目标不是再生成一份让我阅读的审计报告,而是自动把代码库拉回我期望的基线。这使我的项目更加一致,也更容易维护。
我把这些技能视为活的工程知识,而不是静态的提示词。
第四条原则是在概率模型周围放置确定性的工程工具。
我有自己的质量检查框架,它封装了 Checkstyle、PMD 和 Spring Modulith 架构检查等工具,并生成一份智能体可以使用的汇总报告。我可以从钩子中运行它,让智能体迭代:
修改 → 执行检查 → 读取发现 → 修复 → 再次执行。
它会一直持续到不再有任何发现为止。
这并不意味着我不再亲自查看软件。我仍然会运行应用、与它交互,并判断它的行为和外观是否符合我的预期。有时我会刻意逐个功能地实现,因为这样反馈循环要紧密得多。
我学到的是,因为“AI 能做到”就一次性要求所有东西,通常是个坏主意。庞大而笼统的规格会产生庞大而笼统的实现——而事后清理它们可能比正确地构建更小的增量更难。
更广泛地说,我认为我们开发者需要更多地讨论我们如何使用这些工具。分享奏效的实验,也分享不奏效的。互相借鉴想法,并让它们适应你自己的情境,而不是寻找一套通用的 AI 开发流程。
这也是我喜欢把 AI 当作陪练这一想法的原因。周五晚上,当我想尝试点什么、又没有人类搭档可用时,我突然有了一个可以与之挑战想法、评审方案,或者当作一个非常高级的橡皮鸭的对象——某个人,或者某个东西。
但我仍然会把这些想法带回给真实的人。人类的反馈、对产品的理解和真实世界的语境仍然至关重要。
你认为 AI 正在如何改变我们的职业?
我认为软件工程专业的学生不应主要立志成为写代码的机器。他们需要成为强大的问题解决者。他们需要理解用户和利益相关者,发现需求背后的真正问题,挑战假设,理解产品和市场,做出架构权衡,进行批判性思考,以结构化的方式工作,并把有用的解决方案从一个情境迁移到另一个情境。
这个模型在生成可能性和执行任务方面极其出色。但作为人类,我通常掌握更多实际背景——包括那些从未被记录下来的事情。
所以我想继续掌控解决方案的塑造,让智能体承担更多执行工作。
从这个意义上说,我认为AI正在把工程重新带回软件工程。
我喜欢这一点。
Frank Delporte
GitHub 个人资料:@FDelporte
你是如何进入科技领域的?
我从11岁得到一台Commodore 64起就对计算机着迷了。放学后我一度转向视频制作和电视工作,但后来又回到了编程,因为那些视频需要刻录到DVD上,还有最早的网站……是的,我就是那么老 ;-)。
GitHub Copilot 最近如何帮助了你?
它是评估拉取请求和调查缺陷报告的完美伙伴。
一个值得注意的故事是关于Pi4J 库的,它让你可以构建 Java 应用来与 Raspberry Pi 上的电子元件交互。2026年2月,我们发布了 V4,它有一个使用 Foreign Function & Memory API 的新插件。我们在发布前进行了充分测试,但发布后不久,仍有人报告说使用5个输入按钮时无法按预期工作。按下前四个已配置按钮中的任意一个都会按预期触发代码执行,而第五个按钮却毫无反应。
这是你不想收到的那种报告。没有任何明显的故障。没有异常,日志里没有警告,第五个按钮就是毫无反应。更糟的是:使用旧的 gpiod 插件、完全相同的硬件和完全相同的应用,却运行正常。所以问题出在我们新的 FFM 代码中,它位于 Linux 内核的 GPIO 字符设备之上,并通过原生调用与之通信。那不是你期望能快速找到答案的那部分代码库。
于是我把这个问题分配给了 Copilot 编码智能体,并给它两个文件路径作为起点:provider 类和 FFMDigitalInput。大约半小时后,出现了一个拉取请求,其中的解释完全出乎我的意料。
每个输入都运行一个事件监视器,它阻塞在一个原生 poll() 调用中,等待内核报告其 GPIO 线路上的变化。这些监视器运行在虚拟线程中。而一个在原生调用内部阻塞的虚拟线程无法从其载体线程上卸载。它会在整个调用期间一直固定在那里。Raspberry Pi 4 有四个核心,因此虚拟线程调度器有四个载体线程。注册四个输入,四个载体就全部永远停在 poll() 中。第五个监视器被创建了,但从未被调度。这正是所报告的那个缺陷。不是“事件不稳定”,而是“第五个什么都不做”。
我最喜欢的不是那个 diff,而是随后在评审中的对话。我留了一条评论,请 Copilot 更详细地解释这一点:
我以为虚拟线程的目标正是摆脱平台线程的限制?那么,在像 Raspberry Pi 这样的四核处理器上,四个虚拟线程阻塞四个线程,这怎么会是个问题呢?
查看拉取请求中的完整对话。Copilot 能够将使用具有四个 CPU 核心的 Raspberry Pi 与所报告的问题联系起来。它能够为这个问题提出一个简单的修复方案,以及它在调查过程中发现的一些额外改进。
你能分享一些技巧和最佳实践吗?
- 告诉它去哪里找:对于 Pi4J 的 issue #622,我添加了两个文件路径。这只需付出一点点努力,却能省去在大型代码库中大量的搜索。即使你对 bug 一无所知,通常也会对相关区域有所直觉。把它交给工具,这样它就不必调查整个代码。
- 要求提供证据和测试:“添加一个单元测试来验证这项更改”是我最近经常提出的要求。嗯,是“提过”,因为它现在已经成为我指令文件中的一条规则。这也能防止诊断错误的情况,因为测试不会在旧代码上失败。
- 追问原因:如果你不理解某个修复,就说出来并提问。解释本身也是一项交付物,应该添加到你的项目文档中,或写入工单或拉取请求里。它能教会之后阅读这些信息的每个人。例如,这也引发了 Pi4J 团队内部关于原生调用上虚拟线程固定(virtual thread pinning)的更多问题。
- 保持掌控:Pi4J 中所有这些拉取请求在合并前都经过了维护者的审查和批准。这是在这个项目中最有效的模式:智能体负责调查,人类始终对最终发布的内容负责。但对我其他项目也是如此,我总是会审查工具生成的代码。我始终希望保持代码的可读性和可维护性。工具常常会创建重复的方法,或重新实现另一个地方已经存在、本应合并的内容。这是你的责任。如今借助 AI 辅助编码,你可以进展得非常快,这也意味着你可能很快就把事情搞得一团糟。不要那样做,保持代码易于管理,你的同事和未来的自己会感谢你——如果他们之后需要调查 bug 或进行改进的话。
文章 How 3 Java Champions are using GitHub Copilot for increased productivity 首次发表于 The GitHub Blog。