停止编码的那天,就是失去架构判断力的开始:一位 30 年架构师的 AI 生存指南

点击查看原文>

在 AI Coding 飞速发展的当下,工程师的价值正从“如何实现”转向“解决什么问题”,那么,手敲代码还有意义吗?作为一名坚持编码近 30 年的架构师,微软最有价值专家 (MVP)、开源项目创作者、现任 Aviva Solutions 的代码架构师 Dennis Doomen 的观点直截了当:如果你不深入代码,就无法做出优秀的架构决策。

最近,Dennis 在播客节目中,与主持人 Patrick Akil 对话,他以大量一线经验为基础,探讨了一个更现实的问题:在 AI 可以生成代码的时代,我们究竟该如何保持对代码质量的掌控?基于该播客视频,InfoQ 对内容进行了整理与部分删改。

核心观点如下:

  • 作为架构负责人,同时仍保持动手实践,这是团队中唯一有效的软件开发方式。

  • 软件工程的核心,无论过去还是未来,都是在已有系统与不断增长的复杂性之间维持平衡。如果对过去的决策缺乏理解,却仍机械遵循,就会不断累积复杂性,而时间会放大这一问题,甚至决定系统成败。

  • 即便未来我们可能不再需要编写代码,现阶段仍然需要对 AI 生成的结果进行接管和维护。

  • 无论是提交记录还是代码评审说明,都应尽量记录决策意图,而不仅是技术细节。

成为高效软件架构师的唯一方式

Patrick:你曾说自己不愿意全职做会议演讲,因为你太热爱现在的工作了。

Dennis:我也不认为有必要全职从事演讲,我仍然希望亲自参与实践。我更愿意称自己为“动手型架构师”或“编码型架构师”,几乎所有分享内容都源于我的一线经验。如果停止编写代码,不再亲自构建并上线生产系统,就会逐渐失去这些经验。

我现在 52 岁,从事这一领域已近 30 年,几乎无法想象自己停止编码。幸运的是,我的工作通常兼具架构设计与团队协作,我既是架构师,也是团队成员,会与开发者一起编写生产代码,从中能够获得大量实践经验。同时,我也能向开发者展示:只要稍微调整方法,代码的可维护性就能显著提升,这一点非常有价值。此外,在实践中还会不断遇到框架限制,学习新技术、新范式,这些都极具价值。因此,我通常只分享自身经验,而不是单纯介绍新技术,因为后者已有很多人可以胜任。我更愿意讲述日常工作中的真实经历,包括遇到的困难与取得的成功。

Patrick:作为架构负责人,同时仍保持动手实践,这是否是团队中最有效的软件开发方式?

Dennis:我认为这是唯一有效的方式。我接触过许多企业架构师,他们通常关注高层设计,例如策略或信息架构,但往往缺乏一线经验,难以判断某种方案是否可行,或某种技术路径对长期可维护性与可持续性的影响。对我来说,软件架构师若想真正发挥作用,必须清楚自己在做什么,并通过实践不断验证设想,需要亲自观察方案在实际中的表现。即使只是修复现有代码库中的缺陷,也极具价值,因为可以从中学到大量经验。我曾多次以顾问身份加入团队,发现他们在维护代码时面临困难,例如高耦合、结构混乱等问题。

当从更高视角审视时,往往会发现其架构本质上类似某种成熟模式。但问题在于,当前团队已经完全失去了对原始架构理念的理解,甚至不知道其底层设计思想。他们只是机械地复制项目结构与文件夹,而不理解其背后的原因,这种教条化做法反而削弱了优化和简化代码的能力。如果不深入代码库,很难发现这些问题。

在从零开始设计系统时,架构师通常会基于功能与非功能需求做出合理假设,但将这些设计真正落地,并非仅靠文档即可完成,开发团队仍会在实现过程中犯错。架构本身也包含假设,例如是否需要某种抽象,或是否采用特定模式,最终可能发现方案过于复杂或性能不足,需要调整。有时团队经验不足,也难以判断某种模式是否适用。因此,这一过程本质上是持续迭代的:设计、实现、反思、再调整,这与敏捷开发非常相似,也是工作的重要组成部分。

Patrick:我认为软件工程的核心,无论过去还是未来,都是在已有系统与不断增长的复杂性之间维持平衡。如果对过去的决策缺乏理解,却仍机械遵循,就会不断累积复杂性,而时间会放大这一问题,甚至决定系统成败。

Dennis:如果你意识到系统中存在不必要的复杂性,就需要持续投入精力去消除它。但实践中常会面临权衡,例如某个模块过于复杂,却遵循统一模式,是否应打破模式以简化该模块。如果这样做,系统的一致性会受到影响,部分开发者更倾向于保持一致性,即使代价是更高复杂度。我的观点是,应将模块视为边界,在该边界内保持一致性即可,而优先简化模块本身,因为这将显著提升可维护性。许多开发者在抽象、单元测试范围等问题上感到困惑,本质上也是复杂性带来的问题。

