2026-04-26 07:56:52

本文永久链接 – https://tonybai.com/2026/04/26/interview-martin-kleppmann-ddia-2nd-edition-ai-distributed-systems
大家好,我是Tony Bai。
在后端架构师的世界里,有一本书被公认为“圣经”级别的存在,那就是 Martin Kleppmann 的《数据密集型应用设计》(Designing Data-Intensive Applications,简称 DDIA)。
自 2017 年出版以来,这本书几乎重塑了一整代工程师对分布式系统的认知。无论你是要搞定千万级并发,还是设计高可用的存储架构,DDIA 永远是那个最初也是最后的“标准答案”。
然而,九年过去了,世界变了。
我们经历了从本地机房到全面云原生的跃迁,见证了 Kafka 从一个内部工具变成行业基础设施,更在这两年,迎来了大模型(LLM)对编程范式的史诗级冲击。
在一个技术日新月异的时代,经典的寿命往往很短。很多人都在问:DDIA 的理论还跟得上这个 AI 时代吗?
就在前几天,Martin Kleppmann 接受了一次的深度专访,正式官宣:DDIA 第二版,终于来了!

在这场长达一个多小时的对话中,Martin 不仅首次揭秘了新版中那些颠覆性的内容更新(比如为什么他“杀死”了 MapReduce),更是重点探讨了一个让所有人脊背发凉的话题:AI,到底会如何颠覆我们苦心经营了几十年的分布式系统架构?
今天,我们就来深度拆解这位分布式系统“教父级人物”的最新思考。

Martin 在访谈中提到,第二版之所以需要“重写”,是因为分布式系统的物理基石已经发生了根本性的位移。
在 DDIA 第一版编写时,主流的架构假设是:你拥有一堆物理机,每台机器挂着本地磁盘。如果你想实现高可用,你需要自己写代码处理副本复制。
但在 2026 年的今天,这种思维模式正在被彻底颠覆。
“现在的工程师不再思考如何给磁盘写数据,他们思考的是如何与对象存储(如 S3)交互。复制不再发生在数据库层,而是被内化到了对象存储这个基础抽象中。”
这种转变是极其深远的。这意味着,我们过去死记硬背的很多关于“本地存储性能优化”的知识正在失效。云原语(Cloud Primitives)正在取代物理硬件,成为新的架构单元。 这正是新版 DDIA 最大的改动之一:将“构建在云服务之上”作为一切讨论的新起点。
访谈中,Martin 抛出了一个让老兵们唏嘘不已的断言:“MapReduce 已经彻底死了。”
在第一版中,MapReduce 占据了大量的篇幅。但在第二版中,它被从核心位置撤下,仅仅作为一个“历史教学案例”。
“没人再手写 MapReduce 了。它的继任者——Spark 和 Flink,用更高级的抽象解决了一切。我们不应该再让读者把精力浪费在过时的工具上,而应该去理解流处理与批处理融合后的新世界。”
这种对技术的断舍离,展现了 Martin 作为顶级分布式系统架构师的冷酷与理性:当一个抽象已经完全被更高层的工具覆盖,它就失去了作为“工程前沿”的价值。
标题中提到的“AI 如何颠覆分布式系统”,是整场访谈最精彩的部分。Martin 并没有谈论那些陈词滥调的“AI 写代码”,他提出了一个极具反差感的预言:AI,将让“形式化验证”这门古老的高端技术回归主流。
分布式系统中最恐怖的事情是什么?是那些人类大脑无法推演出的、由于网络延迟和时钟漂移引发的“隐性 Bug”。
以往,我们用 TLA+ 或 FISB 进行形式化验证,代价极高,只有剑桥、谷歌的顶级研究员才玩得转。Martin 坦言,他在工业界工作时也从未用过。
但现在,AI 改变了这一切。
“LLM 正在变得越来越擅长编写数学证明。当我们可以让 AI 自动进行形式化验证,而不仅仅是跑单元测试时,我们就有可能在安全和金融等高风险领域,彻底消灭那些困扰我们几十年的分布式陷阱。”
这是一种降维打击。 以前我们靠“经验”去踩坑,未来我们靠 AI 和数学去“封印”坑位。
Martin 在访谈中对 AI 的普及展现出了一种深刻的忧虑。他认为,AI 正在剥夺初级工程师“建立心智模型(Mental Models)”的机会。
“为了学会一样东西,你必须经历挣扎。如果你遇到一个复杂的数据库性能 Bug,你翻遍文档、调试源码、最终解决它,这个过程会让你对系统产生极其深刻的直觉。
但如果 AI 直接跳出来给了你答案,你虽然解决了问题,但你的大脑却是一片空白。没有了挣扎,就没有了深刻的理解。”
Martin 预言,未来的软件工程将面临一次严重的“人才断层”:顶层是理解系统本质的、拥有 DDIA 级认知的架构师;底层是只会调 API 的“提示词操作员”。中间那一层,正在消失。
除了 AI,Martin 现在倾注心血最多的研究领域是 Local-first Software(本地优先软件)。
Martin 对当前的 SaaS 订阅模式提出了猛烈的批评:
“现在的 SaaS 公司,实际上是拿着枪指着用户的头:‘交钱,否则我们就删了你的数据’。这种极度中心化的模式,是极其不健康的。”
他正在研究如何构建去中心化的协作系统(如去中心化版的 Google Docs)。这引出了分布式系统最底层的极限挑战:在没有中心服务器、甚至没有统一时钟的情况下,如何解决并发冲突?
你在 DDIA 里学到的时钟偏移、向量时钟、共识协议,在 Local-first 的世界里,将从“大厂面试题”变成每一个开发者都要面对的“生存命题”。
访谈的最后,Martin 感慨,尽管技术层出不穷,但分布式系统的“第一性原理”从未改变。
“作为工程师,我们的核心价值正从‘如何实现一个算法’迁移到‘如何在复杂的权衡(Trade-offs)中做出决策’。”
AI 可以写下每一行代码,但它无法替你决定:是在这个业务场景下追求极致的一致性(Consistency),还是为了用户体验牺牲部分可靠性以换取低延迟(Latency)。
这种基于商业目标、社会伦理和技术约束的“决策力”,才是架构师真正的护城河。
DDIA 第二版的到来,并不是为了教你最新的工具,而是为了在这个被 AI 搅得天翻地覆的时代,给你一根能定住风浪的“定海神针”。
九年磨一剑。如果你想在这个 AI 颠覆一切的洪流中,依然能看透系统的本质,那么 Martin Kleppmann 的这本新版“圣经”,是你必须拿下的武器。
资料链接:https://www.youtube.com/watch?v=SVOrURyOu_U
今日互动探讨:
你觉得在 AI 能够生成绝大部分代码的未来,一个“懂分布式底层原理”的架构师,身价是会暴涨还是贬值?在你的日常工作中,有哪些分布式系统的痛点,是你最希望在 DDIA 第二版中看到的?
欢迎在评论区分享你的看法!
还在为写 Agent 框架频频死循环、上下文爆炸而束手无策?我的新专栏 《从0 开始构建 Agent Harness》 将带你:
扫描下方二维码,开启从 0 开始构建Agent Harness 的实战之旅。

