你写的代码,其实是一本团队词典!martinfowler.com这篇文章解释代码不仅是给电脑的指令,更是帮人理解问题的概念模型。用好代码的核心是建立团队通用的词汇表,这比单纯写指令更重要,尤其在AI能自动生成代码的今天。
作者背景
Unmesh Joshi,软件架构师,专注分布式系统设计
什么是代码?
写代码这件事,表面上看就是给电脑下指令。你用Java、Python或者Go告诉电脑:去把这块数据挪到那儿,再算个结果出来。以前我们得一个字一个字敲进去,进度快慢全看打字速度和调试水平。
但现在不一样了。你对着AI说一句“给我写个用户登录功能”,它能哗啦吐出一大段能跑的代码。生成代码变得跟复制粘贴一样便宜。这时候我们就得琢磨一个扎心的问题:如果代码本身不值钱了,那什么东西还值钱?
答案藏在一个挺反直觉的地方。代码不只是机器说明书,它更像一本团队词典。你写出来的每一个变量名、每一个函数、每一个类,都是在给项目里的其他人(包括未来的你自己)解释:这个世界是怎么运转的。好的代码,你读一遍就能懂业务逻辑。烂的代码,你配上注释都猜不透当初那哥们想干嘛。
所以这篇文章要聊的核心就一句话:写代码的本质,是建立大家都能懂的概念和词汇。AI能帮你敲键盘,但建立这个词汇表,还得靠人。
代码有两个面,大多数人只看了一个面
咱们从最基础的地方拆。代码从诞生那天起,就干两件完全不同的事。
第一件很明显,就是指挥机器干活。你写个循环,电脑就乖乖转一圈又一圈。你写个判断,电脑就选一条路走。这部分是纯技术活,拼的是谁更懂内存、CPU、网络这些硬家伙。
第二件事就没那么直观了。代码其实是一个概念模型,是对真实世界里某个问题的抽象。比如说你要写一个电商系统。真实世界里有人在逛店、加购物车、下单、付款。电脑不懂这些,它只懂0和1。那怎么办?你得用代码造一个虚拟世界,把“用户”、“订单”、“商品”这些概念塞进去,让电脑能理解并处理它们。
这两个面一直缠在一起。以前大家更看重第一个面,因为那时候写代码费劲啊,编译器也不聪明,跑一次要等半天。所以衡量程序员水平的标准是:你能不能写出高效、稳定、不崩的指令。
但现在AI把第一个面干成了白菜价。你给AI一个清晰的需求,它生成的代码很可能比你手写还规范。这下子,第二个面就浮出水面了。那些藏在代码里的概念、命名、边界、关系,才是真正值钱的东西。因为AI不懂你的业务,它不知道你公司里“客户”和“用户”到底是不是一个意思。这事儿只有你知道。
词汇表才是团队的真正资产
咱们举个特接地气的例子。你去一家新公司上班,进了一个开发群。群里的人说:“把那个SKU的ROP调一下,注意BOM里的替代料。” 你一脸懵,心想这帮人说啥黑话呢?SKU、ROP、BOM这些词,外人听不懂,但团队里每个人都知道它们指啥。这就是词汇表。
写代码完全一样。好的代码库里,每个名字都不是随便起的。“Customer”这个类一出现,所有人都知道它带着姓名、地址、会员等级。“Order”这个对象一创建,大家就知道它关联着商品列表、总价、订单状态。这就像你一说“足球”,大家脑子里就浮现出圆球、草坪、射门这些画面。词汇让沟通变快,让思考变准。
那这个词汇表从哪来?不是从天上掉下来的,也不是产品经理写个文档就完事的。它是程序员在跟业务方反复撕扯、不断改代码的过程中长出来的。你改一次命名,重构一次类,拆一个接口,都是在打磨这本词典。
举个例子。你在写一个零售系统。一开始你写了个“Product”类,里面有价格、名称、库存。后来业务方说:“不对,我们有一种叫‘套装’的东西,里面包含好几个产品,但是价格要单独算。” 你就得琢磨:是给Product加个类型字段呢,还是新建一个叫做“ProductBundle”的类?讨论几次、写几版代码之后,你们团队慢慢形成了一个共识:Product是单个商品,Bundle是组合包。这两个词就成了你们团队的专属词汇。
所以说,一个项目的核心资产不是那些能跑的代码,而是藏在代码里的那套词汇表。这套词汇表越精确,团队干活就越顺。新人来了看懂也快,改需求时不容易翻车。
技术领域和业务领域来回翻译
你可能会问:那这套词汇表怎么建起来?其实过程就是翻译。你在两个世界之间来回倒腾。一个世界是业务领域,比如银行、电商、医院、物流。银行里的人说“账户”、“交易”、“对账”。另一个世界是技术领域,比如网络、数据库、前端框架。搞技术的人说“HTTP方法”、“事务”、“缓存”。
程序员就是这两边的翻译官。你得先把业务那边的话听明白,然后用技术这边的话表达出来。更重要的是,你要在代码里造出新的词来连接两边。比如在Web开发里,你把“商品目录”翻译成一个“资源”,然后用GET去查它,用POST去改它。你写出来的Controller、Repository这些类,就是新造的词汇。
这个过程特别考验人。你不光要懂业务,还得懂技术。更重要的是,你得知道什么时候该造新词,什么时候该复用老词。比如说“日志”这个概念,几乎所有系统都需要。那你就没必要自己发明一个“记事情本”类,直接用现成的Log框架就行。这些框架本身就是现成的词汇表,帮你省了不少力气。
反过来,有些概念就得你们团队自己长出来。比如你们公司有个特殊的折扣规则:会员生日当天买满三百块打八五折,但是不能跟其他优惠叠加。这种规则你没法直接套用通用框架,得自己写一个“BirthdayDiscountPolicy”类。这个名字和它的逻辑,就成了你们团队的专有词汇。
边界很重要,同一个词在不同地方意思可能不同
这就引出一个特别容易踩的坑:同一个词,在不同场景下意思完全不一样。你想想,“客户”这个词在销售部门眼里是“潜在购买者”,在客服部门眼里是“需要服务的人”,在财务部门眼里是“付钱的那个账户”。如果在代码里全用一个Customer类,保准乱套。
领域驱动设计里有个概念叫“限界上下文”,就是为了解决这个问题。简单说,你得画个圈,在这个圈里,每个词只有一个明确的意思。出了这个圈,哪怕同一个词,也可以有不同的定义。
举具体例子。你在做一个外卖系统。在“点餐”这个圈里,“用户”就是那个拿着手机选菜的人。在“配送”这个圈里,“用户”是那个等着开门取餐的人。虽然都叫用户,但前者的核心属性是购物车、收藏夹,后者的核心属性是地址、电话、送餐时间。如果你把这两个混在一个类里,代码就会变得又臃肿又拧巴。
更好的做法是分两个圈,分别建两个User类,或者起不同的名字比如Diner和Receiver。每个圈里单独维护自己的词汇表,互不干扰。这样就清爽多了。
那怎么发现这些边界呢?答案是反复写、反复改。你写一段代码,跑一跑,发现不对劲,就重构。改命名、挪方法、拆类。这个过程像玩泥巴,不断捏不断修,最后才能成型。测试驱动开发在这种场景下特别好用。你先写测试,描述你想要的行为,然后写代码让测试通过。测试就像一面镜子,逼着你想清楚:这个名字到底合适吗?这个类的边界到底在哪?
编程语言不只是工具,还是思考方式
很多人觉得编程语言就是个工具,Python顺手就用Python,Java需要性能就用Java。这种看法太表面了。编程语言其实在塑造你怎么思考问题。
你想想,用Go的时候,你会想着轻量级线程,一个请求开一个goroutine,用channel传数据。用Java的时候,你会想着类、继承、接口、设计模式。用Rust的时候,你得天天琢磨所有权、生命周期、借用检查器。每种语言都有自己的规矩,你在这个规矩里呆久了,看问题的方式就被带偏了。
这不是坏事。这些规矩其实在帮你发现好的设计。比如你写异步编程,需要实现一个Future。你要设计它的API,让它能串联多个操作。这时候如果你懂函数式编程里的map、flatMap这些概念,你就能设计出流畅好用的接口。如果你不懂,硬写出来的东西又丑又难用。
有时候代码写起来太啰嗦,或者想不清楚,你可以换种方式。不用直接上代码,先写个伪代码或者形式化规范。比如你在设计一个支持快照隔离的数据库,光用英文描述总觉得差点意思,直接写Java又太沉。这时候你写一页像数学公式一样的伪规范,反而能把思路理清楚。这就像画草图,不用画得多细,先把骨架搭出来。伪代码本身就是一种轻量级词汇表,帮你跟自己和队友对齐想法。
跟AI配合,词汇表越准越好用
既然AI能写代码,那咱们怎么跟AI配合干活?秘诀还是这套词汇表。AI训练的时候看过几亿行代码,它知道Controller、Repository、Factory这些词背后一般跟着什么结构。你在提示词里说“写一个订单仓储”,AI就知道要搞增删改查,知道要用事务,知道要处理并发。你要是乱起名字,比如写个“OrderKeeper”或者“ThingThatSavesOrders”,AI就懵了,只能瞎猜。
所以跟AI打交道,提示词的质量直接取决于你们团队的词汇表质量。如果你的代码库命名清晰、概念统一,AI就能更好地理解你的意图。生成的代码大概率直接就能用。如果你的代码库全是a、b、c这种变量名,类名也起得驴唇不对马嘴,那AI再强也帮不了你。
更深的坑在于:AI生成代码太快了,会造成一种叫“认知债务”的东西。啥意思?传统技术债是你图省事写了烂代码,后面得还。认知债务是你或者你的团队不理解代码里的概念,但代码已经在那了。AI一口气给你生成了二十个类,每个都有模有样的,有工厂有仓储有策略有处理器。代码能编译能跑,但你们没人真懂这些类之间的关系。这时候你们的代码库就多了一大堆没被理解的词汇。这种债务比技术债更难还,因为你看不到哪里出问题了,只是感觉改代码越来越费劲,加个功能要动一大堆地方,还经常改出bug来。
怎么避免?别让AI一口气生成整个系统。一小块一小块来。先跟AI讨论清楚概念,让它解释为什么要用某个设计模式,然后生成一小段代码,你们跑测试,改命名,重构。确认理解了,再继续。AI应该当你的副驾驶,别当自动驾驶。
好的抽象是护栏,让AI不乱来
反过来想,如果你已经有一套很稳的词汇表和抽象,那AI用起来就舒服多了。好的抽象就像高速公路上的护栏,把AI限制在安全范围内,它再怎么跑也翻不了车。
怎么做?你先把核心的抽象写稳。比如你写了一套交易系统的核心接口:Account、Transaction、Ledger。每个接口都有明确的语义和测试。然后你让AI去实现具体的用例,比如“给用户退款的流程”。因为AI看到你定义的Account里有debit和credit方法,看到Transaction需要原子性,它生成的退款代码就大概率是正确的。就算出了错,你的测试也能抓住它。
更进一步,你可以用这套词汇表写一个外部领域特定语言。比如你定义了一套脚本,让业务方都能看懂:when order cancelled then refund payment。然后让AI当翻译,把这种自然语言转成真正的代码。这种模式特别好用,因为AI天生就是干这个的。你把词汇表喂给它,它就能在表里自由组合。
所以说,AI时代反而更需要高质量的基础代码。以前觉得基础代码就是给机器跑的,现在发现它更是给AI看的说明书。说明书越清晰,AI干活越靠谱。
代码本身就是最好的上下文
现在有很多人在研究“上下文工程”和“护栏工程”。说白了就是怎么在提示词里给够信息,怎么用测试和静态检查来约束AI,让它不乱来。这些都很重要,但大家往往忽略了一点:代码本身,就是你最重要的上下文和护栏。
你有一个设计良好的代码库,里面有清晰的抽象、完整的测试、明确的类型约束。当你给AI提需求时,这些代码就是最好的例子。AI会看你的代码风格,看你测试怎么写,看你接口怎么用,然后照着样子生成新的代码。这比你在提示词里写八百字描述都有用。
我试过好多次。一个烂代码库,让AI干活,提示词得写特别长,还得反复调试。一个好代码库,你一句话“参照订单模块写个退款模块”,AI就能给出差不多的东西。因为代码结构本身已经告诉了AI:你应该新建一个RefundService,里面要有create、cancel这些方法,要调用Transaction和Account,要写对应的测试。
所以别老想着怎么把提示词写得花里胡哨。先把代码写规矩了。代码规矩了,AI自然就规矩了。你甚至不用太在意用哪个AI模型。换了模型也不怕,因为代码里的信息足够多,足以约束任何模型的行为。
结尾:代码的价值正在转移
回到开头那个问题。生成代码变便宜了,什么还值钱?答案已经很清楚:是那个藏在代码里的概念模型,是那套团队通用的词汇表,是那些经过反复打磨的抽象。
写代码这门手艺不会消失,但它在变。以前拼的是手速,是语法熟练度,是API记忆量。现在拼的是你能否把一个模糊的需求,拆解成清晰的概念;能否用精准的命名,让所有人都能看懂;能否在业务和技术的边界上,架起一座结实的桥。
编程语言依然重要,因为每种语言都在教你怎么思考。重构依然重要,因为每次改名都是在打磨词汇。测试依然重要,因为每条测试都在验证概念是否成立。跟AI合作也重要,但前提是你得有自己的主心骨。
代码是给电脑看的,但更是给人看的。在AI能写代码的今天,这句话比任何时候都更真实。未来的程序员,不是写代码更快的人,而是能建立更好概念模型、更好词汇表、更好地基的人。在这个地基上,人和AI才能一起干活,互不添乱。