关于避免重复(DRY)原则,我持相对务实的态度:在某些情况下,我会有意识地复制代码,以降低耦合,但这必须是经过权衡的决策,而非盲目复制或完全避免复制。我观察到,许多有 10 至 15 年经验的开发者,在掌握设计模式后,往往会过度依赖这些模式。当你提出当前并不需要某种抽象时,他们常常会引用开闭原则或单一职责原则进行辩护,但这些抽象往往只是为未来的可能性做准备,而非现实需求。例如,有人会为了未来可能支持多种数据库而设计复杂抽象,即使当前并无此需求。但不同数据库在语义上的差异,使这种抽象往往难以真正成立。

Patrick:如果存在一套固定规则,严格遵循是否会更简单?

Dennis:理论上可以想象这样的情况,例如一种完全统一的标准,但现实并非如此。

Patrick:我更感兴趣的是“规范与务实”的平衡,以及当下与未来的取舍。随着 AI 辅助开发不断加速,我们或许会逐渐不再关注实现方式本身,只要系统最终是可维护的即可。

Dennis:我认为在未来的某个阶段,人们可能真的不再关心代码本身,就像科幻作品中那样,只需表达需求,系统便能自动完成。去年,我开发了一个 .NET 的开源 HTTP Mock 库,起因是现有工具无法满足需求,于是我开始自行构建,并整理需求与 API 设计。

出于好奇,我将 GitHub issue 分配给 Copilot。令人惊讶的是,它生成了一个高质量的开源项目,基本实现了所有需求,并遵循了我的编码规范。随后我通过评论不断补充需求,例如增加断言方法、支持不同版本等,它也能够很好地完成这些任务,甚至可以自动拆分项目、生成文档示例。在此基础上,我继续手动优化,并将其视为自己的代码进行迭代。现在,我采用人机协作的方式开发:部分功能由 AI 生成,部分由我完成。目前代码中存在一些不完全符合我标准的部分,例如方法较长,但我选择接受这一现实,并在后续逐步重构。

Patrick:只要功能正确、测试通过,就可以接受,而不必立即优化。

Dennis:确实如此。代码本身并不差,也遵循一定规范。我仍在不断尝试新的工具与方法,同时会重点审查测试,确保其能够准确反映预期行为。测试不仅用于验证功能,也帮助我理解系统行为与 API 设计。在实践中持续迭代,而对于重复性任务,我通常会优先交由 AI 处理,以提高效率。

即使是在日常项目中,我也会让 AI 生成额外的测试用例,以确保覆盖率足够全面。但随后我一定会逐一审查这些测试,确认它们确实达到了预期目的,同时也符合我偏好的编码模式。在此基础上,我会要求 AI 进行调整,并同步更新指令文件,使其在下一次生成时更贴近我的规范。虽然这并不能完全保证结果,但这已经成为当前较为有效的工作流程。

测试在 AI 时代成为“安全网”

Patrick:我曾在一些团队中经历过这样的流程:在需求细化阶段,就将解决方案写得非常具体,包括要修改的内容、代码位置、采用的规范和模式等。在没有 AI 辅助工具的情况下,我并不喜欢这种方式,但它的优点是开发者只需读取任务并执行。如今,执行本身正在显著加速,我们不再需要亲自完成所有实现。这让我开始思考:当构建能力不断提升、各种工具层出不穷时,研究与规划、识别问题本身的重要性是否会进一步提升?与此同时,分发与用户获取也将变得更加关键,因为如果用户可以轻易自行构建工具,那么产品真正解决的问题才是核心。

Dennis:这也让我思考,开发开源项目是否仍然值得。不过,从现实来看,并非所有人都具备自行构建工具的能力。我们往往容易忽视自己身处一个“技术圈层”之中:以我为例,我有机会参加各种会议,并活跃于开源社区,接触到大量持续学习、追求技术前沿的开发者。在会议交流中,可以从许多经验丰富的人身上学到东西。但事实上,还有大量开发者并没有这样的条件,他们只能在日常工作中获取知识,甚至可能因为缺乏引导而长期停滞。因此,我们所做的事情不仅是为自己或这个小圈子,也是为更广泛的开发者群体服务。

以我的开源项目为例,很多团队在实际项目中会使用它,并结合 AI 来重写测试、替换旧的 mock 方案,或为特定场景自动生成测试代码。我始终坚持的目标,是让代码尽可能具备良好的可读性。同时,我一直推崇测试驱动开发,并努力让测试本身具备自解释性,避免噪音,使其可以作为文档使用。因此,我倾向于使用更清晰的测试方式,而不是依赖复杂、难以理解的 mock 结构。本质上,这些工具最初是为我自己服务的,在此基础上再开放出来,观察是否能被更多人接受。