原「Gopher部落」已重装升级为「Go & AI 精进营」知识星球,快来加入星球,开启你的技术跃迁之旅吧!
我们致力于打造一个高品质的 Go 语言深度学习 与 AI 应用探索 平台。在这里,你将获得:
衷心希望「Go & AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚,享受技术精进的快乐!欢迎你的加入!

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.
2026-04-25 07:43:32

本文永久链接 – https://tonybai.com/2026/04/25/rust-popularity-vs-redmonk-ranking-reality-check
大家好,我是Tony Bai。
在过去几年的技术圈,Rust 是当之无愧的“流量之王”。
它连续多年在 Stack Overflow 开发者调研中蝉联“最受喜爱的语言”;它是 Linux 内核 30 年来引入的唯一非 C 语言;它是微软、亚马逊等大厂重塑底层安全架构的希望。
如果只看社交媒体和社区讨论,你会觉得 Rust 已经“统治了世界”。在一片赞歌中,大家默认 Rust 杀进主流榜单前十、取代传统语言只是时间问题。
但就在 2026 年 4 月,一份来自权威分析机构 RedMonk 的2026.1编程语言排行榜,却给所有“Rust 狂热者”泼了一盆透心凉的冷水。

数据呈现了一个极其残酷的反差:
在这份以“开发者真实选择”为核心指标的榜单上,Rust 的排名并没有像预期的那样一飞冲天,而是停滞在了第 20 位,甚至被曾被视为小众的 Dart 所超越。相比之下,那个常被调侃“无趣”的 Go 语言,依然稳稳地坐在第 12 位,并在云原生领域保持着统治地位。

为什么人人爱 Rust,但它在工业界的大规模普及却显得如此缓慢?为什么它“攻陷”了最硬核的 Linux 内核,却迟迟进不了普通开发者的日常?
今天,我想结合近期社区的深度讨论,扒开 Rust 这层华丽的外衣,带大家看看这门“天选之子”背后的生存现状与真实挑战。

在开发者 Alejandra 最近整理的一份清单里,Rust 的“战绩”堪称辉煌:Windows 11 的核心组件、AWS 的 Firecracker 虚拟化、Cloudflare 的下一代代理服务器 Pingora……
但这恰恰揭示了 Rust 目前最大的尴尬:它是一个“属于 1% 的神兵利器”。
这些成功的 Rust 项目,无一例外都属于“系统级基础设施”领域。它们雇佣的是全球前 1% 的顶级程序员,拥有极其漫长的研发周期和近乎奢侈的调试成本。
正如 RedMonk 的分析师在报告中一针见血地指出:
“Rust 依然面临着非专家程序员难以逾越的学习门槛。专家们愿意投入时间,但更广泛的主流采用似乎面临着巨大的惯性。”
开发者 Alejandra 在其博文的自白中也坦言:
“无论我们如何自我安慰 Rust 已经进入主流,事实是:它离 C++ 甚至 Java 的普及程度,依然有着深不见底的鸿沟。大学教的第一门语言依然是 Java,飞机上依然在用 C++,网页里依然全是 Javascript。”
Rust 已经完成了从 0 到 1 的“极客突围”,却正在撞向从 1 到 N 的“工业化之墙”。
除了学习曲线,Rust 进军主流的第二个障碍,也许就是它那小而美的标准库。
这篇名为《Unpopular opinion: Rust should have a larger standard library》(非主流观点:Rust 应该有一个更大的标准库)的帖子,戳中了无数一线开发者的泪点:
在我之前写过的一篇文章《别搞“小而美”了!Rust 开发者请愿:求求标准库学学 Go 吧》中也曾提过社区对 Rust 标准库的述求:
“我不想写个程序就要拉几百个三方库!生成一个随机数,std 里没有;想要个异步运行时,std 里也没有。我不得不把信任托付给几百个散落在 GitHub 各地、由个人维护的小型包(Crate)。”
这种对“核心精简”的极致追求,正在引发严重的“供应链安全焦虑”。
在 Go 的世界里,你可以用标准库完成 90% 的后端开发,这意味着你的核心链路是由 Google 顶尖团队直接背书的。但在 Rust 的世界里,开发者面临着“碎片化依赖”的内耗。
这种“标准库贫血”导致了一个反直觉的现象:Rust 是一门为了“安全”而生的语言,但它极度依赖社区包的机制,却在客观上增加了供应链被“投毒”的风险。
正如评论区所感慨的:“标准库是模块最终的坟场。”Rust 团队为了避免标准库变得臃肿,却无意中将“复杂性”和“审计成本”全部转嫁给了一线开发者。这种“技术洁癖”在处理顶级项目时是美德,但在处理追求效率的通用业务时,却成了巨大的阻碍。
为什么 Go 能在 RedMonk 榜单上稳坐第 12,而 Rust 只能在第 20 徘徊?
这是两种完全不同的工程学审美,也决定了它们在大规模协作中的不同命运:
但在现代软件工业中,“下限的稳定性”往往比“上限的惊艳度”更具普适价值。 绝大多数公司需要的不是一个能手搓编译器的天才,而是一群能够按照既定流程、稳健产出、且易于维护代码的合格工程师。
RedMonk 的报告里还提出了一个极具前瞻性的观察:理论上,AI 编码辅助工具应该能抹平 Rust 的学习曲线,但现实并非如此。
为什么?
大模型(LLM)的本质是模式识别和概率预测。
对于语法单一、推崇“唯一路径”的 Go 语言来说,AI 生成的代码准确率极高,且人类审查的认知负荷极低。
而对于规则极其复杂、生命周期标记繁琐的 Rust 来说,AI 生成的代码极易出现“微妙的语法错误”或“不地道的生命周期设计”。人类开发者在审查 AI 生成的 Rust 代码时,往往比自己重写一遍还要痛苦。
在“机器写代码”即将接管开发流程的未来,简单、标准、甚至有些“死板”的语言,反而拥有更宽、更深的护城河。《HashiCorp 创始人亲口“认错”:AI 让我重新爱上了 Go (文末福利)》一文中Hashicorp创始人Mitchell Hashimoto 因 AI 重新爱上Go,以及Pandas 之父近期更喜欢让 AI 用Go写代码也印证了这一点。
作为一个架构师,我们不必因为 Rust 在榜单上的“冷水”而否定它的伟大。
Rust 正在解决软件工程中最难的问题——在不牺牲性能的前提下,从根源上消灭内存漏洞。它的价值,已经在 Linux 内核和那些“不容有失”的领域得到了证明。
但我们也必须清醒地认识到:技术的流行度(Popularity)与技术的高级感(Elegance)并不总是正相关。
如果你在构建下一代安全操作系统、数据库内核或高性能边缘网关,Rust 是你不二的利剑。
但如果你在构建一个需要快速迭代、支撑公司核心营收、且由几十甚至上百人协作的后端业务系统,请务必保持客观:那个排名第 12、虽然有些“平庸”但永远能准时交付、且对 AI 极度友好的 Go,或许才是那个更优的工程方案。
再次祭出那句话:你的技术护城河,从来不是由你用什么语言决定的,而是由你解决问题的深度,以及你在各种极端权衡(Trade-offs)中做出的选择决定的。
资料链接:
今日互动探讨:
看完这份“人人爱 Rust,但榜单很冷酷”的现实反差,你觉得 Rust 挺进主流最大的障碍是什么?你认为“大标准库”是未来编程语言的必然趋势吗?
欢迎在评论区分享你的看法!
还在为写 Agent 框架频频死循环、上下文爆炸而束手无策?我的新专栏 《从0 开始构建 Agent Harness》 将带你:
扫描下方二维码,开启从 0 开始构建Agent Harness 的实战之旅。

