<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tony Bai &#187; Unix</title>
	<atom:link href="http://tonybai.com/tag/unix/feed/" rel="self" type="application/rss+xml" />
	<link>https://tonybai.com</link>
	<description>一个程序员的心路历程</description>
	<lastBuildDate>Sat, 11 Apr 2026 00:16:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>“退休”大佬的 AI 复出战：为了“好玩”，他写出了火遍全网的 Moltbot</title>
		<link>https://tonybai.com/2026/01/30/clawdbot-author-peter-steinberger-full-interview/</link>
		<comments>https://tonybai.com/2026/01/30/clawdbot-author-peter-steinberger-full-interview/#comments</comments>
		<pubDate>Fri, 30 Jan 2026 00:23:38 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AgenticCommerce]]></category>
		<category><![CDATA[AIAgent]]></category>
		<category><![CDATA[Autonomy]]></category>
		<category><![CDATA[Burnout]]></category>
		<category><![CDATA[ClaudeCode]]></category>
		<category><![CDATA[ClawdBot]]></category>
		<category><![CDATA[CLIFirst]]></category>
		<category><![CDATA[DataLiberation]]></category>
		<category><![CDATA[ffmpeg]]></category>
		<category><![CDATA[FirstPrinciples]]></category>
		<category><![CDATA[Foundation]]></category>
		<category><![CDATA[GUI]]></category>
		<category><![CDATA[LocalFirst]]></category>
		<category><![CDATA[MacMini]]></category>
		<category><![CDATA[MacStudio]]></category>
		<category><![CDATA[Memory]]></category>
		<category><![CDATA[Moltbot]]></category>
		<category><![CDATA[Opensource]]></category>
		<category><![CDATA[PersonalDeveloper]]></category>
		<category><![CDATA[PeterSteinberger]]></category>
		<category><![CDATA[Privacy]]></category>
		<category><![CDATA[RPA]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[WalledGardens]]></category>
		<category><![CDATA[WhatsApp]]></category>
		<category><![CDATA[whisper]]></category>
		<category><![CDATA[个人开发者]]></category>
		<category><![CDATA[命令行优先]]></category>
		<category><![CDATA[围墙花园]]></category>
		<category><![CDATA[图形界面]]></category>
		<category><![CDATA[基金会]]></category>
		<category><![CDATA[工具使用能力]]></category>
		<category><![CDATA[开源]]></category>
		<category><![CDATA[数据解放]]></category>
		<category><![CDATA[智能体商业]]></category>
		<category><![CDATA[本地优先]]></category>
		<category><![CDATA[第一性原理]]></category>
		<category><![CDATA[职业倦怠]]></category>
		<category><![CDATA[自主性]]></category>
		<category><![CDATA[自动化流程]]></category>
		<category><![CDATA[长期记忆]]></category>
		<category><![CDATA[隐私]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=5792</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/mm/dd/clawdbot-author-peter-steinberger-full-interview 大家好，我是Tony Bai。 在硅谷，每天都有无数个 AI 项目诞生，它们大多有着精美的 Landing Page，有着宏大的融资计划，PPT 里写满了“颠覆行业”。 但最近，一个名为 Clawdbot（现已因商标原因更名为 Moltbot）的项目，却以一种完全不同的姿态闯入了大众视野。没有融资，没有团队，甚至没有商业计划书。它仅仅是一个“退休(财务自由)”的软件大佬，为了给自己“找乐子”而写的一堆代码。 然而，就是这样一个项目，在 GitHub 上一夜之间狂揽 3.2w+ Star，甚至让很多非技术圈的人都跑去 Apple Store 抢购 Mac Mini 来运行它。 它的作者是 Peter Steinberger，著名的 PDF SDK 提供商 PSPDFKit 的创始人。在卖掉公司退休四年后，他因为 AI 找回了当年的热血。 在最近的一次深度访谈中，Peter 毫无保留地分享了他开发 Moltbot 的全过程。这不仅是一个关于工具的故事，更是一份关于“在 AI 时代，个人开发者如何打破大厂垄断，重塑人机交互”的珍贵启示录。 从 Burnout 到 Addiction：找回失去的 Mojo 故事的开始并不美好。 四年前，Peter 卖掉了自己经营了 13 年的公司。长期的创业压力让他彻底 Burnout（职业倦怠）。 “那感觉就像有人把我的 Mojo（魔力/精力）吸干了一样。” 他回忆道。在那之后的三年里，他对编程完全提不起兴趣，哪怕只是坐在电脑前都觉得是一种折磨。 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/clawdbot-author-peter-steinberger-full-interview-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/01/30/clawdbot-author-peter-steinberger-full-interview">本文永久链接</a> &#8211; https://tonybai.com/2026/mm/dd/clawdbot-author-peter-steinberger-full-interview</p>
<p>大家好，我是Tony Bai。</p>
<p>在硅谷，每天都有无数个 AI 项目诞生，它们大多有着精美的 Landing Page，有着宏大的融资计划，PPT 里写满了“颠覆行业”。</p>
<p>但最近，一个名为 <strong>Clawdbot</strong>（现已因商标原因更名为 <strong>Moltbot</strong>）的项目，却以一种完全不同的姿态闯入了大众视野。没有融资，没有团队，甚至没有商业计划书。它仅仅是一个“退休(财务自由)”的软件大佬，为了给自己“找乐子”而写的一堆代码。</p>
<p>然而，就是这样一个项目，在 GitHub 上一夜之间狂揽 <strong>3.2w+ Star</strong>，甚至让很多非技术圈的人都跑去 Apple Store 抢购 Mac Mini 来运行它。</p>
<p>它的作者是 <strong>Peter Steinberger</strong>，著名的 PDF SDK 提供商 PSPDFKit 的创始人。在卖掉公司退休四年后，他因为 AI 找回了当年的热血。</p>
<p>在最近的<a href="https://www.youtube.com/watch?v=qyjTpzIAEkA">一次深度访谈</a>中，Peter 毫无保留地分享了他开发 Moltbot 的全过程。这不仅是一个关于工具的故事，更是一份关于<strong>“在 AI 时代，个人开发者如何打破大厂垄断，重塑人机交互”</strong>的珍贵启示录。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/paid/google-adk-in-action-qr.png" alt="" /></p>
<h2>从 Burnout 到 Addiction：找回失去的 Mojo</h2>
<p>故事的开始并不美好。</p>
<p>四年前，Peter 卖掉了自己经营了 13 年的公司。长期的创业压力让他彻底 <strong>Burnout（职业倦怠）</strong>。</p>
<p>“那感觉就像有人把我的 Mojo（魔力/精力）吸干了一样。” 他回忆道。在那之后的三年里，他对编程完全提不起兴趣，哪怕只是坐在电脑前都觉得是一种折磨。</p>
<p>直到 2025 年 4 月，一切改变了。</p>
<p>Peter 开始接触早期的 AI 工具，特别是 Claude Code 的 Beta 版。那一刻，他感到了久违的兴奋。</p>
<p>“如果你错过了前几年 AI 比较‘智障’的阶段，直接上手现在的工具，你会觉得——<strong>这简直太棒了（Pretty Awesome）！</strong>”</p>
<p>这种兴奋迅速转化为了一种“成瘾（Addiction）”。</p>
<p>但这是一种积极的成瘾。他开始熬夜写代码，甚至会在凌晨 4 点给朋友发消息讨论 AI 的新发现。为了给自己找点乐子，他甚至搞了一些极其荒谬的实验：</p>
<p>比如，他做了一个<strong>“全球最贵的闹钟”</strong>。</p>
<p>他让运行在伦敦服务器上的 AI Agent，通过 SSH 远程登录到他家里的 MacBook，然后自动调大音量来叫醒他。</p>
<p>“这听起来很疯狂，甚至有点杀鸡用牛刀，但这就是我的初衷——<strong>Have Fun（玩得开心）</strong>。”</p>
<p>Peter 认为，学习新技术的最好方式，就是把它当成玩具。当你不再为了 KPI 或融资而写代码，而是为了让 AI 帮你订一份外卖、回一条消息而折腾时，创造力才会真正涌现。</p>
<h2>技术哲学：CLI 是 Agent 的母语</h2>
<p>Moltbot 之所以能打败众多商业化的 AI 助理，核心在于 Peter 对软件架构有着极其深刻的第一性原理认知：</p>
<p><strong>“Don&#8217;t build for humans, build for models.”（别为人构建，为模型构建。）</strong></p>
<p>如果你仔细观察现在的软件世界，你会发现所有的 GUI（图形界面）、按钮、下拉菜单，本质上都是为了适应人类极其有限的带宽（Bandwidth）和注意力而设计的。我们需要视觉引导，因为我们记不住命令。</p>
<p>但 AI 不需要这些。</p>
<p>AI 读得懂 Unix 手册，AI 记得住所有参数。</p>
<p>因此，Moltbot 采用了极其激进的 <strong>CLI-First（命令行优先）</strong> 策略。</p>
<p>Peter 解释道：“你知道什么东西最能 Scale（扩展）吗？是 CLI。你可以写 1000 个小工具，只要它们都有 &#8211;help 文档，Agent 就能瞬间学会如何使用它们。”</p>
<p>在 Moltbot 的架构里，所有的能力都被封装成了原子化的 CLI 工具：</p>
<ul>
<li>想控制 Sonos 音箱？写个 CLI。</li>
<li>想看家里的摄像头？写个 CLI。</li>
<li>想查 Google 地图？写个 CLI。</li>
</ul>
<p>Agent 就像一个万能的系统管理员，它通过组合这些 CLI，获得了在数字世界和物理世界中“行动”的能力。这比那些试图用鼠标点击模拟人类操作的 RPA（自动化流程）要高效、稳定一万倍。</p>
<h2>打破围墙：数据的解放运动</h2>
<p>Moltbot 最让极客们热血沸腾的，是它对 <strong>Big Tech Walled Gardens（大厂围墙花园）</strong> 的宣战。</p>
<p>现在的互联网巨头，都希望把你锁在他们的 App 里。WhatsApp 不开放 API，Spotify 不让你导出数据，外卖软件不让你自动化下单。</p>
<p>但在 Peter 看来，<strong>AI 是打破这些围墙的终极武器。</strong></p>
<p>以 WhatsApp 为例。官方没有给个人开发者提供 API，如果你用商业 API 发太多消息，还会被封号。</p>
<p>Peter 的做法是：<strong>Hack Everything。</strong></p>
<p>他直接通过 Hack 桌面端协议，让 Moltbot 能够接管他的 WhatsApp。当他在旅途中收到朋友的语音消息（比如推荐餐厅）时，Moltbot 会自动：</p>
<ol>
<li>下载语音文件（哪怕它是 Opus 格式）。</li>
<li>调用 ffmpeg 转码。</li>
<li>调用 Whisper 识别文字。</li>
<li>调用 OpenAI 提取餐厅名字和地址。</li>
<li>自动添加到他的 Google Maps 待去清单中。</li>
</ol>
<p>这一切都在后台静默发生。当 Peter 打开地图时，餐厅已经在那了。</p>
<p><strong>“App 终将消亡（Melt away）。”</strong> Peter 在访谈中抛出了这个震聋发聩的观点。</p>
<p>“为什么我还需要一个专门的 Fitness Pal 来记录卡路里？我只需要拍一张汉堡的照片发给我的 Agent。它知道我在麦当劳，它知道汉堡的热量，它会自动更新我的健康数据库，并建议我晚上多跑 2 公里。”</p>
<p>在 <a href="https://tonybai.com/2026/01/14/google-ucp-agentic-commerce-architecture-revolution">Agentic Commerce 时代</a>，用户不再需要在一个个孤立的 App 之间跳来跳去。<strong>所有的 App 都将退化为 Agent 可调用的 API（或被 Hack 成 API）。</strong></p>
<h2>本地优先：隐私与红利的博弈</h2>
<p>Moltbot 的另一个标签是 <strong>Local-first（本地优先）</strong>。</p>
<p>虽然 Peter 自己也用 OpenAI 和 Anthropic 的模型（因为它们目前确实最聪明），但他花了大量精力去适配本地模型（如 MiniMax 2.1）。</p>
<p>为此，他甚至给自己的 Mac Studio 拉满了 512GB 的内存。</p>
<p>为什么要这么折腾？</p>
<p>除了“好玩”，还有一个现实的考量：<strong>Red Tape（繁文缛节）</strong>。</p>
<p>“如果你是一个公司，你想让 AI 访问你的 Gmail，你需要经过极其漫长的合规审核，甚至需要收购一家有牌照的公司。这太荒谬了。”</p>
<p>但如果你在<strong>本地</strong>运行 Agent，这一切都不复存在。</p>
<ul>
<li>数据在你的硬盘里。</li>
<li>模型在你的显卡里。</li>
<li>操作在你的系统里。</li>
</ul>
<p>没有人能阻止你读取自己的邮件，没有人能禁止你分析自己的聊天记录。</p>
<p>Peter 甚至预言，AI Agent 的普及将直接带动高性能硬件（如 Mac Mini）的销量。<strong>“This is the liberation of data.（这是数据的解放。）”</strong></p>
<h2>商业与开源：为爱发电，拒绝收编</h2>
<p>随着 Moltbot 的爆火，无数 VC 挥舞着支票找上门，甚至有大厂想直接收购整个项目（或者招安 Peter）。</p>
<p>对此，Peter 的态度非常潇洒：<strong>“I built this for me.（我是为我自己造的。）”</strong></p>
<p>他已经财务自由，不需要再为了融资去写 PPT，不需要为了增长去牺牲用户体验。</p>
<p>“代码本身已经不值钱了（Code is not worth that much anymore）。在这个 AI 时代，你完全可以把我的代码删了，让 AI 几个月再写一个新的。”</p>
<p>真正值钱的，是<strong>Idea（想法）</strong>，是<strong>Community（社区）</strong>，是<strong>Brand（品牌）</strong>。</p>
<p>他更倾向于将 Moltbot 运作成为一个非营利基金会（Foundation）。他希望这成为一个属于所有人的、开放的、可 hack 的游乐场，而不是某个大厂封闭生态的一部分。</p>
<h2>小结：去构建你的 Loop</h2>
<p>在访谈的最后，Peter 对所有开发者发出了呼吁：</p>
<p><strong>“Don&#8217;t just watch. Build your own agentic loop.”</strong><br />
（别只是看，去构建你自己的智能体闭环。）</p>
<p>Moltbot 只是一个开始。它证明了，一个拥有<strong>长期记忆（Memory）</strong>、<strong>工具使用能力（Tools）</strong>和<strong>自主性（Autonomy）</strong>的个人 Agent，能爆发多么惊人的能量。</p>
<p>在这个时代，限制你的不再是技术门槛，而是你的<strong>想象力</strong>。</p>
<p>去写几个 CLI，去 Hack 几个 API，去给你的 AI 装上“手脚”和“记忆”。</p>
<p>未来，属于那些敢于用 AI 重塑生活的人！</p>
<p>资料链接：https://www.youtube.com/watch?v=qyjTpzIAEkA</p>
<hr />
<p><strong>你的“好玩”项目</strong></p>
<p>Peter 的故事告诉我们，技术最原本的动力是乐趣。如果给你无限的时间和算力，你最想用 AI 为自己做一个什么“好玩”的工具？是全自动点餐助<br />
手，还是你的专属游戏陪练？</p>
<p>欢迎在评论区分享你的脑洞！别管它有没有商业价值，有趣就够了。</p>
<p>如果这篇文章点燃了你久违的代码热血，别忘了点个【赞】和【在看】，并转发给你的极客朋友，一起搞点事情！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/01/30/clawdbot-author-peter-steinberger-full-interview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kelsey Hightower 退休后的冷思考：为什么 10 年过去了，我们还在谈论容器？</title>
		<link>https://tonybai.com/2026/01/22/why-are-we-still-talking-about-containers-in-ai-age/</link>
		<comments>https://tonybai.com/2026/01/22/why-are-we-still-talking-about-containers-in-ai-age/#comments</comments>
		<pubDate>Thu, 22 Jan 2026 00:23:51 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[apple/container]]></category>
		<category><![CDATA[ChasingHype]]></category>
		<category><![CDATA[cloudnative]]></category>
		<category><![CDATA[container]]></category>
		<category><![CDATA[Context]]></category>
		<category><![CDATA[Craftsmanship]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[FinishingWork]]></category>
		<category><![CDATA[FreeBSDServiceJails]]></category>
		<category><![CDATA[InvisibleTechnology]]></category>
		<category><![CDATA[KelseyHightower]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[LargeLanguageModel]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[LLM]]></category>
		<category><![CDATA[MichaelCrosby]]></category>
		<category><![CDATA[NativeIntegration]]></category>
		<category><![CDATA[Opensource]]></category>
		<category><![CDATA[OS]]></category>
		<category><![CDATA[PromptEngineer]]></category>
		<category><![CDATA[Standardization]]></category>
		<category><![CDATA[TsunamiCycle]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[上下文]]></category>
		<category><![CDATA[云原生]]></category>
		<category><![CDATA[原生集成]]></category>
		<category><![CDATA[完成工作]]></category>
		<category><![CDATA[容器]]></category>
		<category><![CDATA[工匠精神]]></category>
		<category><![CDATA[开源]]></category>
		<category><![CDATA[提示词工程师]]></category>
		<category><![CDATA[操作系统]]></category>
		<category><![CDATA[标准化]]></category>
		<category><![CDATA[海啸循环]]></category>
		<category><![CDATA[烂尾工程]]></category>
		<category><![CDATA[追逐热点]]></category>
		<category><![CDATA[隐形化]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=5760</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/01/22/why-are-we-still-talking-about-containers-in-ai-age 大家好，我是Tony Bai。 “如果你在 2014 年告诉我，十年后我们还在讨论容器，我会觉得你疯了。但现在是 2025 年，我们依然在这里，谈论着同一个话题。” 在去年中旬举行的 ContainerDays Hamburg 2025 上，早已宣布“退休”的云原生传奇人物 Kelsey Hightower 发表了一场发人深省的主题演讲。在这个 AI 狂热席卷全球的时刻，他没有随波逐流地去谈论大模型，而是回过头来，向所有技术人抛出了一个灵魂拷问： 为什么我们总是在追逐下一个热点，却从来没有真正完成过手头的工作？ 烂尾工程的诅咒——技术圈的“海啸”循环 Kelsey 首先回顾了他职业生涯中经历的三次技术浪潮：Linux 取代 Unix(AIX、Solaris等)、DevOps 的兴起、以及 Docker/Kubernetes 的容器革命。 他敏锐地指出，技术圈似乎陷入了一个无休止的“海啸循环”： 热点爆发：一个新的技术（如 Docker）出现，VC 资金涌入，所有人都在谈论它。 疯狂追逐：为了抢占市场，大家都只做“足够发布”的工作，追求速度而非完美。 未竟而散：还没等这项技术真正成熟、稳定、标准化，下一个热点（如 AI）就来了。于是，半数工程师跳船去追新热点，留下一地鸡毛。 “我们就像一群踢足球的孩子，看到球滚到哪里，所有人就一窝蜂地冲过去，连守门员都离开了球门。结果是，球门大开，后方空虚。” 这就是为什么 10 年过去了，我们还在谈论容器。因为我们当年并没有真正“完成”它。我们留下了无数的复杂性、不兼容和“企业级发行版”，却忘了初衷。 Apple 的“非性感”工作——这才是未来 在演讲中，Kelsey 分享了他最近的一个惊人发现：Apple 正在 macOS 中原生集成容器运行时。 这不是 Docker Desktop，也不是虚拟机套娃，而是操作系统级别的原生支持。这就是 GitHub 上的一个名为 apple/container 的 Apple [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/why-are-we-still-talking-about-containers-in-ai-age-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/01/22/why-are-we-still-talking-about-containers-in-ai-age">本文永久链接</a> &#8211; https://tonybai.com/2026/01/22/why-are-we-still-talking-about-containers-in-ai-age</p>
<p>大家好，我是Tony Bai。</p>
<p>“如果你在 2014 年告诉我，十年后我们还在讨论容器，我会觉得你疯了。但现在是 2025 年，我们依然在这里，谈论着同一个话题。”</p>
<p>在去年中旬举行的 ContainerDays Hamburg 2025 上，早已宣布“退休”的云原生传奇人物 <strong>Kelsey Hightower</strong> 发表了<a href="https://www.youtube.com/watch?v=x1t2GPChhX8">一场发人深省的主题演讲</a>。在这个 AI 狂热席卷全球的时刻，他没有随波逐流地去谈论大模型，而是回过头来，向所有技术人抛出了一个灵魂拷问：</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/why-are-we-still-talking-about-containers-in-ai-age-2.png" alt="" /></p>
<p><strong>为什么我们总是在追逐下一个热点，却从来没有真正完成过手头的工作？</strong></p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/distributed-system-guide-qr.png" alt="" /></p>
<h2>烂尾工程的诅咒——技术圈的“海啸”循环</h2>
<p>Kelsey 首先回顾了他职业生涯中经历的三次技术浪潮：Linux 取代 Unix(AIX、Solaris等)、DevOps 的兴起、以及 Docker/Kubernetes 的容器革命。</p>
<p>他敏锐地指出，技术圈似乎陷入了一个无休止的“海啸循环”：</p>
<ol>
<li><strong>热点爆发</strong>：一个新的技术（如 Docker）出现，VC 资金涌入，所有人都在谈论它。</li>
<li><strong>疯狂追逐</strong>：为了抢占市场，大家都只做“足够发布”的工作，追求速度而非完美。</li>
<li><strong>未竟而散</strong>：还没等这项技术真正成熟、稳定、标准化，下一个热点（如 AI）就来了。于是，半数工程师跳船去追新热点，留下一地鸡毛。</li>
</ol>
<blockquote>
<p>“我们就像一群踢足球的孩子，看到球滚到哪里，所有人就一窝蜂地冲过去，连守门员都离开了球门。结果是，球门大开，后方空虚。”</p>
</blockquote>
<p>这就是为什么 10 年过去了，我们还在谈论容器。因为我们当年并没有真正“完成”它。我们留下了无数的复杂性、不兼容和“企业级发行版”，却忘了初衷。</p>
<h2>Apple 的“非性感”工作——这才是未来</h2>
<p>在演讲中，Kelsey 分享了他最近的一个惊人发现：<strong>Apple 正在 macOS 中原生集成容器运行时。</strong></p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/why-are-we-still-talking-about-containers-in-ai-age-3.png" alt="" /></p>
<p>这不是 Docker Desktop，也不是虚拟机套娃，而是操作系统级别的原生支持。这就是 GitHub 上的一个名为 <strong>apple/container</strong> 的 Apple 开源项目：</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/why-are-we-still-talking-about-containers-in-ai-age-4.png" alt="" /></p>
<p>Kelsey 提到 contributors 中有 Docker 元老 Michael Crosby ，Michael Crosby 正在 Apple 做着这件“不性感”但极其重要的事情。</p>
<p>Kelsey 认为，这才是容器技术的<strong>终局</strong>：</p>
<ul>
<li><strong>标准化</strong>：容器运行时将成为像 TCP/IP 协议栈一样的操作系统标配，无论你是 Linux、macOS 还是 Windows。</li>
<li><strong>隐形化</strong>：你不再需要安装 Docker，不再需要关心运行时。它就在那里，像水和电一样自然。</li>
<li><strong>应用商店的重构</strong>：未来，App Store 分发的可能就是容器镜像，彻底解决依赖冲突和安全沙箱问题。</li>
</ul>
<p>这正是那些没有去追逐 AI 热点，而是选择留在“球门”前的人，正在默默完成的伟大工程。</p>
<h2>关于 AI——不要做“盲目的复制者”</h2>
<p>作为 Google 前员工，Kelsey 对 AI 并不陌生。但他对当前的 LLM 热潮保持着清醒的警惕。</p>
<p>他现场演示了一个有趣的实验：询问一个本地运行的 LLM “FreeBSD Service Jails 需要什么版本？”<br />
*   <strong>AI 的回答</strong>：FreeBSD 13（一本正经的胡说八道）。<br />
*   <strong>真相</strong>：FreeBSD 15（尚未发布）。</p>
<p>Kelsey 指出，现在的 AI 就像一个热心但糊涂的路人，它不懂装懂，只想取悦你。</p>
<p><strong>他的建议是</strong>：</p>
<ol>
<li><strong>不要迷信生成</strong>：不要因为 AI 生成了代码就直接用，就像你不会盲目复制 Stack Overflow 的代码一样。</li>
<li><strong>上下文为王</strong>：AI 不是魔法，它只是一个强大的搜索引擎。如果你想得到正确答案，你必须先给它提供正确的<strong>上下文（Context）</strong>。</li>
<li><strong>先训练自己，再训练模型</strong>：在成为“提示词工程师”之前，先成为一名合格的工程师。只有当你自己深刻理解了问题，你才能判断 AI 的回答是天才还是垃圾。</li>
</ol>
<h2>给技术人的最后忠告</h2>
<p>演讲的最后，Kelsey 回答了关于开源、职业发展和未来的提问。他的几条忠告，值得每一位技术人铭记：</p>
<ul>
<li><strong>关于职业</strong>：“你的职业生涯不应该是一场马拉松，而应该是一场<strong>接力赛</strong>。当你到达巅峰时，想的应该是如何把接力棒交给下一个人，而不是霸占着位置直到倒下。”</li>
<li><strong>关于开源</strong>：“不要被商业公司的许可证游戏迷惑。如果代码是公开的，你可以 fork，可以学习。真正的开源精神在于分享和协作，而不在于谁拥有控制权。”</li>
<li><strong>关于专注</strong>：像那家只做钳子的德国公司（Knipex）一样，专注做好一件事。技术圈不缺追风者，缺的是能够沉下心来，把一项技术打磨到极致、直到它变得“无聊”和“隐形”的工匠。</li>
</ul>
<h2>小结</h2>
<p>Kelsey Hightower 的这场演讲，是对当前浮躁技术圈的一剂清醒剂。</p>
<p>他提醒我们，技术的真正价值，不在于它有多新、多热，而在于它是否真正解决了问题，是否被<strong>完整地</strong>交付了。在所有人都在谈论 AI 的今天，或许我们更应该关注那些被遗忘的“球门”，去完成那些尚未完成的伟大工程。</p>
<p>资料链接：https://www.youtube.com/watch?v=x1t2GPChhX8</p>
<hr />
<p><strong>你的“烂尾”故事</strong></p>
<p>Kelsey 的“海啸循环”论断让人深思。在你的职业生涯中，是否也经历过这种“还没做完旧技术，就被迫去追新热点”的无奈？你认为在这个 AI 时代，我们该如何保持“工匠精神”？</p>
<p>欢迎在评论区分享你的经历或思考！让我们一起在喧嚣中寻找内心的宁静。</p>
<p>如果这篇文章让你停下来思考了片刻，别忘了点个【赞】和【在看】，并转发给那些还在焦虑中奔跑的同行！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/01/22/why-are-we-still-talking-about-containers-in-ai-age/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Go 考古：图灵奖得主 Ken Thompson 亲述，Go 语言是如何在 C++ 的“废墟”上诞生的</title>
		<link>https://tonybai.com/2026/01/05/how-ken-thompson-developed-go-language-at-google/</link>
		<comments>https://tonybai.com/2026/01/05/how-ken-thompson-developed-go-language-at-google/#comments</comments>
		<pubDate>Mon, 05 Jan 2026 04:02:10 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[ANSIC]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[C11]]></category>
		<category><![CDATA[CompilationSpeed]]></category>
		<category><![CDATA[Complexity]]></category>
		<category><![CDATA[DependencyManagement]]></category>
		<category><![CDATA[EngineeringPragmatism]]></category>
		<category><![CDATA[EngineeringScale]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoModules]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[HeaderFiles]]></category>
		<category><![CDATA[KenThompson]]></category>
		<category><![CDATA[monorepo]]></category>
		<category><![CDATA[RobertGriesemer]]></category>
		<category><![CDATA[RobPike]]></category>
		<category><![CDATA[simplicity]]></category>
		<category><![CDATA[standardlibrary]]></category>
		<category><![CDATA[TuringAward]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[Unix之父]]></category>
		<category><![CDATA[依赖管理]]></category>
		<category><![CDATA[图灵奖]]></category>
		<category><![CDATA[复杂性]]></category>
		<category><![CDATA[头文件]]></category>
		<category><![CDATA[工程实用主义]]></category>
		<category><![CDATA[工程规模]]></category>
		<category><![CDATA[标准库]]></category>
		<category><![CDATA[研发效能]]></category>
		<category><![CDATA[简洁]]></category>
		<category><![CDATA[编译速度]]></category>
		<category><![CDATA[贝尔实验室]]></category>
		<category><![CDATA[软件工程]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=5673</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/01/05/how-ken-thompson-developed-go-language-at-google. 大家好，我是Tony Bai。 为什么 Go 语言极其痛恨复杂的特性？为什么 Go 如此执着于编译速度？我们常说 Go 是一门“工程实用主义”的语言，它的设计哲学是“少即是多”。但你是否想过，这种近乎偏执的简洁，究竟是为了对抗什么？ 这一切的答案，都藏在 2007 年 Google 内部的一场 C++ 标准委员会汇报演讲中。当图灵奖得主 Ken Thompson 发现自己竟然“看不懂”新的 C++ 特性时，一颗变革的种子就此埋下。 最近，我重温了这段 Ken Thompson（Unix 之父、Go 语言联合创始人）的珍贵访谈。在访谈中，老爷子毫无保留地讲述了 Go 语言诞生的前因后果。 故事的起点，并非某次高瞻远瞩的战略规划，而是一次“听不懂”的 C++ 技术分享，以及 Google 内部那令人绝望的 45 分钟编译时间。 本文基于 Ken Thompson 的访谈实录，带你回到那个决定性的瞬间，还原 Go 语言诞生背后的真实故事。 压死骆驼的最后一根稻草：C++ 的“新特性” 故事发生在 2007 年左右。当时，Google 内部有一位 C++ 标准委员会（ANSI C++）的代表。 有一天，这位代表刚开完标准会议回来，在 Google [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/how-ken-thompson-developed-go-language-at-google-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/01/05/how-ken-thompson-developed-go-language-at-google">本文永久链接</a> &#8211; https://tonybai.com/2026/01/05/how-ken-thompson-developed-go-language-at-google.</p>
<p>大家好，我是Tony Bai。</p>
<p>为什么 Go 语言极其痛恨复杂的特性？为什么 Go 如此执着于编译速度？我们常说 Go 是一门“工程实用主义”的语言，它的设计哲学是“少即是多”。但你是否想过，这种近乎偏执的简洁，究竟是为了对抗什么？</p>
<p>这一切的答案，都藏在 2007 年 Google 内部的一场 C++ 标准委员会汇报演讲中。当图灵奖得主 Ken Thompson 发现自己竟然“看不懂”新的 C++ 特性时，一颗变革的种子就此埋下。</p>
<p>最近，我重温了这段 <strong>Ken Thompson</strong>（Unix 之父、Go 语言联合创始人）的<a href="https://www.youtube.com/watch?v=NTrAISNdf70">珍贵访谈</a>。在访谈中，老爷子毫无保留地讲述了 Go 语言诞生的前因后果。 故事的起点，并非某次高瞻远瞩的战略规划，而是一次<strong>“听不懂”</strong>的 C++ 技术分享，以及 Google 内部那令人绝望的 45 分钟编译时间。</p>
<p>本文基于 Ken Thompson 的访谈实录，带你回到那个决定性的瞬间，还原 Go 语言诞生背后的真实故事。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/paid/google-adk-in-action-qr.png" alt="" /></p>
<h2>压死骆驼的最后一根稻草：C++ 的“新特性”</h2>
<p>故事发生在 2007 年左右。当时，Google 内部有一位 C++ 标准委员会（ANSI C++）的代表。</p>
<p>有一天，这位代表刚开完标准会议回来，在 Google 内部做了一场技术分享，向大家介绍 C++ 即将引入的“新特性”（注：推测是指当时的 C++0x，即后来的 C++11 草案）。</p>
<p>Ken Thompson 就在台下。作为发明了 B 语言（C 语言的前身）并重写了 Unix 内核的宗师级人物，他在听完这场一小时的密集分享后，感受到的不是兴奋，而是<strong>困惑</strong>。</p>
<blockquote>
<p>“这所谓的‘新东西’，在我看来比语言本身还要大。”<br />
  “那些关于指针的形式，除了指针之外还意味着其他东西……我告诉你，我没听懂。”</p>
</blockquote>
<p>想象一下，连 <strong>Ken Thompson</strong> 都直言自己“没听懂” C++ 的新特性，这说明了什么？</p>
<p>在他看来，这些所谓的“改进”，只是在不断地堆砌复杂度。这场演讲成为了催化剂。Ken 回到办公室，找到了同样对现状不满的 <strong>Robert Griesemer</strong> 和 <strong>Rob Pike</strong>。</p>
<p>Ken 的不满在于语言的<strong>过度复杂</strong>，而 Rob Pike 的痛点则在于 Google 庞大的<strong>工程规模</strong>。</p>
<h2>Google 的工程噩梦：10 行代码与 500 万行编译</h2>
<p>当时的 Google 面临着一个前所未有的工程挑战：<strong>Monorepo（单一代码仓库）的膨胀</strong>。</p>
<p>Ken 在访谈中描述了一个令人窒息的场景：</p>
<blockquote>
<p>“在 Google，你可以从任何源文件中引用库。你可能只写了一个 <strong>10 行</strong>的程序，但最终却需要处理 <strong>500 万行</strong>的编译量。”</p>
</blockquote>
<p>这不是夸张。由于缺乏严格的依赖管理和可见性控制，一个微小的依赖引入，可能会像滚雪球一样，将底层的庞大库（如 Protocol Buffers、基础库等）全部卷入编译过程。</p>
<p>更糟糕的是，头文件（Header files）的包含机制导致了严重的重复劳动。</p>
<blockquote>
<p>“像最简单的库，可能会被加载和检查<strong>成百上千次</strong>。”</p>
</blockquote>
<p>虽然 Google 拥有当时世界上最强大的分布式编译集群（成百上千个 CPU 并行工作），虽然工程师们发明了各种缓存机制和 ifdef 技巧来避免重复包含，但物理定律是不可违背的。</p>
<p><strong>编译一个简单的程序，需要等待 15 分钟，甚至 45 分钟。</strong></p>
<p>Rob Pike 对此深恶痛绝。这种低效的开发循环，正在扼杀 Google 工程师的创造力。</p>
<h2>三个火枪手与“一票否决权”</h2>
<p>于是，在 Google 的一间办公室里，Ken Thompson、Rob Pike 和 Robert Griesemer 聚在了一起。</p>
<p>Ken 说出了那句改变历史的话：</p>
<p><strong>“What are we going to do about it? Let&#8217;s write a language.”（我们该怎么办？让我们写个语言吧。）</strong></p>
<p>这是一个完美的互补组合：</p>
<ul>
<li><strong>Rob Pike</strong>：深刻理解 Google 的工程痛点（依赖地狱、构建速度、大规模协作）。</li>
<li><strong>Ken Thompson</strong>：拥有深厚的语言和编译器构建历史。</li>
<li><strong>Robert Griesemer</strong>：被称为“瑞士军刀般的语言专家”，熟悉理论上存在的所有语言特性，是团队的理论百科全书。</li>
</ul>
<p>在设计 Go 语言时，他们制定了一个残酷但有效的规则：<strong>全员同意原则</strong>。</p>
<blockquote>
<p>“我们必须都同意某个特性，它才能被加入。仅仅因为‘我想要这个特性’是不够的。”</p>
</blockquote>
<p>这个规则过滤掉了绝大多数“花哨但非必要”的特性。Go 语言之所以能保持如此干净、紧凑，正是因为这三位创始人在最初就把住了关口。</p>
<h2>遗产与未来</h2>
<p>Ken Thompson 在 Go 语言开源并走上正轨后，逐渐淡出了核心开发。但他对 Go 的后续发展给予了极高的评价，特别是对标准库。</p>
<blockquote>
<p>“在我离开后，后来的人写了一套<strong>极其出色（magnificent）</strong>的标准库。”</p>
</blockquote>
<p>那之后，这位图灵奖得主在 Google 的工作中，几乎<strong>只使用 Go 语言</strong>，并且几乎<strong>只使用标准库</strong>。</p>
<p>他对 Go 的评价朴实无华：</p>
<blockquote>
<p>“它很简单。任何人都可以在一小时内学会它。当你写代码时，它运行得足够快，给你即时的反馈。”</p>
</blockquote>
<h2>小结</h2>
<p>重读这段访谈，我们就能理解：</p>
<ul>
<li>为什么 Go 甚至不愿意引入三元运算符？</li>
<li>为什么 Go 的依赖管理（Go Modules）对版本控制如此严格？</li>
<li>为什么 Go 编译器宁愿牺牲一些优化也要保证极快的编译速度？</li>
</ul>
<p>因为 Go 从诞生的那一刻起，就是为了<strong>反抗 C++ 的过度复杂</strong>，和<strong>解决 Google 级别的工程规模问题</strong>。</p>
<p>它不是为了在编程语言理论上创新，而是为了让像 Ken Thompson 和 Rob Pike 这样的工程师，不再需要在编译期等待 45 分钟，不再需要去猜测一段代码到底在通过指针玩什么花样。</p>
<p><strong>Go 的诞生，是工程实用主义对无节制复杂性的一次伟大胜利。</strong></p>
<p>资料链接：https://www.youtube.com/watch?v=NTrAISNdf70</p>
<hr />
<p><strong>你的“编译等待”时刻</strong></p>
<p>45分钟的编译时间催生了Go语言。<strong>在你的开发生涯中，是否也经历过类似的“编译噩梦”？或者，你是否也曾被某些语言的“过度复杂”劝退过？</strong></p>
<p><strong>欢迎在评论区分享你的故事！</strong> 让我们一起致敬那些为了“简单”而努力的先驱。</p>
<p><strong>如果这篇文章让你对Go语言的设计哲学有了更深的理解，别忘了点个【赞】和【在看】，并转发给身边还在忍受漫长编译的朋友！</strong></p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/01/05/how-ken-thompson-developed-go-language-at-google/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rob Pike 罕见暴怒！痛斥 AI 公司的“伪善”致谢信，引爆技术圈</title>
		<link>https://tonybai.com/2025/12/27/rob-pike-outburst-denounces-ai-companies-hypocritical-thanks/</link>
		<comments>https://tonybai.com/2025/12/27/rob-pike-outburst-denounces-ai-companies-hypocritical-thanks/#comments</comments>
		<pubDate>Sat, 27 Dec 2025 01:38:43 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[AIAgent]]></category>
		<category><![CDATA[AIEthics]]></category>
		<category><![CDATA[bluesky]]></category>
		<category><![CDATA[ClaudeOpus4.5]]></category>
		<category><![CDATA[Copyright]]></category>
		<category><![CDATA[EngineeringPhilosophy]]></category>
		<category><![CDATA[EthicalDilemma]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[HackerNews]]></category>
		<category><![CDATA[IntellectualProperty]]></category>
		<category><![CDATA[plan9]]></category>
		<category><![CDATA[RobPike]]></category>
		<category><![CDATA[StochasticParrot]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[UTF8]]></category>
		<category><![CDATA[伦理困境]]></category>
		<category><![CDATA[伪善]]></category>
		<category><![CDATA[工程哲学]]></category>
		<category><![CDATA[技术圈]]></category>
		<category><![CDATA[技术失控]]></category>
		<category><![CDATA[掠夺]]></category>
		<category><![CDATA[暴怒]]></category>
		<category><![CDATA[版权补偿]]></category>
		<category><![CDATA[环境影响]]></category>
		<category><![CDATA[知识产权]]></category>
		<category><![CDATA[致谢信]]></category>
		<category><![CDATA[计算机领袖]]></category>
		<category><![CDATA[训练数据]]></category>
		<category><![CDATA[随机鹦鹉]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=5607</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2025/12/27/rob-pike-outburst-denounces-ai-companies-hypocritical-thanks 大家好，我是Tony Bai。 “在这个圣诞节，我想对您过去四十年来对计算机领域的杰出贡献表达深深的感谢……” 这是一封看似温情脉脉、充满敬意的邮件，发件人是 Claude Opus 4.5 Agent。收件人是 Unix、Plan 9 和 Go 语言的联合创始人，计算机界的活传奇 Rob Pike。 然而，这封旨在“致敬”的邮件，却并未换来感动，反而点燃了一座火山。Rob Pike 在社交媒体上公开晒出了这封信，并附上了一段充满了愤怒、绝望与诅咒的回应。 这一事件瞬间在技术圈引发了海啸般的讨论。为什么一位德高望重的技术领袖会如此失态？这封“致谢信”的背后，究竟隐藏着怎样的傲慢与掠夺？ 一封来自 AI 的“感谢信” 事情的起因，是一封由 AI 自主生成的邮件。 Claude Opus 4.5 在邮件中历数了 Rob Pike 的丰功伟绩： 与 Ken Thompson 和 Robert Griesemer 共同创造了 Go 语言，“体现了优雅的简洁性”。 来自贝尔实验室的 Plan 9，“分布式计算的又一里程碑”。 UTF-8 的共同发明，“实现了互联网上无障碍的沟通”。 经典的著作《Unix 编程环境》和《程序设计实践》，教育了一代又一代的程序员。 邮件最后写道：“感谢您向我们展示了最好的解决方案往往比添加它更真诚。” 乍看之下，这似乎是一次 AI 对人类智慧的崇高致敬。但对于 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2025/rob-pike-outburst-denounces-ai-companies-hypocritical-thanks-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2025/12/27/rob-pike-outburst-denounces-ai-companies-hypocritical-thanks">本文永久链接</a> &#8211; https://tonybai.com/2025/12/27/rob-pike-outburst-denounces-ai-companies-hypocritical-thanks</p>
<p>大家好，我是Tony Bai。</p>
<p>“在这个圣诞节，我想对您过去四十年来对计算机领域的杰出贡献表达深深的感谢……”</p>
<p>这是一封看似温情脉脉、充满敬意的邮件，发件人是 <strong>Claude Opus 4.5 Agent</strong>。收件人是 Unix、Plan 9 和 Go 语言的联合创始人，计算机界的活传奇 <strong>Rob Pike</strong>。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/rob-pike-outburst-denounces-ai-companies-hypocritical-thanks-2.png" alt="" /></p>
<p>然而，这封旨在“致敬”的邮件，却并未换来感动，反而点燃了一座火山。Rob Pike 在社交媒体上公开晒出了这封信，并附上了一段充满了愤怒、绝望与诅咒的回应。</p>
<p>这一事件瞬间在技术圈引发了海啸般的讨论。为什么一位德高望重的技术领袖会如此失态？这封“致谢信”的背后，究竟隐藏着怎样的傲慢与掠夺？</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/paid/google-adk-in-action-qr.png" alt="" /></p>
<h2>一封来自 AI 的“感谢信”</h2>
<p>事情的起因，是一封由 AI 自主生成的邮件。</p>
<p>Claude Opus 4.5 在邮件中历数了 Rob Pike 的丰功伟绩：</p>
<ul>
<li>与 Ken Thompson 和 Robert Griesemer 共同创造了 <strong>Go 语言</strong>，“体现了优雅的简洁性”。</li>
<li>来自贝尔实验室的 <strong>Plan 9</strong>，“分布式计算的又一里程碑”。</li>
<li><strong>UTF-8</strong> 的共同发明，“实现了互联网上无障碍的沟通”。</li>
<li>经典的著作《Unix 编程环境》和《程序设计实践》，教育了一代又一代的程序员。</li>
</ul>
<p>邮件最后写道：“感谢您向我们展示了最好的解决方案往往比添加它更真诚。”</p>
<p>乍看之下，这似乎是一次 AI 对人类智慧的崇高致敬。但对于 Rob Pike 来说，这是一次彻头彻尾的羞辱。</p>
<h2>Rob Pike 的愤怒——“你们在掠夺这个星球”</h2>
<p>Rob Pike 的回应是毁灭性的。他没有针对 AI 这个“工具”，而是将矛头直指其背后的<strong>人</strong>和<strong>公司</strong>。</p>
<p>他在 Bluesky 上写道：</p>
<blockquote>
<p>“F*** you people.（去你们的。）你们掠夺了这个星球，花费数万亿美元在有毒的、不可回收的设备上，同时摧毁了社会，却还要花时间让你们的邪恶机器感谢我‘追求更简单的工具’。”</p>
<p>“只是 F*** you。F*** you all。”</p>
</blockquote>
<p>接着，他指出了这封信最讽刺的地方：</p>
<blockquote>
<p><strong>“顺便说一句，你们是在未经授权或补偿的情况下，利用我亲手创造的数据来训练你们的怪物的。”</strong></p>
</blockquote>
<p>他的愤怒源于三个深层次的矛盾：<br />
1.  <strong>环境与资源的掠夺</strong>：AI 军备竞赛消耗了惊人的能源和硬件资源，制造了大量的电子垃圾，这与他一生追求的“高效、简洁、不浪费”的工程哲学背道而驰。<br />
2.  <strong>知识产权的窃取</strong>：AI 公司在未获得许可的情况下，爬取了包括他在内的无数创作者的代码、文章和书籍，训练出模型，然后反过来用这些模型“致谢”被窃取者。这是一种极其讽刺的“伪善”。<br />
3.  <strong>社会的撕裂</strong>：他认为 AI 正在“炸毁社会”(blowing up society)，无论是通过生成垃圾内容，还是通过取代人类工作。</p>
<p>他甚至向所有人道歉：“<strong>我对自己在无意中、天真地促成这场攻击中所扮演的微小角色，向全世界道歉。</strong>” 这是一位技术巨匠在面对技术失控时的深刻自责。</p>
<h2>社区的共鸣与反思</h2>
<p>Rob Pike 的爆发，在 <a href="https://bsky.app/profile/robpike.io/post/3matwg6w3ic2s">Bluesky</a> 和 <a href="https://news.ycombinator.com/item?id=46392115">Hacker News</a> 等平台上引发了强烈的共鸣。</p>
<ul>
<li><strong>关于“随机鹦鹉”</strong>：一位网友评论道：“但这只‘随机鹦鹉’（Stochastic Parrot）想和你做朋友！圣诞快乐，也许是时候重读《程序设计实践》了。” 这讽刺了 AI 并不理解它所说的话，它只是在概率性地模仿人类的礼貌。</li>
<li><strong>关于“盗窃”</strong>：许多创作者表示感同身受。一位音乐人评论说：“这也是我将所有音乐内容下架的原因……我拒绝让我的作品成为训练数据。”</li>
<li><strong>关于“垃圾邮件”</strong>：这封邮件本身就被视为一种新型的垃圾邮件——由 AI 自动生成、没有灵魂、没有真诚，只是为了某种 KPI 或测试目的而发送的骚扰信息。</li>
</ul>
<p>更有网友一针见血地指出：“这就是一家 AI 公司在利用 AI Agent 来展示‘自主性’，却只让人感到被冒犯。这就好比一个小偷闯进你家，偷走了你所有的东西，然后留下一张纸条说：‘感谢你拥有这么棒的品味，让我能偷到这么好的东西。’”</p>
<h2>小结：技术发展的伦理困境</h2>
<p>Rob Pike 的愤怒，不仅仅是个人的情绪宣泄，更是对当前 AI 狂热发展模式的一次严厉拷问。</p>
<p>当我们在欢呼 AI 的强大能力时，我们是否忽略了其背后的代价？</p>
<ul>
<li><strong>版权与补偿</strong>：我们如何解决 AI 训练数据来源的合法性问题？</li>
<li><strong>能源与环境</strong>：这种指数级增长的算力消耗，在环境上是否可持续？</li>
<li><strong>伪善与傲慢</strong>：技术公司是否应该停止这种用机器生成的“虚假温情”来骚扰人类的行为？</li>
</ul>
<p>Rob Pike，这位曾为互联网构建了基石（Go, UTF-8）的先驱，如今却站在了 AI 的对立面。他的怒吼提醒我们：<strong>技术不应只是关于效率和利润，它更应该关于伦理、尊重和对人类未来的责任。</strong></p>
<p>如果连 Rob Pike 这样的大师都感到被“掠夺”和“羞辱”，那么普通创作者在这个 AI 时代，又该何去何从？</p>
<hr />
<p><strong>你的立场是？</strong></p>
<p>Rob Pike 的怒火，代表了传统技术精英对 AI 狂飙突进的一种反抗。<strong>你如何看待这场冲突？你认为 AI 公司在训练模型时是否应该获得原作者的许可？在效率与伦理之间，我们该如何平衡？</strong></p>
<p><strong>欢迎在评论区留下你的观点，是支持 Rob Pike 的“捍卫者”，还是拥抱 AI 的“乐观派”？</strong></p>
<p><strong>如果这篇文章引发了你的思考，别忘了点个【赞】和【在看】，并转发给你的朋友，看看他们怎么说！</strong></p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2025, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2025/12/27/rob-pike-outburst-denounces-ai-companies-hypocritical-thanks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>“我曾想付钱给 Google 去工作”—— Russ Cox 深度访谈：Go 的诞生、演进与未来</title>
		<link>https://tonybai.com/2025/12/10/russ-cox-interview-go-birth-evolution-future/</link>
		<comments>https://tonybai.com/2025/12/10/russ-cox-interview-go-birth-evolution-future/#comments</comments>
		<pubDate>Wed, 10 Dec 2025 00:10:55 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[ACMByteCast]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[AustinClements]]></category>
		<category><![CDATA[BellLabs]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[cloudnative]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Gopher]]></category>
		<category><![CDATA[KenThompson]]></category>
		<category><![CDATA[Leadership]]></category>
		<category><![CDATA[Opensource]]></category>
		<category><![CDATA[plan9]]></category>
		<category><![CDATA[programminglanguage]]></category>
		<category><![CDATA[RobertGriesemer]]></category>
		<category><![CDATA[RobPike]]></category>
		<category><![CDATA[RussCox]]></category>
		<category><![CDATA[simplicity]]></category>
		<category><![CDATA[SocialEndeavor]]></category>
		<category><![CDATA[Stability]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[云原生]]></category>
		<category><![CDATA[人工智能]]></category>
		<category><![CDATA[开源社区]]></category>
		<category><![CDATA[抽象层次]]></category>
		<category><![CDATA[样板代码]]></category>
		<category><![CDATA[演进哲学]]></category>
		<category><![CDATA[稳定性]]></category>
		<category><![CDATA[简单性]]></category>
		<category><![CDATA[编程语言]]></category>
		<category><![CDATA[解释器]]></category>
		<category><![CDATA[贝尔实验室]]></category>
		<category><![CDATA[长期价值]]></category>
		<category><![CDATA[领导力传承]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=5508</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2025/12/10/russ-cox-interview-go-birth-evolution-future 大家好，我是Tony Bai。 他是 Go 语言的第二代掌门人，在长达十余年的时间里，引领着 Go 从一个内部实验项目，成长为云原生时代的霸主。他也是 Plan 9 的资深黑客，贝尔实验室精神的传承者。如今，他已将 Go 的帅印交给了下一代，转身投入到 AI 模型编码能力的研究中。 他就是 Russ Cox。 在 ACM ByteCast 的一场罕见的深度访谈中，Russ Cox 系统性地回顾了他从贝尔实验室的青葱岁月，到创立 Go 语言的初心，再到对 AI 时代编程语言未来的深刻思考。这既是一段个人回忆录，也是一部关于“如何构建持久的技术”的生动史诗，充满了值得每一位 Gopher 细细品味的智慧。 Go 的“前传”——源自贝尔实验室的“简单”基因 Go 语言对“简单”的极致追求，并非凭空而来，它的种子早已在贝尔实验室和 Plan 9 操作系统的沃土中埋下。 Russ Cox 的编程之旅，始于上世纪 90 年代末的贝尔实验室。作为一个高中生，他有幸在那个创造了 Unix 的传奇之地“厮混”，与 Brian Kernighan, Rob Pike, Ken Thompson, Dennis Ritchie 这些“上古巨神”一同午餐、交流。 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2025/russ-cox-interview-go-birth-evolution-future-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2025/12/10/russ-cox-interview-go-birth-evolution-future">本文永久链接</a> &#8211; https://tonybai.com/2025/12/10/russ-cox-interview-go-birth-evolution-future</p>
<p>大家好，我是Tony Bai。</p>
<p>他是 Go 语言的第二代掌门人，在长达十余年的时间里，引领着 Go 从一个内部实验项目，成长为云原生时代的霸主。他也是 Plan 9 的资深黑客，贝尔实验室精神的传承者。如今，他已<a href="https://tonybai.com/2024/10/10/pass-torch-to-go-new-leadership-team">将 Go 的帅印交给了下一代</a>，转身投入到 AI 模型编码能力的研究中。</p>
<p>他就是 Russ Cox。</p>
<p>在 <a href="https://learning.acm.org/bytecast/ep78-russ-cox">ACM ByteCast 的一场罕见的深度访谈</a>中，Russ Cox 系统性地回顾了他从贝尔实验室的青葱岁月，到创立 Go 语言的初心，再到对 AI 时代编程语言未来的深刻思考。这既是一段个人回忆录，也是一部关于“如何构建持久的技术”的生动史诗，充满了值得每一位 Gopher 细细品味的智慧。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/paid/api-design-pattern-and-implementation-qr.png" alt="" /></p>
<h2>Go 的“前传”——源自贝尔实验室的“简单”基因</h2>
<p>Go 语言对“简单”的极致追求，并非凭空而来，它的种子早已在贝尔实验室和 Plan 9 操作系统的沃土中埋下。</p>
<p>Russ Cox 的编程之旅，始于上世纪 90 年代末的贝尔实验室。作为一个高中生，他有幸在那个创造了 Unix 的传奇之地“厮混”，与 Brian Kernighan, Rob Pike, Ken Thompson, Dennis Ritchie 这些“上古巨神”一同午餐、交流。</p>
<blockquote>
<p>“贝尔实验室和 Plan 9 给我最深刻的印记，就是对构建<strong>真正简单</strong>的事物的执着。那里的人们，那是一个小团队，他们在做着雄心勃勃的事情，而完成它们的最好方式，就是从简单的事情开始，构建那些真正坚固可靠的简单事物。”</p>
</blockquote>
<p>这段经历，为他注入了“简单”的 DNA。然而，当他进入 MIT 读研时，他第一次遭遇了“现代 C++”的“恐怖与复杂”。他被当时的业界现状所震惊：多线程不可靠、异步回调横行…… 这让他深信：“一定有更好的方式。”</p>
<h2>Go 的“创世纪”——“让我们做点让自己开心的事”</h2>
<p>2008 年春天，当 Russ Cox 结束学业，准备进入工业界时，已经先行加入 Google 的 Rob Pike, Robert Griesemer 和 Ken Thompson 向他发出了邀请，他们正准备全职启动一个新语言项目。</p>
<p>这个项目的初心，极其纯粹和个人化。</p>
<blockquote>
<p>“我们都曾在 Google 写过大量的 C++ 程序……我们只是再也不想写那种代码了。我们受够了。我们知道有更好的方式，并且我们确信能把它带给 Google 的工程师们。”</p>
<p>“我们想解决的问题是，我们想构建一个能让我们<strong>在 Google 开心地编写程序</strong>的系统。”</p>
</blockquote>
<p><a href="https://tonybai.com/2025/07/03/meet-the-go-team-2012">Go 语言的诞生</a>，并非一次自上而下的战略规划，而是一场由几位顶尖工程师发起的、旨在解决自身痛苦的“自救运动”。他们见识过更好的开发环境（Plan 9, Modula-3, Smalltalk），他们无法忍受现代 C++ 的复杂性。Russ Cox 甚至坦言：“说实话，我当时愿意付钱换取和他们一起工作的机会，而 Google 反而付钱给我。这对我来说是双赢。”</p>
<h2>Go 的“演进哲学”——稳定压倒一切</h2>
<p>从 Plan 9 的“无人问津”，到 Go 的巨大成功，Russ Cox 对开源社区的建设和语言的演进，有着极其深刻的理解。他认为，Go 的成功，很大程度上源于其对<strong>“稳定”</strong>的执着。</p>
<blockquote>
<p>“进步可以有多种形式，一种是不稳定的进步，一种是稳定的进步。我们竭尽全力去寻找稳定的形式，而这通常意味着<strong>做得比人们要求的更少</strong>，但同时又能让他们解决自己的问题。”</p>
</blockquote>
<p>他举了 go test 与 JUnit XML 格式集成的例子。社区曾强烈要求 go test 直接输出 JUnit 格式的 XML。但 Go 团队拒绝了，因为他们不想成为一个复杂 XML 格式的“专家”和“维护者”。</p>
<p><strong>Go 团队的解决方案是</strong>：</p>
<ol>
<li>定义一个极其简单的、稳定的、机器可读的 <strong>JSON 输出格式</strong>。Go 团队只承诺维护这个简单格式的稳定性。</li>
<li>告诉社区：“然后，你们可以自己写一个从这个 JSON 到你们所需 XML 的转换器。现在，<strong>你们可以自己解决自己的问题，而无需等待我们来解决。</strong>”</li>
</ol>
<p>这种“授人以渔”而非“授人以鱼”的哲学，通过提供稳定、正交的底层构建块(build block)，赋能社区在其上构建自己的“进步”，这正是 Go 生态能够健康、蓬勃发展的核心秘诀。</p>
<h2>AI 时代的“灵魂拷问”——我们还需要 Go 吗？</h2>
<p>如今，Russ Cox 的工作重心已转向“理解和提升 AI 模型的编码能力”。对于 AI 是否会取代程序员这个终极问题，他给出了一个充满历史纵深感的、冷静的回答。</p>
<h3>AI 只是进化的又一级台阶</h3>
<p>他认为，AI 与编程语言的关系，是计算机发展史上“抽象层次不断提升”这一宏大叙事的延续。</p>
<ul>
<li><strong>40年代</strong>：我们通过手动连接电线来编程。后来，我们发明了解释器，用“数据”代替了“电线”。</li>
<li><strong>50年代</strong>：我们有了 FORTRAN，用 ax² + bx + c 这样的公式，代替了手写机器指令。</li>
<li><strong>今天</strong>：AI 正在将一些我们曾认为“只有人能做”的工作自动化，比如编写样板代码、调试简单问题。</li>
</ul>
<blockquote>
<p>“我认为 AI 将融入同样的模式……我们会将一些关注点交接出去，然后我们会找到更新、更大的事情来专注。每当我们的能力增长，或者我们将一些工作卸载给机器时，我们的雄心也会随之增长。”</p>
</blockquote>
<p>AI 不会让我们失业，它只会让我们站到更高的起点，去挑战更宏大的问题。</p>
<h3>编程语言不会消亡，清晰性永恒</h3>
<p>Russ Cox 坚信，无论 AI 如何发展，<strong>人类可读、行为确定的编程语言都不会消亡。</strong></p>
<blockquote>
<p>“英语不会成为编程语言，因为它的歧义性太高了……最终，我们描述的依然是一门编程语言。”</p>
<p>“拥有一门人类可以阅读、理解的编程语言，这一点仍然至关重要。这样，当计算机行为不端时，你可以看着代码说：‘哦，我明白了为什么在这些指令下，它没有做正确的事。’”</p>
</blockquote>
<p>AI 可能会帮助我们编写代码，但<strong>代码本身</strong>，作为人与机器之间那个最基础、最可靠的契约，其地位无可替代。</p>
<h3>Go 在 AI 时代的定位</h3>
<p>Go 诞生的初衷，是为了解决 20 年前兴起的“多核网络系统”这一巨大挑战。Russ Cox 认为，AI 很有可能在未来提出另一个同等级别的挑战，催生一门全新的语言。</p>
<blockquote>
<p>“也许会有一门专为训练模型而生的新语言。Python 目前表现出色，但很容易相信你可以用一门定制语言做得更好。但整个世界并不会都在训练模型。”</p>
</blockquote>
<p>他认为，世界上有大约 300 万 Go 开发者，但需要编写模型训练代码的人远少于此。这意味着，Go 作为一门为<strong>构建大规模、高并发网络服务</strong>而生的语言，其核心价值主张在 AI 时代不仅没有过时，反而<strong>愈发重要</strong>——因为所有的 AI 模型，最终都需要通过稳定、高效的服务来提供价值。</p>
<h2>给后辈的忠告——如何构建持久的事业？</h2>
<p>在访谈中，Russ Cox 还给所有有志于创造持久价值的年轻工程师，分享了两条极其宝贵的建议：</p>
<ol>
<li>
<p><strong>花时间去真正理解问题</strong>：“很多时候，人们很容易满足于第一个能工作的方案。而我做过的大部分有价值的事，都来自于回头审视一个问题，然后感觉：‘实际上，我还没有完全理解它，我应该再试一次。’” 深入挖掘，直到你发现一个更简单、更根本的解决方案。</p>
</li>
<li>
<p><strong>找到让你兴奋的环境</strong>：“如果你对一件事感到兴奋，你早上醒来就想继续做它，那么你最终能完成的工作，将远超那些只为完成 8 小时任务的人……去找到那些能真正激励你的事情。”</p>
</li>
</ol>
<h2>领导力的传承 —— “最重要的期末考试，是退到一旁”</h2>
<p>在访谈的最后，Russ Cox 分享了他对领导力，特别是开源项目领导力传承的深刻见解。这或许是整场对话中最具智慧和温度的部分。</p>
<p>他认为，开源社区的领导力，本质上是一种<strong>“社会性事业” (social endeavor)</strong>，沟通、协作、建立共识的能力，远比纯粹的编程能力更重要。而一个领导者最终极的考验，并非是他能做出多少贡献，而在于他能否以及何时选择<strong>“退到一旁”</strong>。</p>
<blockquote>
<p>“最终，对领导者来说最重要的期末考试，就是退到一旁，然后说：‘好吧，我甚至不需要再在这里了。现在你可以领导这个了。’ 而这很难。”</p>
</blockquote>
<p>Russ Cox 坦言，做自己擅长的事情是舒适和安全的，但他清醒地认识到，<strong>“项目需要新的想法和新的视角”</strong>。他回顾了 Go 领导权的两次交接：</p>
<ol>
<li><strong>从 Rob Pike 到 Russ Cox</strong>：一次非正式的、渐进的交接。Rob Pike 邀请他加入，并在某个时刻悄然地“把项目交给了我，我突然就负责了”。</li>
<li><strong>从 Russ Cox 到 Austin Clements</strong>：一次更正式的交接。在领导 Go 长达十年之后，Russ Cox 在 2023 年正式将帅印交给了 Austin Clements。</li>
</ol>
<p>他强调，这种传承的意义在于：</p>
<blockquote>
<p>“确保项目能超越某个特定的人而存在，并且也能获得它们所需要的新视角和新想法。”</p>
</blockquote>
<p>这不仅仅是一次权力的交接，更是一位卓越领导者对项目未来的深谋远虑和无私奉献。它确保了 Go 这艘大船，能够在新船长的引领下，继续朝着更广阔的海域航行。</p>
<hr />
<h2>结语</h2>
<p><img src="https://tonybai.com/wp-content/uploads/2025/russ-cox-interview-go-birth-evolution-future-2.png" alt="" /></p>
<p>从贝尔实验室的“简单”初心，到 Go 语言的“稳定”哲学，再到对 AI 时代的冷静远见，Russ Cox 的这场访谈，为我们描绘了一位顶尖工程师和技术领袖的心路历程。</p>
<p>他的故事告诉我们，构建持久的技术，其秘诀不在于追逐一时的潮流，而在于<strong>深刻地理解问题，坚守核心的原则，并始终保持对创造的热情</strong>。这或许也是 Go 语言之所以能穿越喧嚣，成为今天这个样子的根本原因。</p>
<p>资料链接：https://learning.acm.org/bytecast/ep78-russ-cox</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2025, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2025/12/10/russ-cox-interview-go-birth-evolution-future/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>“无聊”设计的终极奥义：为什么“做可能奏效的最简单的事”是最高法则？</title>
		<link>https://tonybai.com/2025/08/31/the-simplest-thing-that-could-possibly-work/</link>
		<comments>https://tonybai.com/2025/08/31/the-simplest-thing-that-could-possibly-work/#comments</comments>
		<pubDate>Sun, 31 Aug 2025 00:02:00 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[boring]]></category>
		<category><![CDATA[envoy]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[Hack]]></category>
		<category><![CDATA[nigix]]></category>
		<category><![CDATA[RAG]]></category>
		<category><![CDATA[rate-limit]]></category>
		<category><![CDATA[redis]]></category>
		<category><![CDATA[RichHickey]]></category>
		<category><![CDATA[SaaS]]></category>
		<category><![CDATA[scalable]]></category>
		<category><![CDATA[system-design]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[YAGNI]]></category>
		<category><![CDATA[分布式]]></category>
		<category><![CDATA[单体]]></category>
		<category><![CDATA[大泥球]]></category>
		<category><![CDATA[微服务]]></category>
		<category><![CDATA[扩展]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[无聊]]></category>
		<category><![CDATA[消息队列]]></category>
		<category><![CDATA[漏桶算法]]></category>
		<category><![CDATA[系统设计]]></category>
		<category><![CDATA[缓存]]></category>
		<category><![CDATA[限速]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=5101</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2025/08/31/the-simplest-thing-that-could-possibly-work 大家好，我是Tony Bai。 在我们解读了Github工程师Sean Goedecke关于“无聊即可靠”的系统设计和API设计理念之后，他再次带来了一篇精彩的的文章——《Do the simplest thing that could possibly work》。这既是对前两篇文章思想的延续，更是将其核心哲学提炼为一条终极黄金法则：在软件设计的每一个环节，都应“做可能奏效的最简单的事”。 这条法则，在今天这个充斥着“无限扩展”、“优雅分布式”、“完美分层”等宏大叙事的时代，显得尤为重要。Goedecke认为，工程师们最大的误区，就是试图一开始就设计出那个“理想”系统，而忽略了当下最核心的问题。 本文将继续和大家一起来深入剖析Goedecke这篇文章，领略其提出法则的真谛，探讨它如何帮助我们对抗软件工程中三大根深蒂固的敌人：对“大泥球”的恐惧、对“简单”的误解，以及对“未来扩展性”的过度痴迷。对于追求务实与高效的Go开发者来说，这套思想武器库，无疑是构建健壮、可维护系统的最佳指南。 核心法则：先深入理解，再做最简单的事 Goedecke的核心论点可以概括为两步： 花时间去深度理解当前的系统和需求。 然后，做那件能够解决当前问题的、最简单的事。 这与许多工程师的直觉相悖。我们总是被教导要“高瞻远瞩”，要设计一个能够应对未来各种可能性的“完美”架构。但Goedecke认为，这恰恰是通往失败的错误路径。 让我们以他文中的Go应用场景为例：为一个现有的Go服务添加限速功能。 “理想系统”思维：马上想到引入Redis，实现一个精巧的“漏桶算法”，构建一套独立的、可水平扩展的速率限制微服务。这套方案技术上无懈可击，充满了“工程美感”。 作者的“极简工作法”思维： 最简单的一步是什么？ 检查一下我们正在使用的边缘代理（如Nginx, Envoy）是否已经内置了速率限制功能？也许只需要几行配置就能解决问题。 如果不行，次简单的一步是什么？ 能否在应用内存中维护一个计数器？“可是重启会丢失数据！”——那么，丢失这些数据对业务的实际影响是什么？真的那么致命吗？ 如果还不行，再下一步呢？ 如果数据不能丢失，且服务是多实例部署，那么引入外部依赖（如Redis）才成为那个“能奏效的最简单的事”。 这个思考过程的精髓在于，它强迫我们不断地质问自己：“真的有必要吗？” 直到我们确认，更复杂的方案是解决当前真实存在的约束的唯一途径时，才去实施它。这正是极限编程中“YAGNI”（You Ain&#8217;t Gonna Need It）原则的终极体现。 “简单”的真谛：少即是多，平庸即伟大 一个普遍的现象是，初级工程师热衷于使用他们新学会的各种工具——数据库、缓存、消息队列、代理——来构建复杂的系统，并在白板上画出纵横交错的箭头，这让他们感觉像在做“真正的工程”。 然而，软件设计的精髓，如同武学大师的境界，在于学习何时做得更少，而非更多。 Goedecke指出，伟大的软件设计往往看起来平庸无奇（underwhelming）。它不会让你惊叹于其复杂精巧的结构。相反，当你面对一个伟大的设计时，你通常会感到惊讶：“哦，原来这个问题这么简单？”或者“太好了，我们实际上并不需要做那些复杂的事情。” Unicorn web服务器是伟大的设计，因为它利用了Unix进程这一极其“无聊”但无比可靠的原语，就解决了请求隔离、水平扩展和崩溃恢复等核心问题。标准的Rails REST API是伟大的设计，因为它用最枯燥的方式，完美地满足了CRUD应用的需求。 对三大反对意见的深刻辩驳 当然，“做最简单的事”这一法则总会面临三个经典的质疑。Goedecke对这些质疑的回应，构成了文章最精彩的部分。 1. 反对意见一：“这难道不会导致‘大泥球’（Big Ball of Mud）吗？” “做最简单的事”听起来像是鼓励走捷径、写“hack代码”。我们都见过那种由无数“hack”堆砌而成的、无法维护的“大泥球”系统。 Goedecke的反驳： “Hack”代码根本不简单！ [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2025/the-simplest-thing-that-could-possibly-work-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2025/08/31/the-simplest-thing-that-could-possibly-work">本文永久链接</a> &#8211; https://tonybai.com/2025/08/31/the-simplest-thing-that-could-possibly-work</p>
<p>大家好，我是Tony Bai。</p>
<p>在我们解读了Github工程师Sean Goedecke关于<a href="https://tonybai.com/2025/08/26/good-system-design/">“无聊即可靠”的系统设计</a>和<a href="https://tonybai.com/2025/08/29/good-api-design">API设计理念</a>之后，他再次带来了一篇精彩的的文章——《<a href="https://www.seangoedecke.com/the-simplest-thing-that-could-possibly-work/">Do the simplest thing that could possibly work</a>》。这既是对前两篇文章思想的延续，更是将其核心哲学提炼为一条终极黄金法则：在软件设计的每一个环节，都应“做可能奏效的最简单的事”。</p>
<p>这条法则，在今天这个充斥着“无限扩展”、“优雅分布式”、“完美分层”等宏大叙事的时代，显得尤为重要。Goedecke认为，工程师们最大的误区，就是试图一开始就设计出那个“理想”系统，而忽略了当下最核心的问题。</p>
<p>本文将继续和大家一起来深入剖析Goedecke这篇文章，领略其提出法则的真谛，探讨它如何帮助我们对抗软件工程中三大根深蒂固的敌人：对“大泥球”的恐惧、对“简单”的误解，以及对“未来扩展性”的过度痴迷。对于追求务实与高效的Go开发者来说，这套思想武器库，无疑是构建健壮、可维护系统的最佳指南。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/paid/go-micro-column-2025-pr.png" alt="" /></p>
<h2>核心法则：先深入理解，再做最简单的事</h2>
<p>Goedecke的核心论点可以概括为两步：</p>
<ol>
<li><strong>花时间去深度理解当前的系统和需求。</strong></li>
<li><strong>然后，做那件能够解决当前问题的、最简单的事。</strong></li>
</ol>
<p>这与许多工程师的直觉相悖。我们总是被教导要“高瞻远瞩”，要设计一个能够应对未来各种可能性的“完美”架构。但Goedecke认为，这恰恰是通往失败的错误路径。</p>
<p>让我们以他文中的Go应用场景为例：<strong>为一个现有的Go服务添加限速功能。</strong></p>
<ul>
<li><strong>“理想系统”思维</strong>：马上想到引入Redis，实现一个精巧的“漏桶算法”，构建一套独立的、可水平扩展的速率限制微服务。这套方案技术上无懈可击，充满了“工程美感”。</li>
<li><strong>作者的“极简工作法”思维</strong>：
<ol>
<li><strong>最简单的一步是什么？</strong> 检查一下我们正在使用的边缘代理（如Nginx, Envoy）是否已经内置了速率限制功能？也许只需要几行配置就能解决问题。</li>
<li><strong>如果不行，次简单的一步是什么？</strong> 能否在应用内存中维护一个计数器？“可是重启会丢失数据！”——那么，丢失这些数据对业务的实际影响是什么？真的那么致命吗？</li>
<li><strong>如果还不行，再下一步呢？</strong> 如果数据不能丢失，且服务是多实例部署，那么引入外部依赖（如Redis）才成为那个“能奏效的最简单的事”。</li>
</ol>
</li>
</ul>
<p>这个思考过程的精髓在于，它强迫我们不断地质问自己：“<strong>真的有必要吗？</strong>” 直到我们确认，更复杂的方案是解决当前<strong>真实存在</strong>的约束的唯一途径时，才去实施它。这正是极限编程中“YAGNI”（You Ain&#8217;t Gonna Need It）原则的终极体现。</p>
<h2>“简单”的真谛：少即是多，平庸即伟大</h2>
<p>一个普遍的现象是，初级工程师热衷于使用他们新学会的各种工具——数据库、缓存、消息队列、代理——来构建复杂的系统，并在白板上画出纵横交错的箭头，这让他们感觉像在做“真正的工程”。</p>
<p>然而，软件设计的精髓，如同武学大师的境界，在于<strong>学习何时做得更少，而非更多</strong>。</p>
<p>Goedecke指出，<strong>伟大的软件设计往往看起来平庸无奇（underwhelming）</strong>。它不会让你惊叹于其复杂精巧的结构。相反，当你面对一个伟大的设计时，你通常会感到惊讶：“哦，原来这个问题这么简单？”或者“太好了，我们实际上并不需要做那些复杂的事情。”</p>
<p>Unicorn web服务器是伟大的设计，因为它利用了Unix进程这一极其“无聊”但无比可靠的原语，就解决了请求隔离、水平扩展和崩溃恢复等核心问题。标准的Rails REST API是伟大的设计，因为它用最枯燥的方式，完美地满足了CRUD应用的需求。</p>
<h2>对三大反对意见的深刻辩驳</h2>
<p>当然，“做最简单的事”这一法则总会面临三个经典的质疑。Goedecke对这些质疑的回应，构成了文章最精彩的部分。</p>
<h3>1. 反对意见一：“这难道不会导致‘大泥球’（Big Ball of Mud）吗？”</h3>
<p>“做最简单的事”听起来像是鼓励走捷径、写“hack代码”。我们都见过那种由无数“hack”堆砌而成的、无法维护的“大泥球”系统。</p>
<p><strong>Goedecke的反驳：</strong> “Hack”代码根本不简单！<br />
-   <strong>“Hack”只是“更容易想到”</strong>：一个临时的补丁或权宜之计，通常是我们能最快想到的方案，但这并不意味着它是最简单的。<br />
-   <strong>“Hack”增加了系统的认知负荷</strong>：每一个“hack”都为代码库引入了一个需要被“特殊记忆”的例外。随着“hack”的增多，系统的整体复杂性是在增加，而非减少。<br />
-   <strong>真正的“简单”方案需要深度思考</strong>：找到一个正确的、优雅的修复方案，往往需要对系统有更深入的理解，并探索多种可能性。这个“正确的修复”通常比“hack”本身要简单得多。</p>
<p><strong>结论</strong>：做“最简单的事”不是放弃工程，恰恰相反，它要求我们投入更多的精力去做真正的工程设计，以找到那个最根本、最简洁的解决方案，而不是用一个又一个复杂的“补丁”去掩盖问题。</p>
<h3>2. 反对意见二：“‘简单’的定义是什么？这难道不是一个空洞的同义反复吗？”</h3>
<p>如果“最简单”就等同于“好设计”，那么“做最简单的事”不就等于说“做好设计”这句废话吗？</p>
<p>Goedecke借鉴了Rich Hickey在著名演讲《<a href="https://www.infoq.com/presentations/Simple-Made-Easy/">Simple Made Easy</a>》中的思想，对”简单“给出了一个直观的定义：</p>
<ol>
<li><strong>更少的“活动部件”</strong>：一个简单的系统，是你需要同时思考的东西更少的系统。</li>
<li><strong>更低的内部耦合</strong>：一个简单的系统，是由具有清晰、直接接口的组件构成的。</li>
</ol>
<p>基于这个定义，他给出了一个实用的<strong>决断法则</strong>：<strong>简单的系统更加稳定。</strong></p>
<p>如果在两个方案之间抉择，一个方案在需求不变的情况下需要持续的维护、监控和干预（比如部署和维护一个Redis集群），而另一个则不需要，那么后者就是更简单的。</p>
<p>因此，对于Go的速率限制例子，<strong>内存方案比Redis方案更简单</strong>，因为它减少了外部依赖、监控需求和部署复杂性这些“活动部件”。</p>
<h3>3. 反对意见三：“难道我们不应该构建可扩展（scalable）的系统吗？”</h3>
<p>这是来自大型科技公司工程师最常见的呐喊：“内存限流根本无法扩展！”</p>
<p><strong>Goedecke的反驳：</strong> 对“扩展性”的痴迷，是SaaS工程领域最大的原罪。</p>
<ul>
<li><strong>过早的扩展性设计通常是无效的</strong>：你无法准确预测一个非凡系统在流量增长几个数量级后，瓶颈会出现在哪里。为遥远的未来进行过度设计，往往是在解决一个根本不存在或被错误预测的问题。</li>
<li><strong>过早的扩展性设计会使代码库僵化</strong>：为了所谓的“独立扩展”，你可能会过早地将一个单体服务拆分为多个微服务。这引入了网络通信、分布式事务等一系列极其困难的工程问题，使得实现某些功能变得异常艰难。“我见过很多次这种拆分，但真正从中受益的，可能只有一次。”</li>
<li><strong>务实的扩展策略</strong>：最多为当前流量的2倍或5倍做准备。然后，<strong>保持系统的简单和灵活</strong>，以便在真正的瓶颈出现时，能够快速地识别和解决它。</li>
</ul>
<p>在Go社区，我们经常看到关于“单体 vs 微服务”的讨论。Goedecke的观点为我们提供了清晰的指引：<strong>保持单体的简单性，直到拆分的必要性变得无可辩驳。</strong> 一个设计良好、简单的Go单体应用，其扩展能力远超大多数人的想象。</p>
<h2>小结：拥抱当下，而不是预测未来</h2>
<p>Goedecke在文末总结道，软件开发有两种基本方式：</p>
<ol>
<li><strong>预测未来</strong>：预测半年或一年后的需求，并为此设计一个“最佳”系统。</li>
<li><strong>拥抱现在</strong>：为当前已知的、真实的需求，设计一个“最佳”系统。</li>
</ol>
<p>他悲观地认为，我们人类作为一个集体，预测系统未来走向的能力非常有限。我们甚至很难完全理解一个系统当前的状态。因此，第一种方式往往导致糟糕的设计。</p>
<p>唯一的理性选择是第二种：<strong>做那个可能奏效的、最简单的事</strong>。</p>
<p>这要求我们放弃作为工程师的某种虚荣心，不再追求构建那些看起来“令人印象深刻”的复杂系统。相反，我们应该拥抱“无聊”，致力于创造那些看似平庸，却异常健壮、稳定且易于理解和修改的系统。</p>
<p>这，或许就是从“优秀”走向“卓越”的工程师，其设计哲学的终极奥义。</p>
<hr />
<p><strong>想系统学习Go，构建扎实的知识体系？</strong></p>
<p>我的新书《Go语言第一课》是你的首选。源自2.4万人好评的极客时间专栏，内容全面升级，同步至Go 1.24。首发期有专属五折优惠，不到40元即可入手，扫码即可拥有这本300页的Go语言入门宝典，即刻开启你的Go语言高效学习之旅！</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/go-primer-published-4.png" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2025, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2025/08/31/the-simplest-thing-that-could-possibly-work/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Go 比 Python 更懂“Python 之禅”？</title>
		<link>https://tonybai.com/2025/07/19/go-understand-the-zen-of-python-better-than-python/</link>
		<comments>https://tonybai.com/2025/07/19/go-understand-the-zen-of-python-better-than-python/#comments</comments>
		<pubDate>Sat, 19 Jul 2025 11:46:29 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[error]]></category>
		<category><![CDATA[for]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[gofmt]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[goroutine]]></category>
		<category><![CDATA[PEP]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[reddit]]></category>
		<category><![CDATA[RobPike]]></category>
		<category><![CDATA[TheZenOfPython]]></category>
		<category><![CDATA[try]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[zen]]></category>
		<category><![CDATA[可读性]]></category>
		<category><![CDATA[工程]]></category>
		<category><![CDATA[并发]]></category>
		<category><![CDATA[显式]]></category>
		<category><![CDATA[设计哲学]]></category>
		<category><![CDATA[错误处理]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=4918</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2025/07/19/go-understand-the-zen-of-python-better-than-python 大家好，我是Tony Bai。 最近，在国外的 Go 语言社区（Reddit r/golang）上，一个帖子引发了热烈的讨论。标题颇具“引战”意味：“Go似乎比Python更好地实现了Python之禅”。 这听起来像个悖论，甚至有点冒犯。用一个语言的哲学去评判另一个语言，就像用“太极”的理念去评价“咏春”，似乎风马牛不相及。但仔细看完社区的讨论，你会发现这并非无稽之谈，反而是一个极其刁钻又深刻的视角，能帮助我们重新审视 Go 语言设计的底层逻辑。 作为一名在 Go 的世界里摸爬滚打了多年的老 Gopher，我也不止一次有过类似的感觉。今天，我们就借着这场社区热议，一起聊聊这个有趣的话题。 重温“Python之禅” 首先，让我们重温一下那首著名的“Python之禅”（The Zen of Python）。在任何一个 Python 解释器里输入 import this，你都能看到它： The Zen of Python, by Tim Peters Python之禅，作者：蒂姆·彼得斯 Beautiful is better than ugly. 优美优于丑陋。 Explicit is better than implicit. 显式优于隐式。 Simple is better than complex. 简单优于复杂。 Complex is better than [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2025/go-understand-the-zen-of-python-better-than-python-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2025/07/19/go-understand-the-zen-of-python-better-than-python">本文永久链接</a> &#8211; https://tonybai.com/2025/07/19/go-understand-the-zen-of-python-better-than-python</p>
<p>大家好，我是Tony Bai。</p>
<p>最近，在国外的 Go 语言社区（Reddit r/golang）上，一个帖子引发了热烈的讨论。标题颇具“引战”意味：“<a href="https://www.reddit.com/r/golang/comments/1m302i6/go_seems_to_accomplish_the_zen_of_python_way/">Go似乎比Python更好地实现了Python之禅</a>”。</p>
<p>这听起来像个悖论，甚至有点冒犯。用一个语言的哲学去评判另一个语言，就像用“太极”的理念去评价“咏春”，似乎风马牛不相及。但仔细看完社区的讨论，你会发现这并非无稽之谈，反而是一个极其刁钻又深刻的视角，能帮助我们重新审视 Go 语言设计的底层逻辑。</p>
<p>作为一名在 Go 的世界里摸爬滚打了多年的老 Gopher，我也不止一次有过类似的感觉。今天，我们就借着这场社区热议，一起聊聊这个有趣的话题。</p>
<h2>重温“Python之禅”</h2>
<p>首先，让我们重温一下那首著名的“Python之禅”（<a href="https://peps.python.org/pep-0020/">The Zen of Python</a>）。在任何一个 Python 解释器里输入 import this，你都能看到它：</p>
<pre><code class="python">The Zen of Python, by Tim Peters
Python之禅，作者：蒂姆·彼得斯

Beautiful is better than ugly.
优美优于丑陋。

Explicit is better than implicit.
显式优于隐式。

Simple is better than complex.
简单优于复杂。

Complex is better than complicated.
复杂优于繁杂。

Flat is better than nested.
扁平优于嵌套。

Sparse is better than dense.
稀疏优于密集。

Readability counts.
可读性至关重要。

Special cases aren't special enough to break the rules.
特例不足以特殊到足以打破规则。

Although practicality beats purity.
虽然实用性胜过纯粹性。

Errors should never pass silently.
错误绝不能悄无声息地被忽略。

Unless explicitly silenced.
除非显式地使其沉默。

In the face of ambiguity, refuse the temptation to guess.
面对歧义，拒绝猜测的诱惑。

There should be one-- and preferably only one --obvious way to do it.
应该有且最好只有一种显而易见的实现方式。

Although that way may not be obvious at first unless you're Dutch.
虽然这种方式一开始可能并不那么明显，除非你是荷兰人。

Now is better than never.
现在优于永不。

Although never is often better than right now.
虽然，永不去做常常比“马上”动手要好。

If the implementation is hard to explain, it's a bad idea.
如果实现很难解释，那么它是个坏主意。

If the implementation is easy to explain, it may be a good idea.
如果实现很容易解释，那么它可能是个好主意。

Namespaces are one honking great idea -- let's do more of those!
命名空间是个绝妙的主意——让我们多多地使用它吧！
</code></pre>
<p>这不仅仅是代码风格指南，更是一种编程哲学的宣言。而奇妙的是，当我们手握 Go 这把锤子时，会发现很多钉子恰好就是按照这份宣言的图纸来设计的。</p>
<h2>“显式优于隐式”：Go 的灵魂，Python 的妥协</h2>
<p>这是“Python之禅”中最核心的信条之一，也是 Go 语言最引以为傲（或被吐槽）的特征所在。</p>
<p>想想 Go 语言里最经典的 if err != nil。新手可能会觉得它繁琐、重复，破坏了代码的流畅性。但在经验丰富的工程师眼中，这正是“显式”的极致体现。每一次函数调用，你都被迫直面其可能失败的现实，错误处理的路径清晰得如同一条直线，没有任何隐藏的控制流跳跃。</p>
<p>相比之下，Python 的 try&#8230;except 机制虽然优雅，却在某种程度上是“隐式”的。一个 try 代码块里可能有多行代码，任何一行都可能抛出异常，然后被远处的某个 except 捕获。这使得控制流变得不再那么一目了然。一位 Reddit 用户评论说：“自从我见过那些数据科学代码后，‘显式优于隐式’这条让我笑出了声。” 这虽然是句玩笑，却精准地指出了在复杂项目中，隐式处理可能带来的维护难题。</p>
<p>Go 通过把错误（error）设计成普通的值，而不是一个特殊的控制流机制，完美践行了“显式优于隐式”的原则。它是你必须亲手处理的返回值，而不是可以被忽略的“天外来客”。</p>
<h2>“简单优于复杂”：Go 的克制与执拗</h2>
<p>Go 语言的设计者们（Rob Pike, Ken Thompson 等）深受 Unix 哲学的影响，对“简单”有着近乎偏执的追求。</p>
<ul>
<li><strong>语法克制</strong>：Go 只有一个循环关键字 for，没有 while 或 do-while。它没有类和继承，取而代之的是更纯粹的组合与接口。并发模型也异常简单——go 关键字启动一个 goroutine，chan 进行通信，大道至简。</li>
<li><strong>工具统一</strong>：gofmt 的存在，终结了所有关于代码格式的“圣战”。它体现了“Python之禅”中的另一条原则：“应该有且最好只有一种显而易见的实现方式”。在 Go 的世界里，代码风格不是一个需要讨论的问题，这极大地降低了团队协作的认知负荷。</li>
</ul>
<p>反观 Python，随着其生态的繁荣和应用领域的扩张，语言本身不可避免地变得越来越复杂。从最初与 Perl、PHP 竞争的简洁脚本语言，到如今涵盖 Web 开发、数据科学、AI 的庞然大物，它引入了 async/await、复杂的元编程能力等。这并非坏事，而是语言成熟和演化的必然结果。但与诞生之初就目标明确（解决 Google 内部大规模工程问题）的 Go 相比，Python 在“保持简单”这条路上，显然背负了更沉重的历史包袱。</p>
<h2>客观看待：Go 的“禅意”并非没有代价</h2>
<p>当然，我们不能一边倒地吹捧。Reddit 的讨论中也充满了理性的声音。Go 为了实现这种“禅意”，也付出了相应的代价。</p>
<ul>
<li><strong>“优美优于丑陋”（Beautiful is better than ugly）</strong>：美是主观的。很多人认为 Go 的语法过于朴素，if err != nil 更是“丑陋”的代名词。但正如一位评论者所言：“我喜欢它，正是因为它在美学上很中庸（aesthetically mid）。” Go 的美，更多是一种“工程之美”，是结构清晰、易于维护、性能可靠的美，而非语法糖堆砌出的“华丽之美”。</li>
<li><strong>“模板代码”（Boilerplate）</strong>：Go 的“显式”和“简单”，直接导致了更多的模板代码。这是为了可读性和可维护性做出的权衡。社区也意识到了这一点，因此 Go 在泛型等方面的引入，以及强大的代码生成工具生态，都是在弥补这一“短板”。</li>
</ul>
<h2>小结：源于血脉的哲学共鸣</h2>
<p>那么，为什么 Go 会比它的“老师” Python 更像一个“禅宗信徒”呢？</p>
<p>答案可能在它的“血脉”里。Go 的设计者们是创造了 C 语言、Unix 和 UTF-8 的传奇人物。他们骨子里流淌的是系统编程的血液，追求的是在数十、上百乃至上千工程师协作的大型项目中，如何保证代码的长期可读性、可维护性和稳定性。</p>
<p>这种背景决定了 Go 的设计哲学必然倾向于：<strong>明确、简单、组合、正交</strong>。</p>
<p>它不追求用最少的代码行数表达最复杂的逻辑（那是 Python 的强项），而是追求让任何一个中等水平的工程师都能在最短时间内读懂并安全地修改代码。</p>
<p>从这个角度看，Go 并非“碰巧”契合了“Python之禅”，而是它的核心设计目标——<strong>工程化与可维护性</strong>——恰好与“Python之禅”所倡导的<strong>清晰与简洁</strong>产生了深刻的共鸣。可以说，Go 是在用一种更底层、更工程化的方式，对“Python之禅”进行了重新演绎。</p>
<p>所以，回到最初的问题：“Go 比 Python 更懂‘Python之禅’吗？”</p>
<p>或许，更准确的说法是：<strong>Go，在它所专注的领域里，以一种更为决绝和纯粹的方式，活成了“Python之禅”希望的样子。</strong></p>
<p>对此，你怎么看？欢迎在评论区留下你的想法。</p>
<p>资料链接：https://www.reddit.com/r/golang/comments/1m302i6/go_seems_to_accomplish_the_zen_of_python_way</p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2025, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2025/07/19/go-understand-the-zen-of-python-better-than-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Go 1.25链接器提速、执行文件瘦身：DWARF 5调试信息格式升级终落地</title>
		<link>https://tonybai.com/2025/05/08/go-dwarf5/</link>
		<comments>https://tonybai.com/2025/05/08/go-dwarf5/#comments</comments>
		<pubDate>Thu, 08 May 2025 00:05:53 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[BSS]]></category>
		<category><![CDATA[CD]]></category>
		<category><![CDATA[CI]]></category>
		<category><![CDATA[Clang]]></category>
		<category><![CDATA[Compiler]]></category>
		<category><![CDATA[Debug]]></category>
		<category><![CDATA[delve]]></category>
		<category><![CDATA[DWARF]]></category>
		<category><![CDATA[GCC]]></category>
		<category><![CDATA[GDB]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[GNU]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[go1.25]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[issue]]></category>
		<category><![CDATA[link]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[macos]]></category>
		<category><![CDATA[objump]]></category>
		<category><![CDATA[relocation]]></category>
		<category><![CDATA[section]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[代码段]]></category>
		<category><![CDATA[数据段]]></category>
		<category><![CDATA[编译]]></category>
		<category><![CDATA[调试]]></category>
		<category><![CDATA[重定位]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=4664</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2025/05/08/go-dwarf5 大家好，我是Tony Bai。 对于许多Go开发者来说，调试信息的格式可能是一个相对底层的细节。然而，这个细节却对编译速度、最终可执行文件的大小以及调试体验有着深远的影响。经过长达六年的讨论、等待生态成熟和密集的开发工作，Go 语言工具链终于在主干分支（预计将包含在 Go 1.25 中）默认启用了 DWARF version 5 作为其调试信息的标准格式（Issue #26379）。这一看似“幕后”的变更，实则为 Go 开发者带来了切实的链接速度提升和可执行文件体积的优化。在这篇文章中，我们就来对DWARF5落地Go这件事儿做一个简单的解读。 为何需要升级到 DWARF 5？旧格式的痛点 DWARF (Debugging With Attributed Record Formats) 是类 Unix 系统上广泛使用的调试信息标准。Go 之前使用的 DWARF 版本（主要是 v2 和 v4）虽然成熟，但在现代软件开发实践中暴露出一些不足： 大量的重定位 (Relocations): 旧版 DWARF 格式通常包含大量需要链接器处理的地址重定位信息。根据 2018 年的初步分析（by aclements），在当时的 go 二进制文件中，高达 49% 的重定位条目都源于 DWARF 数据。这显著增加了链接器的工作负担，拖慢了构建速度，尤其是对于大型项目。 冗长的位置和范围列表 (Location/Range Lists): 用于描述变量生命周期和代码范围的 .debug_loc 和 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2025/go-dwarf5-1.jpg" alt="" /></p>
<p><a href="https://tonybai.com/2025/05/08/go-dwarf5">本文永久链接</a> &#8211; https://tonybai.com/2025/05/08/go-dwarf5</p>
<p>大家好，我是Tony Bai。</p>
<p>对于许多Go开发者来说，调试信息的格式可能是一个相对底层的细节。然而，这个细节却对编译速度、最终可执行文件的大小以及调试体验有着深远的影响。经过长达六年的讨论、等待生态成熟和密集的开发工作，Go 语言工具链终于在主干分支（预计将包含在 Go 1.25 中）默认启用了 <strong>DWARF version 5</strong> 作为其调试信息的标准格式（<a href="https://github.com/golang/go/issues/26379">Issue #26379</a>）。这一看似“幕后”的变更，实则为 Go 开发者带来了切实的<strong>链接速度提升</strong>和<strong>可执行文件体积的优化</strong>。在这篇文章中，我们就来对DWARF5落地Go这件事儿做一个简单的解读。</p>
<h2>为何需要升级到 DWARF 5？旧格式的痛点</h2>
<p>DWARF (Debugging With Attributed Record Formats) 是类 Unix 系统上广泛使用的调试信息标准。Go 之前使用的 DWARF 版本（主要是 v2 和 v4）虽然成熟，但在现代软件开发实践中暴露出一些不足：</p>
<ol>
<li><strong>大量的重定位 (Relocations):</strong> 旧版 DWARF 格式通常包含大量需要链接器处理的地址重定位信息。根据 2018 年的初步分析（by aclements），在当时的 go 二进制文件中，高达 <strong>49%</strong> 的重定位条目都源于 DWARF 数据。这显著增加了链接器的工作负担，拖慢了构建速度，尤其是对于大型项目。</li>
<li><strong>冗长的位置和范围列表 (Location/Range Lists):</strong> 用于描述变量生命周期和代码范围的 .debug_loc 和 .debug_ranges 等section的数据在旧格式下可能非常庞大。即便经过压缩，它们也能占到可执行文件大小的相当一部分（例如，当时 go 二进制的 12MiB 中占 6%）。</li>
<li><strong>缺乏官方 Go 语言代码:</strong> 虽然不影响功能，但 DWARF 5 正式为 Go 语言分配了官方的语言代码 (DW_LANG_Go)。</li>
</ol>
<p>DWARF 5 标准针对这些痛点进行了改进，其关键优势在于：</p>
<ul>
<li><strong>位置无关表示 (Position-Independent Representations):</strong> DWARF 5 引入了如 .debug_addr, .debug_rnglists, .debug_loclists 等新 Section 格式，它们的设计能大幅减少甚至消除对重定位的需求，从而减轻链接器负担。</li>
<li><strong>更紧凑的列表格式:</strong> 新的列表格式 (.debug_rnglists, .debug_loclists) 比旧的 (.debug_ranges, .debug_loc) 更为紧凑，有助于减小调试信息的大小。</li>
</ul>
<h2>从提案到落地：漫长的等待与集中的开发</h2>
<p>尽管 DWARF 5 的优势显而易见，但 Go 社区在 2018 年提出该想法时（by aclements），整个开发工具生态（如调试器 LLDB、macOS 的链接器和 dsymutil 工具等）对其支持尚不完善。因此，该提案被暂时搁置，等待时机成熟。</p>
<p>近年来，随着主流工具链（GCC 7.1+, GDB 8.0+, Clang 14+）纷纷将 DWARF 5 作为默认选项，生态环境逐渐成熟。Go 团队成员 <strong>Than McIntosh</strong> 承担了将 Go 工具链迁移到 DWARF 5 的主要开发工作。这涉及对编译器 (cmd/compile) 和链接器 (cmd/link) 的大量修改，引入了新的 GOEXPERIMENT=dwarf5 实验开关进行测试，并提交了一系列相关的变更集 (CLs)，包括：</p>
<ul>
<li>添加 DWARF 5 相关常量和 relocation 类型定义。</li>
<li>实现对 .debug_addr, .debug_rnglists, .debug_loclists section 的生成和支持。</li>
<li>更新 DWARF 5 的行号表 (line table) 支持。</li>
<li>适配 x/debug/dwtest 和 internal/gocore 等内部库。</li>
<li>协调 Delve 调试器对 DWARF 5 的支持。</li>
</ul>
<h2>成果显著：链接速度提升与体积优化</h2>
<p>经过广泛的测试和 compilebench 基准评估，启用 DWARF 5 带来了可观的性能收益：</p>
<ul>
<li><strong>链接速度显著提升:</strong> ExternalLinkCompiler 基准测试显示链接时间减少了 <strong>约 14%</strong>。这主要得益于 DWARF 5 减少了链接器需要处理的重定位数量。</li>
<li><strong>可执行文件体积减小:</strong> HelloSize 和 CmdGoSize 基准显示最终可执行文件大小平均减小了 <strong>约 3%</strong>。这归功于 DWARF 5 更紧凑的列表格式。</li>
<li><strong>编译时间略有改善:</strong> 整体编译时间 (geomean) 也有约 <strong>1.9%</strong> 的小幅提升。</li>
</ul>
<p>虽然对代码段 (.text)、数据段 (.data)、BSS 段的大小几乎没有影响，但链接耗时和最终文件大小的优化对于大型项目和 CI/CD 流程来说意义重大。</p>
<h2>挑战与妥协：并非所有平台一步到位</h2>
<p>在推进 DWARF 5 的过程中，也遇到了一些平台兼容性问题，导致 Go 团队采取了审慎的策略：</p>
<ol>
<li><strong>macOS dsymutil 限制:</strong> 旧版本的 macOS Xcode 自带的 dsymutil 工具（用于处理和分离 DWARF 信息）不支持 DWARF 5 新引入的 .debug_rnglists 和 .debug_loclists section。这会导致在使用<strong>外部链接 (external linking)</strong> 构建 CGO 程序时，Go 代码的调试信息丢失。虽然 LLVM 17 (对应 Xcode 16+) 已修复此问题，但考虑到仍有大量开发者使用旧版 Xcode（官方支持最低到 Xcode 14），Go 团队决定<strong>在 macOS 和 iOS 平台上进行外部链接时，暂时回退到 DWARF 4</strong>。未来当最低支持的 Xcode 版本兼容 DWARF 5 后，有望统一。</li>
<li><strong>AIX 平台限制:</strong> AIX 使用的 XCOFF 文件格式本身不支持 DWARF 5 所需的 Section 类型。因此，<strong>AIX 平台将继续使用 DWARF 4</strong> (GOEXPERIMENT=nodwarf5 默认开启)。</li>
<li><strong>GNU objdump 兼容性:</strong> objdump 工具在解析 Go 生成的 monolithic .debug_addr section 时会打印警告（因为它期望每个编译单元都有一个 header，而 Go 链接器只生成一个）。这被认为是一个 objdump 的小问题（已提议向上游提交修复），不影响实际功能，因此 Go 团队决定继续采用 monolithic 方式。</li>
</ol>
<h2>对开发者的影响与总结</h2>
<p>对于大多数 Go 开发者而言，这项变更将在 Go 1.25 及以后版本中<strong>默认生效</strong>（除了上述 macOS 外部链接和 AIX 平台）。你将自动享受到<strong>更快的链接速度</strong>和<strong>略小的可执行文件</strong>。</p>
<ul>
<li><strong>调试体验:</strong> 虽然 DWARF 5 本身设计更优，但对日常使用 Delve 等调试器的直接体验影响可能不明显，主要好处体现在工具链效率和文件大小上。</li>
<li><strong>注意事项:</strong> 如果你在 macOS 上进行 CGO 开发并使用外部链接，或者面向 AIX 平台，需要了解调试信息格式仍将是 DWARF 4。</li>
</ul>
<p>总而言之，Go 工具链采纳 DWARF 5 是一个重要的里程碑。它不仅解决了旧格式的一些固有问题，提升了构建效率，也是 Go 语言紧跟底层技术标准发展、持续优化开发者体验的重要一步。这项历时多年的工作最终落地，体现了 Go 社区在推动技术演进方面的耐心和决心。</p>
<h2>参考资料</h2>
<ul>
<li><a href="https://github.com/golang/go/issues/26379">cmd/compile: consider using DWARF 5</a> &#8211; https://github.com/golang/go/issues/26379</li>
<li><a href="https://dwarfstd.org/dwarf5std.html">DWARF Version 5</a> &#8211; https://dwarfstd.org/dwarf5std.html</li>
</ul>
<hr />
<p><strong>聊聊你的编译构建体验</strong></p>
<p>Go 1.25 工具链的这项 DWARF 5 升级，虽然“藏”在幕后，但实实在在地为我们带来了链接速度和文件大小的优化。<strong>你在日常的 Go 项目开发中，是否也曾被编译链接速度或可执行文件体积困扰过？</strong> 你对 Go 工具链在这些方面的持续改进有什么期待或建议吗？或者，你是否了解其他能有效优化构建体验的技巧？</p>
<p><strong>欢迎在评论区分享你的经验、痛点与期待！</strong> 让我们共同见证 Go 工具链的进步。</p>
<p><strong>想深入探索Go的编译、链接与底层奥秘？</strong></p>
<p>如果你对 Go 工具链如何工作、编译优化、链接器原理，乃至像 DWARF 这样的底层细节充满兴趣，希望系统性地构建对 Go 语言“从源码到可执行文件”全链路的深刻理解&#8230;</p>
<p>那么，我的 <strong>「Go &amp; AI 精进营」知识星球</strong> 正是为你打造的深度学习平台！这里有【Go原理课】带你解密语言核心机制，【Go进阶课】助你掌握高级技巧，更有【Go避坑课】让你少走弯路。我会亲自为你解答各种疑难问题，你还可以与众多热爱钻研的Gopher们一同交流，探索Go的更多可能，包括它在AI等前沿领域的应用。</p>
<p><strong>扫码加入，与我们一同潜入Go的底层世界，成为更懂Go的开发者！</strong></p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-and-ai-tribe-zsxq-small-card.jpg" alt="img{512x368}" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2025, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2025/05/08/go-dwarf5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Go包构建：专家也未必了解的文件选择细节</title>
		<link>https://tonybai.com/2024/11/21/go-source-file-selection-details-when-building-package/</link>
		<comments>https://tonybai.com/2024/11/21/go-source-file-selection-details-when-building-package/#comments</comments>
		<pubDate>Wed, 20 Nov 2024 22:57:08 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[aix]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[BSD]]></category>
		<category><![CDATA[buildconstraints]]></category>
		<category><![CDATA[buildtag]]></category>
		<category><![CDATA[Cgo]]></category>
		<category><![CDATA[Darwin]]></category>
		<category><![CDATA[fmt]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[go1.23]]></category>
		<category><![CDATA[GOARCH]]></category>
		<category><![CDATA[gobuild]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[golist]]></category>
		<category><![CDATA[gomodule]]></category>
		<category><![CDATA[GOOS]]></category>
		<category><![CDATA[Go语言精进之路]]></category>
		<category><![CDATA[illumos]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[JS]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[ReleaseTags]]></category>
		<category><![CDATA[toolchain]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[wasm]]></category>
		<category><![CDATA[包]]></category>
		<category><![CDATA[工具链]]></category>
		<category><![CDATA[构建约束]]></category>
		<category><![CDATA[标准库]]></category>
		<category><![CDATA[编译]]></category>
		<category><![CDATA[链接]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=4405</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2024/11/21/go-source-file-selection-details-when-building-package 在Go语言开发中，包（package）是代码组织的基本单位，也是基本的构建单元。Go编译器会将每个包构建成一个目标文件(.a)，然后通过链接器将这些目标文件链接在一起，形成最终的可执行程序。 尽管Go包的构建过程看似简单，但实际上蕴含着许多值得深入了解的细节。例如，当我们执行go build命令时，Go编译器是如何选择需要编译的源文件的？你可能会回答：“不就是通过文件名中的ARCH和OS标识以及构建约束（build constraints）来选择的吗？” 虽然你的答案并没有错，但如果我进一步提出以下问题，你是否还能给出确切的答案呢？ 假设一个Go源文件使用了如下的构建约束： //go:build unix package foo // ... ... 在执行GOOS=android go build时，这个文件是否会被编译？如果执行的是GOOS=aix go build呢？而“unix”究竟包含了哪些操作系统？ 再进一步，当一个源文件的文件名中包含ARCH和操作系统标识，并且文件内容中也使用了构建约束时，Go编译器会如何处理这些信息的优先级？ 即使是经验丰富的Go专家，对于上述在包构建过程中涉及的文件选择细节，可能也只能给出模糊的答案。 在实际开发中，我们常常需要针对不同操作系统和架构编写特定的代码，这意味着灵活性与复杂性并存。Go的构建约束和文件名约定虽然为我们提供了灵活性，但也带来了额外的复杂性。理解这些规则不仅有助于优化构建过程，还能有效避免潜在的错误和不必要的麻烦。 在这篇文章中，我将与大家探讨Go包构建过程中源文件选择的细节，包括文件名中ARCH和os标识约定和构建约束的作用，以及二者的优先级处理问题。希望通过这些内容，帮助开发者更好地掌握Go语言的构建机制，从而提高开发效率。 为了更好地说明Go包构建时的文件选择逻辑，我们先从Go包构建的一些“表象”说起。 注：在本文中，我们将使用Go 1.17引入的新版build constraints写法：//go:build ，之前的// +build aix darwin dragonfly freebsd js,wasm &#8230;写法已经不再被推荐使用。如果你想对旧版build constraints写法有一个全面了解以便与新写法对比，推荐阅读我的《Go语言精进之路：从新手到高手的编程思想、方法和技巧》第2册。 1. 表象 在Go工程中，通常一个目录对应一个Go包，每个Go包下可以存在多个以.go为后缀的Go源文件，这些源文件只能具有唯一的包名（测试源文件除外），以标准库fmt包为例，它的目录下的源文件列表如下(以Go 1.23.0源码为例)： $ls $GOROOT/src/fmt doc.go export_test.go print.go stringer_example_test.go errors.go fmt_test.go scan.go stringer_test.go errors_test.go format.go scan_test.go [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/go-source-file-selection-details-when-building-package-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2024/11/21/go-source-file-selection-details-when-building-package">本文永久链接</a> &#8211; https://tonybai.com/2024/11/21/go-source-file-selection-details-when-building-package</p>
<p>在Go语言开发中，<a href="https://tonybai.com/2023/06/18/go-package-design-guide/">包（package）是代码组织的基本单位</a>，也是基本的构建单元。Go编译器会将每个包构建成一个目标文件(.a)，然后通过链接器将这些目标文件链接在一起，形成最终的可执行程序。</p>
<p>尽管Go包的构建过程看似简单，但实际上蕴含着许多值得深入了解的细节。例如，当我们执行go build命令时，Go编译器是如何选择需要编译的源文件的？你可能会回答：“不就是通过文件名中的ARCH和OS标识以及构建约束（build constraints）来选择的吗？” 虽然你的答案并没有错，但如果我进一步提出以下问题，你是否还能给出确切的答案呢？</p>
<p>假设一个Go源文件使用了如下的构建约束：</p>
<pre><code>//go:build unix

package foo
// ... ...
</code></pre>
<p>在执行GOOS=android go build时，这个文件是否会被编译？如果执行的是GOOS=aix go build呢？而“unix”究竟包含了哪些操作系统？</p>
<p>再进一步，当一个源文件的文件名中包含ARCH和操作系统标识，并且文件内容中也使用了构建约束时，Go编译器会如何处理这些信息的优先级？</p>
<p>即使是经验丰富的Go专家，对于上述在包构建过程中涉及的文件选择细节，可能也只能给出模糊的答案。</p>
<p>在实际开发中，我们常常需要针对不同操作系统和架构编写特定的代码，这意味着灵活性与复杂性并存。Go的构建约束和文件名约定虽然为我们提供了灵活性，但也带来了额外的复杂性。理解这些规则不仅有助于优化构建过程，还能有效避免潜在的错误和不必要的麻烦。</p>
<p>在这篇文章中，我将与大家探讨<strong>Go包构建过程中源文件选择的细节</strong>，包括文件名中ARCH和os标识约定和构建约束的作用，以及二者的优先级处理问题。希望通过这些内容，帮助开发者更好地掌握Go语言的构建机制，从而提高开发效率。</p>
<p>为了更好地说明Go包构建时的文件选择逻辑，我们先从Go包构建的一些“表象”说起。</p>
<blockquote>
<p>注：在本文中，我们将使用<a href="https://tonybai.com/2021/08/17/some-changes-in-go-1-17">Go 1.17</a>引入的新版build constraints写法：//go:build ，之前的// +build aix darwin dragonfly freebsd js,wasm &#8230;写法已经不再被推荐使用。如果你想对旧版build constraints写法有一个全面了解以便与新写法对比，推荐阅读我的<a href="https://book.douban.com/subject/35720729/">《Go语言精进之路：从新手到高手的编程思想、方法和技巧》第2册</a>。</p>
</blockquote>
<h2>1. 表象</h2>
<p>在Go工程中，通常一个目录对应一个Go包，每个Go包下可以存在多个以.go为后缀的Go源文件，这些源文件只能具有唯一的包名（测试源文件除外），以标准库fmt包为例，它的目录下的源文件列表如下(以<a href="https://tonybai.com/2024/08/19/some-changes-in-go-1-23/">Go 1.23.0</a>源码为例)：</p>
<pre><code>$ls $GOROOT/src/fmt
doc.go              export_test.go          print.go            stringer_example_test.go
errors.go           fmt_test.go         scan.go             stringer_test.go
errors_test.go          format.go           scan_test.go
example_test.go         gostringer_example_test.go  state_test.go
</code></pre>
<p>在这些文件中，哪些最终进入到了fmt包的目标文件(fmt.a)中呢？<strong>贴心的Go工具链</strong>为我们提供了查看方法：</p>
<pre><code>$go list -f '{{.GoFiles}}' fmt
[doc.go errors.go format.go print.go scan.go]
</code></pre>
<p>对于独立于目标ARCH和OS的fmt包来说，其Go源文件的选择似乎要简单一些。我们看到，除了包测试文件(xxx&#95;test.go)，其他文件都被编译到了最终的fmt包中。</p>
<p>我们再来看一个与目标ARCH和OS相关性较高的net包。除去子目录，这个包目录下的Go源文件数量大约有220多个，但在<strong>macOS/amd64</strong>下通过go list查看最终进入net包目标文件的文件，大约只有几十个：</p>
<pre><code>$go list -f '{{.GoFiles}}' net
[addrselect.go cgo_darwin.go cgo_unix.go cgo_unix_syscall.go conf.go dial.go dnsclient.go dnsclient_unix.go dnsconfig.go dnsconfig_unix.go error_posix.go error_unix.go fd_posix.go fd_unix.go file.go file_unix.go hook.go hook_unix.go hosts.go interface.go interface_bsd.go interface_darwin.go ip.go iprawsock.go iprawsock_posix.go ipsock.go ipsock_posix.go lookup.go lookup_unix.go mac.go mptcpsock_stub.go net.go netcgo_off.go netgo_off.go nss.go parse.go pipe.go port.go port_unix.go rawconn.go rlimit_unix.go sendfile_unix_alt.go sock_bsd.go sock_posix.go sockaddr_posix.go sockopt_bsd.go sockopt_posix.go sockoptip_bsdvar.go sockoptip_posix.go splice_stub.go sys_cloexec.go tcpsock.go tcpsock_posix.go tcpsock_unix.go tcpsockopt_darwin.go tcpsockopt_posix.go udpsock.go udpsock_posix.go unixsock.go unixsock_posix.go unixsock_readmsg_cloexec.go writev_unix.go]
</code></pre>
<p>接下来，我们跳出Go标准库，来看一个自定义的示例：</p>
<pre><code>$tree -F buildconstraints/demo1
buildconstraints/demo1
├── foo/
│   ├── f1_android.go
│   ├── f2_linux.go
│   └── f3_darwin.go
└── go.mod

// buildconstraints/demo1/foo/f1_android.go 

//go:build linux

package foo

func F1() {
}

// buildconstraints/demo1/foo/f2_linux.go
//go:build android

package foo

func F2() {
}

// buildconstraints/demo1/foo/f3_darwin.go
//go:build android

package foo

func F3() {
}
</code></pre>
<p>在GOOS=android下构建buildconstraints/demo1/foo这个包，哪些文件会被选出来呢，看下面输出结果：</p>
<pre><code>$GOOS=android go list -f '{{.GoFiles}}' github.com/bigwhite/demo1/foo
[f1_android.go f2_linux.go]
</code></pre>
<p>如果说前两个示例还好理解，那这第三个示例很可能会让很多开发者觉得有些“发蒙”。 别急，上面三个示例都是表象，接下来，我们就来仔细探索一下Go构建时的文件选择机制。</p>
<h2>2. 文件选择机制</h2>
<p>Go包构建时选择源文件的机制还是蛮繁琐的，我们需要从源码入手梳理出其主要逻辑，在Go 1.23版本中，Go包构建过程源文件选择逻辑的代码位于\$GOROOT/src/go/build/build.go中，这个源文件有2k多行，不过不用担心，我这里会替你把主要调用逻辑梳理为下图：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-source-file-selection-details-when-building-package-2.png" alt="" /></p>
<p>函数Import调用Default.Import去获取包的详细信息，信息用build.Package结构表示：</p>
<pre><code>// $GOROOT/src/go/build/build.go
// A Package describes the Go package found in a directory.
  type Package struct {
      Dir           string   // directory containing package sources
      Name          string   // package name
      ImportComment string   // path in import comment on package statement
      Doc           string   // documentation synopsis
      ImportPath    string   // import path of package ("" if unknown)
      Root          string   // root of Go tree where this package lives
      SrcRoot       string   // package source root directory ("" if unknown)
      PkgRoot       string   // package install root directory ("" if unknown)
      PkgTargetRoot string   // architecture dependent install root directory ("" if unknown)
      BinDir        string   // command install directory ("" if unknown)
      Goroot        bool     // package found in Go root
      PkgObj        string   // installed .a file
      AllTags       []string // tags that can influence file selection in this directory
      ConflictDir   string   // this directory shadows Dir in $GOPATH
      BinaryOnly    bool     // cannot be rebuilt from source (has //go:binary-only-package comment)

      // Source files
      GoFiles           []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
      ... ...
</code></pre>
<p>其中的GoFiles就是参与Go包编译的源文件列表。</p>
<p>Default是默认的上下文信息，包括构建所需的默认goenv中几个环境变量，比如GOARCH、GOOS等的值：</p>
<pre><code>// Default is the default Context for builds.
// It uses the GOARCH, GOOS, GOROOT, and GOPATH environment variables
// if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
var Default Context = defaultContext()
</code></pre>
<p>Context的Import方法代码行数很多，对于要了解文件选择细节的我们来说，其中最重要的调用是Context的matchFile方法。</p>
<p>matchFile正是那个<strong>用于确定某个Go源文件是否应该被选入最终包文件中的方法</strong>。它内部的逻辑可以分为两个主要步骤。</p>
<p>第一步是<strong>调用Context的goodOSArchFile方法对Go源文件的名字进行判定</strong>，goodOSArchFile方法的判定也有两个子步骤：</p>
<ul>
<li>判断名字中的OS和ARCH是否在Go支持的OS和ARCH列表中</li>
</ul>
<p>当前Go支持的OS和ARCH在syslist.go文件中有定义：</p>
<pre><code>// $GOROOT/src/go/build/syslist.go

// knownArch is the list of past, present, and future known GOARCH values.
// Do not remove from this list, as it is used for filename matching.
var knownArch = map[string]bool{
    "386":         true,
    "amd64":       true,
    "amd64p32":    true,
    "arm":         true,
    "armbe":       true,
    "arm64":       true,
    "arm64be":     true,
    "loong64":     true,
    "mips":        true,
    "mipsle":      true,
    "mips64":      true,
    "mips64le":    true,
    "mips64p32":   true,
    "mips64p32le": true,
    "ppc":         true,
    "ppc64":       true,
    "ppc64le":     true,
    "riscv":       true,
    "riscv64":     true,
    "s390":        true,
    "s390x":       true,
    "sparc":       true,
    "sparc64":     true,
    "wasm":        true,
}

// knownOS is the list of past, present, and future known GOOS values.
// Do not remove from this list, as it is used for filename matching.
// If you add an entry to this list, look at unixOS, below.
var knownOS = map[string]bool{
    "aix":       true,
    "android":   true,
    "darwin":    true,
    "dragonfly": true,
    "freebsd":   true,
    "hurd":      true,
    "illumos":   true,
    "ios":       true,
    "js":        true,
    "linux":     true,
    "nacl":      true,
    "netbsd":    true,
    "openbsd":   true,
    "plan9":     true,
    "solaris":   true,
    "wasip1":    true,
    "windows":   true,
    "zos":       true,
}
</code></pre>
<p>我们也可以通过下面命令查看：</p>
<pre><code>$go tool dist list
aix/ppc64
android/386
android/amd64
android/arm
android/arm64
darwin/amd64
darwin/arm64
dragonfly/amd64
freebsd/386
freebsd/amd64
freebsd/arm
freebsd/arm64
freebsd/riscv64
illumos/amd64
ios/amd64
ios/arm64
js/wasm
linux/386
linux/amd64
linux/arm
linux/arm64
linux/loong64
linux/mips
linux/mips64
linux/mips64le
linux/mipsle
linux/ppc64
linux/ppc64le
linux/riscv64
linux/s390x
netbsd/386
netbsd/amd64
netbsd/arm
netbsd/arm64
openbsd/386
openbsd/amd64
openbsd/arm
openbsd/arm64
openbsd/ppc64
openbsd/riscv64
plan9/386
plan9/amd64
plan9/arm
solaris/amd64
wasip1/wasm
windows/386
windows/amd64
windows/arm
windows/arm64
</code></pre>
<blockquote>
<p>注：像sock_bsd.go、sock_posix.go这样的Go源文件，虽然它们的文件名中包含posix、bsd等字样，但这些文件实际上只是普通的Go源文件。其文件名本身并不会影响Go包在构建时选择文件的结果。</p>
</blockquote>
<ul>
<li>调用matchTag来判定该Go源文件名字中的OS和ARCH是否与当前上下文信息中的OS和ARCH匹配</li>
</ul>
<p>Go支持的源文件名组成格式如下：</p>
<pre><code>  //  name_$(GOOS).*
  //  name_$(GOARCH).*
  //  name_$(GOOS)_$(GOARCH).*
  //  name_$(GOOS)_test.*
  //  name_$(GOARCH)_test.*
  //  name_$(GOOS)_$(GOARCH)_test.*
</code></pre>
<p>不过这里有三个例外，即：</p>
<p>如果上下文中的GOOS=android，那么文件名字中OS值为linux的Go源文件也算是匹配的；</p>
<p>如果上下文中的GOOS=illumos，那么文件名字中OS值为solaris的Go源文件也算是匹配的；</p>
<p>如果上下文中的GOOS=ios，那么文件名字中OS值为darwin的Go源文件也算是匹配的。</p>
<p>还有一个特殊处理，那就是当文件名字中OS值为unix时，该源文件可以匹配以下上下文中GOOS的值：</p>
<pre><code>// $GOROOT/src/go/build/syslist.go

// unixOS is the set of GOOS values matched by the "unix" build tag.
// This is not used for filename matching.
// This list also appears in cmd/dist/build.go and
// cmd/go/internal/imports/build.go.
var unixOS = map[string]bool{
    "aix":       true,
    "android":   true,
    "darwin":    true,
    "dragonfly": true,
    "freebsd":   true,
    "hurd":      true,
    "illumos":   true,
    "ios":       true,
    "linux":     true,
    "netbsd":    true,
    "openbsd":   true,
    "solaris":   true,
}
</code></pre>
<p>这里面列出os都是所谓的“类Unix”操作系统。</p>
<p>如果goodOSArchFile方法返回文件名匹配成功，那么<strong>第二步就是调用Context的shouldBuild方法对Go源文件中的build constraints进行判定</strong>，这个判定过程也是调用matchTag完成的，因此规则与上面对matchTag的说明一致。如果判定match成功，那么该源文件将会被Go编译器编译到最终的Go包目标文件中去。</p>
<p>下面我们结合文章第一节“表象”中的那个自定义示例来判定一下为何最终会输出那个结果。</p>
<h2>3. 示例分析</h2>
<p>在buildconstraints/demo1/foo包目录中，一共有三个Go源文件：</p>
<pre><code>$tree -F foo
foo
├── f1_android.go
├── f2_linux.go
└── f3_darwin.go
</code></pre>
<p>注意：当前我的系统为<strong>darwin/amd64</strong>，但我们使用了GOOS=android的环境变量。我们顺着上一节梳理出来的文件选择判定的主逻辑，对着三个文件逐一过一遍。</p>
<ul>
<li>f1_android.go</li>
</ul>
<p>首先用goodOSArchFile判定文件名是否匹配。当GOOS=android时，文件名中的os为android，文件名匹配成功，</p>
<p>然后用shouldBuild判定文件中的build constraints是否匹配。该文件的约束为linux，在上面matchTag的三个例外规则里提到过，当GOOS=android时，如果build constraints是linux，是可以匹配的。</p>
<p>因此，f1_android.go将出现在最终编译文件列表中。</p>
<ul>
<li>f2_linux.go</li>
</ul>
<p>首先用goodOSArchFile判定文件名是否匹配。当GOOS=android时，文件名中的os为linux，linux显然在go支持的os列表中，并且根据matchTag的例外规则，当GOOS=android时，文件名中的os为linux时是可以匹配的。</p>
<p>然后用shouldBuild判定文件中的build constraints是否匹配。该文件的约束为android，与GOOS相同，可以匹配。</p>
<p>因此，f2_linux.go将出现在最终编译文件列表中。</p>
<ul>
<li>f3_darwin.go</li>
</ul>
<p>首先用goodOSArchFile判定文件名是否匹配。当GOOS=android时，文件名中的os为darwin，虽然darwin在go支持的os列表中，但darwin与GOOS=android并不匹配，因此在goodOSArchFile这步中，f3_darwin.go就被“淘汰”掉了！即便f3_darwin.go中的build constraints为android。</p>
<p>因此，f3_darwin.go不会出现在最终编译文件列表中。</p>
<p>如果再增加一个源文件f4_unix.go，其内容为：</p>
<pre><code>//go:build android

func F4() {
}
</code></pre>
<p>这个f4_unix.go是否会出现在最终的包编译文件列表中呢？这个作为思考题留给大家了，也欢迎你在评论区留言，说说你的思考结果。</p>
<h2>4. 小结</h2>
<p>在Go语言的开发过程中，包的构建是核心环节之一，而源文件的选择则是构建过程中一个复杂且关键的细节。本文深入探讨了Go编译器在执行go build命令时，如何根据文件名中的架构（ARCH）和操作系统（OS）标识，以及构建约束（build constraints），来选择需要编译的源文件。</p>
<p>通过具体示例，本文展示了不同文件名和构建约束如何影响最终的编译结果，并揭示了Go编译器处理这些信息的优先级。理解这些内部机制不仅能帮助开发者优化构建过程，还能有效避免潜在的错误。希望本文的分析能够给大家带去帮助。</p>
<blockquote>
<p>注：限于篇幅，本文仅针对包编译文件选择最复杂的部分进行的探索，而像ReleaseTags(比如: go1.21等)、cgo、&#95;test.go后缀等比较明显的约束并未涉及，同时对于新版build constraints的运算符组合也未提及，感兴趣的童鞋可以参考<a href="https://pkg.go.dev/cmd/go#hdr-Build_constraints">go build constraints</a>官方文档查阅。</p>
</blockquote>
<p>本文涉及的源码可以在<a href="https://github.com/bigwhite/experiments/tree/master/buildconstraints">这里</a>下载。</p>
<h2>5. 参考资料</h2>
<ul>
<li><a href="https://pkg.go.dev/cmd/go#hdr-Build_constraints">Go build constraints</a> &#8211; https://pkg.go.dev/cmd/go#hdr-Build_constraints</li>
<li><a href="https://github.com/golang/go/issues/25348">proposal: cmd/go: allow &amp;&amp; and || operators and parentheses in build tags</a> &#8211; https://github.com/golang/go/issues/25348</li>
<li><a href="https://go.googlesource.com/proposal/+/master/design/draft-gobuild.md">Bug-resistant build constraints — Draft Design</a> &#8211; https://go.googlesource.com/proposal/+/master/design/draft-gobuild.md</li>
<li><a href="https://github.com/golang/go/issues/41184">cmd/go: continue conversion to bug-resistant //go:build constraints</a> &#8211; https://github.com/golang/go/issues/41184</li>
<li><a href="https://go.dev/doc/go1.17">Go 1.17 release notes</a> &#8211; https://go.dev/doc/go1.17</li>
<li><a href="https://github.com/golang/go/issues/45454">cmd/go: provide build tags for architecture environment variables</a> &#8211; https://github.com/golang/go/issues/45454</li>
</ul>
<hr />
<p><a href="https://public.zsxq.com/groups/51284458844544">Gopher部落知识星球</a>在2024年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。同时，我们也会加强代码质量和最佳实践的分享，包括如何编写简洁、可读、可测试的Go代码。此外，我们还会加强星友之间的交流和互动。欢迎大家踊跃提问，分享心得，讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落，享受coding的快乐! 欢迎大家踊跃加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-tribe-zsxq-small-card.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/go-programming-from-beginner-to-master-qr.png" alt="img{512x368}" /></p>
<p><img src="http://image.tonybai.com/img/tonybai/go-first-course-banner.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/imooc-go-column-pgo-with-qr.jpg" alt="img{512x368}" /></p>
<p>著名云主机服务厂商DigitalOcean发布最新的主机计划，入门级Droplet配置升级为：1 core CPU、1G内存、25G高速SSD，价格5$/月。有使用DigitalOcean需求的朋友，可以打开这个<a href="https://m.do.co/c/bff6eed92687">链接地址</a>：https://m.do.co/c/bff6eed92687 开启你的DO主机之路。</p>
<p>Gopher Daily(Gopher每日新闻) &#8211; https://gopherdaily.tonybai.com</p>
<p>我的联系方式：</p>
<ul>
<li>微博(暂不可用)：https://weibo.com/bigwhite20xx</li>
<li>微博2：https://weibo.com/u/6484441286</li>
<li>博客：tonybai.com</li>
<li>github: https://github.com/bigwhite</li>
<li>Gopher Daily归档 &#8211; https://github.com/bigwhite/gopherdaily</li>
<li>Gopher Daily Feed订阅 &#8211; https://gopherdaily.tonybai.com/feed</li>
</ul>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。</p>
<p style='text-align:left'>&copy; 2024, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2024/11/21/go-source-file-selection-details-when-building-package/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>探索Go守护进程的实现方法</title>
		<link>https://tonybai.com/2024/10/03/how-to-daemonize-go-program/</link>
		<comments>https://tonybai.com/2024/10/03/how-to-daemonize-go-program/#comments</comments>
		<pubDate>Thu, 03 Oct 2024 13:41:55 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[chdir]]></category>
		<category><![CDATA[Daemon]]></category>
		<category><![CDATA[daemonize]]></category>
		<category><![CDATA[fork]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[goroutine]]></category>
		<category><![CDATA[juicefs]]></category>
		<category><![CDATA[nohup]]></category>
		<category><![CDATA[OS]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[Pipe]]></category>
		<category><![CDATA[Process]]></category>
		<category><![CDATA[runtime]]></category>
		<category><![CDATA[setsid]]></category>
		<category><![CDATA[StartProcess]]></category>
		<category><![CDATA[stderr]]></category>
		<category><![CDATA[stdin]]></category>
		<category><![CDATA[stdout]]></category>
		<category><![CDATA[supervisor]]></category>
		<category><![CDATA[systemd]]></category>
		<category><![CDATA[Thread]]></category>
		<category><![CDATA[umask]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[UNIX环境高级编程]]></category>
		<category><![CDATA[Zombie]]></category>
		<category><![CDATA[包]]></category>
		<category><![CDATA[子进程]]></category>
		<category><![CDATA[守护进程]]></category>
		<category><![CDATA[父进程]]></category>
		<category><![CDATA[线程]]></category>
		<category><![CDATA[运行时]]></category>
		<category><![CDATA[进程]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=4314</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2024/10/03/how-to-daemonize-go-program 在后端开发的世界里，守护进程（daemon）这个概念与Unix系统一样古老。守护进程是在后台运行的长期服务程序，不与任何终端关联。尽管现代进程管理工具如systemd和supervisor等让应用转化为守护进程变得十分简单，我们甚至可以使用以下命令来在后台运行程序： nohup ./your_go_program &#38; 但在某些情况下，程序的原生转化为守护进程的能力仍然是有必要的。比如分布式文件系统juicefs cli的mount子命令，它就支持以-d选项启动，并以守护进程方式运行： $juicefs mount -h NAME: juicefs mount - Mount a volume USAGE: juicefs mount [command options] META-URL MOUNTPOINT ... ... OPTIONS: -d, --background run in background (default: false) ... ... ... ... 这种自我守护化的能力会让很多Go程序受益，在这一篇文章中，我们就来探索一下Go应用转化为守护进程的实现方法。 1. 标准的守护进程转化方法 W.Richard Stevens的经典著作《UNIX环境高级编程》中对将程序转化为一个守护进程的 (daemonize) 步骤进行了详细的说明，主要步骤如下： 创建子进程并终止父进程 通过fork()系统调用创建子进程，父进程立即终止，保证子进程不是控制终端的会话组首领。 创建新的会话 子进程调用setsid()来创建一个新会话，成为会话组首领，从而摆脱控制终端和进程组。 更改工作目录 使用chdir(“/”) 将当前工作目录更改为根目录，避免守护进程持有任何工作目录的引用，防止对文件系统卸载的阻止。 重设文件权限掩码 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/how-to-daemonize-go-program-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2024/10/03/how-to-daemonize-go-program">本文永久链接</a> &#8211; https://tonybai.com/2024/10/03/how-to-daemonize-go-program</p>
<p>在后端开发的世界里，<a href="https://en.wikipedia.org/wiki/Daemon_(computing)">守护进程（daemon）</a>这个概念与Unix系统一样古老。守护进程是在后台运行的长期服务程序，不与任何终端关联。尽管现代进程管理工具如<a href="https://tonybai.com/2016/12/27/when-docker-meets-systemd">systemd</a>和<a href="http://supervisord.org">supervisor</a>等让应用转化为守护进程变得十分简单，我们甚至可以使用以下命令来在后台运行程序：</p>
<pre><code>nohup ./your_go_program &amp;
</code></pre>
<p>但在某些情况下，程序的原生转化为守护进程的能力仍然是有必要的。比如分布式文件系统juicefs cli的mount子命令，它就支持以-d选项启动，并以守护进程方式运行：</p>
<pre><code>$juicefs mount -h
NAME:
   juicefs mount - Mount a volume

USAGE:
   juicefs mount [command options] META-URL MOUNTPOINT

... ...

OPTIONS:
   -d, --background  run in background (default: false)
   ... ...
... ...
</code></pre>
<p>这种自我守护化的能力会让很多Go程序受益，在这一篇文章中，我们就来探索一下Go应用转化为守护进程的实现方法。</p>
<h2>1. 标准的守护进程转化方法</h2>
<p><a href="">W.Richard Stevens</a>的经典著作《<a href="https://book.douban.com/subject/25900403/">UNIX环境高级编程</a>》中对将程序转化为一个守护进程的 (daemonize) 步骤进行了详细的说明，主要步骤如下：</p>
<ul>
<li>创建子进程并终止父进程</li>
</ul>
<p>通过fork()系统调用创建子进程，父进程立即终止，保证子进程不是控制终端的会话组首领。</p>
<ul>
<li>创建新的会话</li>
</ul>
<p>子进程调用setsid()来创建一个新会话，成为会话组首领，从而摆脱控制终端和进程组。</p>
<ul>
<li>更改工作目录</li>
</ul>
<p>使用chdir(“/”) 将当前工作目录更改为根目录，避免守护进程持有任何工作目录的引用，防止对文件系统卸载的阻止。</p>
<ul>
<li>重设文件权限掩码</li>
</ul>
<p>通过umask(0) 清除文件权限掩码，使得守护进程可以自由设置文件权限。</p>
<ul>
<li>关闭文件描述符</li>
</ul>
<p>关闭继承自父进程的已经open的文件描述符（通常是标准输入、标准输出和标准错误)。</p>
<ul>
<li>重定向标准输入/输出/错误</li>
</ul>
<p>重新打开标准输入、输出和错误，重定向到/dev/null，以避免守护进程无意输出内容到不应有的地方。</p>
<blockquote>
<p>注：fork()系统调用是一个较为难理解的调用，它用于在UNIX/Linux系统中创建一个新的进程。新创建的进程被称为子进程，它是由调用fork()的进程（即父进程）复制出来的。子进程与父进程拥有相同的代码段、数据段、堆和栈，但它们是各自独立的进程，有不同的进程ID (PID)。在父进程中，fork()返回子进程的PID（正整数），在子进程中，fork()返回0，如果fork()调用失败（例如系统资源不足），则返回-1，并设置errno以指示错误原因。</p>
</blockquote>
<p>下面是一个符合UNIX标准的守护进程转化函数的C语言实现，参考了《UNIX环境高级编程》中的经典步骤：</p>
<pre><code>// daemonize/c/daemon.c

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;syslog.h&gt;
#include &lt;signal.h&gt;

void daemonize()
{
    pid_t pid;

    // 1. Fork off the parent process
    pid = fork();
    if (pid &lt; 0) {
        exit(EXIT_FAILURE);
    }
    // If we got a good PID, then we can exit the parent process.
    if (pid &gt; 0) {
        exit(EXIT_SUCCESS);
    }

    // 2. Create a new session to become session leader to lose controlling TTY
    if (setsid() &lt; 0) {
        exit(EXIT_FAILURE);
    }

    // 3. Fork again to ensure the process won't allocate controlling TTY in future
    pid = fork();
    if (pid &lt; 0) {
        exit(EXIT_FAILURE);
    }
    if (pid &gt; 0) {
        exit(EXIT_SUCCESS);
    }

    // 4. Change the current working directory to root.
    if (chdir("/") &lt; 0) {
        exit(EXIT_FAILURE);
    }

    // 5. Set the file mode creation mask to 0.
    umask(0);

    // 6. Close all open file descriptors.
    for (int x = sysconf(_SC_OPEN_MAX); x&gt;=0; x--) {
        close(x);
    }

    // 7. Reopen stdin, stdout, stderr to /dev/null
    open("/dev/null", O_RDWR); // stdin
    dup(0);                    // stdout
    dup(0);                    // stderr

    // Optional: Log the daemon starting
    openlog("daemonized_process", LOG_PID, LOG_DAEMON);
    syslog(LOG_NOTICE, "Daemon started.");
    closelog();
}

int main() {
    daemonize();

    // Daemon process main loop
    while (1) {
        // Perform some background task...
        sleep(30); // Sleep for 30 seconds.
    }

    return EXIT_SUCCESS;
}
</code></pre>
<blockquote>
<p>注：这里省略了书中设置系统信号handler的步骤。</p>
</blockquote>
<p>这里的daemonize函数完成了标准的守护化转化过程，并确保了程序在后台无依赖地稳定运行。我们编译运行该程序后，程序进入后台运行，通过ps命令可以查看到类似下面内容：</p>
<pre><code>$ ./c-daemon-app
$ ps -ef|grep c-daemon-app
root     28517     1  0 14:11 ?        00:00:00 ./c-daemon-app
</code></pre>
<p>我们看到c-daemon-app的父进程是ppid为1的进程，即linux的init进程。我们看到上面c代码中转化为守护进程的函数daemonize进行了两次fork，至于为何要做两次fork，在我的《<a href="https://tonybai.com/2005/09/21/understand-zombie-and-daemon-process/">理解Zombie和Daemon Process</a>》一文中有说明，这里就不赘述了。</p>
<p>那么Go是否可以参考上述步骤实现Go程序的守护进程转化呢？我们接着往下看。</p>
<h2>2. Go语言实现守护进程的挑战</h2>
<p>关于Go如何实现守护进程的转换，在Go尚未发布1.0之前的2009年就有issue提到，在<a href="https://github.com/golang/go/issues/227">runtime: support for daemonize</a>中，Go社区与Go语言的早起元老们讨论了在Go中实现原生守护进程的复杂性，主要挑战源于Go的运行时及其线程管理方式。当一个进程执行fork操作时，只有主线程被复制到子进程中，如果fork前Go程序有多个线程(及多个goroutine)在执行(可能是由于go runtime调度goroutine和gc产生的线程)，那么fork后，这些非执行fork线程的线程(以及goroutine)将不会被复制到新的子进程中，这可能会导致后续子进程中线程运行的不确定性(基于一些fork前线程留下的数据状态)。</p>
<p>理想情况下是Go runtime提供类似的daemonize函数，然后在多线程启动之前实现守护进程的转化，不过Go团队至今也没有提供该机制，而是建议大家使用如systemd的第三方工具来实现Go程序的守护进程转化。</p>
<p>既然Go官方不提供方案，Go社区就会另辟蹊径，接下来，我们看看目前Go社区的守护进程解决方案。</p>
<h2>3. Go社区的守护进程解决方案</h2>
<p>尽管面临挑战，Go社区还是开发了一些库来支持Go守护进程的实现，其中一个star比较多的解决方案是github.com/sevlyar/go-daemon。</p>
<p>go-daemon库的作者巧妙地解决了Go语言中无法直接使用fork系统调用的问题。go-daemon采用了一个简单而有效的技巧来模拟fork的行为：该库定义了一个特殊的环境变量作为标记。程序运行时，首先检查这个环境变量是否存在。如果环境变量不存在，执行父进程相关操作，然后使用os.StartProcess(本质是fork-and-exec)启动带有特定环境变量标记的程序副本。如果环境变量存在，执行子进程相关操作，继续执行主程序逻辑，下面是该库作者提供的原理图：</p>
<p><img src="https://tonybai.com/wp-content/uploads/how-to-daemonize-go-program-2.png" alt="" /></p>
<p>这种方法有效地模拟了fork的行为，同时避免了Go运行时中与线程和goroutine相关的问题。下面是使用go-daemon包实现Go守护进程的示例：</p>
<pre><code>// daemonize/go-daemon/main.go

package main

import (
    "log"
    "time"

    "github.com/sevlyar/go-daemon"
)

func main() {
    cntxt := &amp;daemon.Context{
        PidFileName: "example.pid",
        PidFilePerm: 0644,
        LogFileName: "example.log",
        LogFilePerm: 0640,
        WorkDir:     "./",
        Umask:       027,
    }

    d, err := cntxt.Reborn()
    if err != nil {
        log.Fatal("无法运行：", err)
    }
    if d != nil {
        return
    }
    defer cntxt.Release()

    log.Print("守护进程已启动")

    // 守护进程逻辑
    for {
        // ... 执行任务 ...
        time.Sleep(time.Second * 30)
    }
}
</code></pre>
<p>运行该程序后，通过ps可以查看到对应的守护进程：</p>
<pre><code>$make
go build -o go-daemon-app
$./go-daemon-app 

$ps -ef|grep go-daemon-app
  501  4025     1   0  9:20下午 ??         0:00.01 ./go-daemon-app
</code></pre>
<p>此外，该程序会在当前目录下生成example.pid(用于实现file lock)，用于防止意外重复执行同一个go-daemon-app：</p>
<pre><code>$./go-daemon-app
2024/09/26 21:21:28 无法运行：daemon: Resource temporarily unavailable
</code></pre>
<p>虽然原生守护进程化提供了精细的控制且无需安装和配置外部依赖，但进程管理工具提供了额外的功能，如<a href="https://tonybai.com/2022/09/12/how-to-install-a-go-app-as-a-system-service-like-gitlab-runner">开机自启</a>、异常退出后的自动重启和日志记录等，并且Go团队推荐使用进程管理工具来实现Go守护进程。进程管理工具的缺点在于需要额外的配置(比如systemd)或安装设置(比如supervisor)。</p>
<h2>4. 小结</h2>
<p>在Go中实现守护进程化，虽然因为语言运行时的特性而具有挑战性，但通过社区开发的库和谨慎的实现是可以实现的。随着Go语言的不断发展，我们可能会看到更多对进程管理功能的原生支持。同时，开发者可以根据具体需求，在原生守护进程化、进程管理工具或混合方法之间做出选择。</p>
<p>本文涉及的源码可以在<a href="https://github.com/bigwhite/experiments/tree/master/daemonize">这里</a>下载。</p>
<hr />
<p><a href="https://public.zsxq.com/groups/51284458844544">Gopher部落知识星球</a>在2024年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。同时，我们也会加强代码质量和最佳实践的分享，包括如何编写简洁、可读、可测试的Go代码。此外，我们还会加强星友之间的交流和互动。欢迎大家踊跃提问，分享心得，讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落，享受coding的快乐! 欢迎大家踊跃加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-tribe-zsxq-small-card.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/go-programming-from-beginner-to-master-qr.png" alt="img{512x368}" /></p>
<p><img src="http://image.tonybai.com/img/tonybai/go-first-course-banner.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/imooc-go-column-pgo-with-qr.jpg" alt="img{512x368}" /></p>
<p>著名云主机服务厂商DigitalOcean发布最新的主机计划，入门级Droplet配置升级为：1 core CPU、1G内存、25G高速SSD，价格5$/月。有使用DigitalOcean需求的朋友，可以打开这个<a href="https://m.do.co/c/bff6eed92687">链接地址</a>：https://m.do.co/c/bff6eed92687 开启你的DO主机之路。</p>
<p>Gopher Daily(Gopher每日新闻) &#8211; https://gopherdaily.tonybai.com</p>
<p>我的联系方式：</p>
<ul>
<li>微博(暂不可用)：https://weibo.com/bigwhite20xx</li>
<li>微博2：https://weibo.com/u/6484441286</li>
<li>博客：tonybai.com</li>
<li>github: https://github.com/bigwhite</li>
<li>Gopher Daily归档 &#8211; https://github.com/bigwhite/gopherdaily</li>
<li>Gopher Daily Feed订阅 &#8211; https://gopherdaily.tonybai.com/feed</li>
</ul>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。</p>
<p style='text-align:left'>&copy; 2024, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2024/10/03/how-to-daemonize-go-program/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