Patrick:我过去非常重视测试的结构与组织,不仅是为当前的自己,也是为未来的自己和团队成员。我会在提交信息和代码评审中尽量提供上下文,使每次变更清晰且可理解。如今,我越来越觉得测试质量就是系统的“安全网”。如果我们将实现过程视为黑箱,那么只要测试足够可靠,就可以信任系统的行为,无论代码是由人还是 AI 生成。因此,如何设计测试、测试什么内容,正变得愈发重要。有些团队甚至会先编写测试和规范,再基于此生成实现。

Dennis:即便未来我们可能不再需要编写代码,现阶段仍然需要对 AI 生成的结果进行接管和维护。回顾过去两三年,从 AI 工具开始普及到现在的发展速度是非常惊人的。尽管底层技术仍在优化,但真正显著的进步更多体现在工具层面,使其更快、更强大。坦率地说,我并不真正理解 AI 的内部原理,但这并不妨碍我高频使用它。

Patrick:我也尝试深入理解 AI,但后来意识到这更多是出于好奇,而非解决实际问题。我更倾向于直接使用工具进行实验,尤其是在个人项目或生产环境中。我曾尝试完全依赖 AI 进行开发,但很快遇到问题,例如上下文被压缩,导致理解丢失,最终甚至在主分支上直接提交了实验性代码。这是一次教训,但也是通过实践获得的经验。与此同时,这种快速变化也带来了一定的焦虑,如果没有实验环境,很容易落后。

Dennis:我也有类似经历。比如我曾使用 AI 工具修改代码,并频繁提交以便随时回滚。但后来发现某些修改被意外覆盖,甚至开始怀疑是自己操作失误。通过查看 Git 记录,才发现是 AI 在某次修改中撤销了我之前的更改。这说明在使用 AI 时必须格外谨慎,良好的分支管理和代码审查尤为重要。

至于“实验”,我更倾向于在已有项目中逐步尝试,而不是随意构建后再丢弃。我曾被问到团队是否应统一使用某种 AI 工具,我的建议是不要这样做。因为工具变化极快,强制统一反而限制探索空间。更合理的方式是允许团队自由选择工具,同时跟踪使用情况并定期评估。

至于成本问题,其实很容易被误解。我曾遇到一些团队在讨论是否引入 Copilot,他们会担心成本问题,例如为几位开发者支付每月订阅费用。但如果从效率角度看,这类投入通常可以在极短时间内收回,甚至带来数倍收益。

不过,另一面的问题在于,一些经验尚浅的开发者在使用 AI 时可能面临挑战。一部分人担心使用 AI 会削弱自身学习能力,因此刻意避免使用;他们更愿意通过查阅资料、阅读文档、反复试错来积累经验。另一部分人则过度依赖 AI,却缺乏判断能力,无法验证生成代码是否正确。我确实见过有人提交代码时并不理解其实现逻辑,只是确认“测试通过”。在这种情况下,我会强调:可以使用 AI,但必须确保代码质量达到团队标准,即使你不完全遵循某种方法论,也应具备相应的设计质量。

在 AI 时代保持好奇心与批判性思维

Patrick:回顾我的学习经历,从最初的独立探索,到进入职场后学会主动提问、与团队协作,再到如今使用 AI 进行“自我问答”,我认为关键在于保持好奇心与批判性思维。你可以选择简单复制答案,也可以利用 AI 深入理解原理,并与团队讨论验证。只要持续提问与反思,就能快速成长。

Dennis:确实如此。在过去,我也经常与不同水平的开发者合作。有些人频繁提问,有些人则因顾虑而不敢发问。如今,这些人可能会转向 AI 获取答案,这未必是坏事。我自己也经常使用 AI 来快速获取信息,例如对比不同技术方案、查询行业实践等。AI 的优势在于能够整合多种观点,提供结构化总结,这在很多场景下非常高效。因此,我几乎每天都会使用它,无论是工作问题,还是生活决策,都会借助 AI 获取参考意见。

Patrick:如果让你从零培养一名软件工程师,基于你现在的经验,你会重点关注哪些方面?

Dennis:实际上,这种情况在我的团队中经常出现,因为团队里有不少刚入行的开发者。从根本上来说,我认为方法与过去并没有本质变化:让他们从真实代码库中入手,例如修复缺陷、完成小规模改进,在逐步接触较大范围代码的过程中理解系统。同时,鼓励他们不断提问。

