跳到正文
原文
GitHub Blog · AI & ML· Julien Dubois·· 3 小时前AI 评分56

三位 Java Champion 如何用 GitHub Copilot 提升开发效率

How 3 Java Champions are using GitHub Copilot for increased productivity

AI 导读

Vlad Mihalcea、Patrick Baumgartner 和 Frank Delporte 三位 Java Champion 分享了用 GitHub Copilot 提升生产与开源开发效率的做法,并强调人要验证结果、对交付负责。

正文 · 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 中的各种功能。

例如,我长期以来一直想开发一个提供 Optimizer 事件历史的 Web 应用,以便我们能看到性能改进工作如何体现在应用性能上。在有 AI 之前,我一直推迟这项任务,因为它本需要数周才能开发完成。但使用 Copilot 就像多了一位新的团队成员,于是我用它创建了一个将在下一版 Hypersistence Optimizer 中发布的应用。这项任务只用了两天就实现了,而不是数周。

你通常如何使用?你是把 GitHub Copilot 当作 IDE 插件,还是使用 GitHub Copilot 应用?

我在 IntelliJ IDEA 中使用 GitHub Copilot,因为在审查源代码或调试期间运行它很方便。

它作为代码助手非常有用,能帮助我加快调查速度,也能更快地为需要验证的功能构建原型。

我仍然会审查 AI 生成的方案和代码,因为它们的目标是提高我的生产力,而不是完全取代我。虽然 AI 在许多情况下能给出正确答案,但仍有一些时候回答并不令人满意,需要我介入。

你能分享一些技巧和最佳实践吗?例如,你在使用哪些技能?

我创建了自己的技能,这样 Copilot 生成的任何文本看起来都像是我亲手写的。

这项技能从我已发表的 65 篇文章中捕捉我的文风,因此草稿读起来像我的博客,而不是语言模型。这在为该项目生成文档时非常有用,因为它能让 LLM 从 12 年的博客写作中学习,并提供遵循相同原则的示例,例如表达力、可测试性和简洁性。

在我作为软件工程师的职业生涯中,我认识到我们花在代码维护上的时间远多于创建代码的时间。因此,由于维护和稳定性对现有产品至关重要,我开发了一些技能,帮助 AI 依照最小惊讶原则模仿现有的代码实践。

一个技巧是根据操作类型更换模型类型。对于需要深入思考的任务,我使用带有 100 万上下文窗口以及 Extra High 或 Max 推理级别的 Opus。而对于较简单的任务,例如生成报告、发布说明或核对文档,我则使用消耗更少 token 的更轻量模型。

Patrick Baumgartner

GitHub 个人主页:@patbaumgartner

你的工作涉及指导团队。你的方法是什么?

我的很多工作都是在日常业务仍需继续运转的情况下进行的。你不可能把一切停下来六个月去做“转型”。我们通常先一起解决眼前的问题,了解团队目前所处的位置,明确我们想去往何处以及如何知道自己在进步,然后一步步朝那里前进。

视情况而定,这可能意味着软件工艺实践,例如 TDD、重构、持续交付和 XP;使用 Spring Boot、Spring Modulith 进行架构与模块化;Spring Security;针对容器优化 Java 和 Spring Boot 应用;或者越来越多地涉及智能体工程。

对我来说,重要的是我是和团队一起工作。我们共同做决定。我不希望团队变得依赖我。理想情况下,过一段时间后他们不再需要我,最多只是把我当作一个陪练伙伴。

也许这正说明了我为什么觉得这一代新的 AI 工具如此有趣:我喜欢与人共事、学习、实验和解决问题。AI 为我们提供了另一个非常强大的工具来做同样的事情。

你能分享一个最近 GitHub Copilot 如何帮助你的好故事吗?

实际上有三个非常不同的例子,改变了我对与 GitHub Copilot 协作的看法。

我们先从第一个说起。

其中一个是将大约 900 张教学幻灯片、共 15 个演示文稿从 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 毫无头绪,通常也会对它所在的大致范围有直觉。把这个信息交给工具,这样它就不必排查全部代码。
  • 要求提供证明和测试:“添加一个单元测试来验证这项改动”是我近来经常提出的要求。嗯,是曾经经常提出,因为它现在已经成为我指令文件中的一条规则。这也能避免诊断有误的情况,因为该测试在旧代码上不会失败。
  • 追问原因:如果你不理解某项修复,就说出来并提问。解释本身也是一项交付物,应当加入项目文档,或写进工单或 pull request 中。它能让之后阅读这些信息的每个人都有所收获。例如,这也引发了 Pi4J 团队内部关于原生调用上 virtual thread pinning 的更多问题。
  • 保持掌控:Pi4J 中的所有这些 pull request 在合入之前,都经过了维护者的审查和批准。这是在这个项目中效果最好的模式:由 agent 负责调查,由人类对最终发布的内容负责。但在我的其他项目中,我也总会审查工具生成的代码。我始终希望代码保持可读、可维护。工具太常会创建重复的方法,或者重新实现别处已经存在、本应合并起来的功能。这是你的责任。如今借助 AI 辅助编程,你可以推进得非常快,这也意味着你可以非常快地制造一团混乱。别这么做,让代码保持可控;如果同事和未来的你之后需要排查 bug 或做改进,他们会感谢你。

开始使用 GitHub Copilot >

文章 3 位 Java Champions 如何使用 GitHub Copilot 提升生产力 首发于 The GitHub Blog。

来源:GitHub Blog · AI & ML · github.blog