原「Gopher部落」已重装升级为「Go & AI 精进营」知识星球,快来加入星球,开启你的技术跃迁之旅吧!
我们致力于打造一个高品质的 Go 语言深度学习 与 AI 应用探索 平台。在这里,你将获得:
衷心希望「Go & AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚,享受技术精进的快乐!欢迎你的加入!

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.
2026-04-24 07:13:22

本文永久链接 – https://tonybai.com/2026/04/24/go-code-design-day-one-principle-practical-patterns-list
大家好,我是Tony Bai。
世界读书日送福利活动火热进行中,点击这里留言参与,赢取属于你的幸运!
每一个 Go 开发者,大概都经历过这样的心路历程:
项目启动初期,为了追求“快”,我们怎么方便怎么来。配置到处写,数据库连接随手建,错误日志直接 fmt.Println。我们安慰自己:“先跑起来,以后再重构。”
结果呢?
半年后,项目变成了一座摇摇欲坠的“屎山”。配置散落在几十个文件里,改一个端口号要动十个地方;数据库连接池因为没关,把连接数打满;线上出了 Bug,日志里只有一行孤零零的 record not found,查个问题比登天还难。
技术债,就像滚雪球,你越是假装看不见,它就滚得越大。
这时候,你的内心肯定在呐喊:有没有一些在Go项目刚创建时期就应该知道的Go代码模式,可以让我在项目的“第一天”,就建立起一套健壮、可维护、可观测的骨架呢!
有的!
我将这套方法论,称为 Go 语言架构的“第一天原则”。掌握它,足以让你在Go 代码设计的道路上,少走五年弯路。
这些原则,没有一条是关于炫技的复杂设计模式。
今天,我们就来逐条硬核拆解这些原则,并用可运行的 Go 代码,手把手教你如何将它们落地。

