本文永久链接 – https://tonybai.com/2025/10/21/yang-zhengning-legacy-beyond-physics 大家好,我是Tony Bai。 提及杨振宁先生,世人首先想到的是诺贝尔物理学奖、杨-米尔斯理论、规范场……这些璀璨的词汇共同构筑了一座物理学史上的丰碑。他无疑是20世纪最伟大的物理学家之一,其学术成就深刻地改变了人类对宇宙基本规律的认知。 然而,若将杨振宁的遗产仅仅局限于物理学的殿堂,那将是对他更深远价值的一种忽视。在一份珍贵的晚年演讲录音稿中,他用平实无华的语言回顾了自己的一生。透过这些回忆,我们得以窥见一座比物理学本身更宏伟的宝库——那是一套关于求知、成长、突破与为人的完整精神遗产。这份遗产,属于每一个渴望真理、追求卓越的探索者。 谨以此文,向这位以103岁高龄仙逝的科学巨匠,致以最崇高的敬意。 遗产一:智识的诚实——将“直觉冲突”视为最高奖赏 真正的学习,始于对自我认知的挑战。杨振宁用一段亲身经历,为我们诠释了何为“智识的诚实”。 在自学高中物理备考西南联大时,他被“向心加速度”的概念困住。他的直觉告诉他,旋转的物体理应向外冲,而书本却说加速度指向圆心。这是一种剧烈的认知失调。他没有选择回避或死记硬背,而是下决心“非要把这个东西搞清楚”。最终,他不仅理解了公式,更穿透现象,领悟了其背后“矢量”这一核心精神。 他从中得到的教训,构成了这份遗产的第一块基石: “当你的直觉跟书本上的知识有冲突的时候,你千万要抓住,因为这是最好的学习的机会。……学习实际上就是不断地修正你的直观观念。” 这份遗产教导我们,不要畏惧内心的困惑,而要拥抱它。每一次与直觉的冲突,都是一次剥离思维茧房、通往更深层次理解的邀请。在一个信息唾手可得、人们习惯于浅尝辄止的时代,这种敢于直面并深究认知冲突的勇气,显得尤为珍贵。 遗产二:时间的智慧——“长期发酵”与“动态专注” 如何在漫长的学术生涯中保持创造力并最终实现突破?杨振宁的经历为我们提供了两条关于时间的智慧。 首先,是“长期发酵”的耐心。 在芝加哥大学的低谷期,他曾投入数月研究伊辛模型等前沿课题,却无功而返,甚至一度感到“理想幻灭”。然而,这些看似“失败”的努力,却像种子一样被埋在了他的知识土壤里。数年后,当一个偶然的机会出现时,曾经的困惑与新知瞬间连接,让他“不到十分钟”就吸收了新思想的核心,并最终写出了自己第一篇成名作。 这份遗产告诉我们,没有任何一次真诚的智力投入会被浪费。那些当下未见成果的探索,正在为未来的顿悟积蓄着深厚的能量。它教我们对抗浮躁,相信复利,理解伟大的成就往往源于漫长而沉默的准备。 其次,是“动态专注”的策略。 他分享了物理学大师费米(Enrico Fermi)的建议:年轻人应主攻可解决的“小问题”,但也要敢于思考“大问题”,关键是“要知道什么时候应该停止”。杨振宁自己正是这一策略的完美践行者。他对“规范场”这一宏大构想的兴趣始于青年时代,虽屡试屡败,却从未完全放弃。他将其搁置,转而去解决其他问题,多年后,在知识和时机成熟时,才与米尔斯共同完成了这一历史性的突破。 这份遗产教导我们,要在眼前的务实与长远的目标之间,找到一种动态的平衡。既要有解决具体问题的能力以立足当下,也要有仰望星空的勇气以指引未来,并在两者之间灵活切换。 遗产三:学者的风骨——开放、谦逊与协作 除了方法论,杨振宁更向我们展示了一种理想学者的精神风貌。 他推崇导师泰勒那种允许“不成熟的想法”存在、乐于与人随时探讨的开放精神,并将其总结为“渗透式学习法”。这与他在西南联大时,与黄昆、张守廉在茶馆里“为物理学的种种问题辩论不休”的岁月遥相呼应。 这份遗产的核心,是一种深刻的智识谦逊与对思想碰撞的极度渴望。它告诉我们,真知灼见往往诞生于非正式的、自由的、允许犯错的交流之中。封闭的头脑无法产生伟大的思想,唯有在与他人的持续对话与辩论中,才能激发出最璀璨的火花。 同时,在他对费米的描述中,我们也能看到他所推崇的品格:“总是可靠、踏实”,“极有能力,但从不滥用他的影响”,“厌恶任何形式的虚伪做作”。他称赞费米为“一位典型的儒家君子”。这种对他人的赞誉,恰恰也映照出他自己一生所追求的境界——将惊世的才华与朴素的为人融为一体。 小结:一份献给所有探索者的礼物 杨振宁在物理学领域的成就,是刻在人类文明史上的不朽篇章。但当我们拨开那些复杂的公式和理论,会发现一份更加温润、更具普适性的遗产。 他教我们以诚实的勇气面对未知,以时间的耐心孕育突破,以开放的精神拥抱协作,以谦逊的风骨对待成就。这些原则,早已超越了物理学的范畴,成为所有领域的创造者、思考者和建设者都能汲取力量的源泉。 他不仅展示了宇宙的奥秘,更示范了一种探索奥秘的卓越方式。这,或许才是杨振宁留给我们每个人,最深邃、最宝贵的遗产。 资料链接:https://www.youtube.com/watch?v=Z90fkUa7fbw 想系统学习Go,构建扎实的知识体系? 我的新书《Go语言第一课》是你的首选。源自2.4万人好评的极客时间专栏,内容全面升级,同步至Go 1.24。首发期有专属五折优惠,不到40元即可入手,扫码即可拥有这本300页的Go语言入门宝典,即刻开启你的Go语言高效学习之旅! 商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。 © 2025, bigwhite. 版权所有.
本文永久链接 – https://tonybai.com/2025/10/21/10-go-programming-rules-from-reddit 大家好,我是Tony Bai。 在团队协作中,Code Review是我们与同事交流最频繁的阵地。我们都渴望自己提交的代码能够清晰、健壮,赢得同事的“LGTM”(Looks Good To Me)。但有时,一些看似“吹毛求疵”的风格评论,如“改下变量名”或“这里缩进不对”,会让我们感到困惑。 这些评论真的只是个人偏好吗?来自Reddit的工程师Konrad Reiche在其GoLab 2025的精彩分享《Writing Better Go》中给出了否定的答案。他一针见血地指出:大多数“风格(style)”评论,其本质并非关乎审美,而是关乎如何避免未来的生产环境之痛。 本文将和大家一起解读一下这场分享中提炼出的十条黄金法则。它们是Konrad从数百个Reddit的内部Pull Request中沉淀出的模式与智慧,内容涵盖了从错误处理的艺术、接口设计的哲学,到并发模式的选择、代码的组织与命名等方方面面。掌握它们,将帮助你写出真正让同事赞不绝口的地道Go代码,从根本上提升代码质量与团队协作效率。 法则 01:精准处理错误 Go的if err != nil是其哲学的核心,但如何正确地处理err,却是一门艺术。错误的错误处理方式,是生产环境中许多难以追踪的bug和panic的根源。这里Konrad列出的几种错误处理禁忌,都十分值得我们注意。 禁忌1:静默丢弃 (Silently Discarding) 这是最危险的行为,完全无视了函数可能失败的契约。 // BAD: Silently Discarding // pickRandom可能会因为输入为空而返回错误,但我们用 _ 彻底忽略了它。 // 如果发生错误,result将是其零值(空字符串),程序可能会在后续逻辑中以意想不到的方式失败。 result, _ := pickRandom(input) log.Printf("The random choice is: %s", result) 禁忌2:静默忽略 (Silently Ignoring) 比丢弃稍好,但同样危险。我们接收了错误,却没有做任何处理。 // BAD: Silently Ignoring [...]
本文永久链接 – https://tonybai.com/2025/10/20/k8s-1m-intro 大家好,我是Tony Bai。 在云原生的世界里,Kubernetes 集群的规模,如同一座待征服的高峰。业界巨头 AWS 已将旗帜插在了 10 万节点的高度,这曾被认为是云的“天际线”。然而,一位前OpenAI工程师(曾参与OpenAI 7.5k节点的Kubernetes集群的建设)发起了一个更雄心勃勃、甚至堪称“疯狂”的个人项目:k8s-1m。他的目标,是向着那座从未有人登顶的、充满未知险峻的“百万节点”之巅,发起一次单枪匹马的极限攀登。 这不简单是一个节点数量级的提升,更像是一场对 Kubernetes 核心架构的极限压力测试。虽然我们绝大多数人永远不会需要如此规模的集群,但这次“攀登”的日志,却为我们绘制了一份无价的地图。它用第一性原理,系统性地拆解和挑战了 Kubernetes 的每一个核心瓶颈,并给出了极具创意的解决方案。 对于每一位 Go 和云原生开发者而言,这既是一场技术盛宴,也是一次关于系统设计与工程哲学的深刻洗礼。 穿越“昆布冰瀑”——征服 etcd 瓶颈 在任何一次珠峰攀登中,登山者遇到的第一个、最著名、也最危险的障碍,是变幻莫测的“昆布冰瀑”。在 k8s-1m 的征途中,etcd 扮演了同样的角色。 无法逾越的冰墙 一个百万节点的集群,仅仅是为了维持所有节点的“存活”状态(通过 Lease 对象的心跳更新,默认每 10 秒一次),每秒就需要产生 10 万次写操作。算上 Pod 创建、Event 上报等其他资源的不断变化,系统需要稳定支撑的是每秒数十万次的写入 QPS。 然而,项目的发起者使用 etcd-benchmark 工具进行的基准测试表明,一个部署在 NVMe 存储上的单节点 etcd 实例,其写入能力也仅有 50K QPS 左右。更糟糕的是,由于 Raft 协议的一致性要求,增加 etcd 副本反而会线性降低写吞吐量。 由此来看,etcd,这座看似坚不可摧的冰墙,以其当前为强持久性和一致性而设计的架构,在性能上与百万节点集群的需求存在着数量级的差距。 登山者的智慧:我们真的需要硬闯冰瀑吗? [...]
本文永久链接 – https://tonybai.com/2025/10/19/flask-creator-choose-go 大家好,我是Tony Bai。 Armin Ronacher,这个名字在 Python 世界如雷贯耳。作为广受欢迎的 Web 框架 Flask 的创造者、Sentry 的首批工程师之一,他被公认为 Python 社区最具影响力的开发者之一。然而,最近在一场深度访谈中,他透露了一个足以让许多人感到惊讶的决定: 在他的新 AI 创业公司中,Go 成为了核心的后端语言。 为什么一位浸淫 Python 和 Rust 生态多年的顶尖开发者,会在 AI 创业的浪潮中,最终将信任票投给了 Go?这个选择的背后,并非一时兴起,而是一场关于务实主义、生态位和 AI 时代生产力的深刻权衡。 在这篇文章中,我们就来看看这位 Python 大师在 AI 时代技术选型的心路历程。 被放弃的“旧爱”——Python 的复杂性与 Rust 的“摩擦力” 要理解为什么选择 Go,我们必须先理解 Armin Ronacher 放弃了什么。他将自己比作一个拥有“分裂大脑”的程序员:一面是追求极致工艺的开源匠人,另一面是追求快速迭代的创业者。对于后者,他曾经深爱的 Python 和 Rust,都显得不再完美。 Python:深爱但日趋复杂 作为 Armin 的“母语”,Python 的务实和灵活性毋庸置疑,尤其是在数据处理和 ML 领域。但他坦言,随着时间的推移,Python 语言本身变得越来越复杂。“对于一众工程师来说,Go [...]
本文永久链接 – https://tonybai.com/2025/10/18/revisit-extreme-programming-in-the-age-of-ai 大家好,我是Tony Bai。 AI 编程助手、自动化代码生成、Agentic 开发系统……我们正目睹一场由 AI 引领的软件生产力革命。代码的产出速度正以 5 倍、10 倍甚至更高的倍率疯狂增长。理论上,我们应该能更快、更好地交付软件。但现实却给了我们一记响亮的耳光:我们的软件交付成功率,数十年来几乎毫无寸进,甚至有所倒退。 这就是 AI 时代软件开发的核心悖论:我们获得了前所未有的“产出”速度,却未能将其转化为更高的“成功”概率。最近,一篇题为《我们是否应该在 AI 时代重温极限编程?》的文章深入探讨了这一现象。文章作者尖锐地指出,我们可能正陷入一个“速度陷阱”,用最先进的工具去解决一个早已不是瓶颈的问题。 本文将和大家一起解读一下这篇文章的核心论点,探讨为何“速度”本身无法带来成功,以及为什么作者认为,那条通往高价值交付的道路,可能需要我们重温极限编程(Extreme Programming, XP)的智慧。 产出的幻觉:我们一直在加速,却在原地打转 文章的核心论点始于一个简单而深刻的观察:代码的生成速度,从来就不是软件开发的根本瓶颈。作者回顾了过去几十年的技术演进,从高级语言到 DevOps,再到云原生,每一次变革都极大地提升了代码产出效率,而 AI 只是将这条“加速”之路推向了极致。 为了支撑这一观点,文章引用了多项权威数据,揭示了一个残酷的现实: 根据长期运行的 Standish CHAOS 研究报告和麦肯锡的分析,超过 70% 的数字化项目仍以失败告终。 从 1994 年到 2020 年,尽管工具链发生了翻天覆地的变化,但项目按时、按预算成功交付的比例净增长微乎其微。 作者由此得出结论:我们只是在更快地制造砖块,却不知道如何用它们建起一座坚固、美观且符合用户需求的房子。当 AI 将制造砖块的成本降至接近于零时,设计的蓝图、工匠的协作和地基的稳固,就成了决定成败的唯一关键。 失控的熵增:AI 如何放大我们最坏的习惯 在文章的分析中,最一针见血的部分莫过于其对 AI 风险的论述。作者认为,当代码生成变得毫不费力时,一个更致命的风险随之而来:我们生产软件垃圾的速度,远远超过了我们验证和清理它的速度。 在没有严格约束的情况下,文章指出 AI 会成为“坏习惯”的放大器: 快速堆积技术债: AI 可以迅速生成大量未经深思熟虑的逻辑,形成一个无人能懂、难以维护的“意大利面条式”代码迷宫。 固化错误的假设: 作者引用了近期研究,表明大语言模型(LLM)的准确性会随着上下文窗口的增长而下降。这意味着 AI [...]
本文永久链接 – https://tonybai.com/2025/10/18/lessons-from-java-26-years-evolution 大家好,我是Tony Bai。 历史不会简单重复,但总是惊人地相似。编程语言的演化,如同一部波澜壮阔的史诗,充满了智慧的闪光、艰难的抉择与深刻的教训。 上月,资深工程师 Neil Madden 发表了一篇引人入胜的文章《点评 26 年的 Java 变更》,以一位亲历者的视角,犀利地回顾了这门“常青”语言的演进之路。 注:Neil Madden口中的Java 26年是指自他1999年学习Java编程开始到2025年的今天。 从Gopher视角来看,这并非一篇简单的技术评论,而是一次宝贵的以史为鉴的机会。 Java 作为企业级开发的“前浪”,其三十年的漫长的发展历程就像一本厚重的教科书,记录了在引入泛型、改进 I/O、简化并发等几乎所有重大议题上的探索与挣扎。 对于 Go 语言乃至整个软件工程领域而言,这其中蕴含着超越语言本身的普适性启示。本文并非旨在对比 Go 与 Java 的优劣,而是希望作为一部“技术沉思录”,通过 Java 这个案例,与各位一同探寻编程语言演进的内在规律。 启示一:核心特性的引入,时机与设计的艺术 Java 5 (2004) – 泛型 (Generics) “as Go discovered on its attempt to speed-run Java’s mistakes all over again, if you don’t add generics [...]
本文永久链接 – https://tonybai.com/2025/10/17/detect-charset-in-go 大家好,我是Tony Bai。 在上一篇关于 Go 语言 string 与 rune 设计哲学的文章发布后,我收到了许多精彩的反馈。其中,一位读者提出了一个极具现实意义的后续问题:“既然 Go 的世界以 UTF-8 为中心,那么当我们从外部系统(如老旧的文件、非标准的 API)接收到一段未知编码的字节流时,我们该如何是好?Go 生态是否有成熟的字符集检测工具/库?” 这个问题,将我们从 Go 语言舒适、有序的“理想国”,直接拉回了那个充满了历史遗留问题、编码标准五花八门的“现实世界”。 字符集检测,本质上是一种“隐式”的、带有猜测成分的“黑魔法”。本文将和大家一起探讨这门“黑魔法”背后的原理,审视 Go 生态中现有的解决方案,并最终回答那个核心问题:在 Go 中,我们应该如何优雅地处理未知编码的文本。 在我们深入探讨具体的 Go 库及其实现之前,建立一个正确的预期至关重要。我们必须首先理解这门“黑魔法”的本质,明白为何字符集检测是一项与编码转换截然不同、且充满不确定性的任务。 字符集检测——一门“不精确”的科学 在我们深入探讨具体的 Go 库及其实现之前,我们必须建立一个核心认知:字符集检测与编码转换截然不同,其本质上不是一个确定性的过程,而是一个基于启发式算法和统计学的概率性猜测。 它就像一位语言学家,仅凭一小段文字(字节序列),就要猜出这段文字是用哪国语言(编码)写成的。 如果文本足够长且特征明显,他可能会充满信心地说:“这看起来 99% 是日语 Shift-JIS。” 如果文本很短,或者内容模棱两可,他可能只能给出一个模糊的答案:“这可能是 latin-1,也可能是 windows-1252。” 在最坏的情况下,他甚至可能完全猜错。 因此,任何字符集检测工具,其返回的结果都应该被理解为一个带有置信度 (Confidence Score) 的“最佳猜测”,而非一个 100% 准确的真理。 既然我们已经认识到字符集检测是一门“不精确”的科学,那么我们的探索自然会引向一个问题:在整个软件行业中,谁是解决这个难题的权威?我们继续往下探索。 行业黄金标准——ICU 是什么? 在字符集检测乃至整个国际化(i18n)领域,ICU (International Components for [...]
本文永久链接 – https://tonybai.com/2025/10/16/rethink-996-culture 大家好,我是Tony Bai。 “996”——早上九点到晚上九点,一周工作六天。这个术语早已成为国内科技行业高强度工作文化的代名词。其背后的逻辑似乎坚不可摧:如果你无法用才华取胜,那就用时间取胜。努力工作,加倍努力,似乎成为了通往成功的唯一路径。随着AI赛道竞争的白热化,996文化开始“传染”给美国西部的高科技行业,这种现象也引起了欧美开发者的关注。 近日一篇名为《996 只是意味着你没有杠杆》的文章,对这一“努力神话”提出了一个颠覆性的批判。作者 J.A. Westenberg 在文中提出了一个尖锐的理论:当一家公司或个人将 996 作为其核心战略时,他们实际上已经输了。他们炫耀的不是自己的力量,而是自己的弱点。 这篇文章既是是对工作文化的批判,也是一堂关于战略、价值和杠杆思维的深刻一课,值得每一位技术从业者深思。 996 的本质:没有帆,只能拼命划船 Westenberg 的核心观点可以用一个生动的比喻来概括: “The grind-maxxed founder is trying to row the boat harder. The leverage-maxxed founder has a sail.” (拼命“卷”的创始人,正试图更用力地划船。而善用杠杆的创始人,早已扬起了帆。) 他认为,996 文化盛行的根本原因,往往不是因为团队充满激情,而是因为他们的想法不够好,不足以在每天八小时内取得成功。 没有 PMF (产品市场契合) 的蛮力冲锋: 当一家公司还没有找到真正被市场需要的产品时,剩下的唯一选择似乎就是“动量表演”——通过让团队长时间工作来制造一种增长的假象。Westenberg 观察到,这种试图用蛮力冲破迷雾的方式,往往在找到突破口之前,就已将团队燃烧殆尽。 用努力掩盖洞察的缺失: 过度沉迷于工作,会给人一种虚假的正义感和安慰感,让人误以为成功只是时间的函数,而非品味、判断力或时机的产物。作者直言:“没有洞察力的痴迷,只是一种病态。” 当一家公司最好的名片是“我们所有人都在拼命工作”时,在 Westenberg 看来,它其实什么都没说。 努力不是价值,“孔雀开屏”式的表演 为什么在没有独特优势(如顶尖人才、强大网络或创新想法)时,人们会倾向于崇拜“埋头苦干”?作者认为,这是一种“身份焦虑”的副作用。 你需要向世界证明你是认真的、投入的。还有什么比所有人都下班回家后,你依然在办公室奋战,并拍照发推更好的方式呢?Westenberg 将这种行为称为“孔雀开屏 (peacocking)”式的表演,目的是展示“看我有多努力”。 然而,这种表演混淆了两个根本不同的概念: 努力 [...]
本文永久链接 – https://tonybai.com/2025/10/16/cpu-cache-friendly-in-go 大家好,我是Tony Bai。 “现代 CPU 很快,而内存很慢。” 这句看似简单的陈词滥调,是理解现代高性能编程的唯一“真理”。我们常常致力于优化算法的时间复杂度,却忽略了一个更为根本的性能瓶颈:数据在内存和 CPU 缓存之间的移动。一次 L1 缓存的命中可能仅需数个时钟周期(~1ns),而一次主内存的访问则需要超过上百个周期(~100ns),这之间存在着超过 100 倍的惊人差距(2020年数据,如下图,近些年内存速度提升,但与L1缓存相比依旧有几十倍的差距)。 访问延迟,来自参考资料2(2020年数据) 近年来,自从 Go 更换了新的技术负责人后,整个项目对性能的追求达到了前所未有的高度。从 Green Tea GC 的探索,到对 map 等核心数据结构的持续优化,再到即将在 Go 1.26 中引入的实验性 simd 包,无不彰显出 Go 团队提升运行时性能和榨干硬件潜能的决心。 在这个背景下,理解并应用“CPU 缓存友好”的设计原则,不再是少数性能专家的“屠龙之技”,而是每一位 Gopher 都应掌握的核心能力。即便算法完全相同,仅仅通过优化数据结构,我们就有可能获得 2-10 倍甚至更高的性能提升。这并非“过早优化”,对于性能敏感的系统而言,这是一种必要优化。 本文受Serge Skoredin的“CPU Cache-Friendly Data Structures in Go: 10x Speed with Same Algorithm”启发,将和大家一起从 CPU 缓存的第一性原理出发,并结合完整的 Go 示例与基准测试,为你揭示一系列强大的“数据驱动设计”(Data-Oriented Design) [...]
本文永久链接 – https://tonybai.com/2025/10/15/physics-in-fanren 大家好,我是Tony Bai。 李淼教授的《三体中的物理学》曾让我们惊叹,原来恢弘的科幻背后,是坚实而又前沿的科学基石。读完《凡人修仙传》人界/灵界篇后,一个念头在我脑海中挥之不去:我们能否为韩立的修仙世界,构建一个自洽的“物理模型”? 这并非要用科学去“祛魅”修仙,恰恰相反,这是一场思想实验。我们旨在探讨:如果修仙世界真的存在,其背后的“天道法则”是否能在现代物理学的框架内找到惊人相似的“投影”? 当韩天尊遇见爱因斯坦,一场连接东方玄幻与前沿科学的奇妙对话,就此展开。我们不纠结“灵气”的具体成分,而是聚焦于修仙世界中更高阶的时空、维度与法则。 界面飞升 —— 膜宇宙理论与高维空间 在《凡人》中,世界由无数“界面”构成——人界、灵界、小灵界、灵寰界、仙界……界面之间壁垒森严,修士需经历九死一生的“飞升”才能跨越。更奇特的是,不同界面的“天地法则”也不同,灵界的空间远比人界稳固,能承受的能量上限也更高。 这听起来玄之又玄,但在现代物理学的前沿,却有一个理论与之惊人地契合——膜宇宙理论(Brane Cosmology)。 源于弦理论/M理论的“膜宇宙”模型认为,我们熟悉的三维宇宙(长宽高),可能只是一张漂浮在更高维度“体宇宙”(The Bulk)中的巨大“膜”(Brane)。想象一下,无数张平行的纸(膜宇宙)漂浮在一个巨大的房间(体宇宙)里。 现在,让我们进行一次大胆的映射: 界面 = 膜宇宙 (Brane): 每个人界、灵界,都是一个独立的“膜宇宙”。它们在更高维度中彼此平行,互不干涉。 飞升 = 跨膜运动 (Brane-hopping): 什么是飞升?它不是在我们的三维空间里向上飞。而是修士集聚了无法想象的能量,将自己从当前所在的三维“膜”上撕裂出去,进入高维的“体宇宙”,再“降落”到另一个物理常数不同的“膜”上。这完美解释了飞升为何如此艰难,因为“体宇宙”中可能充满了凡人无法理解的能量风暴。 法则不同 = 物理常数差异: 为何灵界空间更稳固?因为不同“膜”上的物理常数、真空能级可能完全不同。灵界那张“膜”的“时空曲率韧性”远超人界,因此能承载更恐怖的能量冲击。 从这个角度看,韩立的飞升,本质上是一次壮丽的高维时空迁跃。 空间裂缝与传送阵 —— 爱因斯坦-罗森桥(虫洞) 在凡人世界,长距离旅行依赖两种方式:稳定精确的传送阵,和天然但危险的空间裂缝。这两种设定,直指广义相对论中一个最迷人的预言——虫洞(Wormhole)。 虫洞,又称爱因斯坦-罗森桥,是理论上连接时空遥远两点的“捷径”。它不是在空间中移动,而是通过更高维度直接“抄近路”。 现在,让我们重新审视韩立的旅行方式: 传送阵 = 人造稳定虫洞: 古代大能修士建造的传送阵,其复杂的符文和灵石能量系统,本质上是一套用于打开并维持一个微型、稳定虫洞的“物理装置”。所谓的“空间节点”,就是时空几何上最适合用当前技术打开虫洞的坐标。驱动传送阵需要海量灵石,这或许就是维持虫洞“喉咙”张开所需的庞大能量。 空间裂缝 = 天然不稳定虫洞: 自然形成的空间裂缝,由于缺乏稳定机制,极其危险,随时可能坍塌。这与物理学中对天然虫洞的描述不谋而合——它们可能瞬息万变,任何物质穿过都可能被潮汐力撕碎。 空间神通 = 局部时空扭曲: 大乘期修士的“瞬移”,可以理解为他们凭借强大的神识和法力,能够小范围、短时间地剧烈扭曲时空几何,制造出临时的、仅供自己通过的微型虫洞。 所以,韩立每一次踏上传送阵,都可能是一次穿越时空隧道的星际旅行。 御风遁光 —— 引力操控与质能转换 除了跨越星辰大海的传送,修士最常用的神通莫过于“遁术”。从御风而行,到脚踏法器,再到化为一道惊天长虹,其背后可能隐藏着对宇宙基本力之一——引力——的精妙操控。 [...]
本文永久链接 – https://tonybai.com/2025/10/15/go-archaeology-defer 大家好,我是Tony Bai。 在 Go 语言的所有关键字中,defer 无疑是最具特色和争议的之一。它以一种近乎“魔法”的方式,保证了资源清理逻辑的执行,极大地提升了代码的可读性和健壮性。f, _ := os.Open(“…”); defer f.Close() 这一行代码,几乎是所有 Gopher 的肌肉记忆。 然而,在这份优雅的背后,曾几何时,defer 却背负着“性能杀手”的恶名。在 Go 的历史长河中,无数资深开发者,包括标准库的维护者们,都曾被迫在代码的可维护性与极致性能之间做出痛苦的抉择,含泪删掉 defer 语句,换上丑陋但高效的手动 if err != nil 清理逻辑。 你是否好奇: defer 的早期实现究竟“慢”在哪里?为什么一个简单的函数调用会被放大数十倍的开销? 从 Go 1.13 到 Go 1.14,Go 团队究竟施展了怎样的“魔法”,让 defer 的性能提升了超过 10 倍,几乎达到了与直接调用函数相媲美的程度? 为了实现这场“性能革命”,defer 在编译器和运行时层面,经历了怎样一场从“堆分配”到“栈上开放编码(open-coded defer)”的“心脏手术”? 今天,就让我们再一次化身“Go 语言考古学家”,在Go issues以及Go团队那些著名的演讲资料中挖掘,并结合 Go 官方的设计文档,深入 defer 性能演进的“地心”,去完整地再现这场波澜壮阔的“救赎之路”。 “事后”的智慧:Defer 的设计哲学与独特性 在我们深入 [...]
本文永久链接 – https://tonybai.com/2025/10/13/string-and-rune-in-go 大家好,我是Tony Bai。 “为什么我的字符又乱码了?!” 这是一个在软件开发历史上,曾让无数程序员彻夜难眠的哀嚎。处理文本,是编程中最基础的任务之一,但其背后关于编码 (Encoding) 和字符集 (Character Set) 的水,远比看起来要深。正如 Joel Spolsky 在其经典文章中疾呼的那样,这是每位软件开发者都必须了解的“绝对最低限度”的知识。 幸运的是,作为 Go 开发者,我们站在了巨人的肩膀上。Go 语言在设计之初,就以一种“独断”而富有远见的方式,为我们解决了大部分历史遗留的编码难题。然而,理解其背后的设计哲学,特别是 string 与 rune 这对“双子星”的共舞,依然是区分一名普通 Gopher 与一名优秀 Gopher 的关键。 本文将带你重温编码的基础,并深入探讨 Go 是如何从语言设计的根源上,让我们得以优雅地驰骋于多语言文本的世界。 回到本源——计算机不认识“字符”,只认识“比特” 让我们先直面一个最基本、但又常常被遗忘的事实:计算机的世界里没有字母、数字或符号,只有比特 (bit)——0 和 1 的序列。计算机所能存储和处理的一切,无论是文本、图片还是声音,最终都必须被翻译成这种二进制形式。为了让这些比特串代表人类可读的文本,我们需要一套规则,这套规则就是编码 (Encoding)。 我们可以将这个过程拆分为两个核心概念: 字符集 (Character Set):一个抽象的符号集合。例如,ASCII 字符集包含了 128 个字符,包括大小写英文字母、0-9 的数字、以及各种标点和控制符号。你可以把它想象成一本“字典”,里面列出了所有“合法”的字符。 编码 (Encoding):一套将字符集中的每个符号,映射为特定比特序列的具体规则。例如,在 ASCII 编码中,这本“字典”规定了字母 A 对应的“页码”是 65,而 A 在计算机中的比特表示就是 65 [...]
本文永久链接 – https://tonybai.com/2025/10/12/the-programmer-identity-crisis 大家好,我是Tony Bai。 “我是一个程序员。一个编码者。一个键盘牛仔……这是我的乐趣,也是我的身份认同。” 近日,一篇题为《程序员的身份危机》的博文在技术社区中引发了广泛的共鸣与讨论。作者Simon Højberg以一个“手艺人”的深情独白开篇,将我们带回了编程的黄金时代——那个在 MIT 26 号楼里,伴随着早期晶体管蜂鸣声,黑客们为了追求“The Right Thing”(那个完美的、简洁优雅的程序)而沉浸于机器语言的“黑暗艺术”的年代。 然而,作者笔锋一转,指出现代 AI 浪潮正以前所未有的力量,威胁着这份传承了近 70 年的技艺(Craft)和身份认同。曾经那个充满奇迹、成就感和优雅解谜的编程未来,如今正被一层“不祥的黑暗、骗局和不确定性”所笼罩。这是一篇警示性的檄文,它迫使我们每一个技术从业者去思考一个根本性问题:当 AI 接管了“思考”,我们还剩下什么? “规范工程师”的崛起与“技艺”的消逝 文章尖锐地指出,如果我们相信 AI 行业的亿万富翁、Hacker News 的舆论领袖和 LinkedIn 上的 LLM 狂人,那么软件开发的未来将与“编程”本身几乎毫无关系。一种被称为 “Vibe Coding(氛围编程)” 的新模式正在成为主流。 在这个新世界里,我们的角色被重新定义为 “规范工程师 (Specification Engineering)”: 输入从代码到 Markdown: 我们不再是深入代码库、解决复杂谜题、发掘技术秘密的工匠,而是变成了在 Markdown 中编写规范的“需求者”。 思考过程外包: 创造性的解谜过程被全权交给了机器,我们只需在多个 AI Agent 的标签页之间进行上下文切换,拥抱一种“分散的认知”。我们从创作者,沦为了“与其技艺相分离的操作员”。 作者悲观地认为,这种转变是对程序员独特抽象思维能力的贬低,将我们推向了一个本已由产品经理和设计师占据的领域。更令人不安的是,一些开发者似乎欣然接受了这个新身份,乐于扮演“指挥管弦乐队”的史蒂夫·乔布斯,却忘记了编程的乐趣源于成为那个亲手打造乐器的沃兹尼亚克。 当工具选择权被剥夺:来自管理的“新叙事” 这场身份危机不仅是技术演进的自然结果,更在企业内部被一股力量所推动。 文章观察到,在“疯狂追求生产力”的竞赛中,企业的管理者们正以一种前所未有的方式,强制要求开发者使用特定的 LLM 工具——“要么遵从,要么出局”。这在历史上是罕见的。我们的工具,无论是 Vim、Emacs 还是 [...]
本文永久链接 – https://tonybai.com/2025/10/11/go-is-a-good-first-programming-language 大家好,我是Tony Bai。 近日,在 r/golang 社区,一个初学者的真诚提问,再次点燃了一场关于 Go 是否适合作为入门语言的激烈辩论。他很困惑:“为什么很多经验丰富的开发者说 Go 不适合作为第一门编程语言,而很多大学却用与之相似的 C 语言作为第一门编程语言呢?” 这个问题,如同一块探针,深入到了编程教育的核心分歧之中,并迅速将社区观点分裂为两大阵营。一方认为,Go 能从第一天起就培养严谨的工程思维,堪称“天才之选”。另一方则认为,它的定位不上不下,对初学者而言是一个“糟糕的开端”。 那么,真相究竟为何?为了厘清思路,让我们深入这场辩论,分别听取两大阵营的观点,并审视其背后的根本分歧:我们学习编程,到底是为了什么? 观点一:Go 是一个“糟糕的开端” 这一方的核心论点是:Go 语言陷入了一个尴尬的“中间地带”,对于编程教育的两个主要目标,它都未能完美胜任。 论据一:Go 不够底层,无法胜任“计算机科学基础教育” 这一方的支持者指出,大学 CS 教育的首要目标,是培养学生对计算机工作原理的深刻理解。在这个目标下,C 语言之所以是“黄金标准”,恰恰在于它的“不友好”: 直面内存:手动 malloc/free 和危险的指针算术,迫使学生直面内存布局、栈与堆等核心概念。 最小化抽象:学生必须从零开始构建数据结构,这个过程能让他们对算法的理解建立在物理实现之上。 而Go 的垃圾回收 (GC) 机制,虽然是工程上的巨大进步,但在教育上却成了一个“黑盒”,完全隐藏了内存管理的复杂性。它让学生“知其然”,却无法“知其所以然”,因此无法胜任传授底层原理的重任。 论据二:Go 不够“温柔”,无法胜任“快速入门与兴趣培养” 接着,这一方展示了另一个极端——以 Python 为代表的“实战派”入门语言。这类语言的目标是让初学者尽快体验到编程的乐趣和效用。 语法“温柔”:Python 的语法接近伪代码,极大地降低了入门的认知门槛。 快速反馈:作为解释型语言,其“编写即运行”的交互式体验,对维持初学者的学习热情至关重要。 尽管 Go 也以简单著称,但其静态类型、编译周期、以及对项目结构的规范要求,都为纯粹的初学者制造了不必要的“摩擦力”。与 Python 相比,它不够“温柔”,可能会在入门阶段就劝退一部分学习者。 由此来看,Go 既不像 C 那样能让你深入底层,又不像 Python 那样能让你轻松起步。它是一个尴尬的“中间派”,对于任何一个明确的教学目标来说,都有比它更好的选择。因此,它是一个“糟糕的开端”。 观点二:Go [...]
本文永久链接 – https://tonybai.com/2025/10/10/proposal-add-buffer-peek 大家好,我是Tony Bai。 在 Go 的世界里,io.Reader 是一个神圣的接口。它如同一条设计精良、四通八达的高速公路,为数据流的传输提供了统一、优雅的抽象。然而,在这条高速公路的尽头,当数据流的目的地就在眼前——一块已然存在的内存([]byte)时,我们却常常被迫驶下一条颠簸、缓慢的“土路”,进行一次本可避免的内存拷贝。 这个从 []byte 到 io.Reader 再回到 []byte 的性能损耗,正是 Go io 体系中长期存在的“最后一公里”问题。 近期,一个看似微小却意义深远的提案(#73794: bytes: add Buffer.Peek)被社区纳入提案委员会的考察范围(Active),它标志着 Go 团队为铺平这条“最后一公里”迈出了务实而关键的一步。这背后,是一场长达数年、关于性能、抽象与设计哲学的深度思辨。 “最后一公里”的痛点:当 io.Reader 遭遇 []byte 问题的根源,正如开发者 Ted Unangst 在其广为流传的文章《Too Much Go Misdirection》中所抱怨的那样: “我手里明明已经有了一份完整的 []byte 数据,但许多标准库函数(如 image.Decode)却只接受一个 io.Reader 接口。为了满足这个接口,我不得不将 []byte 包装成一个 bytes.Reader。结果,本应可以零拷贝完成的操作,却因为这层“中间商”,被迫进行了一次代价高昂的内存拷贝。” image.Decode 的工作机制完美地暴露了这个问题:为了确定图片格式,它需要“窥探”(peek) 数据流的头部几个字节。如果传入的 io.Reader 没有 Peek 方法,image.Decode 就会用 bufio.NewReader 将其包裹起来,这个过程必然涉及数据的拷贝。 [...]
本文永久链接 – https://tonybai.com/2025/10/09/json-isnt-json 大家好,我是Tony Bai。 JSON (JavaScript Object Notation),以其简洁、轻量、人类可读的特性,早已成为 Web API 和系统集成的“通用语”。它的承诺是:“一次编写,随处解析”。然而,这份看似美好的承诺背后,隐藏着一个被许多开发者忽略的残酷现实:JSON 并不像其规范所暗示的那样通用。 它的简约性,恰恰为其留下了太多“解释空间”。当 JavaScript 前端、Go 后端、Python 数据管道、以及 Java 企业服务开始以各自的方式“解释”同一个 JSON 时,一个现代版的“巴别塔”便悄然建起:每个人都在说 JSON,但每个人表达的意思却可能不尽相同。 这篇文章,是一份为 Go 开发者量身定制的“防御指南”,将为你全面揭示 JSON 在跨语言环境中最隐蔽、最危险的几大陷阱,并展示如何利用 Go 的特性(包括实验性的 json/v2)来构建坚不可摧的防线。 陷阱一:数字精度 —— 无声的整数溢出 这是 JSON 跨语言中最常见、也最致命的陷阱。 问题根源:JavaScript 将所有数字都表示为 64 位浮点数,其能精确表示的最大安全整数是 Number.MAX_SAFE_INTEGER (2^53 – 1)。任何超过这个值的整数,都会在解析时无声地丢失精度。 { "id": 9007199254740993 } 在 JavaScript 中,JSON.parse 会得到 9007199254740992 (错误!)。 [...]
本文永久链接 – https://tonybai.com/2025/10/08/go-network-programming-complete-guide 大家好,我是Tony Bai。 作为一个后端工程师,你一定对这个场景不陌生: 深夜,告警响起。你负责的一个核心服务,对下游的调用延迟飙升,错误率激增。你第一时间检查了日志、指标,代码逻辑似乎无懈可击。于是,一个熟悉的声音在团队频道里响起:“是不是网络又抖动了?@运维 同学帮忙看一下!” 网络,这个我们每天都在依赖,却又常常感到陌生的“透明层”,似乎成了我们排查问题时的“终极甩锅对象”。它像一个巨大的黑盒,我们知道数据进去了,也知道数据出来了,但中间发生了什么?为什么会慢?为什么会断?我们往往一知半解。 尤其是对于我们 Gopher 来说,这种感觉可能更加强烈。 Go 语言为我们创造了一个“网络编程很简单”的美好幻觉。 我们不得不赞叹,Go 的 net 包设计得实在太过优雅。一行 net.Listen 就能启动一个服务器,一行 net.Dial 就能连接到远端,go handle(conn) 更是将困扰了 C/C++ 程序员几十年的并发模型化于无形。再加上 net/http 这个“开箱即用”的神器,我们似乎只用关心业务逻辑,网络?交给 Go 就好了。 但这种美好的幻觉,也正是最危险的陷阱。 当你的服务出现以下问题时,你是否曾感到束手可策? 连接超时,到底是 DNS 解析慢,还是 TCP 握手慢,或是 TLS 握手慢? 面对海量短连接,为什么系统会出现大量的 TIME_WAIT 状态,它会耗尽端口吗? 线上出现大量 CLOSE_WAIT 状态,是谁的代码忘记了 Close() 连接? 为什么我的 TCP 通信会“粘包”?应用层协议该如何设计? HTTP/1.1、HTTP/2、HTTP/3 之间,除了名字,核心区别是什么?我的 gRPC 服务为什么比 REST [...]
本文永久链接 – https://tonybai.com/2025/10/07/proposal-must-do 大家好,我是Tony Bai。 if err != nil 不仅是 Go 代码中最常见的片段,更是其错误处理哲学的基石。它强制开发者在每一个可能出错的地方,都必须直面失败的可能性。然而,当一个错误在理论上可能发生,但在实践中(尤其是在处理静态、已知的常量时)又“不可能”发生时,这种严谨性是否就变成了一种冗余的样板代码? 这种在便利性与哲学纯粹性之间的张力并非新生事物。Go 标准库自身,就在特定场景下为我们提供了“捷径”。例如,text/template 包就提供了一个 Must 函数: func Must(t *Template, err error) *Template 它接收一个 (*Template, error),并在 error 不为 nil 时直接 panic。这正是为了简化那些基于静态字符串、本不应失败的模板解析过程。 这种“我断言此操作必不失败,否则就是程序级错误”的模式,可以被称为“断言式初始化” (Assertive Initialization)。 这一既有模式,正是最近一个被Go技术负责人Austin Clements纳入到Active阶段的提案(#54297)的灵感来源。该提案由前Go团队成员 Brad Fitzpatrick 发起,其核心问题是:我们是否应该将这种模式从特定包的“特例”,提升为一个通用的、由标准库提供的泛型函数? 这个看似微小的提议,却在 Go 社区引发了一场关于便利性、最佳实践与语言哲学的深度辩论,在这篇文章中,我们就一起来看看这场辩论的过程,并看看是否能从中学习到一些值得借鉴的东西。 问题的缘起:那些“不可能失败”的失败 Brad Fitzpatrick 最初的痛点非常具体而普遍:在初始化一个 httputil.ReverseProxy 时,你需要一个 *url.URL。而创建一个 *url.URL 的标准方式是调用 url.Parse,这是一个会返回 error 的函数: // [...]
本文永久链接 – https://tonybai.com/2025/10/04/the-software-essays-that-shaped-me 大家好,我是Tony Bai。 二十年前,一位年轻的程序员在还未踏入职场时,便开始沉浸于软件开发的博客文章与深刻思考之中。二十年后,他已成为一名资深工程师,回首望去,成千上万的文字中,只有寥寥数篇真正沉淀下来,如基石般塑造了他的思维方式和职业生涯。 这份由 Michael Lynch 精心筛选出的“思想塑造清单”,本身就是一次对软件工程领域永恒智慧的巡礼。清单中的每一篇文章,都如同一个思想的火种,点燃了关于工程文化、代码哲学、乃至技术选型的深刻辩论。 今天,也让我们重新打开这些经典,逐一剖析其中的智慧,看看它们在瞬息万变的当下,能为我们——尤其是追求简约与高效的 Go 开发者——带来怎样历久弥新的启示。 1. Joel 测试:衡量开发者幸福感的 12 条黄金标准 (“The Joel Test: 12 Steps to Better Code” by Joel Spolsky, 2000) Joel Spolsky 的这 12 个问题,与其说是对代码质量的测试,不如说是一面镜子,映照出一家公司是否真正尊重开发者的时间和心智。二十多年过去了,这些问题依然是衡量一个工程团队成熟度的“试金石”。 Do you use source control? (你用源码控制吗?) Can you make a build in one step? (你能一步构建吗?) Do you make daily builds? [...]
本文永久链接 – https://tonybai.com/2025/10/02/go-archaeology-slice 大家好,我是Tony Bai。 slice(切片),可以说是 Go 语言中最重要、也最常用的数据结构,没有之一。我们每天都在使用它,尤其是 append 函数,它就像一个魔术师,总能“恰到好处”地为我们管理好底层数组的容量,让我们几乎感受不到内存分配的烦恼。 但你是否想过,这份“恰到好处”的背后,隐藏着怎样的代价与权衡?append 的扩容策略,是简单的“翻倍”吗?如果不是,那它遵循着怎样一条精密的数学公式? 更进一步,slice 的设计真的是完美的吗?它有一个与生俱来的“危险”——共享底层数组。一个不经意的函数调用,就可能导致意想不到的数据修改,引发难以追踪的 bug。Go 团队是否考虑过一种更“安全”的切片?如果考虑过,它又为何最终没有出现在我们今天的 Go 语言中? 理解这些位于“隐秘角落”历史问题,不仅能让你写出性能更好、更安全的代码,更能让你洞悉 Go 语言设计的核心哲学——在简单性、性能和安全性之间,那永恒的、精妙的平衡艺术。 今天,就让我们扮演一次“Go 语言考古学家”,带上放大镜和洛阳铲,深入 Go 官方的设计文档和 CL (Change List) 的历史尘埃中,去挖掘 slice 背后那两个鲜为人知的故事:一个是被遗弃的“只读切片”提案,另一个是 append 扩容策略的“精益求精”。 失落的“伊甸园”:Read-Only Slice 提案 我们先从一个几乎所有 Gopher 都遇到过,或者未来一定会遇到的“坑”开始。看下面这段代码: func processData(data []int) { // 假设我们只是想读取 data,但某个“新手”在这里修改了它 data[0] = 100 } func main() { metrics := [...]
本文永久链接 – https://tonybai.com/2025/09/30/good-taste-in-software-engineering 大家好,我是Tony Bai。 在软件工程领域,我们习惯于用“技术能力”(Technical Skill)来衡量一位工程师的优劣。他是否精通并发模型?能否写出高性能的代码?对底层原理的理解有多深?这些能力可以通过学习和重复练习来获得,是我们评价体系中的“硬通货”。 然而,github工程师Sean Goedecke在他最新的博文中,提出了一个新的观点:决定工程师成长上限的是“技术品味”(Technical Taste)。他认为,“品味”与“能力”是两个正交的维度。你可以技术能力很强,但品味很差;也可以技术尚在发展,但已具备良好的品味。就像一个美食家,即使自己不会烹饪,也能分辨出食物的好坏。同样,一个有品味的工程师,在能亲手构建一个复杂系统之前,就已经知道自己喜欢什么样的软件。在文章中,他还特意以Go的一些语法特性举例,来诠释什么是工程品味。 在这篇文章中,我们将一起拆解“技术品味”这个看似玄妙的概念,学习如何识别自己和他人身上的“坏品味”(比如对“最佳实践”的盲从),并探索一条培养“好品味”的实践路径,帮助我们Go开发者在日常的权衡与决策中,做出更成熟的选择。 “品味”不是“对错”,而是“价值观”的排序 文章以一个经典的例子开场:for循环 vs. map/filter。 许多来自函数式编程背景的开发者会认为,使用map/filter的代码“看起来更美”,因为它们通常涉及纯函数,易于推理,还能避免一类的迭代器bug。这似乎是一个关乎“正确”与“错误”的技术问题。 然而,Go语言的设计者们,出于“有原则的理由”,并没有在语言核心中原生内置map/filter。在Go中,一个简单的for循环: 性能上更易于推理:没有高阶函数调用的开销。 更灵活:可以轻松扩展到更复杂的迭代策略(如一次处理两个或多个元素)。 这个分歧的本质是什么?Goedecke一针见血地指出:这不是一个关于技术能力高低的争论,而是一个关于“工程价值观”(Engineering Values)优先级排序的差异。 偏爱map/filter的工程师,可能将“表达力”和“数学上的优雅”排在了更高的位置。 偏爱for循环的Go语言设计者们,则将“性能透明度”和“实现的直接性”置于首位。 成熟的工程师,能够理解并承认这种差异源于价值观的不同,而非技能的缺失。 什么是工程中的“好品味”? 几乎所有软件工程决策都是一次权衡(tradeoff)。 你很少能在两个选项中找到一个绝对更优的。你总是在不同的工程价值观之间做艰难的取舍,比如在“性能”和“可读性”之间,或者在“开发速度”和“正确性”之间。 不成熟的工程师会固执己见,认为“X永远比Y好”。而成熟的工程师则会评估双方的优劣,并思考:“在当前这个特定的项目中,X的收益是否大于Y的收益?” 因此,Goedecke对“技术品味”给出了一个精辟的定义: Taste is the ability to adopt the set of engineering values that fit your current project. (品味,是为当前项目选择一套恰如其分的工程价值观的能力。) 你的个人技术偏好,构成了你的基础“品味”。而“好品味”,则是在这个基础上,根据项目所处的真实环境(团队能力、业务阶段、性能要求、交付压力等),灵活调整你的价值观优先级的能力。 如何识别“坏品味”?—— “最佳实践”的诅咒 “坏品味”最常见的表现形式,就是僵化(inflexibility)。 I will always distrust engineers [...]
本文永久链接 – https://tonybai.com/2025/09/29/synctest-bugs-in-go-1-25 大家好,我是Tony Bai。 Go 1.25的发布,为我们带来了一个期待已久的“并发测试神器”—— testing/synctest。这个在Go 1.24中作为实验性功能首次亮相的包,承诺将我们从time.Sleep、channel和各种脆弱的同步技巧中解放出来,让我们能够编写出快速、可靠、确定性的并发测试。 然而,任何强大的新工具在投入真实世界的熔炉后,都必然会经历一场严酷的“成人礼”。Go 1.25发布后,社区的早期使用者们迅速将其应用于各种复杂的并发场景,并遇到了一些隐藏在“气泡”(bubble)之下的微妙问题。 本文将聚焦于三个典型的、由社区报告的synctest“首日bug” (#75052, #74837, #75134),它们分别涉及了io.Pipe、context和sync.WaitGroup这三个常用并发原语。需要澄清的是,这些所谓“Bug”并非都是synctest本身的Bug。它们有的源于开发者对并发原语的常见误用,synctest只是更严格地揭示了问题;有的则反映了一个实验性API在社区反馈下的设计演进;当然,其中也包含了一个深藏在运行时中的、真正的实现Bug。 通过剖析这些案例,我们不仅能学会如何正确、安全地使用synctest,更能一窥这个新范式背后的设计哲学、Go团队的应对智慧以及它如何帮助我们编写更健壮的并发代码。 Bug 1: io.Pipe与context的“谎言”—— Goroutine泄漏之谜 一位开发者在迁移测试到synctest后,遇到了一个神秘的panic:panic: deadlock: main bubble goroutine has exited but blocked goroutines remain。这通常意味着测试中存在goroutine泄漏。 你可以将以下代码保存为leak_test.go并运行go test来复现这个panic。 // synctest-bugs/bug1/leak_test.go package main_test import ( "context" "io" "testing" "testing/synctest" ) func TestGoroutineLeakWithPipe(t *testing.T) { synctest.Test(t, func(t *testing.T) { pr, pw := [...]
本文永久链接 – https://tonybai.com/2025/09/28/how-top-performers-stand-out-in-the-age-of-ai 大家好,我是Tony Bai。 AI 正在以前所未有的速度重塑软件开发领域。从代码生成到信息检索,AI 工具无疑极大地提升了工程师的生产力。一个普遍的假设是,谁能更好地利用 AI,谁就能成为新时代的顶尖人才。然而,Dropbox 最近发布的一项内部研究,却对这个看似理所当然的结论提出了一个深刻的挑战。 研究发现,虽然 AI 工具(如 ChatGPT 或 Dropbox Dash)确实让所有员工的效率都得到了提升,但它并不是区分最高绩效员工(即那些“卓越”的员工)与普通高绩效员工(“优秀”的员工)的关键因素。当 AI 将“写代码”的效率门槛普遍拉高后,一个更核心的问题浮出水面:在一个 AI 成为标配的时代,顶尖开发者究竟凭借什么脱颖而出? 本文将和大家一起解读这份研究报告,逐层剖析 AI 带来的生产力悖论,并揭示那些在 AI 时代真正让顶尖开发者与众不同的“剧本”和核心特质。 AI 生产力悖论:当所有人都开上了“跑车” Dropbox 的研究首先确认了一个事实:AI 是强大的生产力引擎。在其内部,高达 78% 的员工认为 AI 工具提高了他们的工作效率,这一比例比去年大幅跃升了 20 个百分点。高达 96% 的员工每周都会使用 AI 来处理信息查找、头脑风暴、软件开发和草拟信息等任务。 然而,一个关键的发现随之而来:AI 带来的生产力增益是普惠的。无论是哪个级别、哪个岗位的员工,在使用 AI 后都报告了相似的效率提升。这意味着 AI 就像是给所有赛车手都换上了一辆更快的跑车——赛道上的整体速度都变快了,但车手之间的排名可能并没有因此改变。 当我们聚焦于那些同时具备高绩效和高敬业度的“卓越员工”(Thriving Employees)时,数据显示,87% 的卓越员工认为 AI 提升了他们的生产力,而其他员工中这个比例是 76%。这个差距是存在的,但并不足以解释他们之间的巨大表现差异。 这导出了研究的核心问题:如果 AI [...]
本文永久链接 – https://tonybai.com/2025/09/27/direct-ref-to-embedded-fields-in-struct-literals 大家好,我是Tony Bai。 在 Go 语言中,结构体嵌入 (Embedding) 是一个强大而独特的特性,它为我们提供了一种优雅的“垂直组合”方式。然而,多年来,它的使用体验中一直存在一个广为人知的“反直觉”之处,一个让无数开发者(包括 Go 核心团队成员自己)都曾踩过的坑。 近日,一个旨在解决此问题的、长达十年的“陈年”提案(#9859)被重新激活并进入了活跃评审阶段(active)。这预示着 Go 结构体字面值的使用方式,可能即将迎来一次意义深远的简化。在本文中,我就和大家一起对该提案做一下解读,看看新提案究竟解决了什么问题,一旦落地后,究竟会给Go开发者带来哪些好处。 核心痛点:不对称的读写行为 让我们从问题的核心开始。假设我们有如下定义: type Point struct { X, Y int } type Circle struct { Point // 嵌入 Point Radius int } 在 Go 中,我们可以通过“字段提升”(Field Promotion) 的特性,非常自然地访问被嵌入的字段: var c Circle c.X = 10 // 直接访问,非常直观 c.Y = 20 然而,当我们尝试在结构体字面值中初始化这个 Circle 时,同样的直觉却会碰壁: [...]
本文永久链接 – https://tonybai.com/2025/09/26/self-reliant-programmer 大家好,我是Tony Bai。 “当代多数软件,对其用户而言是一种耻辱。” 最近,一篇措辞激烈、观点鲜明的《自立程序员宣言》(Self-Reliant Programmer Manifesto)在技术圈流传开来。它以一种近乎愤怒的姿态,抨击了现代软件开发中日益增长的复杂性、对臃肿工具的过度依赖以及脆弱的供应链。 对于许多沉浸在复杂框架和无尽工具链中的开发者来说,这份宣言可能显得有些“原教旨主义”。然而,在我们Go社区,当这篇文章被转发和讨论时,一种奇特的、会心一笑的共鸣油然而生。我们中的许多人看完后的第一反应是:“这不就是我们一直在说的Go语言哲学吗?” 这份宣言的核心呼吁——相信简单、最小化依赖、并勇于编写自己的工具——听起来就像是Go社区日常交流的“黑话”。 本文将和你一起解读这份“檄文”,并逐一印证,为什么它所倡导的“自立”之道,早已深深烙印在Go语言的DNA之中。 Go语言哲学:我们一直在坚持什么? 在解读宣言之前,让我们先回顾一下Go社区长期以来所珍视的一些核心价值观: 少即是多 (Less is exponentially more):Go语言刻意保持规范的微小,避免引入带有额外认知负荷的特性。 清晰优于聪明 (Clear is better than clever):代码首先是写给人读的,显式的错误处理、简单的控制流远比“魔法般”的语法糖更受推崇。 “自带电池” (Batteries Included):一个强大的标准库,是我们抵御外部依赖泛滥的第一道,也是最重要的一道防线。 “一点复制胜过一点依赖” (A little copying is better than a little dependency):这句社区谚语,体现了我们对引入新依赖的极度审慎。 现在,让我们带着这些“Go味十足”的理念,去看看《自立程序员宣言》都说了些什么。 宣言的核心法则 vs. Go的内在基因 法则一:“简单即是善” (Simple is good) 宣言说:“一切复杂的事物,都是由简单的东西构成的……你不需要四十二层抽象来实现一些简单的事情。” 这不就是我们所说的“少即是多”吗? Go的设计哲学正是建立在对“简单性”的极致追求之上。它通过减少语言特性,来降低程序员的心智负担。当你在阅读一段Go代码时,你很少需要去猜测这段代码背后隐藏着什么复杂的继承链或元编程魔法。你所见即所得。 宣言强调:“理解事物的工作原理能帮助你建立更好的心智模型。” Go的显式错误处理 (if err != nil)虽然常被诟病冗长,但它强迫我们直面每一个可能出错的环节,而不是将其隐藏在try-catch的便利之下。这正是帮助我们建立健壮心智模型的绝佳实践。 [...]
本文永久链接 – https://tonybai.com/2025/09/25/go-security-past-present-and-future 大家好,我是Tony Bai。 在软件安全领域,最成功的战役,往往是那些从未被公众所知的“隐形战争”。当一门编程语言的安全性被认为是理所当然时,这背后必然有一支团队在持续不断地进行着防御、修复与规划。对于 Go 语言而言,这支团队就是 Google 内部的 Go 安全/密码学团队。 在今年的 GopherCon UK 大会上,该团队负责人 Roland Shoemaker 发表了一场罕见的、对 Go 安全内核进行深度揭秘的演讲。 这场演讲更像是一部关于 Go 语言在安全领域攻防战的编年史,清晰地描绘了其过去的经验教训、现在的核心工作,以及未来的宏大蓝图,值得每位对Go安全感兴趣的Go开发者参考。 本文也将遵循这一“过去、现在与未来”的宏大叙事,首先深入 Go 语言的安全历史,从其诞生至今的攻防对抗中,汲取那些塑造了其安全基因的深刻教训。 过去 —— 从历史漏洞中汲取的教训 Go 的安全故事,始于其内存安全的基因。这一设计从根源上消除了 C/C++ 中最臭名昭著的内存损坏类漏洞。然而,安全之路远非一片坦途。通过对历史上约 160 个 CVE (Common Vulnerabilities and Exposures,通用漏洞披露) 的分析,我们可以勾勒出 Go 语言独特的漏洞画像。 一份优异但非完美的成绩单 与同类语言相比,Go 的 CVE 总数表现优异,远低于 Python 和 Node.js。虽然高于 Rust,但必须指出,Go 的 CVE [...]
本文永久链接 – https://tonybai.com/2025/09/24/evolving-your-go-api 大家好,我是Tony Bai。 你在 package 中导出的每一个 func 和 type,都是一份对用户的承诺。然而,变化是软件开发中唯一不变的真理。当需求变更、bug 修复、甚至认知升级时,你将如何修改这份“承诺”,同时又最大限度地减少对你和你的用户造成的破坏? 在最近的 GopherCon EU 大会上,来自 Google Go 团队的 Jonathan Amsterdam 就“如何管理 Go API 变更”这一核心议题,分享了官方团队的深刻见解与最佳实践。 这次演讲更像是一堂关于工程哲学与用户同理心的必修课。本文为你提炼了其中最关键的四大核心原则,供大家参考。 原则一:“未来防护”——在设计之初就预见变化 避免破坏性变更的最好时机,是在你写下第一行 API 代码的时候。Amsterdam 强调,通过“未来防护” (Future-Proofing) 的设计,可以从源头上消除大量未来的麻烦。 核心理念:保持最小化 “你可以随时添加东西,但修改或移除它们要困难得多。” 这是未来防护的第一信条。在你导出任何一个符号之前,请三思: 非必要,不导出:如果一个符号可以在包内私有化,就绝不要导出它。一个常见的误区是为了方便测试而导出内部函数,更好的做法是使用 _test.go 文件和黑盒测试。 巧用 internal 包:如果一个符号需要在你的模块内部跨包共享,但又不希望被外部用户依赖,请将它放在 internal 包中。你知道吗?标准库的 net/http 树下有 4 个 internal 包,而 crypto 树下则多达 58 个!这正是 Go [...]
本文永久链接 – https://tonybai.com/2025/09/23/go-maphash-portability-costs-and-runtime-boundaries 大家好,我是Tony Bai。 对于大多数Go开发者来说,标准库似乎是一个浑然天成的整体。我们理所当然地使用着fmt、net/http和encoding/json,很少去思考它们内部的依赖关系和架构边界。然而,在标准库光鲜的外表之下,一场关于其核心架构的深刻变革正在悄然发生,而hash/maphash这个看似不起眼的包,正处在这场变革的风暴中心。 最近,Go核心团队的技术负责人Austin Clements在2025年9月17日的提案审查会议中,将他在2025年6月提出的issue #74285的提案设置为“已接受”(Accepted)状态。该提案名为“maphash: drop purego version and establish stronger runtime boundary”,建议移除maphash包的purego实现,并为Go标准库建立一个更清晰的“运行时边界”。 在过去几个月中,Go团队与社区围绕maphash的讨论,以及与TinyGo、GopherJS等社区的精彩互动,揭示了在设计一个世界级标准库时,面临的关于可移植性、依赖管理和生态系统健康的深刻权衡。 在这篇文章中,我就和大家一起来探讨这一提案的背景、影响以及在实现过程中所面临的挑战。 问题的核心:maphash的两副面孔 maphash包的功能很简单:它暴露了Go语言内置map类型所使用的哈希函数。但为了支持不同的Go实现(如标准编译器gc、TinyGo、GopherJS),它内部存在两个截然不同的版本: gc版本 (运行时绑定,对应标准编译器gc): 实现: 深度绑定Go gc运行时,直接使用编译器为map生成的、经过高度优化的哈希函数。 依赖: 极其轻量,只依赖8个底层包。 优点: 性能极高,依赖图谱干净。 purego版本 (可移植): 实现: 为了能在非gc环境(如TinyGo、GopherJS)中运行,它使用纯Go代码重新实现了一套哈希算法(wyhash),并通过reflect包来遍历类型,用crypto/rand生成随机种子。 依赖: 这是一个灾难。purego版本引入了多达87个包的依赖,形成了一个庞大的依赖树。 优点: 理论上具有更好的可移植性。 这个“可移植”的purego版本,正是问题的根源。一个本应是底层、基础的哈希库,却因为reflect和crypto/rand的引入,使其在依赖图谱中的位置变得异常之高。 “可移植性”的隐藏成本 这种臃肿的依赖关系带来了致命的副作用:标准库的底层包无法使用maphash。 想象一下,如果internal/sync或unique这些极其底层的包想要使用maphash,它们就会被迫将reflect和crypto/rand等80多个重量级包引入到Go运行时的最底层。这将造成灾难性的依赖循环和二进制文件膨胀。 正如Austin Clements在提案中所说,purego版本的存在,使得maphash无法在它本该发挥最大价值的地方被使用,甚至在一些高层包中也引入了棘手的依赖问题。为了追求对非标准编译器的“开箱即用”支持,整个标准库的架构健康付出了沉重的代价。 提案:划定边界,回归简单 因此,Go团队提出了一个看似激进但实则回归本源的方案:移除purego实现,并正式声明maphash是“运行时的一部分”。 这也是Go团队的一种态度的表达:Go标准库需要一条清晰的界线,来区分哪些是可移植的、与运行时无关的代码,哪些是与特定工具链(如gc)紧密绑定的代码。 提案初期,Go团队提出的实现方案如下: maphash的核心哈希逻辑保留在可移植的文件中。 与gc运行时交互的“胶水代码”被隔离到一个单独的文件中,并使用//go:build gc标签进行标记。 其他Go实现(如TinyGo)可以轻松地提供它们自己的“胶水代码”文件,来对接它们各自的运行时,而无需维护一个完整、复杂且依赖臃肿的purego版本。 但这个方案立刻引发了TinyGo和GopherJS社区核心维护者的深入讨论: TinyGo的视角: TinyGo维护者表示,他们更倾向于使用//go:linkname来链接到运行时的内部函数。这种方式的“接口”更小、更稳定,比为每个包提供一个“胶水文件”更容易维护。 [...]
本文永久链接 – https://tonybai.com/2025/09/22/go-team-gave-up-on-features 大家好,我是Tony Bai。 在 GopherCon Europe 2025 的 Go 团队座谈会上,Michael Stapelberg(负责go protobuf)、Damien Neil(负责Go安全相关)、Michael Pratt(负责Go运行时和Go性能相关) 和 Jonathan Amsterdam(log/slog作者,负责Go工具相关) 四位核心成员与社区进行了一场坦诚的对话。他们不仅分享了诸如官方 MCP SDK、“裸金属”Go 等激动人心的进展,更以一种罕见的坦率,正面回应了社区长期以来关心的多个“老大难”问题——包括不可变类型、泛型错误处理和非 nil 指针。其中最引人注目的一句“我们放弃了”,几乎为 Go 语言在某些方向上的演进画上了句号。 本文将带你深入这场座谈会的核心内容,一探 Go 语言的现在与未来。 语言设计的哲学——“不做什么”比“做什么”更重要 座谈会最精彩的部分,莫过于对多个长期存在的语言功能提案的讨论。Go 团队的态度清晰而一致:为了维护 Go 的核心价值——简洁性和易读性,他们愿意对许多看似“美好”的功能说“不”。 不可变数据类型 (immutable) 社区的期待:为 Go 增加类似 immut和const(修饰变量的) 的关键字,以增强代码的安全性和可预测性。 团队的困境:Michael Pratt 承认,这是“可能做的最好的事情之一”,但他紧接着说,“我们不知道该如何实现它”。内部曾有多个提案,但都未成功。核心问题在于,任何这类功能都会像病毒一样在代码库中蔓延,迫使所有 API 都需要考虑 const 和非 const 两种版本,这与 Go 的设计哲学背道而驰。 结论:在社区提出一个绝佳的、能保持语言简洁性的提案之前,官方不会主动推进。 泛型错误处理 [...]
本文永久链接 – https://tonybai.com/2025/09/21/why-maintainers-should-say-no-to-good-idea 大家好,我是Tony Bai。 维护一个开源项目,最难的部分往往不是修复 bug 或实现新功能,而是对一个设计精良、技术上无懈可击的“好主意”说“不”。Prefect 和 FastMCP 的创始人 Jeremiah Lowin 最近发表了一篇深刻的文章,探讨了这种看似“不近人情”的行为背后的管理哲学。他指出,项目的成功最终取决于其愿景的连贯性,而非功能的堆砌。在 LLM 让代码变得“廉价”的今天,这种对项目“灵魂”的守护变得比以往任何时候都更加重要。 这篇文章让我产生了强烈的共鸣。近期,当我在维护自己的一个小工具类开源项目 bigwhite/issue2md 时,也遇到了类似的抉择:一个国外开发者提交了一个由Gemini cli实现的功能完备的 PR,但我最终还是选择了拒绝。那一刻,我深切地体会到了 Lowin 所描述的、作为维护者的艰难与责任。 一个看似完美的“好主意”,为何可能成为项目的“威胁”?Lowin 的文章为我们提供了深刻的答案。在本文中,我们就一起来看看Lowin给出的这一套在 AI 时代下尤为宝贵的实践剧本。 软件的灵魂:与用户心智模型一致的抽象 文章开篇便引用了 Prefect CTO Chris White 的一句名言: “人们选择一个软件,是因为它的抽象与他们的心智模型相符。” 这正是开源维护者的核心职责:首先,建立并清晰地阐述这个心智模型;然后,不懈地构建反映该模型的软件。 一个功能,即便在名义上很有用,但如果与项目的“精神”不符,它就可能成为一种威胁。这种威胁的形式多种多样: 范围失控:为一个 CLI 工具请求增加 GUI。 增加复杂度:为一个用户的利基问题,给所有用户增加维护负担。 破坏一致性:最微妙的,是引入一个与项目既定模式相悖的 API,为未来的用户制造认知失调。 维护者的工作,就是像守护神一样,捍卫项目的灵魂,确保每一次代码的合并都是对项目愿景的增强,而非稀释。 LLM 时代的新挑战:廉价代码与昂贵的审查 曾几何时,编写代码是一项高成本、高投入的活动。贡献者在投入大量时间之前,通常会先通过 issue 进行讨论,以确保自己的努力不会白费。 然而,LLM 的出现彻底颠覆了这一模式。代码变得廉价,而讨论和审查变得稀缺。 作者观察到一种新常态:用户带着一个从未讨论过的、由 LLM 生成的、功能完备的 [...]
本文永久链接 – https://tonybai.com/2025/09/20/refactoring-go-in-large-codebases 大家好,我是Tony Bai。 “要不……我们重写吧?” 在任何一个发展到一定阶段的 Go 项目中,这句话都像一个幽灵,反复出现在技术讨论中。面对一个布满补丁、逻辑盘根错节、维护成本日益高昂的“大泥球” (Big Ball of Mud),彻底推倒重来的想法总是充满了诱惑。 然而,这往往是通往灾难的捷径。重写项目常常陷入延期、超出预算、甚至最终失败的泥潭。那么,正确的道路究竟在何方? 在 GitHub 的软件工程师 Brittany Ellich 最近的一次分享中,她系统性地为大型 Go 项目的维护者提供了一份清晰的实践指南。本文将为你完整呈现这份源自顶级工程团队的宝贵经验。 核心困境——为何“重写”如此诱人? 在深入探讨如何重构之前,我们必须先理解“为何不应轻易重写”。推动重写的往往是三个看似合理、实则充满谬误的论点。 谬误一:“重写会更快” 这是最普遍的错觉。我们往往只看到了系统中那 20% 腐烂的部分,并天真地认为重写它们就是全部工作。但我们忽略了: 那 80% 仍在正常工作的部分也必须重写。 在重写期间,旧系统仍需维护,团队精力被一分为二。 数据迁移和系统下线本身就是极其复杂且耗时的大型项目。 最终,“快速重写”几乎无一例外地会演变成一场旷日持久的拉锯战。 谬误二:“这次我们能写出‘干净’的代码” “如果我们从头开始,就能‘做对’。” 这句话听起来无比正确,却忽视了一个残酷的现实: “生产应用程序本质上就是混乱的。这是特性,不是 Bug。” 那些看似丑陋的边界情况,恰恰是多年用户反馈积累下的业务逻辑;那些晦涩的变通方案,是无数次深夜故障排查后沉淀下的组织知识。一个“干净”的重写版本,往往意味着这些宝贵的隐性知识被全部丢弃,你将不得不重新踩一遍所有过去的坑。 谬误三:“新技术栈能解决我们的问题” “如果我们用 Rust 重写,性能问题就都解决了!” 这是技术驱动的典型陷阱。 学习一门新技术很容易,但精通它很难。在重写项目中引入一个全新的技术栈,意味着团队将在“学习”和“构建”之间反复横跳,犯下大量新手错误。更明智的做法是,用现有、成熟的技术栈,通过重构解决已知问题,这远比用一门新语言写出同样有问题的代码要高效得多。 诊断结论:重构,而非重写,是持续改进的唯一路径。正如敏捷宣言早已告诉我们的那样,最好的软件产品源于持续的改进,而非完美的规划。 系统性重构框架——一套可落地的实践指南 既然重写不可取,我们该如何系统性地对现有 Go 代码库进行“外科手术”?Ellich 提出了一套以“易读、易测、易改”为核心原则的实践框架-THINK。 实践一:建立测试安全网 在修改任何代码之前,第一步永远是建立安全网。如果你的代码库测试覆盖率不足,可以采用 Michael [...]
本文永久链接 – https://tonybai.com/2025/09/19/the-tension-in-programmer-comments 大家好,我是Tony Bai。 做公众号/博客这些年,我收到了成千上万条来自程序员朋友的评论。绝大多数都充满了智慧、好奇和善意,正是这些交流,构成了我持续分享的最大动力。但与此同时,我也常常在评论区里,感受到一股强烈的、带有攻击性的无形之气。 比如,当我分享一篇关于Go在业务场景实践的文章时,总会有人跳出来,言简意赅地留下一句:“用Go写业务是不是很垃圾?” 又比如,当社区在探讨用Rust重构某个C++项目时,评论区可能会出现这样的“高论”:“用Rust重写C++代码,就是从一坨屎变成了另一坨屎。” 这些评论,往往脏字当头,不带任何论据,纯粹是情绪的宣泄。我思来想去,觉得用“戾气”或“喷子”来形容,似乎都不够精准。直到有一天,一个词蹦进了我的脑海——“煞气”。 这个词,源于传统文化,意指一种凶戾、非理性、具有破坏性的气场。它精准地捕捉了这类评论的本质:其目的并非交流思想,而是用情绪的冲击波,扼杀讨论,打击分享者的热情。正因如此,我之前公众号的自动精选评论和留言不得不改为手工精选,这不仅增加了工作量,还降低了评论展示的及时性。 今天,这篇文章不旨在批判,而是想和大家一起,深入地聊一聊程序员评论区里的这股“煞气”,尝试理解它从何而来,并探讨作为技术社区的一员,我们该如何面对它,如何保护我们共同的精神家园。 “煞气”的百态图鉴:你一定见过的几种典型“煞评” 这股“煞气”并非铁板一块,它以多种面目出现在我们的视野中,总有一种让你觉得似曾相识: “一言以蔽之”型 这类评论堪称“断言大师”,从不屑于提供论据,仅用一句话便能给一门语言、一个框架甚至一个技术方向盖棺定论。 “Go就是不行。” “WebAssembly没前途。” “微服务就是个坑。” 简洁,有力,不容置疑,仿佛掌握了宇宙的终极真理。 “非黑即白”型(技术圣战) 在他们眼中,技术选型不是基于场景和权衡,而是一场关乎信仰的“圣战”。语言、编辑器、操作系统……万物皆可站队,异端必须被消灭。 “用Rust重写C++就是从一坨屎变成另一坨屎。” “Vim/Emacs之外皆异端!” “还在用Windows/Mac开发?笑死。” “资格论”与“秀优越”型 这类评论善于通过攻击对方的身份、资历或知识储备,来釜底抽薪式地否定其观点,从而建立自己的优越感。 “你连源码都没读过,凭什么评论?” “这东西我十年前就玩过了,没什么新意。” “等你写到百万行代码再来讨论架构吧。” “情绪投射”型 这类评论者,往往将自己在工作中因某项技术受挫而产生的负面情绪,无差别地投射到所有相关的公开讨论中,把评论区当成了情绪的垃圾桶。 “我们项目刚被XXX坑惨了,这玩意儿就是个彻头彻尾的垃圾!” “又在吹这门语言?我刚因为它的GC问题加了三天班!” 这些充满“煞气”的评论,像病毒一样侵蚀着技术社区的讨论氛围,让许多乐于分享的创作者心生寒意,也让许多渴望学习的新人望而却步。 溯源“煞气”:它们究竟从何而来? 要应对“煞气”,首先要理解它的来源。它并非简单的“素质问题”,背后往往有更深层次的、属于程序员群体的心理动因: 高认知负荷与挫败感: 软件开发本质上是一项与复杂性搏斗的高难度、高挫败感的工作。代码不工作是常态,被需求反复折磨是日常。长期累积的压力和挫败感,需要一个宣泄的出口,而匿名的网络评论区便成了最廉价的选择。 强身份认同与技术部落主义: 许多程序员倾向于将自我价值与所掌握的技术栈深度绑定。“我是Gopher”、“我是Rustacean”,这种身份认同感带来了归属感,但也催生了“部落主义”。攻击对立的技术,本质上是在捍卫自我身份和所属部落的“荣耀”。 对“最优解”的执念与抽象能力的差异: 我们的工作是与逻辑打交道,追求严谨和正确,这使得许多程序员潜意识里相信存在一个放之四海而皆准的“最优解”。这种思维惯性,导致在面对需要权衡(Trade-off)的工程问题时,容易陷入“非黑即白”的二元对立,无法容忍不同场景下的不同选择。 知识的诅咒: 一些资深开发者,已经忘记了自己初学时期的困惑和挣扎。他们对自己领域内“显而易见”的知识缺乏同理心,容易将新手的提问或不成熟的观点视为“愚蠢”,并报以轻蔑或不耐烦。 网络匿名性的放大效应: 这是所有网络社区的通病。脱离了现实世界的社交约束,人们更容易释放出内心的攻击性。 化解“煞气”:我们每个人的社区修行 面对弥漫的“煞气”,无论是内容创作者还是普通读者,我们每个人都身处其中,既可能是受害者,也可能在不经意间成为助推者。与其抱怨环境,不如从自身做起,共同参与到社区的净化与建设中来。 给所有社区参与者的“修行建议”: 评论前,区分“观点”与“情绪”: 在敲下键盘前,花一秒钟审视内心:我即将表达的,是基于逻辑和事实的技术观点,还是仅仅是想吐槽一下今天遇到的某个Bug或者糟糕的心情?有意识地分离这两者,是理性讨论的第一步。 拥抱“建设性批评”的艺术: 如果你不同意某个观点,这非常正常,甚至是技术进步的源泉。但请尝试用建设性的方式来表达: 提供论据: “我认为这个方案有风险,因为在XX场景下,它可能会导致YY问题。” [...]
本文永久链接 – https://tonybai.com/2025/09/18/go-runtime-free-proposal 大家好,我是Tony Bai。 Go 的垃圾收集器(GC)是其简单性和并发安全性的基石,但也一直是性能优化的焦点。近年来,Go 核心团队为了进一步降低 GC 开销,进行了一系列前沿探索:从备受争议的arena 实验,到更优雅但实现复杂的 memory regions构想,最终,焦点似乎汇聚在了一项更务实、更具潜力的提案上——runtime.free。这项编号为 #74299 的实验性提案,正试图为 Go 的内存管理引入一个革命性的新维度:允许编译器和部分标准库在特定安全场景下,绕过 GC,直接释放和重用内存。其原型已在 strings.Builder 等场景中展现出高达 2 倍的性能提升。 本文将带着大家一起回顾 Go 内存管理的这段探索之旅,并初步剖析一下 runtime.free 提案的背景、核心机制及其对 Go 性能生态的深远影响。 背景:一场关于“手动”内存管理的漫长探索 Go 语言自诞生以来,其自动内存管理(GC)一直是核心特性之一。然而,对于性能极致敏感的场景——例如高吞吐量的网络服务——GC 的开销始终是开发者关注的焦点。为了赋予开发者更多控制力,Go 团队近年来开启了一系列关于“手动”或“半自动”内存管理的探索。 第一站:arena 实验——功能强大但难以融合 arena 实验(#51317)是第一次大胆的尝试。它引入了一个 arena.Arena 类型,允许开发者将一组生命周期相同的对象分配到一个独立的内存区域中,并在不再需要时一次性、批量地释放整个区域。 优点:arena 在特定场景下取得了显著的性能提升,因为它极大地减少了 GC 的扫描和回收工作。 问题:arena 的 API 侵入性太强。几乎所有需要利用 arena 的函数都必须额外接收一个 arena 参数,这会导致 API 的“病毒式”传播,并且与 Go [...]
本文永久链接 – https://tonybai.com/2025/09/17/some-things-i-keep-repeating-about-go 大家好,我是Tony Bai。 在阔别公众视野数年后,Go 社区的传奇人物 Dave Cheney 终于重返 GopherCon Europe 的舞台,发表了一场备受瞩目的复出首谈(注:我印象中的回归首谈^_^)。这场题为《那些我反复强调的 Go 编程之事》的演讲,没有追逐时髦的技术热点,而是选择回归编程的本源,分享了他十五年 Go 编程生涯中,那些被反复实践、验证并沉淀下来的核心理念。 本文将和大家一起深入解读这场演讲的三大核心支柱:命名、初始化与流程控制、以及辅助函数,并探讨为何这些看似简单的模式,却是编写可读、可维护、可测试 Go 代码的基石。 引言:一位 Go “哲人”的回归与沉淀 对于许多 Go 开发者而言,Dave Cheney 的名字不仅代表着一位高产的贡献者,更像是一位编程哲学的布道者。在他“消失”的几年里,社区依旧在流传和实践着他提出的诸多模式。因此,当他重返 GopherCon Europe 2025的舞台时,整个社区都在好奇:他反复强调的那些 Go 编程理念,变了吗? 答案既是“没有”,也是“更加深刻了”。 正如他在开场时所言,这次演讲是他对自己为多家公司编写了超过十年 Go 代码的经验总结,是他对 Peter Bourgon 经典演讲《Ways to do things》的致敬,更是一次对他自己编程风格的提纯与升华。他所分享的,正是那些在无数次代码审查、项目重构和生产救火中,被他反复提及、反复实践的编程模式。这些“重复之事”,构成了他编程哲学的坚实内核。 支柱一:命名 —— 程序的灵魂与第一印象 “我们应该执着地、狂热地关注程序中使用的每一个名字。” 演讲开篇,Dave 便直指编程的核心——命名。它涵盖了变量、常量、包、类型、方法和函数,是代码清晰度的源头。 告别“短标识符”的圣战 对于 Go 社区经久不衰的“短标识符 vs. 长标识符”之争,Dave [...]
本文永久链接 – https://tonybai.com/2025/09/16/go-language-when-simple-becomes-complex 大家好,我是Tony Bai。 “我没有时间写一封短信,所以我写了一封长信。” —— 马克·吐温 这句名言的字面意思是写长信很容易,但把长信写成短信,就要删掉很多,这个过程是很难的。 在Go社区近期的一场热议中,该名言被引用来概括讨论的核心议题:简单是复杂的,而把事情搞复杂,反而简单。 这场讨论始于一个 Gopher 的真诚提问:在重温了 Rob Pike 2015 年关于“Simplicity is Complicated”的著名演讲后,他感到困惑。Go 语言在近些年增加了不少新特性,尤其是泛型,这是否违背了当初的简约哲学?语言真的因此变得更好了吗? 这个问题,如同投入平静湖面的一颗石子,激起了层层涟漪。它既是对 Go 语言演进方向的拷问,更是对“简单”这一核心价值观的再审视。 但要厘清这场复杂的辩论,我们不能简单地给出“是”或“否”的答案。相反,通过挖掘和解读社区的集体智慧,我们可以发现,Go 语言的演进其实遵循着三条深刻的内在法则。 本文将为大家曾现这三大法则,以期揭示 Go 语言在保持其灵魂的同时,如何拥抱变化。 法则一:演进,是语言保持生命力的唯一途径 在讨论中,一个压倒性的共识是:语言必须演进以保持其生命力。 这也和2023年末Go前任技术负责人Russ Cox演讲中的观点不谋而合。 一位资深开发者引用了 Pascal 的例子:一门曾经辉煌的语言,因其未能跟上时代的需求而逐渐式微。与之相对,C 语言虽然演进缓慢,但其核心结构的简单性使其成为构建其他语言(如 C++)的基石,从而获得了永生。 Go 团队显然深谙此道。无论是备受争议的 go.mod 还是千呼万唤始出来的泛型,社区普遍认为,这些都不是轻率的“功能堆砌” (feature creep),而是 Go 团队在经过漫长、缓慢且深思熟虑的辩论后,对真实世界需求的审慎回应。 “不演进的语言,将面临失去其存在意义的风险。” 这种演进并非盲目追逐潮流,而是为了解决社区在实践中遇到的真实痛点。Go 的选择,不是停滞不前,而是以自己独有的、极其克制的节奏向前迈进。 法则二:复杂性守恒——从“脑海”到“工具”的迁移 “复杂性永远不会消失,它只是在迁移。” 一位来自 Perl 世界的开发者分享了这一深刻洞见。 在 Go [...]
本文永久链接 – https://tonybai.com/2025/09/15/go-context-column 大家好,我是Tony Bai。 作为一个 Gopher,如果说 Go 语言里哪个标准库最能引发“灵魂拷问”,我想 context 说第二,没人敢说第一。 我们每天都在和它打交道,不是吗? 打开任何一个 Go 项目,从 Gin 的 c.Request.Context(),到 gRPC 的方法签名,再到数据库的 QueryContext,context.Context 这个参数就像一个“幽灵”,无处不在,却又常常让人捉摸不透。 它总是雷打不动地占据着函数签名的第一个位置,仿佛在宣告自己的“正宫”地位。我们依葫芦画瓢地将它一层层往下传,似乎只要照做,程序就能安然无恙。 但你是否也曾在某个深夜,对着一段因为 context deadline exceeded 而崩溃的代码,陷入沉思: 这个 ctx 到底是个什么“东西”?为什么它能“凭空”知道超时了? context.Background() 和 context.TODO(),我到底该用哪个?感觉好像都能跑… 那个 WithValue,用起来真方便!我是不是可以把所有参数都塞进去,告别冗长的函数签名?(危险的想法!) 为什么我的 goroutine 明明收到了取消信号,却还在后台疯狂吃内存,最后 OOM 了? 这些问题,就像一个个幽灵,盘旋在许多 Gopher 的脑海里。我们似乎懂 context,但又好像只懂它的皮毛。这种“半懂不懂”的状态,在平时或许相安无事,但在复杂的生产环境中,往往就是那个导致服务雪崩的“致命稻草”。 说实话,我曾经也为此挣扎了很久。 我读过官方文档,写过零散的学习体会博客,但总感觉知识是碎片化的。直到我下定决心,从 context 诞生的“前世”开始,一路追溯到它的源码“心脏”,再回到真实世界的“最佳实践”和“天坑”现场,我才终于将这些碎片拼成了一幅完整的、清晰的地图。 那一刻,我豁然开朗。 原来 context 的设计如此精妙,它用最简单的接口,解决的是 Go 并发编程中最核心的两个难题:生命周期控制和数据传递。它就是 [...]
本文永久链接 – https://tonybai.com/2025/09/14/code-complete-with-steve-mcconnell 大家好,我是Tony Bai。 二十年前,Steve McConnell 的《代码大全》(Code Complete 2nd) 以其近 900 页的体量,成为软件工程领域一座难以逾越的丰碑。二十年后,它依然是无数工程师书架上的必备经典。在一场深度的访谈(https://www.youtube.com/watch?v=iPKmcLxuS_A)中,McConnell分享了这部巨著背后的故事、对职业发展的深刻洞见,以及对 AI 时代的冷静思考。 尽管技术浪潮已更迭数代,但 McConnell 的核心思想依然闪耀着永恒的光芒。我从中提炼出三大“启示”,它们穿越了语言和工具的变迁,直指软件开发的本质,为每一位追求卓越的工程师提供了清晰的行动指南。 启示一:“软件构建”远不止编码,它是专业性的基石 访谈中,McConnell 反复强调一个核心概念:他所著述的领域是“软件构建” (Software Construction),而这远不止我们通常理解的“编码” (Coding)。这是一个至关重要的区分,是从业余爱好者迈向专业工程师的第一道分水岭。 软件构建是一个广阔的领域,它涵盖了详细设计、编码、调试、测试集成、可读性与长期维护等一系列与代码紧密相关的活动。 在 McConnell 看来,只关注“编码”的工程师,如同只知道砌砖的建筑工人;而懂得“软件构建”的工程师,则是在思考整面墙的结构、承重与美学。 这意味着,在你编写每一行代码之前和之后,都需要思考: 设计:这个函数或类的内部结构是否清晰、易于理解? 验证:我将如何测试这段代码,以确保它的正确性? 可读性:几个月后,我自己或同事还能轻松读懂这段代码吗? 维护性:我的实现是否为未来的修改和扩展留下了空间? 这个启示提醒我们,卓越的软件并非代码的堆砌,而是深思熟虑的“构建”过程的产物。 启示二:战略性构建你的生涯,而非随机“跳荷叶” 在访谈最发人深省的部分,McConnell 分享了他对抗职业生涯随机性的强大心智模型:“职业金字塔” (Career Pyramid) vs. “跳荷叶” (Lily Pad Hopping)。 “跳荷叶”:工程师们从一个项目跳到另一个项目,看似在不断学习新技术、接触新业务,但这些经历是零散的、不连贯的。年复一年,知识面变广了,但核心价值并未实现质的飞跃,因为这些努力“没有累积成任何东西”。 “职业金字塔”:这是一种战略性思维。将职业生涯视为一座需要亲手建造的金字塔,每一次选择——无论是学习一门技术,还是参与一个项目——都是在为这座金字塔添砖加瓦。所有努力都服务于一个长远目标,层层叠加,最终形成一个深厚、独特且极具价值的能力体系。 这个启示提醒我们要时常自省,有意识地规划你的成长路径,让每一次努力都成为你“职业金字塔”的一部分。 我当前的工作,是在随机跳向下一片看似新奇的荷叶,还是在为我的金字塔奠定坚实的基础? 我应该学习什么,才能让我的能力体系更加稳固和高耸? McConnell 给出了一个终极评判标准:“这个选择,能让我对我的组织或整个世界变得更有价值吗?” 启示三:AI 时代,工程师的终极价值是追求“完全正确” 面对 AI [...]
本文永久链接 – https://tonybai.com/2025/09/13/package-managers-are-evil 大家好,我是Tony Bai。 “包管理器是万恶之源 (Package Managers are Evil)。” 这句石破天惊的论断,出自Odin语言的创造者Ginger Bill最近发表的一篇博文。在一个npm install、pip install、go get已经成为开发者肌肉记忆的时代,这无异于一篇挑战整个现代软件开发基石的“檄文”。 对于我们这些深度依赖go mod的Gopher来说,这无疑也是一次直击灵魂的拷问。我们早已习惯了Go Modules带来的便利——它解决了版本锁定、依赖传递和可复现构建等核心问题,被公认为Go生态走向成熟的里程碑。但我们是否在享受便利的同时,也正在“自动化我们的依赖地狱”? Ginger Bill的这篇文章并非无的放矢的抱怨,而是一次对开发者文化、信任模型和软件工程第一性原理的深刻反思。让我们直面这次拷问,并以此为镜,重新审视我们与go mod的关系。 核心论点:包管理器是“依赖地狱的自动化” 首先,Ginger Bill做了一个关键的区分,他的矛头并非指向: 包(Packages): 代码组织单元。 仓库(Repositories): 发现和存储包的地方(如GitHub)。 构建系统(Build Systems): 编译和链接代码的工具。 他精准地将炮火对准了包管理器(Package Managers)的核心功能:自动化地下载、解析和处理依赖关系。 他认为,这正是问题的根源所在。“依赖地狱”(Dependency Hell)是一个真实存在的、困扰着所有大型项目的难题——成千上万个你并不真正了解的传递依赖,版本冲突、潛在的bug、未知的安全漏洞,共同构成了一个巨大的泥潭。 而包管理器的作用,就是“将这个通往地狱的过程自动化了”。 他辛辣地指出:“不是所有能被自动化的东西,都应该被自动化,尤其是依赖地狱。” 他的核心观点是,npm install或go get这种一键式的便利,剥夺了开发者一个至关重要的环节:思考。 “当你必须手动下载和集成一个库时,你会开始思考:‘我也许并不需要这个’,或者‘我可以用别的方式来实现’。当需要更新时,手动操作会迫使你变得非常小心。” 这种被刻意放慢的、充满“摩擦力”的过程,迫使开发者去审视每一个引入的依赖,将其视为一个严肃的决策,而不是一次随意的命令行敲击。 Go的悖论:一个“幸免于难”的生态? 有趣的是,在Ginger Bill的批判中,Go被作为一个相对正面的例子提及。他观察到,即便Go拥有一个内置的包管理器,但大多数Go开发者似乎并不需要引入大量的第三方包。 “通往地狱的入口似乎又远又难走。” 为什么Go生态在一定程度上抵御了其他生态(如JavaScript)中那种失控的依赖爆炸?答案在于Go语言的设计哲学:“自带电池”(Batteries Included)。 Go拥有一个极其强大和全面的标准库。你想构建一个高性能的Web服务器?net/http就在那里。你需要处理JSON、加密、模板或者并发?标准库为你提供了一流的、经过实战检验的工具。你甚至可以在标准库里找到一个完整的Go编译器。 这种设计极大地降低了对外部微小、功能单一的“工具包”的依赖。当标准库就能满足80%的需求时,开发者自然不会像在其他生态中那样,为了实现一个最基本的功能(比如left-pad)就去引入一个外部依赖。 然而,这并不意味着Go开发者可以高枕无忧。go mod依然是一个强大的自动化工具,当我们开始引入大型框架(如Gin、GORM)或复杂的SDK时,我们同样面临着瞬间引入数十甚至上百个传递依赖的风险。 每一个依赖,都是你签下的一份“责任状” 文章中最深刻的观点之一,是对“依赖”一词含义的重新诠释。 “在现实生活中,当你有一个依赖时,你要对它负责。如果你的孩子或你的公司做错了事,你可能会因此进监狱。包依赖与此相去不远,但人们却在几乎没有任何验证的情况下就信任了它们。” [...]
本文永久链接 – https://tonybai.com/2025/09/12/go-constructor-pattern-guide 大家好,我是Tony Bai。 Go 语言的设计哲学崇尚简约与直白(straightforward)。其中,结构体字面量 (Struct Literal) 的存在,让我们可以用极其简单的方式创建数据结构。然而,在构建大型、复杂的系统时,这种简单性也可能成为一把双刃剑。当一个对象的创建需要满足特定前置条件、执行复杂初始化或强制执行业务规则时,我们便需要一个更强大、更可控的工具。 这个工具,就是 Go 语言中地道 (Idiomatic) 且被广泛采用的“构造模式”,通常以工厂函数(New或NewXXX)的形式出现。 在本文中,我们就来系统性地说明一下Go语言构造模式的必要性、核心应用场景,并探讨其在实践中的关键决策点,如指针与值的选择。 Go 的“构造模式”:一个约定俗成的工厂函数 首先,我们必须明确一个基本事实:Go 语言在语法层面并没有内置“构造函数” (Constructor) 的概念。它不像许多面向对象语言那样,拥有在实例化时被自动调用的特殊方法。在 Go 的世界里,我们通过一种广为流传且极为有效的设计模式来达到同样的目的。 这个模式就是遵循 New… 命名约定的工厂函数 (Factory Function)。它的核心职责是封装创建逻辑,并返回一个特定类型的、立即可用的实例。让我们通过一个具体的例子,来看看这个模式在代码中是如何体现的。 // 这不是语言特性,而是一个遵循“构造模式”的工厂函数 func NewUser(name string, age int) (*User, error) { if age < 18 { return nil, errors.New("user must be at least 18 years old") } [...]
本文永久链接 – https://tonybai.com/2025/09/11/microsoft-is-getting-rusty 大家好,我是Tony Bai。 近日,微软 Azure CTO、技术巨擘 Mark Russinovich 在一场 Rust 技术会议上发表了闭幕演讲,以前所未有的坦诚和力度,揭示了微软内部正在进行的一场深刻的技术变革:全面拥抱 Rust,并战略性地替代 C/C++。 他不仅分享了 Rust 在 Windows 内核、Office、Azure 云等核心产品中的惊人实践案例,还首次披露了微软正在研发的、利用 AI 大模型自动将 C/C++ 代码转换为安全 Rust 的前沿工具。这既是一次技术分享,也是一份来自行业顶层的宣言。 在这篇文章中,我们就来看看微软在走向Rust的路上究竟做了哪些工作和改变,用户和社区的反馈又是如何。 战略驱动:为何微软必须转向 Rust? 演讲开篇,Mark Russinovich 就抛出了一个触目惊心的数据,这也是驱动微软进行这场变革的根本原因: 在过去十几年中,微软所有产品中 70% 的安全漏洞,均由 C/C++ 中的内存安全问题导致。 他直言,这种趋势仍在继续,这已不仅仅是技术债,更是持续不断的安全事件和威胁。正是基于此,他个人早已成为 Rust 的坚定拥护者,并分享了一段有趣的往事:2022年,他在看到编程语言排行榜后,有感而发地发布了一条推文——“是时候停止在任何新项目中使用 C/C++ 了,业界应该转向 Rust”。 这条推文成为了他有史以来互动量最高的内容,甚至引来了微软 CEO Satya Nadella 的电话询问。而他的回答坚定不移:“是的,我坚信如此。” 这并非一时冲动,而是一场席卷微软的、自下而上与自上而下相结合的运动。从美国国家安全局 (NSA) 呼吁业界放弃内存不安全的语言,到微软自身因不安全代码被攻击后发起的“安全未来倡议 (Secure Future Initiative)”,微软上下已经形成共识:必须摆脱不安全的语言。 [...]
本文永久链接 – https://tonybai.com/2025/09/11/gophercon-2025-contributor-summit-notes 大家好,我是Tony Bai。 GopherCon 2025 贡献者峰会刚刚落下帷幕。在这场Go核心团队与全球顶尖贡献者齐聚一堂的闭门会议中,Go语言的未来方向被激烈地讨论和塑造。这些讨论或许不像发布泛型那样惊天动地,但它们如同地壳深处的板块运动,深刻地影响着Go生态的未来走向——一个更加成熟、务实,并决心直面企业级开发真实痛点的Go正在到来。 在这篇文章中,我深入研读了这份信息密度极高的会议纪要,为你提炼并解读了其中与每位Gopher息息相关的四大核心动向,希望可以帮助大家了解Go语言的下一步进化方向。 动向一:依赖管理的“中年危机”与应对之道 “你是否也曾被Kubernetes的依赖搞得焦头烂额?” 随着Go在大型项目中的广泛应用,曾经被引以为傲的Go Modules也开始面临“中年危机”。依赖管理,尤其是处理大型、复杂项目中的破坏性变更,已从社区的零星抱怨,正式升级为贡献者峰会的核心议题。 痛点:当生态系统足够庞大 会议中,来自Kubernetes等大型项目的贡献者明确指出,他们在升级Go版本和依赖时正经历巨大痛苦。例如,zap等核心日志库最近的仓库迁移引发了棘手的“菱形依赖”问题;而golang.org/x系列库为了快速跟进Go的最新特性,频繁提升其要求的Go版本,也给下游项目带来了巨大的维护压力和“升级多米诺”效应。 这些问题标志着Go生态已经进入了一个新的阶段:简单的go get -u已不足以应对庞大、交错的依赖网络。 探索的解决方案 Go团队和社区贡献者正从多个维度探索解决方案,虽然没有银弹,但方向已逐渐清晰: 更智能的弃用警告:目前,在代码中添加// Deprecated:注释来标记弃用API的方式有些“脆弱”,如果格式稍有不慎(例如没有另起一段),工具就无法识别。未来可能会通过go vet检查来强制执行正确的格式,或者放宽解析规则,确保弃用信息能被稳定传达。 go.mod元数据增强:一个极具前瞻性的讨论是,是否可以在go.mod文件中加入“路径转发”元数据。这样,当一个模块的导入路径发生变更时(如从github.com/org/repo迁移到github.com/new-org/repo),旧的go.mod文件可以明确指示工具去新的地址寻找,从而以一种声明式的方式解决仓库迁移带来的依赖中断问题。 推广强兼容性保证:社区呼吁更多核心库能像k8s.io/utils一样,提供明确且严格的向后兼容性保证。一个激进但有趣的想法是,如果企业开始资助这些开源项目,并将“不破坏兼容性”作为资助的条件之一,或许能形成一种更强有力的约束。 解读:Go生态正从“野蛮生长”的青春期,步入需要精细化治理的成熟期。Go团队正严肃对待这些大型项目遇到的真实痛点,未来的工具链和最佳实践,将更加关注稳定性和可预测性,而非仅仅是功能的增加。 动向二:crypto/tls迎来“配置文件”时代,告别选择困难 Go标准库的crypto/tls包功能强大,但其约15个核心配置选项(密码套件、TLS版本、椭圆曲线等)的组合,对于非密码学专家来说,无疑是一个巨大的心智负担。如何配置出一个既安全又具备良好兼容性的TLS客户端或服务器,一直是一个难题。 峰会上的讨论,为这个问题带来了一个“大道至简”的解决方案:引入TLS Profiles(配置文件)。 “陈述你的目标,而非你的手段” 这个想法的核心,是改变配置TLS的思维模式。开发者未来可能不再需要去手动挑选每一个密码学参数,而是向标准库“陈述你的目标”。 什么是TLS Profile? 它是一套预先定义好的、经过专家审核的配置集合。例如,可能会有: ModernProfile: 提供最高级别的安全性,可能只支持TLS 1.3和最新的加密算法。 CompatibleProfile: 在保证安全性的前提下,兼顾对一些老旧客户端的兼容。 FIPS140Profile: 严格遵循美国联邦信息处理标准140,适用于政府和金融等高合规性场景。 CNSA2.0Profile: 遵循美国国安局的下一代加密标准。 如何使用? 开发者只需在tls.Config中设置一个字段,如Profile: tls.ModernProfile。标准库会根据这个Profile,自动为你配置好所有底层的密码学细节。 动态演进:这些Profiles将是“活”的。随着Go版本的更新,ModernProfile可能会自动引入更安全的算法,并淘汰那些已被发现存在漏洞的旧算法。这意味着,你的应用安全级别可以随着Go的升级而自动提升。 解读:这是Go“约定优于配置”和“让正确的事情变得容易”哲学的又一次精彩体现。通过将复杂的安全决策封装成几个简单的高级选项,Go极大地降低了开发者犯错的概率,将安全变成了默认选项。这对于整个互联网的安全都是一件好事。 动向三:项目治理进化,提案流程走向透明与协作 随着Go社区的日益壮大,原有的语言变更提案流程(Proposal Process)正面临巨大的压力。许多社区成员反映,提案提交后如同石沉大海,其审阅状态不透明,处理周期漫长,这极大地挫伤了社区的贡献热情。 峰会上,Go团队坦诚地面对了这一治理瓶颈,并提出了一系列改革思路,旨在让Go的治理模式更加透明、高效和可扩展。 队列透明化:Go团队正在探索如何让积压了数百个提案的队列状态更加公开透明,让贡献者能知道自己的提案处于哪个阶段。 任务小组/委员会制度:对于像jsonv2、collections这样重大而复杂的提案,Go团队正在试验性地建立专门的“任务小组”(Task [...]
本文永久链接 – https://tonybai.com/2025/09/10/happy-teachers-day-2025 大家好,我是Tony Bai。 今天一早,收到了来自极客时间的教师节贺卡,当看到上面那一行数字时,内心瞬间被温暖与感动填满: 与极客时间相遇的第 5 年,累计已有 25220 位用户加入了我的 Go 语言课程。 我从未想过,自己能以“老师”的身份,通过《Go语言第一课》和《Go语言进阶课》这两个专栏,陪伴这么多 Gopher 走过他们学习路上的日日夜夜。 这 25220 份订阅,对我而言绝不仅仅是一个数字,它代表着 2.5 万份沉甸甸的信任、以及无数次的提问、探讨与反馈。是你们,让我这位“老师”的布道之路,充满了意义和价值。 这份认可,是我在这个特别的日子里,收到过的,最好的教师节礼物。 也正是带着这份信任与责任,我与人民邮电出版社的老师们,将这份经过数万人检验的《Go语言第一课》精心打磨成册。 如果说专栏是我们在线上的初遇,那这本《Go语言第一课》纸质版,便是我为大家准备的一份更系统、更完善、更触手可及的“课堂笔记”。 祝所有在技术道路上探索的同行者们,教师节快乐!愿我们都能在学习与分享中,成为更好的自己。 商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。 © 2025, bigwhite. 版权所有.
本文永久链接 – https://tonybai.com/2025/09/10/introducing-the-mcp-registry 大家好,我是Tony Bai。 近日,模型上下文协议 (Model Context Protocol, MCP)官方发布了其生态系统的核心基础设施:MCP 注册中心 (MCP Registry)的预览版。这个开放的、分布式的目录服务不仅为 MCP 服务器的发现与实施提供了“单一事实来源”,更值得我们 Go 开发者关注的是,Go 语言在其中扮演了从官方工具链到客户端集成的关键角色。 MCP 注册中心:AI 感知应用的“中央应用商店” 在深入探讨 Go 的角色之前,我们首先需要理解 MCP 注册中心是什么。简单来说,你可以将它想象成一个专为 MCP 服务器打造的、分布式的“应用商店”或“包管理器”。 在此之前,MCP 服务器的发现和使用依赖于零散的社区列表或口口相传。MCP 注册中心的发布,旨在解决这一核心痛点,其目标是: 标准化发现与分发:为公开可用的 MCP 服务器提供一个集中、开放的目录和 API,让客户端能轻松找到并连接它们。 构建可信的“单一事实来源”:作为官方的上游数据源,所有 MCP 服务器的维护者都可以将他们的服务信息发布于此。 支持联合生态 (Federated Ecosystem):它不仅是一个中心化的服务,更鼓励社区和企业基于官方数据构建自己的子注册中心 (subregistry)。这些子注册中心可以根据自身需求,对上游数据进行筛选、增强(例如增加安全扫描评级、兼容性信息)和分发,从而形成一个既统一又多元的生态系统。 这种“中心化上游 + 联合化下游”的设计,为公共“MCP 市场”和有严格安全要求的私有企业部署提供了极大的灵活性。 Go 的角色:从官方 CLI 到 API 客户端 那么,Go 在这个新兴生态中处于什么位置?答案是:核心。Go 不仅是推荐的实现语言之一,更是官方钦定的核心工具链的构建者。 [...]
本文永久链接 – https://tonybai.com/2025/09/09/the-power-of-ten-in-go 大家好,我是Tony Bai。 在软件工程领域,有些智慧是永恒的。 2006 年,NASA/JPL(喷气推进实验室)的 Gerard J. Holzmann 公布了其团队用于开发安全关键 (Safety-Critical) 软件的十条黄金法则——“The Power of Ten: Rules for Developing Safety-Critical Code”。这些规则诞生于 C 语言主导的嵌入式世界,旨在为火星车、深空探测器等“不容有失”的系统构建坚不可摧的代码基石。 近二十年过去了,我们迎来了云原生和人工智能时代,那么,这些看似“古老”且严苛的 C 语言法则,在如今的世界里过时了吗?还是说,它们的核心思想能够穿越时空,赋予我们Gopher构建更健壮、更可靠的 Go 程序的全新视角? 今天,就让我将这十条“诫律”嫁接到 Go 语言上,看看它们在今天究竟意味着什么。 规则 1:限制使用复杂的控制流 C 语言的意图: 禁用 goto、setjmp/longjmp 和递归,确保代码路径清晰、可预测、易于静态分析。goto 和 longjmp 会制造出难以追踪的“意大利面条式代码”,而无限递归则会导致栈溢出。 Go视角下的“新意”: Go 保留了 goto,但社区共识是“能不用就不用”。而 setjmp/longjmp 的现代对应物——panic/recover,Go 官方也明确指出它应用于处理真正的“异常”情况(如程序内部出现不可恢复的错误),而非用作常规的控制流。这条规则在 Go 中的新解读是:严格区分错误处理与异常处理,不要滥用 panic 来替代错误返回。 此外,禁止递归对于 C [...]
本文永久链接 – https://tonybai.com/2025/09/08/fanren-xiuxian-programmer-levels 大家好,我是Tony Bai。 最近《凡人修仙传》的电视剧大火,想必各位道友都有耳闻。鄙人也没忍住,不仅刷完了杨洋主演的网剧,还趁着这股热乎劲儿,一口气在微信读书连读再听地补完了小说的人界篇。 当看到韩立资质平平,相貌普通,却凭着“小绿瓶”、远超常人的心智和不懈的努力,在残酷的修仙界中,历经炼气、筑基、结丹、元婴,终至化神时,我猛然拍案: 这不就是我们程序员升级打怪的真实写照吗?! 仔细一想,还真是如此。在这“码农”修仙界,人人皆望飞升,脱离 CRUD 的苦海,证得架构大道。韩天尊从一介凡人,在人界一步步逆天修行;我们则从一行“Hello World”开始,在代码的世界里摸爬滚打。从初窥门径到执掌乾坤,其间的艰辛与突破,又何尝不是一场惊心动魄的修行? 今日,不妨让我们借韩天尊的人界飞升之路,一同探寻这程序员的修仙境界。看看你我,如今身在何处,又该如何“破境”飞升。 第一境:炼气期 – 程序员学徒 炼气期 此境界的修士初入仙门,刚刚感应到“天地灵气”(编程语言),开始学习吐纳之法(基础语法)。灵力微薄,法术生疏,面对浩如烟海的功法秘籍(API文档),常常感到力不从心,一不小心就可能“走火入魔”(写出 Bug)。 境界特征: 初窥门径,灵力微薄: 刚掌握一门或多门“功法”(Java/Python/Go),但理解不深。能写出基础的业务逻辑,但对底层原理一知半解,如同只会念咒却不知其所以然。 修炼功法,打牢根基: 每日勤修不辍,疯狂“吸收灵石”(看文档、刷 LeetCode、学习框架)。主要任务是完成导师(Mentor)分配的“宗门任务”(小功能、Bug修复),以此换取修炼资源。 依赖法器,难离其身: 严重依赖各种“低阶法器”,如 Stack Overflow、CSDN 和各类 AI 代码助手。一旦“法器”失灵(断网),便束手无策,战力大减。 心魔与瓶颈: 最大的心魔是“我是不是不适合写代码”的自我怀疑。常常会遇到“瓶颈”,一个简单的 Bug 可能要耗费数日才能解决,此时急需一颗“筑基丹”(高人指点)方能突破。 第二境:筑基期 – 合格的工程师 筑基期 经历无数次“走火入魔”后,终于炼化灵气,开辟丹田,成功“筑基”,体内的“灵力”(知识体系)凝聚成形。从此,你不再是修仙界的炮灰,而是一名真正的修士,可以独立执行任务,在宗门(团队)中有了一席之地。 境界特征: 筑基成功,道途有望: 能够独立负责一个模块或一条业务线。对团队的技术栈了如指掌,是项目的中坚力量,道基稳固。 拥有本命法器: 不再是见什么用什么,而是有了自己得心应手的“本命法器”(精通的框架或工具链),如 Spring 全家桶、Vue/React 生态。使用起来得心应手,威力倍增。 神识初成,洞察秋毫: 开始具备一定的“神识”(Code Review 能力和设计嗅觉),能发现炼气期修士代码中的明显问题,并预见一些潜在的风险,如同神识外放,探查四周。 独立执行宗门任务: 可以独立外出执行有一定难度的“宗门任务”(负责一个完整需求),并能顺利归来,不再需要师兄寸步不离地看护。 [...]
本文永久链接 – https://tonybai.com/2025/09/07/the-power-of-an-interface-for-performance 我的《Go语言第一课》已上市,赠书活动正在进行中,欢迎点击此链接参与。 大家好,我是Tony Bai。 我们通常如何看待性能优化?答案往往是:更快的算法、更少的内存分配、更底层的并发原语、甚至用SIMD指令压榨CPU的每一个周期。我们痴迷于“引擎盖之下”的实现细节,坚信更好的代码和更强的硬件能带来更高的性能。 然而,TigerBeetle数据库创始人Joran Dirk Greef在Strange Loop上的一场精彩的演讲(https://www.youtube.com/watch?v=yKgfk8lTQuE),用一场耗资百万美元的数据库比赛,颠覆了这一传统认知。他通过无可辩驳的基准测试数据证明:在分布式系统中,接口(Interface)的设计,而非代码实现或硬件堆砌,才是决定性能上限的真正瓶颈。 在深入探讨之前,我们必须对本文的“接口”一词进行关键澄清。对于Go开发者而言,“接口”通常指代语言层面的interface类型,一种实现行为契约以及多态的工具。但本文中所说的“接口”,则是一个更宏观、更广义的概念,它指的是系统与系统之间、或用户与系统之间进行通信的交互模式、契约与协议。你的REST API设计、gRPC的.proto文件、微服务间的调用时序,都属于这个“广义接口”的范畴。 这场演讲虽然以数据库为载体,但其揭示的“接口即天花板”的原理,对于每一位设计和使用Go API、微服务的工程师来说,都无异于一声惊雷。它迫使我们重新审视,我们日常构建的系统,是否在设计之初,就已为自己埋下了无法逾越的性能枷锁。 赛场设定:一场关于“转账”的终极对决 Greef的实验设计极其巧妙,他回归了OLTP(在线事务处理)的本质,重拾了图灵奖得主Jim Gray定义的最小交易单元:“借贷记”(Debit-Credit),即我们熟知的“转账”操作。 这个工作负载的核心是:在两个账户之间转移价值,并记录一笔历史。它的关键挑战在于竞争(Contention)。在高流量的真实世界系统中,总会有大量的交易集中在少数“热门”账户上,这就是帕累托法则(80/20原则)的体现。 传统接口:交互式事务 大多数通用数据库处理这种事务的标准接口是“交互式”的,即一个业务操作需要多次网络往返才能完成: 1. 第一步(读):客户端发起一个网络请求,SELECT Alice和Bob的账户余额。 2. 第二步(计算):数据返回到客户端,应用代码在本地检查余额是否充足。 3. 第三步(写):客户端发起第二个网络请求,在一个事务中UPDATE两个账户的余额,并INSERT一条转账记录。 这个看似天经地义的流程,隐藏着一个致命的缺陷。 百万美元的“滑铁卢”:当硬件和实现都失灵 Greef设立了三组“选手”来进行一场性能对决: Postgres (单机): 经典的、备受尊重的开源数据库。 “迈凯伦” (16节点集群): 一个匿名的、顶级的云原生分布式数据库,年费超过一百万美元。 TigerBeetle: Greef自己设计的、专为OLTP优化的新一代数据库。 比赛结果令人瞠目结舌: 在零竞争下,“迈凯伦”集群的性能甚至不如单机Postgres。 随着竞争率提升,16台机器的“迈凯伦”性能暴跌,甚至出现了节点越少、性能越高的荒谬情况。 在整个高竞争测试期间,这百万美元硬件的CPU利用率从未超过12%。 为什么? 硬件在空转,代码在等待。钱,并没有买来性能。 性能的枷锁:跨网络持有锁 问题的根源,就出在那个“交互式事务”的接口设计上。 当一个事务开始时,数据库为了保证ACID,必须锁定被操作的行。在这个接口模型中,锁的持有时间 = 数据库处理时间 + 两次网络往返(RTT)的时间 + 客户端应用的处理时间。 Greef指出,数据库内部的处理时间可能是微秒级的,但一次跨数据中心的网络往返,轻易就是几十甚至上百毫秒。这意味着,数据库中最宝贵的锁资源,其生命周期被廉价且缓慢的网络I/O牢牢绑架了。 [...]
本文永久链接 – https://tonybai.com/2025/09/06/gopher-pseudocode-translation-guide 大家好,我是Tony Bai。 你是否曾在阅读顶会论文时,感觉其中的算法描述像一本晦涩难懂的“天书”?那些看不太懂的数学符号、奇特的箭头和看似代码又无法编译的语句(如下图),是不是常常让你望而却步,感叹理论与实践之间隔着一道鸿沟? 别担心,这不是你的问题。你遇到的正是连接学术象牙塔与工程世界的桥梁——伪代码 (Pseudocode)。它并非一门具体的编程语言,而是算法世界的“通用语” (Lingua Franca),旨在剥离所有语言特定的语法噪音,只保留逻辑的纯粹核心。 对于我们工程师而言,掌握伪代码的阅读技巧,就像是学会了一门新的“翻译”艺术。这门艺术能让你直接与算法设计者的思想对话,将世界上最聪明的头脑的智慧,转化为你手中坚实、高效的主流编程语言的代码。 本文就是你的学术伪代码“翻译”指南。我们将从最基础的符号“字母表”开始,探索不同风格的伪代码“文体”,通过完整的“翻译”实战,让你最终不仅能读懂,更能欣赏伪代码之美,并自信地将任何算法“天书”都转化为优雅的编程语言实现(本文将以Go语言为例)。 罗塞塔石碑 —— 破译伪代码的核心符号 任何翻译工作都始于对基本词汇的掌握。伪代码的符号系统虽然看似五花八门,但其核心元素却非常稳定。让我们一同来构建我们的“罗塞塔石碑”,将最常见的伪代码符号与 Go 语言进行映射。 1. 赋值操作: ← (The Left Arrow) 这是伪代码最具标志性的符号,代表赋值。 伪代码: max_val ← A[0] i ← 1 为什么用 ← 而不是 =? 为了在学术上严格区分赋值 (Assignment) 和 相等判断 (Equality Test)。在算法和数学语境中,= 通常是逻辑断言,表示“等于”。← 则清晰地表达了“将右边的值赋予左边变量”这一动作,杜绝了歧义。 Go “译文”: maxVal := A[0] // 声明并赋值 i := 1 // [...]
本文永久链接 – https://tonybai.com/2025/09/05/go-proxy-revise-background-refresh-pacing 大家好,我是Tony Bai。 2025年8月14日,Go开发者Ted Unangst发表了一篇措辞犀利的博文——《What is the go proxy even doing?》。他用服务器日志作为证据,公开质疑Go官方模块代理(proxy.golang.org)对其个人代码托管服务humungus.tedunangst.com产生了“洪水般”的、看似毫无意义的巨大流量。这个事件迅速在社区发酵,将一个通常在后台默默工作的核心基础设施,推上了风口浪尖。当然在我的印象中,这已经不是Go社区第一次“抱怨” 官方Go proxy的“诡异”行为给一些小型站点带来的烦恼了。 不过不同的是,这次Go团队的前技术leader、核心成员Russ Cox (rsc) 迅速响应,在Go的官方issue追踪系统中创建了两个关键问题(#75120 和 #75191),不仅承诺调查并解决问题,更罕见地、极其详尽地公开了Go Module Proxy的内部工作原理、缓存策略以及导致此次事件的深层原因。 这场由一篇博文引发的“悬案”及其官方复盘,为我们提供了一个绝佳的机会,去深入理解Go Module Proxy这个我们每天都在使用,却又知之甚少的系统。它背后的“背景刷新”机制,究竟是为了提升开发者体验的“优化”,还是在某些边缘情况下会演变成对小型开源社区的“DDoS”? 事件回顾:来自小型服务器的“呐喊” Ted Unangst的博文主要控诉了以下几个现象: 持续的背景流量:即使没有任何新版本发布,proxy.golang.org也会以几分钟一次的频率,持续尝试从他的服务器hg clone(克隆)多个仓库。由于他的服务器设置了24小时内只允许一次克隆的速率限制,这些请求大多被429 Too Many Requests拒绝,但在日志中形成了持续的“背景辐射”。 “惊群效应”(Thundering Herd):当他推送一个新版本(一个新tag)并本地执行go mod tidy后,短短14秒内,他的服务器就遭到了来自Google不同IP地址的、数十个并发的hg clone请求。他将其形容为“洪水来了”。 低效的拉取策略:Proxy每次都执行完整的hg clone,而不是更高效的hg pull,这对于非Git的VCS(版本控制系统)来说,意味着巨大的带宽浪费。 Unangst的质疑直击要害:“为什么你们要这样构建一个分布式系统?……难道Google认为从我的服务器下载比从他们自己的云存储下载更便宜吗?” Go官方的深度复盘:揭开代理的神秘面纱 Russ Cox的官方回应堪称透明沟通的典范。他不仅承认了问题的存在,还详细解释了Proxy的设计理念和实现细节,让我们得以一窥其内部运作。 Go Module Proxy的核心目标 可用性与可靠性:作为Go生态的中央缓存,确保开发者在任何上游代码仓库宕机时,依然能获取到模块。 降低延迟:通过主动的背景刷新,提前将热门或近期被访问过的模块信息更新到缓存中,使得开发者在执行go get等命令时,能立即获得响应,而不是等待Proxy实时回源。 缓存与刷新策略的权衡 Proxy缓存多种类型的数据,每种都有不同的刷新策略,而这些策略正是问题的根源: 模块Zip包: [...]
本文永久链接 – https://tonybai.com/2025/09/04/simple-is-not-easy 大家好,我是Tony Bai。 在软件工程领域,有些演讲如同灯塔,其光芒足以穿透时间的迷雾,持续为后来者指引方向。Clojure语言的创造者Rich Hickey在2011年的Strange Loop大会上发表的“Simple Made Easy”,正是这样一例。他以一种近乎哲学家的思辨,对我们行业中最被滥用、最被误解的两个词——“简单”(Simple)和“容易”(Easy)——进行了本源性的解构。 时至今日,这场演讲对于以“简单”著称的Go语言社区,依然具有重要的警示意义。我们常常自豪于Go的语法“简单”,工具链“容易”上手,但我们追求的,究竟是真正的“简单”,还是仅仅是表面的“容易”? 本文将和你一起重温Hickey的这场经典演讲,并结合Go语言的实践,提炼出每一位Gopher都应该深刻理解的五个核心道理。这既是对一个经典演讲的回顾,更是一次对我们日常编码决策和技术选型标准的反思。 道理一:精确你的词汇——“简单”与“容易”是两回事 Hickey的第一记重拳,就砸向了我们混乱的词汇表。他从词源学出发,为这两个概念划定了清晰的界限: 简单 (Simple):源于拉丁语sim-plex,意为“一个褶皱”或“一股编绳”。它的反义词是复杂 (Complex),意为“交织、缠绕在一起”。因此,“简单”描述的是事物的内在状态,关乎其是否存在交织和纠缠。它是一个客观属性。 容易 (Easy):源于拉丁语adjacens,意为“靠近的、在旁边的”。它的反义词是困难 (Hard)。因此,“容易”描述的是事物与我们的相对关系,关乎其是否与我们的认知、技能或工具相近。它是一个相对概念。 这个区分至关重要。当我们说“我喜欢用Go,因为它很简单”时,我们真正的意思往往是“它对我来说很容易”,因为: 它很熟悉 (Familiar):它的语法类似C,没有复杂的泛型或宏。 它很就手 (At hand):安装方便,工具链开箱即用。 Hickey警告说,我们整个行业都对“容易”——尤其是“熟悉”和“就手”——有一种不健康的迷恋。这种迷恋让我们倾向于选择那些看起来像我们已知事物的东西,从而拒绝学习任何真正新颖但可能更简单的东西。 对于Go开发者:我们需要警惕,不要将Go的“语法简洁”(一种形式上的“容易”)与系统的“结构简单”划等号。一个用简洁语法写成的、充满了全局状态和隐式依赖的Go程序,其本质是复杂的。 道理二:警惕“容易”的复杂性——状态、对象与继承的陷阱 Hickey指出,许多我们认为“容易”的编程范式,恰恰是复杂性的最大来源,因为它们将不同的关注点“编织”在了一起。 1. 状态(State)是万恶之源 var x = 1; x = 2; 这种可变状态,在Hickey看来,是软件中最根本的“交织”——它将值(Value)与时间(Time)紧密地缠绕在一起。你永远无法在不考虑时间点的情况下,获得一个确定的值。 对于Go开发者:虽然Go不是一门纯函数式语言,但我们应该在力所能及的范围内,尽量推崇不可变性。 优先使用值传递:对于小型结构体,按值传递而非指针传递,可以避免意外的副作用。 警惕共享的可变状态:在并发编程中,与其用sync.Mutex保护一堆共享的可变数据,不如思考如何通过channel传递不可变的“消息”,从根本上消除状态的交织。 2. 对象 (Objects) 是复杂性的打包机 传统的面向对象编程,将状态、身份(Identity)和值这三个独立的概念打包进了一个叫做“对象”的东西里。你无法轻易地将它们分开处理。 对于Go开发者:Go在这一点上做得相对出色。Go的struct更接近于纯粹的数据聚合(C-style struct),而不是带有复杂继承体系和封装状态的“对象”。我们应该保持并发扬这一优点: 让Struct保持简单:让它专注于承载数据。 将行为(方法)与数据分离:Go的方法是附加在类型上的函数,而非封装在对象内部。这鼓励我们编写更多无状态的、可测试的纯函数来处理数据。 3. 继承 (Inheritance) [...]
本文永久链接 – https://tonybai.com/2025/09/03/gopher-first-lesson-to-big-factory 大家好,我是Tony Bai。 很多计算机专业的同学们都在问:想进大厂,要先学好哪门编程语言? 从应用广泛程度来说,学好Go语言肯定错不了!我们来看一下大厂们都用Go在做哪些开发: 阿里用于基础服务、网关、容器、服务框架等开发。 字节跳动用于即时通信(IM)、K8s、微服务等开发。 腾讯用于微信后台、云服务、游戏后端等开发。 滴滴用于数据平台、调度系统、消息中间件等开发。 此外,美团、百度、京东、小米等都在业务中大量使用Go语言做开发。可见,同学们只要玩转Go语言,大厂都会张开双臂欢迎你们。 大厂为何如此青睐Go语言呢?有三点重要原因: 简单易上手: Go语法简洁,学习成本低,代码易维护; 生产力与性能有效结合: Go拥有卓越的并发性能,内置调度器和非抢占式模型,保证了超高的稳定性; 使用快乐且前景广阔: 优良的开发体验,包括得心应手的工具链、丰富健壮的标准库、广泛的社区支持等。 总的来说,Go相对于C/C++,性能并没有明显差距,可维护性还更好;相对于Python,Go性能大幅领先,入门难度则相差无几。 直通大厂,同学们请看《Go 语言第一课》这本书,书中详细介绍了Go的设计哲学与核心理念,全面讲解了Go的重要语法特性。没有基础也完全不必担心,本书手把手式教学,小白立即轻松上手。 扫描上方二维码,即可五折购书(在有效期内) 现在,让我们进入课堂,开始Go语言学习的第一课吧。 Part.1 零基础起步,Go开发全掌握 本书为读者设计了一条循序渐进的学习路线,可以分为三个部分。 首先讲述Go语言的起源与设计哲学; 然后说明开发环境的搭建方法; 最后详细介绍Go的重要语法与语言特性,以及工程实施的一些细节。 初次学习Go开发的同学们一定要注意,动手实践是学习编程的不二法门,在进入第二部分学习时,就要根据书中内容同步搭建实验环境,一步一个脚印地走稳走好。 Go的设计哲学 本部分先介绍了Go语言在谷歌公司内部孵化的过程,描述了其在当今云计算时代的广泛应用。 Go的第一版官网 重点说明了Go的5个核心设计哲学: 简单: 仅有25个关键字,摒弃了诸多复杂的特性,便于快速上手; 显式: 要求代码逻辑清晰明确,避免隐式处理带来的不确定性; 组合: 通过类型嵌入提供垂直扩展能力,通过接口实现水平组合,灵活扩展功能; 并发: 原生支持并发,用户层轻量级线程,轻松支持高并发访问; 面向工程: 注重解决实际问题,围绕Go的库、工具、惯用法和软件工程方法,都为开发提供全面支持。 读者理解了Go的设计哲学就能明确它擅长的方向,澄清心中的疑问,也掌握了使用Go进行编程的指导原则。 Part.2 搭建Go开发环境 这部分先针对Windows、macOS、Linux三种主流操作系统给出了多种安装方法,包括使用安装包、使用预编译二进制包、通过源码编译,说明如何管理多个Go版本。 然后基于经典的“Hello World”示例,演示编译运行的方法,讲解Go的基本程序结构,包括包声明、导入包、main函数等内容。接着深入讲解Go包的定义、导入、初始化与编译单元。 // ch3/helloworld/main.go package main [...]
您可以订阅此RSS以获取更多信息