什么是代码?

TL;DR · AI 摘要
在大语言模型时代,代码的核心价值已从机器指令执行转向概念模型设计,开发者需聚焦领域词汇和系统设计。
核心要点
- LLMs使代码指令生成成本降低,但概念模型设计(如领域词汇)成为核心价值。
- 领域词汇(如abstraction)是概念模型的关键,需开发者显式构建以提升系统可理解性。
- 开发者应从'写代码'转向'设计概念',提升系统设计质量。
结构提纲
按章节快速跳转。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- 代码的双重价值
- 机器指令
- LLMs商品化
- 概念模型
- 领域词汇
- abstraction等
金句 / Highlights
值得收藏与分享的关键句。
LLMs商品化代码指令,使概念模型设计成为新的价值驱动。
领域词汇(如'abstraction')是概念模型可见的体现。
我们称之为编码的活动是这两个方面交汇的地方,塑造系统理解。
什么是代码?

[](https://martinfowler.com/articles/what-is-code.html#navmenu-bottom)
- 重构
- 敏捷开发
- 架构
- 关于我
- Thoughtworks
- [](https://martinfowler.com/feed.atom "feed")
- [](https://www.twitter.com/martinfowler "Twitter 流")
- [](https://toot.thoughtworks.com/@mfowler "Mastodon 流")
- [](https://www.linkedin.com/in/martin-fowler-com/ "LinkedIn")
- [](https://bsky.app/profile/martinfowler.com "BlueSky")
主题
关于我
内容
Thoughtworks
关注
目录
什么是代码?
2026年5月12日
- * *

Unmesh Joshi 是 Thoughtworks 的杰出工程师,工作地点在印度浦那。他是《分布式系统模式》(Patterns of Distributed Systems)一书的作者。
目录
- * *
什么是代码?从宏观层面看,这个问题的答案似乎显而易见。代码是开发者编写的程序:用编程语言表达的指令,用于告诉机器执行什么操作。多年来,编写代码意味着逐字逐句输入。进步的标准是代码编写、编译、测试和部署的效率。借助现代大型语言模型(LLM),我们不再需要逐字输入代码。如今,大量可执行代码能从高层次描述中生成。这引出了一个更深层的问题:如果代码生产成本降低,代码的价值何在?
代码的两个维度
代码始终服务于两个相互交织但截然不同的目的。
首先,代码是机器的指令集。它指导计算、移动数据、与存储交互、协调执行。在大型语言模型时代,这部分正被商品化。
其次,代码是问题领域的概念模型。这是“设计”层面。一个设计良好的代码库不仅包含机器指令,还包含人类和工具可理解的概念体系。
我们称之为“编码”的活动正是这两个维度的交汇点。我们通过塑造系统所依赖的概念、命名、边界和关系来构建理解框架。
概念模型与术语体系
将概念模型显性化是编码的深层本质,它由系统所解决的领域和用例驱动。每个领域都拥有既定的流程、实践,更重要的是共享的术语体系。这个术语体系正是概念模型的具象化体现。
术语体系通常指特定语言或主题中使用的词汇集合。我之所以能撰写本文,是因为我掌握了英语的术语体系。读者能理解本文,是因为他们与我共享这一术语体系。
但仅懂英语不足以理解本文。本文讨论的是软件开发。软件开发是涵盖广泛、成熟的领域,拥有自己的技术术语体系。当我使用“抽象”一词时,我不仅是在使用英语词汇,更是在指代软件开发中特定的概念——它有自身的含义、历史和影响。对软件开发不熟悉的人可能仅理解该词的表层含义,却无法把握其在本文语境中的深层含义。拥有成熟术语体系的领域被称为“领域”。
所有严肃的领域皆是如此。沟通依赖于共享的术语体系。无论我们与人、框架还是大型语言模型交流,所用词汇必须映射到接收方能理解并执行的概念。
代码中的术语体系
设计良好的代码库是特定术语体系的体现。代码中的术语体系从何而来?这正是软件开发独特性的核心所在。软件开发处于多个领域的交汇点。一端是银行、金融、零售、库存、医疗、保险等业务领域;另一端是网络、基础设施、人工智能、数据工程等技术领域。
领域开发人员需要深刻理解网络架构、网络方法的语义、GET方法的通用缓存潜力及其语义影响。不了解这些的人难以构建复杂的系统。其他领域也是如此。词汇表不仅仅是标签的集合,它承载着语义、约束和设计后果。
以零售领域为例。当我们编写零售代码时,会涉及客户、产品、订单、发货、支付等概念。在进行零售领域的Web开发时,代码将零售领域概念映射到Web领域。例如,商品目录(Catalog)是一个资源,我们可以使用GET、POST、PUT、DELETE等HTTP方法对其进行操作。编写代码的人员需要熟悉这两个领域的词汇表。
为特定领域编码本质上是一种翻译行为。开发者将领域词汇映射到技术领域的词汇。在此过程中,编程语言提供的结构也构建了新的词汇表。例如,日志、仓储、法定人数、事务等概念,以及像货币这样的特定概念。概念转化为类型,关系转化为接口,规则转化为不变量,工作流转化为组合。
变量的精确名称、方法的边界以及类的层次结构是逐步发现的。正确的抽象往往并非一目了然,只有在持续根据现实世界约束重构代码时才会显现。当运用得当时,代码会逐渐成为领域本身的可读、高度具体的表达。
对于技术领域,我们通常会找到提供基础实现模式的框架和库。框架和库是编码化的词汇表,它们捕获了最常见的使用模式。这也是为什么像Spring Framework这样的生态系统能用于构建涉及Web、集成及相关问题的企业级应用。不同编程语言带来各自的特点,以及反映在框架和库中的特定设计约束。
有界上下文与局部词汇表
当领域具有稳定且广泛共享的结构时,框架能发挥最佳效果。但“在线零售”或“股票交易所”这类领域则不同。它们不仅仅是技术栈。没有通用高层框架的主要原因是,该领域的词汇表在所有实例中不够稳定。试图寻找通用抽象往往要么过于宽泛而无用,要么过于主观而难以普及。越接近核心商业模式,抽象就越需要在本地发现。这正是领域驱动设计中有界上下文概念如此重要的原因:有界上下文标记了特定词汇表和模型有效的边界。同一词汇在不同上下文中可能有不同含义,每个上下文都需要自己的抽象、规则和语言。
我们如何构建这些局部抽象和词汇表?大量词汇是通过迭代式编码和反思过程构建的。测试驱动开发(TDD)等技术非常适合这种词汇表的迭代开发。它们通过持续反馈模型与行为之间的关系,帮助我们发现正确的名称、抽象和边界。
编码无法孤立进行。领域专家、用户和开发人员必须紧密协作。这种协作对于构建局部抽象和词汇表至关重要。
这直接关联到敏捷软件开发的要义:强调个体与互动、客户协作、可工作的软件以及响应变化,这不仅是流程建议,更是通过反馈发现和精炼词汇的方式。
领域驱动设计通过通用语言的概念使这一点更加明确:由开发人员和领域专家共同构建、并通过可工作的软件持续验证的共享语言。
编程语言作为思维工具
通过代码构建词汇表需要主动参与编写和重构代码,而不仅仅是被动审查生成的代码。深入思考代码的真正过程往往发生在我们主动编码时。编程语言及其结构和约束本身成为思维工具。不同编程语言提供的设计约束帮助塑造我们的思考方式。Go语言的通道和轻量级线程、Java的面向对象模型,或Rust的所有权模型,都促使我们以特定方式看待结构、边界和权衡。从这个意义上说,编程语言不仅帮助我们表达设计,还帮助我们发现设计。我最近需要为异步编程示例设计自定义Future实现。Future API的一个重要方面是设计组合方式,以表达一系列操作。
var future1 = action1();
future1.thenCompose(val1 -> action2(val1))
.thenCompose(val2 -> action3(val2))掌握函数式编程的概念和词汇表对实现此API至关重要。缺乏这些概念会导致实现和使用变得别扭。
有时,编程语言的语法会过于冗长,掩盖解决方案的底层结构。例如,最近在为我的工作坊实现快照隔离(snapshot isolation)时,用自然语言描述核心需求显得有些模糊,而用 Java 代码实现又过于冗长。更严格的正式规范(如 TLA+)本会有所帮助,但即使只写一页伪正式规范,也极大地澄清了思路。
Begin(T, coord):
R(T) := HLC(coord).now()
writeSet(T) := {}
Read(T, N, key):
N.HLC.tick(R(T)) // HLC 已推进。因此后续的写入或提交必然具有更高时间戳
return key 的最新已提交版本(时间戳 ≤ R(T))
Write(T, N, key, value):
N.HLC.tick(R(T))
if LatestCommittedVersion(key).ts > R(T):
abort T
place provisional intent for (key, value)
writeSet(T) := writeSet(T) union {key}这份伪正式规范帮助我理清思路,成为后续讨论、实现和测试验证的良好基础。
与 LLMs 的协作
"将编码视为词汇构建"(Coding as Vocabulary Building)对 LLMs 具有重要启示。LLMs 通过大量文本和代码中的词汇进行训练,学习名称、API、库、框架、惯用语、设计模式和实现结构之间的常见关联。当 LLMs 遇到 Controller、Repository、Reducer、ConsensusModule 或 TransactionLog 等名称时,这些名称远不止是标签——它们承载着已知代码结构和预期行为的关联。
这正是词汇在 LLMs 协作中至关重要的原因。若提示词使用模糊或不一致的表述,模型将不得不猜测我们意图的设计;若代码库使用模糊的命名和不一致的概念,模型便缺乏稳定的结构可遵循。但当词汇精准、一致且融入代码时,LLMs 能更可靠地将我们的意图映射为有用实现。
认知债务
这也解释了 LLM 辅助编码的特定风险:认知债务(cognitive debt)。当词汇、抽象和结构被使用,但使用者对其含义缺乏充分理解时,认知债务便开始累积。LLMs 加剧了这一风险,因为它们能快速生成大量看似合理的代码。生成的代码可能包含 Controller、Repository、Reducer、Factory、Transaction、Scheduler 等熟悉结构,可能编译通过,甚至通过基础测试。但若团队不理解这些结构背后的概念模型,代码库便获得了词汇却缺乏共识。问题不在于 LLM 生成了代码,而在于代码引入的词汇速度远超开发者建立理解的速度。这种差距是认知债务的主要成因之一。
代码作为共享概念模型
正如我们在 《用 LLMs 设计抽象》 中讨论的,编写代码包含两个深度交织的活动:发现抽象和应用抽象。发现抽象是构建词汇的过程。当词汇体系建立稳固后,它便代表了一个共享概念模型。一旦该模型存在,编码的大部分工作便转化为运用该概念模型构建用例。这正是优秀库和基础代码的闪光点——它们隐藏编程语言和环境的复杂性,为已构建的词汇提供越来越接近自然语言的接口。典型做法是构建领域特定语言(DSL),使词汇或抽象的使用更简单、更贴近自然语言。
LLMs 在此方面表现出色。它们为抽象词汇提供自然语言接口。更关键的是,若抽象词汇背后有可执行代码,该代码本身便成为 LLM 修正错误的优秀护栏。良好的抽象、可执行行为、测试、类型和不变量共同约束模型,使输出更具实用性。
我们可以用词汇构建外部 DSL。LLMs 作为外部 DSL 的自然语言接口运作极佳。我已成功将 LLMs 用于 PlantUML 等工具。这并不意外,因为 LLMs 本质上最适合映射词汇。
因此,在 LLMs 时代,扎实的基础代码变得更为重要。一旦系统词汇体系完善,编码便不再聚焦于生成原始语法,而是聚焦于运用成熟的概念语言构建可靠软件。
代码本身即框架与上下文
关于上下文工程和框架工程的大量讨论将代码视为黑盒,认为其正确生成的责任应由外部通过提供恰当提示上下文或构建包含规范、测试和静态验证的框架来管理。而结构良好的代码,其抽象形成的清晰词汇体系,本身就是框架和上下文最重要的组成部分。我多次见证,精心设计的代码与 LLMs 协作效果极佳。更重要的是,当代码基于稳定、语义清晰的抽象构建时,你可以自由选择任何 LLM 模型,无需过度担忧提示词的精确性。代码结构和配套测试本身即提供上下文与框架,使 LLMs 的输出可靠且实用。
结论
编码的角色不会消失,但正在演变。
随着大型语言模型使代码生成成本降低,机械性编写指令的操作变得不那么核心。真正重要的是将概念模型显式化,发现合适的术语体系,并通过迭代、领域专业知识和反馈来优化该术语体系。这也是编程语言持续重要的原因。我们不应被动地审阅生成的代码,编写代码本身也是我们思考过程的一部分。
代码仍是机器的指令,但它也是理解的模型。在大型语言模型时代,后者的角色变得更为重要。编码的未来不仅在于更快地编写更多代码,更在于构建更好的概念模型、更优的术语体系,以及更坚实的基础,使人类和大型语言模型都能在此基础上协同工作。
- * *
致谢
感谢丽贝卡·帕森斯(Rebecca Parsons)和马丁·福勒(Martin Fowler)对本文初稿提供的宝贵意见。
玛格丽特·斯托里(Margaret Story)、麦克斯·卡纳特-亚历山大(Max Kanat-Alexander)、普拉曼南·昌德拉塞卡兰(Premanand Chandrasekaran)、内特·舒塔(Nate Schutta)、卡维·塞克洪(Kavi Sekhon)、米斯玛·西尔弗(Misma Silfver)、里卡多·皮科利(Ricardo Piccoli)和维诺德·库马尔·鲁(Vinod Kumaar R)审阅了文稿并提出了建议。
Gemini 和 ChatGPT 用于优化现有文稿的语言表达,并协助完成校对工作。
重要修订 _2026年5月12日_:发布
主题
关于我
内容
Thoughtworks
关注

© Martin Fowler | 披露信息