在代码评审中,我有一个长期使用的做法:通过表情符号来传达反馈的语气和意图。这并不是为了表达情绪,而是帮助开发者理解评论的重要程度。例如,我会用“镐子⛏️”表示这是细节层面的改进建议,尤其是在面对初级开发者时,这种方式可以更清晰地传达“可以优化但不是错误”的信息。我还会用“思考🤔”的表情表示这是一种可讨论的实现方式,从而引导他们主动思考不同方案的优缺点,并通过交流进一步加深理解。有时我还会使用“营地⛺️”的表情,表达“让代码比来时更干净”的理念,即当前实现是可接受的,但仍有优化空间。

这些评审本身就是一种学习过程,如果开发者在某个问题上卡住,即使我知道答案,也可能会建议他们先借助 AI 工具进行探索,然后将结果作为讨论基础。这样不仅能提高效率,也能促进更深入的理解。不过,在架构层面,例如抽象设计或依赖反转原则的应用,仍然需要整体视角的判断,这类问题目前 AI 还难以完全胜任。只要系统仍需维护,我们就必须持续关注耦合、内聚等核心设计问题。

Patrick:有时我会因为不懂某些问题而感到尴尬,不敢直接问同事,而是先借助工具理解背景,再进行讨论。我认为 AI 可以帮助我们快速获取上下文信息,尤其是在复杂系统中,但最终决策仍然需要人来承担。

Dennis:确实如此,AI 在理解复杂代码库方面非常有帮助。例如,在微服务架构中,它可以帮助你梳理服务之间的数据流,快速定位调用路径。但对于“为什么这样设计”的历史原因,仍需要依赖版本控制系统或文档记录。因此,我始终强调:在提交代码时,不仅要说明“做了什么”,更要说明“为什么这么做”。

代码本身往往无法体现决策背后的动机,而这些信息极易丢失。因此,无论是提交记录还是代码评审说明,都应尽量记录决策意图,而不仅是技术细节。我自己也会借助 AI 自动生成提交说明,并对结果进行适当调整。这些工具往往能够准确抓住变更的本质,而不仅仅是文件层面的修改。这也进一步说明,高质量的历史记录对于后续理解系统至关重要。

Patrick:有些公司会记录业务决策,如成本优化或增长策略,而不仅是技术决策。如果能够通过提交记录、任务系统和文档持续积累上下文,那么在未来借助 AI 工具进行分析时,这些信息将极具价值。

Dennis:在实践中,我通常会推动团队使用文档工具来记录关键决策,包括背景、备选方案及其优缺点,以及参与决策的人。尤其对于非简单决策,这些记录在长期来看极为重要。当新成员加入团队或有人质疑既有方案时,这些文档可以清晰还原当时的决策背景,避免重复讨论或错误推翻原有设计。

Patrick:记录决策是否可能导致“路径依赖”,即团队过于坚持过去的选择,而忽视当前环境的变化?

Dennis:这种情况确实存在,但我也经历过相反的情境:当管理层变动或新成员加入时,可能会基于不完整的信息质疑既有架构。如果缺乏记录,很容易做出错误决策。而有了清晰的决策依据,就可以解释当时选择的合理性,从而避免不必要的推翻。关键在于:如果环境发生变化,应重新评估;如果没有变化,就不应轻易否定过去的决定。

Patrick:随着 AI 可以快速复现开源项目的部分功能,一些依赖“开源+付费扩展”的商业模式正面临挑战,这是否会影响开发者参与开源的动力?

Dennis:使用开源并不意味着可以获得长期维护的保证,很多用户会默认项目会持续更新,但实际上并非如此。在架构实践中,我通常会制定开源使用规范。例如,在选择开源库时,需要评估其质量、维护情况以及社区活跃度。如果未来该项目停止维护,团队是否有能力接手?这意味着,开源代码在某种程度上也可能成为你的“自有代码”。

因此,需要考虑多个因素,例如维护者规模、代码质量、测试覆盖、文档完善程度以及发布流程等。关键不是简单判断“能不能用”,而是充分理解其风险与成本。如果采用这种思路,即使项目停止维护,也可以通过分叉继续维护。

很多人低估了构建高质量库的复杂度,即使借助 AI,开发成熟工具仍需要大量时间与经验。因此,在大多数情况下,使用开源依然是更高效的选择。

Patrick:如果有人在考虑是否将自己的项目开源,你会如何建议?

Dennis:首先它本身是有趣的过程,同时也是展示能力的一种方式。当看到他人使用你的项目并从中受益,会带来很大的成就感。如果项目被广泛采用,甚至有人主动提交修复或改进,这种协作体验非常宝贵。

更重要的是,开源是一个“付出与回报并存”的过程。你不仅分享成果,也能从社区中获得大量反馈、经验以及新的技术视角。很多改进建议、工具推荐甚至全新的思路,都是通过社区互动获得的。这些知识与经验的积累,是开源最具价值的部分。

参考链接:https://www.youtube.com/watch?v=Z4MUDojhihQ


本文来源:InfoQ