这是所有“混乱”的根源。如果你的代码里,到处都是 os.Getenv(“DB_HOST”),那你的项目已经走在了通往地狱的路上。
反模式:
在某个业务函数的深处,为了连一下 Redis,临时去读环境变量。这使得你的函数与外部环境强耦合,极难进行单元测试。
第一天原则:
在 main 函数中,一次性完成所有配置的解析和校验,然后通过构造函数,将“配置好”的依赖(如数据库连接池),以“接口”的形式,显式地注入到需要的服务中。
【Go 代码实战】
// https://go.dev/play/p/CrGDShmoFFJ
package main
import (
"context"
"database/sql"
"fmt"
"log"
"net/http"
"os"
_ "github.com/lib/pq"
)
type Config struct {
DatabaseURL string
ListenAddr string
}
func loadConfig() Config {
dbURL := os.Getenv("DATABASE_URL")
if dbURL == "" {
log.Fatal("DATABASE_URL is not set")
}
return Config{
DatabaseURL: dbURL,
ListenAddr: ":8080",
}
}
type UserRepo interface {
GetUser(ctx context.Context, id int) (string, error)
}
type PostgresUserRepo struct {
db *sql.DB
}
func (r *PostgresUserRepo) GetUser(ctx context.Context, id int) (string, error) {
var name string
err := r.db.QueryRowContext(ctx, "SELECT name FROM users WHERE id=$1", id).Scan(&name)
return name, err
}
func NewPostgresUserRepo(db *sql.DB) *PostgresUserRepo {
return &PostgresUserRepo{db: db}
}
type Server struct {
repo UserRepo
}
func NewServer(repo UserRepo) *Server {
return &Server{repo: repo}
}
func (s *Server) HandleGetUser(w http.ResponseWriter, r *http.Request) {
name, err := s.repo.GetUser(r.Context(), 1)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "User: %s", name)
}
func main() {
cfg := loadConfig()
db, err := sql.Open("postgres", cfg.DatabaseURL)
if err != nil {
log.Fatalf("failed to connect to database: %v", err)
}
defer db.Close()
repo := NewPostgresUserRepo(db)
server := NewServer(repo)
http.HandleFunc("/user", server.HandleGetUser)
log.Printf("Server starting on %s", cfg.ListenAddr)
log.Fatal(http.ListenAndServe(cfg.ListenAddr, nil))
}
这样一来,你的业务代码将变得极其纯粹,不依赖任何全局状态,测试时也可以轻松地 Mock 掉 UserRepo 接口。
“不就是打个日志吗,fmt.Println 走起!”——这是毁掉一个项目最快的方式。
反模式:
遇到错误,直接 log.Printf(“Error: %v”, err)。当线上出现几万条这样的日志时,你根本无法进行聚合、告警和趋势分析。
第一天原则:
从第一天起,就引入结构化日志(如 log/slog 或 zap)。将所有关键信息(如 user_id, trace_id)作为独立的字段打印。同时,为关键业务指标(如缓存命中率、数据库查询延迟)埋入 Metrics。
【Go 代码实战】
// https://go.dev/play/p/h4_8a4nzCFx
package main
import (
"log/slog"
"net/http"
"os"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
cacheHits = prometheus.NewCounter(prometheus.CounterOpts{
Name: "myapp_cache_hits_total",
Help: "Total number of cache hits.",
})
dbQueryDuration = prometheus.NewHistogram(prometheus.HistogramOpts{
Name: "myapp_db_query_duration_seconds",
Help: "Histogram of database query durations.",
Buckets: prometheus.DefBuckets,
})
)
func init() {
prometheus.MustRegister(cacheHits, dbQueryDuration)
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info("handling request", "method", r.Method, "path", r.URL.Path, "remote_addr", r.RemoteAddr)
cacheHits.Inc()
start := time.Now()
time.Sleep(100 * time.Millisecond)
duration := time.Since(start)
dbQueryDuration.Observe(duration.Seconds())
logger.Info("request handled successfully", "duration_ms", duration.Milliseconds())
w.WriteHeader(http.StatusOK)
}
func main() {
http.HandleFunc("/", handleRequest)
http.Handle("/metrics", promhttp.Handler())
log.Println("Server starting on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
有了结构化日志和Metrics的加持,你的系统不再是一个“黑盒”。通过 Grafana 和 VictoriaLogs,你可以清晰地看到它的每一个内部状态,问题定位速度提升 10 倍。
这是 Dave Cheney 反复强调的血泪教训。一个失控的 Goroutine,就是一个内存炸弹。
反模式:
go doSomething()。然后呢?它什么时候结束?如果它卡住了怎么办?
第一天原则:
任何一个需要长久运行的 Goroutine,都必须接受一个 context.Context 参数,并在 select 中监听 ctx.Done()。将所有后台 Goroutine 的生命周期,与你的应用程序生命周期绑定。
【Go 代码实战】
// https://go.dev/play/p/Fi1JUZfs4E-
package main
import (
"context"
"log"
"os"
"os/signal"
"syscall"
"time"
)
func worker(ctx context.Context, id int) {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
log.Printf("Worker %d started", id)
for {
select {
case <-ticker.C:
log.Printf("Worker %d is doing work", id)
case <-ctx.Done():
log.Printf("Worker %d is shutting down...", id)
return
}
}
}
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer cancel()
go worker(ctx, 1)
<-ctx.Done()
log.Println("Main application shutting down.")
time.Sleep(100 * time.Millisecond)
}
这样,你的应用就可以实现优雅停机(Graceful Shutdown),在 k8s 环境中滚动更新时,不会丢失任何正在处理的数据。
在复杂的业务系统中,最难测试的不是“Happy Path”,而是各种千奇百怪的“Unhappy Paths”。
第一天原则:
为你的核心业务逻辑,构建独立的“数据生成器(Data Generators)”和“数据接收器(Sinks)”。在测试中,用内存中的模拟实现(Mocks)替换掉真实的外部依赖,从而能 100% 控制输入和验证输出。
【Go 代码实战】
// https://go.dev/play/p/NBsxpVE84Zb
package main
import (
"context"
"fmt"
"sync"
"testing"
)
type Order struct { ID int }
type OrderNotifier interface {
Notify(ctx context.Context, order Order) error
}
type OrderProcessor struct {
notifier OrderNotifier
}
func NewOrderProcessor(notifier OrderNotifier) *OrderProcessor {
return &OrderProcessor{notifier: notifier}
}
func (p *OrderProcessor) Process(ctx context.Context, order Order) error {
return p.notifier.Notify(ctx, order)
}
type MockNotifier struct {
mu sync.Mutex
Notified []Order
ShouldErr bool
}
func (m *MockNotifier) Notify(ctx context.Context, order Order) error {
m.mu.Lock()
defer m.mu.Unlock()
if m.ShouldErr {
return fmt.Errorf("mock notifier failed")
}
m.Notified = append(m.Notified, order)
return nil
}
func TestOrderProcessor_Success(t *testing.T) {
mockNotifier := &MockNotifier{}
processor := NewOrderProcessor(mockNotifier)
order := Order{ID: 1}
err := processor.Process(context.Background(), order)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if len(mockNotifier.Notified) != 1 || mockNotifier.Notified[0].ID != 1 {
t.Errorf("notifier was not called correctly")
}
}
遵守该原则后,你的单元测试将变得极快、极度稳定,并且能够 100% 覆盖所有你能想到的成功和失败分支。
不相信任何外部输入。这是所有安全系统的第一性原理。
第一天原则:
在数据的入口处(如 HTTP Handler、gRPC Server),对所有传入的数据进行严格的、显式的校验(Validation)。只有通过了“安检”的干净数据,才能被允许进入系统的核心领域。
【Go 代码实战(不完全示例)】
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/mail"
)
type CreateUserRequest struct {
Username string json:"username"
Email string json:"email"
Age int json:"age"
}
func (r *CreateUserRequest) Validate() error {
if len(r.Username) < 3 || len(r.Username) > 20 {
return fmt.Errorf("username length must be between 3 and 20")
}
if _, err := mail.ParseAddress(r.Email); err != nil {
return fmt.Errorf("invalid email format: %w", err)
}
if r.Age < 18 {
return fmt.Errorf("user must be at least 18 years old")
}
return nil
}
func HandleCreateUser(w http.ResponseWriter, r *http.Request) {
var req CreateUserRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
if err := req.Validate(); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// processValidatedRequest(req) ...
w.WriteHeader(http.StatusCreated)
}
这种防御可以让你的核心业务逻辑变得极其纯粹和安全,不再需要处理各种脏数据和边界情况。
注:如果是服务器,外部(甚至是内部其他服务的)请求的速度也可能是一种“安全威胁”。因此无论是通过中间件,还是代码自行实现,限速机制是必不可少的。
一个好的错误信息,应该像一份精准的“尸检报告”,而不是一句无意义的“他死了”。
第一天原则:
在错误产生的最底层,用 fmt.Errorf(“…: %w”, err) 详细包裹上下文。对于可预期的业务异常,定义成自定义的“类型化错误(Typed Errors)”,让上层逻辑可以通过 errors.As 进行精准的判断和处理。
【Go 代码实战(不完全示例)】
package main
import (
"errors"
"fmt"
"net/http"
)
type ErrDuplicateUser struct { Email string }
func (e *ErrDuplicateUser) Error() string {
return fmt.Sprintf("user with email %s already exists", e.Email)
}
func RegisterUser(email string) error {
// 模拟数据库层返回一个已知类型的错误
if email == "[email protected]" {
return &ErrDuplicateUser{Email: email}
}
return fmt.Errorf("db connection failed: %w", errors.New("timeout"))
}
func HandleRegister(w http.ResponseWriter, r *http.Request) {
err := RegisterUser("[email protected]")
if err != nil {
var dupErr *ErrDuplicateUser
if errors.As(err, &dupErr) {
http.Error(w, dupErr.Error(), http.StatusConflict)
} else {
// 对于未知的底层错误,只打日志,不暴露给用户
slog.Error("failed to register user", "error", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
}
return
}
w.WriteHeader(http.StatusCreated)
}
这样处理后,你的错误处理逻辑变得极其清晰和健壮,业务异常可以被优雅地反馈给用户。
这是 Go 语言最精髓、也最反直觉的一条哲学。
第一天原则:
永远不要在“定义侧”声明臃肿的接口。而是在“消费侧”,根据你真正需要的功能,定义一个只包含 1-2 个方法的“小接口”。
【Go 代码实战(不完全示例)】
// --- cache/cache.go ---
package cache
type BigCache struct {}
func (c *BigCache) Get(key string) (string, error) { /* ... */ }
func (c *BigCache) Set(key, val string) error { /* ... */ }
// --- user/service.go ---
package user
import "fmt"
// 我们在 user 包里,只定义我们真正需要的小接口
type Getter interface {
Get(key string) (string, error)
}
type UserService struct {
cache Getter // 依赖的是小接口,而不是具体的 BigCache
}
func (s *UserService) GetUserName(id int) (string, error) {
return s.cache.Get(fmt.Sprintf("user:%d", id))
}
示例代码中,你的 UserService 彻底与 BigCache 的具体实现解耦。在测试时可以极其轻松地传入 Mock 对象。
看完上述的七条原则,你是否发现所有这些“第一天原则”都指向了一个共同的核心:可维护性(Maintainability)。
你在项目第一天偷的每一个懒,都会在未来的某一个深夜,变成一颗狠狠炸伤你或你同事的“技术地雷”。架构的本质,不是选择一个多么牛逼的框架,而是与未来的自己、未来的同事进行一场清晰、友好的对话。
关掉这篇文章,打开你手头那个最新的项目。看看这 7 条原则,你触犯了哪几条?是时候,给你的代码库做一次“体检”了。
今日互动探讨:
在你过去的 Go 项目中,踩过哪些因为早期“野蛮生长”而导致的设计大坑?除了这 7 条,你还有哪些“压箱底”的项目启动最佳实践?
欢迎在评论区分享你的血泪史与独家心法!
还在为写 Agent 框架频频死循环、上下文爆炸而束手无策?我的新专栏 《从0 开始构建 Agent Harness》 将带你:
扫描下方二维码,开启从 0 开始构建Agent Harness 的实战之旅。

原「Gopher部落」已重装升级为「Go & AI 精进营」知识星球,快来加入星球,开启你的技术跃迁之旅吧!
我们致力于打造一个高品质的 Go 语言深度学习 与 AI 应用探索 平台。在这里,你将获得:
衷心希望「Go & AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚,享受技术精进的快乐!欢迎你的加入!

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.
2026-04-23 08:18:03

本文永久链接 – https://tonybai.com/2026/04/23/hashicorp-founder-admits-go-is-alive-thanks-to-ai
大家好,我是Tony Bai。
今天是世界读书日,在同款公众号文章的文末我将送出两个价值 99 元的《从 0 开始构建 Agent Harness》专栏的免费兑换码,欢迎大家点击这里积极留言参与!
在技术圈的江湖里,总有那么几位“扫地僧”级别的人物。他们的一言一行,足以引发整个行业的地震。Mitchell Hashimoto,正是其中之一。
作为 HashiCorp 的创始人,曾连续12年,一手使用Go 缔造了Consul、Nomad、Terraform、Vagrant、Vault 等一系列云原生基础设施与Devops“神器”以及Ghostty Terminal (使用 Zig )的他,被无数开发者奉为“云基础设施时代教父级的人物”。
但在 Go 社区,Mitchell 的形象却颇具争议。因为他曾在公开场合不止一次地表达过对 Go 语言的失望,甚至抛出过“Go has no place anymore”(Go 已无立足之地)这样的“暴论”。
然而,就在最近,这位曾经的“Go 社区的争议人物”,却在 X 平台上发表了一篇 180 度大转弯的“认错”长推,瞬间引爆了整个技术圈,获得了超过 21 万的阅读量。

他写道:
“我又开始写 Go 了……‘等等,我以为你说过 Go 已经没有位置了?’我错了。”
“我错的原因,主要是因为 AI 智能体(Agent)在 Go 语言上的生产力高得惊人。我不会把其他语言扯进来,因为我不想喂饱那些螃蟹(暗指 Rust 社区)。”
是什么,让这位顶级大神发生了如此戏剧性的转变?
今天,我们就来深度扒开 Mitchell 的这篇“忏悔录”,看看在 AI Agent 席卷一切的时代,Go 语言那些曾被我们疯狂吐槽的“缺点”,是如何摇身一变,成为最顶级的“超能力”的。

Mitchell 在推文中,首先就点出了一个极其“讽刺”的现象:
“这很有趣,因为 Go 的很多 CLI 工具,比如 go doc 和 gopls,它们糟糕的人体工程学(shitty ergonomics)……竟然被 Agent 完美地规避了。不仅如此,讽刺的是,它们对 Agent 来说简直是天赐之物。”
这句话,堪称整篇推文的点睛之笔。
如果你是一个有经验的 Go 开发者,你一定吐槽过 go doc 的简陋,或者早期 gopls 的各种不智能。相比于 Rust 的 rust-analyzer 那种极其强大的类型推断和代码补全,Go 的工具链显得既“笨”又“直白”。
但在 AI Agent 的世界里,这种“笨拙”,恰恰成了最顶级的优点!
Mitchell 指出,他现在根本不需要给 Agent 写任何复杂的 Skill。只需要在 AGENTS.md 里写一句极其简单的指令:“想找 API 或者调用者?去用 gopls。”
Agent 就能利用 gopls 提供的底层 LSP(语言服务器协议)接口,以极低的 Token 成本,精准地找到接口的实现、方法的定义,以及所有的调用关系。
另一位开发者在评论中也补充道:
“我们一直抱怨 Go 的啰嗦(verbosity),结果证明这恰恰是 LLM 最喜欢的。它们能清晰地读懂意图,而且工具链(如 go doc)给了它们足够的上下文,让它们第一次就能写出能跑通的代码。”
看懂了吗?
那些曾经被人类程序员嫌弃的“机器友好”的接口,在 AI Agent 这个“硅基程序员”面前,摇身一变成了最高效、最廉价的沟通方式。
我们过去追求的“CLI 人体工程学”,在 AI 时代,正在被“Agent 机器工程学”所降维打击。
Mitchell 的“认错”,不仅仅是因为工具链的意外适配。更深层次的原因,在于 Go 语言本身的“无聊”哲学。
在另一场由 OpenAI 创始人引发的“Go vs Rust”论战中,我们已经探讨过这个观点:
Go 语言极简的语法、强制的 gofmt 格式化、以及“万物皆 for 循环”的单一表达方式,使得所有 Go 代码库看起来都像是一个模子里刻出来的。
这种极度的“同质化”,对于基于概率预测的 AI Agent 来说,简直就是天堂。
AI 在生成 Go 代码时,不需要去猜测这个项目是函数式风格还是面向对象风格,不需要去处理复杂的生命周期和所有权问题。它只需要遵循那套刻在骨子里的“Go Way”,就能生成出八九不离十的、能跑通的代码。
评论区里,HashiCorp 的前同事现身说法:
“我当年就是看到 HashiCorp 在用 Go 才入坑的。你今天的这篇帖子,完美地解释了为什么我最近又回到了 Go 的怀抱。”
简单、可预测、没有魔法。 这些在人类极客眼中可能是“缺点”的特质,在 AI Agent 眼里,却成了最宝贵的“确定性”。
当然,Mitchell 也并非无脑吹捧 Go。作为一个顶级的开发者,他清醒地认识到 Go 的边界。
当他需要编写一个“可移植的、能轻松嵌入各种生态系统”的底层库时,他并没有选择 Go,而是选择了 Zig。
“对我来说,重要的是可移植性。我正在写一个必须能轻松嵌入各种生态系统的通用库。一个独立的、不依赖 libc、没有操作系统原语要求、能说 C ABI、并且只有 100KB 大小的库,是一个很容易推销的方案。”
在这里,Mitchell 亮出了他的答案:Go + Zig。
这套组合拳,既享受了 Go 无与伦比的开发效率和并发模型,又利用了 Zig 对底层的极致压榨能力,同时还避开了原生 CGO 的种种编译噩梦。
这或许是比“Go vs Rust”之争,更具前瞻性和实操价值的“版本答案”。
如果说 Mitchell Hashimoto 的“回归”还带有一丝 云原生以及DevOps 创始人的恋旧情结,那么另一位顶级大神——Pandas 库的创始人、数据科学界的“教父级”人物 Wes McKinney——的2026表态,则更像是一封写给 Python 的“分手信”,充满了痛苦、不舍,但又极其决绝。
就在 Mitchell 的推文引发热议的同时,有人在评论区挖出了 Wes McKinney 今年年初的一篇极具前瞻性的博文《从人类工程学到智能体工程学》。
在这篇文章里,Wes McKinney 抛出了一个极其震撼的开场白:
“我最近用 Go 写了很多新软件。但问题是,我这辈子其实一行 Go 代码都没写过。这到底是怎么回事?”
答案,同样是 AI Agent。
作为一个将毕生心血都奉献给了 Python 数据科学生态的巨匠,Wes McKinney 坦言,当软件的“主要作者”从人类变成 AI 时,我们评判一门编程语言优劣的标准,发生了根本性的改变。
“人类工程学(Human Ergonomics)的重要性正在急剧下降。Python 对人类来说极其愉快和高效,但当 Agent 替你写所有代码时,这个好处就显得无足轻重了。”
他用一种近乎“残忍”的视角,剖析了 Python 在 AI Agent 时代的三个致命缺陷:

那么,AI Agent 时代的“赢家”是谁?
Wes McKinney 给出了和 Mitchell Hashimoto 几乎一模一样的答案:Go。当然在数据科学以及人工智能的基础设施层面,Wes McKinney认为 Rust 也将会占据着越来越重要的地位。
因为它们解决了最关键的三个问题:
他甚至更进一步指出,由于 Go 拥有比 Rust 快得多的编译时间,在 Agent 高频迭代的场景下,Go 甚至比 Rust 更具优势。
“我依然深爱着 Python,并为我们建立的生态系统感到自豪。但很明显,鉴于 Agent 循环带来的生产力优势,我和业界的大部分人,将会写越来越少的 Python,转而拥抱 Go 和其他现代编译语言。”
一个为 Python 奋斗了近 20 年的灵魂人物,最终为了 AI,选择了自己从未写过的 Go。
这已经不是简单的技术选型,这是一场关于“工程师生存法则”的深刻变革。
Mitchell 的这篇“认错”长文,像一声号角,引来了无数在 Go 与其他语言之间摇摆的开发者的共鸣。
Bun 的创始人 Jarred Sumner 激动地在评论区留言:“我想看看你到底在搞什么!”(Mitchell 回复:“我早点联系你!”)
一位前 Vercel 工程师更是直言:“老哥你终于兜了一圈又回来了!”
当然也有一些开发者表示这也许是Mitchell的“幻觉”或“偏见”,一位开发者(显然不是很熟悉 Mitchell 的开发过往)写道:
“也许你只是比 Zig 更不习惯 Go,所以你注意到的 Go 的问题更少。而且你已经是 Zig 的专家了,用它提升的空间不大了(想学习一下新的编程语言)。LLM 让你看到在你不懂的领域(指Go)正确率是 100%,但在你懂 60% 的领域(指Zig),只对了 60%”。
(Mitchell 则毫不客气地回怼:“我写了 12 年全职的、纯粹的 Go。我的判断力很可靠。”)
这场大讨论,最终演变成了一场关于“回归 Go”的集体狂欢。
Mitchell Hashimoto 的故事,是 AI 时代软件工程演进的一个完美缩影。
一个曾经因为 Go 的“不够底层”、“人体工程学差”而选择离开的顶级大神,最终又因为 AI Agent 的出现,重新发现了这门语言在“机器工程学”上的巨大价值。
这提醒我们所有技术人:对一门语言的评判,永远不能脱离其所处的时代背景和生产力工具。
在人类手搓代码的时代,我们追求的是表达力的丰富和语法的灵巧。
而在 AI 自动生成的时代,简单、可预测、无歧义、易于机器理解,反而成了最稀缺的“黄金法则”。
Go 语言的缔造者们,在十几年前就用近乎偏执的克制,为我们埋下了一颗时间的种子。
直到今天,在 AI 的催化下,这颗种子,终于长成了参天大树。
资料链接:
今日互动探讨:
在 AI 编程的浪潮中,你是否也像 Mitchell 一样,重新审视了自己对某门语言的看法?你认为在 AI Agent 眼里,最“友好”和最“劝退”的语言分别是什么?
欢迎在评论区分享你的观点!
世界图书日特别福利:一本定义未来的“活书”
今天(4月23日)就是世界图书日。
在这个属于知识与智慧的节日里,与其被动地阅读别人写的书,不如我们亲手来“写”一本定义未来的“书”——构建一个属于你自己的 AI Agent Harness。
Mitchell Hashimoto 和 Wes McKinney 的故事告诉我们,AI Agent 正在成为这个时代最强大的生产力杠杆。而驾驭这头巨兽的核心,不在于你会背多少 Prompt,而在于你是否懂得如何为它构建一个坚不可摧的“驾驭系统(Harness)”。
为了庆祝我的全新极客时间专栏 《从 0 开始构建 Agent Harness》 上线,并感谢大家一直以来的支持,我将拿出 2 个免费的专栏兑换码送给大家!
参与方式:
关注本公众号,并在本文的评论区留言,聊一聊:“在 AI Agent 时代,你认为一个程序员最不可被替代的核心技能是什么?为什么?”
我将在 72 小时后,从所有精选留言中,挑选 2 位最深刻、最走心的思考,每人赠送一份价值 99 元的《从 0 开始构建 Agent Harness》专栏兑换码。
还在为写 Agent 框架频频死循环、上下文爆炸而束手无策?我的新专栏 《从0 开始构建 Agent Harness》 将带你:
扫描下方二维码,开启从 0 开始构建Agent Harness 的实战之旅。

还在为“复制粘贴喂AI”而烦恼?我的新专栏 《AI原生开发工作流实战》 将带你:
扫描下方二维码,开启你的AI原生开发之旅。

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.
2026-04-21 07:15:47

本文永久链接 – https://tonybai.com/2026/04/21/why-we-are-building-agent-harness-from-scratch
大家好,我是Tony Bai。
今天想和大家分享一个好消息:我筹备已久的极客时间专栏 《从0 开始构建 Agent Harness》 于昨日(2026.4.20)正式上架了。
在这个各种 AI 应用框架满天飞、“几行 Python 代码就能跑起一个智能体”的时代,很多朋友可能会问:“Tony,大家都在用现成且免费的轮子,你为什么还要花这么大的精力,甚至专门开一个 24 讲的专栏,带着大家用 Go 语言从零去手写一个底层的 Agent Harness 引擎?”

借着专栏上架的机会,我想和大家聊聊,我是如何看待当前 AI 应用开发的,以及为什么我坚定地认为,现在是时候撕开框架的黑盒,回归底层的 Harness(驾驭工程)了。
如果你在一年多前开发过 AI Agent,你大概率深度使用过 LangChain、AutoGen 等框架。在那个大模型(如 GPT-3.5 时代)推理能力还比较薄弱的时期,我们需要框架来帮模型做意图路由、做任务拆解,框架扮演的是一个“事无巨细的微管家”。
但现在的技术发展,已经到了一个明确的“拐点”。
随着 Claude Sonnet 4.6/Opus 4.7、GPT-5.4、Gemini 3.1 Pro 等前沿模型的问世,模型原生已经具备了极其恐怖的逻辑规划和工具调用(Function Calling)能力。这时候,如果你尝试把基于传统框架拼接出来的 Agent 投入到真实的生产环境(比如让它去排查线上日志、或者做复杂的代码重构),问题往往接踵而至:
这些令人“绝望”的瞬间让我意识到:单纯靠堆砌 Prompt 或者调用更高层级的应用框架,是永远无法构建出工业级 Agent 的。我们把最核心的控制权统统交给了不可见的黑盒。
在剖析了近期震撼业界的顶级原生智能体(如 Claude Code、开源神作 OpenClaw、以及自带进化能力的 Hermes等)的工作机制后,我看到了一个不可逆转的趋势:
传统的框架层正在加速坍塌,作为独立工程研究的 Harness(驾驭工程)正在全面崛起。
什么是 Harness?简单来说,如果把大模型比作 CPU,把上下文(Context Window)比作极其昂贵的内存,那么 Harness 就是为这个 CPU 打造的微型操作系统(OS)。
Harness 不去干涉大模型的思考,它的核心职责极其底层且硬核:
我花这么大的精力带大家手写 Harness,就是因为现在的难点,早就不是“怎么让大模型输出 JSON”,而是“怎么在物理层面驾驭大模型的破坏力与失控”。
当我们拥有了一个健壮的 Harness 之后,我们对 AI 应用的认知也会随之重塑。
以前,AI 只是应用里的一个 Feature(功能),比如挂在网页右下角的一个聊天框。
但今天,当你把一个配置了特定 System Prompt 和专属 Skills(技能 SOP)的 Harness 引擎,丢进某一个特定的业务目录里运行时,这个 Agent 本身,就成了一个完整的 Application。
当然,AI 应用的形态是多元的,Agent 并非唯一的范式——AI 作为功能模块嵌入传统产品的场景依然大量存在。
但对于那些以自主完成复杂任务为核心价值的应用而言,”AI App = AI Agent”这个等式正在越来越多的场景下成立。我们不再是写满是 CRUD 的业务代码,我们是在为不同形态的智能体(如:编码Agent、自动化运维 Agent、自动化 CR 助手等)编写底层”物理定律”。
相较于一两年前的开发模式,今天顶尖的 Agent 项目展现出了一种令人拍案叫绝的“返璞归真”。
以 OpenClaw 为代表的新一代驾驭工程,抛弃了复杂:
如果你不亲自手写一遍这个引擎,你永远只能在外围惊叹这些设计,而无法将其转化为自己解决复杂业务问题的武器。
为了把这些前沿的理念落地,我没有选择纸上谈兵。我决定带着大家用 Go 语言(云原生时代构建基础设施的最佳语言),手敲一个名为 go-tiny-claw 的工业级引擎。
我们的旅程不走捷径,专栏规划了极具层次感的 24 讲大纲:

细心的朋友会发现,除了核心引擎和工具链,我在专栏的后期(模块五),花了不小的篇幅去写 成本追踪(Cost Tracker)、链路回放(Tracing) 和 自动化跑分(Benchmark)。
之所以加入这些章节,是出于对 AI Agent 工程化落地 的深切体悟。
在企业里,如果一个智能体没有“仪表盘”,你连它跑一次花了多少美金都不知道;如果没有 Tracing 的 JSON 树,当任务在半夜崩溃时,你面对满屏黑盒日志根本无从 Debug;如果没有自动化的 Benchmark,你改了一行提示词,都不知道系统是变聪明了还是变笨了。
把玄学变成工程学,这是从“玩具”走向“工业级”的必经之路。
坦白地说,Harness Engineering(驾驭工程)是一个极其前沿、且目前在业界依然处于野蛮生长和快速迭代的阶段。
无论是开源的 OpenClaw 和 Hermes ,还是Claude Code 的非官方流出,又或是学术界的最新研究论文,都在不断刷新着我们对 Harness 架构的认知上限。
这个专栏定位是 Agent Harness 的概念入门与环环相扣的底层实战。专栏里的每一讲(比如基于双重降级的上下文掩码压缩、或者是错误自愈模板的注入),其实都值得单独抽出来,作为更深入的课题去研究。
我就算是为大家“抛砖引玉”了。
以专栏中提到的 “Session Context 阶梯压缩” 为例。在专栏里,为了保持架构的极简易懂,我们采用了高效的字符级“远期全量掩码”与“近期掐头去尾截断”策略。
但这远非终点。
大家在学习后,完全可以去查阅 Claude Code 源码中更多层级的上下文折叠思路,或者探索多智能体(Multi-Agent)在 Harness 层的更优调度解法。
如果在未来业界出现了颠覆性的架构理论,我也会以“加餐”的形式在专栏中及时跟进。
未来已来,它就藏在那些最底层的代码和极简的架构哲学中。
只有亲自造过轮子的人,才知道车辆在高速过弯时,底盘的极限到底在哪里。如果你也不满足于做大模型时代的“调包侠”,如果你也渴望掌控代码的绝对执行权,欢迎加入我的新专栏。
点击这里或扫描下方二维码,亲自打造属于你的工业级智能体引擎。

感谢大家一直以来的支持。我们,专栏里见!
原「Gopher部落」已重装升级为「Go & AI 精进营」知识星球,快来加入星球,开启你的技术跃迁之旅吧!
我们致力于打造一个高品质的 Go 语言深度学习 与 AI 应用探索 平台。在这里,你将获得:
衷心希望「Go & AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚,享受技术精进的快乐!欢迎你的加入!

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.