<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>reading on </title>
    <link>/tags/reading/</link>
    <description>Recent content in reading on </description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Sun, 20 Sep 2026 16:17:01 +0800</lastBuildDate><atom:link href="/tags/reading/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>ploeh blog 回读者来信：LLM 时代怎么学编程</title>
      <link>/posts/ploeh-learning-programming-llm-age/</link>
      <pubDate>Sun, 20 Sep 2026 16:17:01 +0800</pubDate>
      
      <guid>/posts/ploeh-learning-programming-llm-age/</guid>
      <description>「我可能造了一个超出我自己理解水平的系统。」写这句话的读者没有 CS 背景，过去一年靠 LLM 攒出一套 TypeScript/JavaScript 系统，里面有 API、PostgreSQL、LLM 流水线和多模型工作流，现在想把它做成正经产品，却修完一个错又冒出下一个。他给 Mark Seemann 写了封长信问该怎么办，Seemann 2026-09-16 在 ploeh blog 上公开作答，开头先声明自己的答案算不上严谨。
一年攒出来的系统，推生产时卡住了 一年前他开始迷上 AI 辅助编程，用他自己的话说，那感觉近乎魔法，AI 好像把「有个想法」和「能做出来」之间的距离压没了。麻烦是往生产环境推的时候才出来的：修掉一个错，另一个冒出来，再有一块的行为自己也讲不明白。系统正常的时候，理解上的那道差距几乎看不见；一出问题，它就实打实地显出来。有时候不去问另一个模型，他真不知道下一步该做什么。
信里最后的疑问是：这一年做出来的到底是一个产品，还是一个看着像产品的东西，复杂到能跑起来，但他还没懂到能独自扛住它。
庆幸在 LLM 之前学过，今天重来会考虑木工 答问题之前，Seemann 先亮了立场：对 AI 还没下定论，但偏向不喜欢，同时清楚它可能拦不住。他是经济学出身，对「技术进步会创造今天想象不到的新岗位」这个论证只信一半：新岗位确实会出现，但常常不落在丢掉工作的那批人身上，煤矿工人不会一夜之间变成程序员。
来信的第一问是：你庆幸自己在 LLM 之前就学过编程吗？今天从头开始，还会认真去学语言、数据结构、数据库、网络、操作系统、调试和架构吗？
前半句他答得干脆，当然庆幸，这套技能管了三十年。后半句的回答拐了个弯：要是今天重新开始，他会认真考虑木工、金工、枪械制作这类需要手眼配合的行当，理由是机器人虽然也在推进，可体力劳动被替代的时间点看起来还远一些。至于基础本身，他眼下正在一个大学课程里学数据结构和语言语义，但把动机说得很清楚，只是好奇，并不指望换来多少经济回报。
往下懂一层，往上懂一层 同一问里还跟了一句更要命的：AI 是不是让人「做东西的能力」跑到了「理解的能力」前面？
Seemann 说这还要再看，因为这件事本身并不新鲜。软件开发者几十年来本来就站在自己不懂的抽象之上：做 web 开发的不怎么懂编译器是怎么实现的，写编译器的不怎么懂集成电路怎么设计，而做集成电路的人，也不了解上面那几层到底在干什么。
A good rule of thumb was: Understand the level of abstractions directly below the one you work in, as well as the one above.
往下懂一层、往上懂一层，大部分故障就排得动。
停下来补基础，今天的人还有那么多时间吗 第二问最贴近来信人自己的处境：换成是你，会停下来系统补基础，还是边做边学，还是两头一起来？
Seemann 说这在他身上和在来信人身上根本是两个问题，因为他早就不缺基础了。他举了个极端的例子：就算让他去维护一个全部用 RISC-V 汇编写的程序，那大概是他能想到的最陌生的环境，他也能靠已有的知识一点点垫上去。</description>
    </item>
    
    <item>
      <title>corrode.dev 的 Go 到 Rust 迁移指南：工具链、类型系统、集成策略与哪些场景留在 Go</title>
      <link>/posts/go-to-rust-migration-guide/</link>
      <pubDate>Wed, 09 Sep 2026 00:15:00 +0800</pubDate>
      
      <guid>/posts/go-to-rust-migration-guide/</guid>
      <description>Go 开发者已经站在静态类型编译语言这一边，所以换 Rust 的收益主要落在类型系统上：一批在 Go 里靠约定、linter 和运行时探测兜住的检查被挪了进去，速度不是重点。要付的代价是借用检查器、编译时间和 async 着色。corrode.dev「Migration Guides」系列里 Go 到 Rust 这篇就是照这条线写的，作者 Matthias Endler 做 Rust 培训和迁移咨询，原文 2026-05-21 发布、2026-07-20 修订，明确只谈后端服务。
作者的立场：不喜欢 Go，开的是 Rust 咨询公司 他不喜欢 Go，认为它把 easiness（写得容易）和 simplicity（本身简单）混为一谈，nil 到处都是、错误处理靠纪律、泛型缺席多年都是他不同意的方向。但他也承认 Go 的成功是事实：JetBrains 开发者生态调查里 Go 长期占 17–19%，Rust 2024 年是 11%。另一层利益相关他也写在前面：他开的是 Rust 咨询公司，用 Rust 的人越多生意越好；同时他在两种语言上都做过职业开发，把 Go 服务送上过生产。
指南的读者定位是想知道「换到 Rust 之后哪些地方变了」的 Go 开发者。他推荐同时读一篇立场相反的文章，Blain Smith 的 Just Fucking Use Go，两个观点同时在脑子里比只拿一个有用。
工具链：cargo 覆盖的范围比 go 命令更大 Go 带头做了「batteries included」的工具链，编译、测试、格式化、依赖管理一套接口；Rust 跟上了这一步，而且 cargo 内置得更多。原文给了一张命令对照表，主干是这几行：
Go Rust go build / go run .</description>
    </item>
    
    <item>
      <title>JVM 怎么把 bytecode 跑成 native code：class loader、runtime data areas、execution engine</title>
      <link>/posts/jvm-bytecode-to-native-code/</link>
      <pubDate>Tue, 08 Sep 2026 23:15:00 +0800</pubDate>
      
      <guid>/posts/jvm-bytecode-to-native-code/</guid>
      <description>JVM 运行时按三块拆开：class loader 把 .class 装进内存并准备好，runtime data areas 安排对象和调用栈，execution engine 先用 interpreter 逐条执行、再由 JIT 把热方法编译成 native code，同一块里的 GC 负责回收内存。这篇 JVM 运行时入门出自 Ajit Singh 的个人博客 singhajit.com，2026-08-11 发表，页面标称 17 分钟读完。
从源码到 bytecode JVM 从不读 .java 文件，它读 bytecode。javac App.java 把源码翻译成 bytecode 写进 .class，这套指令紧凑且平台无关，不是 Intel 或 ARM 的机器码，它是「一台假想计算机」的机器码，那台假想机器就是 JVM。
原文举的例子只有一个方法：
int add(int a, int b) { return a + b; } 用 javap -c 看，javac 生成的 bytecode 大致是这样：
iload_1 // 把局部变量 a 压到 operand stack 上 iload_2 // 把局部变量 b 压到 operand stack 上 iadd // 弹出两个，相加，结果压回栈 ireturn // 返回栈顶 这里没有 CPU 寄存器。JVM 是一台 stack-based machine：指令靠 push/pop operand stack 传值，不像 eax、r0 那样直接点名寄存器。这个设计让 bytecode 保持简单、可移植。</description>
    </item>
    
    <item>
      <title>Feature flag 的隐藏成本：被低估的复杂度、flag 债务的成因、Keystone Interface 模式</title>
      <link>/posts/feature-flags-hidden-complexity/</link>
      <pubDate>Thu, 23 Jul 2026 09:00:00 +0800</pubDate>
      
      <guid>/posts/feature-flags-hidden-complexity/</guid>
      <description>加一个 feature flag 的代价大多在水下：开关本身好加，加完清理不掉，攒起来就成了债。Pete Hodgson 在 KubeCon + CloudNativeCon NA 2025（Atlanta）的演讲 Feature Flags Suck! 拆的是这笔债的成因，以及管控开关成本的几条路子：元数据治理、Keystone Interface 架构模式、CNCF OpenFeature 标准。他是 OpenFeature 治理委员会成员、软件交付顾问，曾在 martinfowler.com 发表过关于 Feature Toggles 的经典长文。
两种常见偏见与同一个病根 Pete 在开场抛出了业界对待 feature flag 的两种典型态度：
偏见一：不就是个 if-else 吗？ 数据库加个字段、写几行逻辑就能搞定，为什么需要框架或付费服务？ 偏见二：代码里的开关太多太乱了！ 充斥着大量过期的 if 判断，无人敢删，测试路径爆炸，系统维护成本飙升。 Pete 的观点是，这两者本质上是同一个问题：正因为最初低估了开关的复杂度，采取了过于粗糙的实现，才导致后期陷入开关膨胀与代码腐化的困境。Feature flag 本身不产生直接业务价值，它只是达成安全发布、灰度验证或实验目的的手段，同时伴随着持续的维护与测试成本。
水下冰山：被低估的开关复杂度 为什么说 feature flag 不仅仅是 if 判断？Pete 用冰山作比喻：水面上能看到的仅仅是「评估一个布尔条件」；但随着使用场景从简单的全局开关扩展到复杂灰度，水面之下会陆续冒出一整套基础设施需求：
Evaluation Context（评估上下文）：需要知道「对谁评估」，包含用户 ID、租户/组织、环境等上下文信息。 Rules Engine（规则引擎）：基于上下文实现动态路由、特定组织可见或百分比灰度。 管理 UI 与权限控制（RBAC）：提供给产品经理等非工程人员配置，同时防止误操作把未就绪功能全量推向生产。 Audit Trail（审计追踪）：记录谁在什么时间修改了哪个开关。 Analytics &amp;amp; Telemetry（可观测性）：将开关评估事件与业务指标、系统耗时及实验数据对齐。 如果团队选择自研开关，通常在 6 到 12 个月后就会发现，自己不知不觉中承担了维护一套内部 Flag 平台的沉重负担。</description>
    </item>
    
    <item>
      <title>Claude Code 用在 Spring 项目上的工程纪律：Context、Skills、Hooks、MCP、Workflows</title>
      <link>/posts/claude-code-for-spring-developers/</link>
      <pubDate>Fri, 12 Jun 2026 14:30:00 +0800</pubDate>
      
      <guid>/posts/claude-code-for-spring-developers/</guid>
      <description>同一个功能反复迭代：先演示「什么都不配」的 vibe coding 怎么翻车，再一层层加上 Context、Skills、Hooks、MCP、Workflows，最后收拢成一套可复用的 &amp;ldquo;agent stack&amp;rdquo;。Spring I/O 2026（巴塞罗那）上这场 Claude Code for Spring Developers 真正的价值就在这个结构上。讲者 Thomas Schilling（tschuehly，PhotoQuest 创始人，Spring/Kotlin/HTMX 圈常客，做过 Spring ViewComponent），主张很冲：2026 年还不用 Claude Code，你就在白白错过一次巨大的效率提升。
他自己的 Claude Code 使用数据也为这套方法背书：3,700+ commits、1,700+ sessions、11k+ prompts、提交速度约 5×，连这些 slides 本身都是用 Claude Code 做的。
本文以他的 slides 八个板块为骨架；其中 /interview 和 Gradle 代理 hook 两处，参考了他配套的两篇博客（见文末）补全细节。
主线：一个功能，从翻车到工程化 Demo 是 PhotoQuest 里的一个照片表情投票游戏（库表就叫 ranking_game）：大屏轮播照片，宾客扫码加入，每人有一份固定的表情额度（3❤️ + 3😂 + 3😮）投给喜欢的照片，限时参与，最后揭晓每个表情类别下票数最高的前三张。同一功能他做了很多遍，每遍都比上一遍多给 Claude 一层支持。
agent 的工作循环是 Read → Plan → Act → Observe → Repeat。顺的时候很顺：给计时加上 1–30 分钟校验，它新建 InvalidTimerDurationException、加上 if (timerSeconds &amp;lt; 60 || timerSeconds &amp;gt; 1800)、确认编译通过，全程 1 分 24 秒。</description>
    </item>
    
    <item>
      <title>让 AI agent 用终端直接搜语料的 DCI 方法</title>
      <link>/posts/agents-need-a-terminal-not-vector-database/</link>
      <pubDate>Sat, 06 Jun 2026 13:00:00 +0800</pubDate>
      
      <guid>/posts/agents-need-a-terminal-not-vector-database/</guid>
      <description>让 agent 绕开 embedding 模型和向量索引，直接用命令行工具去搜原始语料。来自多所高校的研究者把这套做法叫 Direct Corpus Interaction（DCI，直接语料交互），VentureBeat 这篇（发在 Orchestration 板块）讲的是它的工程含义。核心论断比较反直觉：在 agent 越来越强的当下，检索质量不再只取决于 embedding 训得好不好，而取决于模型与语料库交互的那个接口的 interface resolution（接口分辨率，可以理解为「这扇窗能看多细、能看几次」）。而 top-k 向量检索，恰恰是一个 resolution 很低、且不可逆的接口。
传统 RAG 的瓶颈：top-k 是一道不可逆的闸门 经典 RAG 的链路是离线的：文档被切块（chunk）、过 embedding 变成向量、灌进向量库建索引。查询来的时候，retriever 在整个库里打分，返回一个排好序的 top-k 片段列表。所有证据都必须先过这道打分闸门，下游推理才能开始。
文章（和论文）点出的问题是：无论 lexical（BM25）还是 semantic（dense retriever），都把「访问语料库」这件事压缩成了推理之前的单步 top-k。对一次性问答这够用，但对 agentic 任务就成了硬伤，
需要精确匹配：确切的字符串、数字、版本号、错误码、文件路径； 需要稀疏线索的组合（sparse clue conjunction）：好几个弱信号凑在一起才指向答案； 需要局部上下文核对：看一眼命中位置前后几行； 需要多步假设修正：先发现中间实体、再根据部分证据改计划。 最值得注意的一条：被 top-k 早早筛掉的证据，再强的下游推理也捞不回来。 闸门关上就是关上了。agentic 任务偏偏要反复试探、回头修正，这种「单步压缩」的接口和它根本不匹配。
DCI 是什么：把语料库当文件系统，用终端工具直接搜 DCI 的做法简单到有点反常规：不要 embedding、不要向量索引、不要 retrieval API，把 agent 放进一个类终端环境里，它的「观测」就是工具的原始输出，文件路径、命中的文本片段、命中处的上下文行。
agent 用的全是标准命令行工具：
导航 / 定位文件：find、glob 遍历目录结构； 精确匹配：grep、rg 找关键词、正则、确切字符串； 局部查看：head、tail、sed、cat，以及临时写的轻量 Python 脚本，去读命中点周围的上下文或某段文件。 这样一来，检索不再是「推理前的一步」，而变成 agent 推理循环里可以反复调用、随时改主意的动作：grep 一下没中就换个 pattern，发现新实体就顺着再搜一层。论文把这叫「提高了交互接口的 resolution」。附带的两个工程好处也很实在：不需要离线建索引，以及天然适配会变的本地语料，语料更新了，下一次 grep 直接就是最新的，没有「重新 embedding、重建索引」的滞后。</description>
    </item>
    
    <item>
      <title>软件工程的临界点：AI 把产量推到 10x 之后，瓶颈迁到评审、测试、版本控制与安全</title>
      <link>/posts/software-engineering-at-the-tipping-point/</link>
      <pubDate>Tue, 02 Jun 2026 15:00:00 +0800</pubDate>
      
      <guid>/posts/software-engineering-at-the-tipping-point/</guid>
      <description>**当 AI 把软件产量推到 10x、100x，今天这套造软件、发软件的基础设施吸收不了这个增量，一定会在某处崩掉。**这是 Adam Bender 在 Google I/O 2026 的一场 talk Software engineering at the tipping point 里的核心命题；他是 Google Principal Software Engineer，长期做 Google 内部开发者基础设施。
主张：当下这套，撑不到 10x Bender 的判断是：AI 正在把&amp;quot;软件产出可能放大一个数量级&amp;quot;从思想实验推到现实问题，而现有的构建、测试、版本控制、评审、安全这套基础设施很可能吸收不了这个增量。他的原话：
I would bet very good money what we&amp;rsquo;re doing today doesn&amp;rsquo;t work at 10x.
他把它定性成 &amp;ldquo;code-red moment&amp;rdquo;，不是思想实验，是逼到眼前的现实：
Suddenly the measure of 10x growth is not just a thought exercise. It&amp;rsquo;s a code-red moment for you and your company. You&amp;rsquo;ll have to figure this out.</description>
    </item>
    
    <item>
      <title>Affirm 用一周让 800 人的工程组织转向 agentic 工作流</title>
      <link>/posts/agentic-retooling-week/</link>
      <pubDate>Tue, 02 Jun 2026 09:00:00 +0800</pubDate>
      
      <guid>/posts/agentic-retooling-week/</guid>
      <description>用一周时间，把一个 800 人的工程组织从写需求到提 PR 全程搬上 agentic 工作流，这一周 Affirm 内部叫 AI Retooling Week；工程效能高级总监 Daniel Martin 在 Affirm Tech Blog 复盘了整个过程。让他们决定这么急的是差距：已经有几十个工程师被 agentic 工具改变了工作方式，正和其余 800 人快速拉开，剩下的问题是怎么把这套方式规模化到整个组织。
出发点：差距正在拉大，不能太慢 到 2025 年 12 月，Affirm 已经有 80% 以上的工程师每周在用某种 AI 辅助工具。但真正让他们下决心的是另一件事：随着 Anthropic Opus 4.5 这类模型把&amp;quot;搜代码 → 规划 → 写代码 → 跑测试 → 自己修&amp;quot;这条链路打通，已经有几十个工程师在用 agentic 工具，并且工作方式被明显改变了，
那几十个用得很好的人，和剩下 800 个人之间的差距，正在快速拉大。
他们选择&amp;quot;集中一周&amp;quot;而不是&amp;quot;慢慢铺开&amp;quot;，这本质上是一个 forcing function（倒逼机制）：靠自愿、靠&amp;quot;有空就试试&amp;quot;很难迈过那道坎。1 月中旬公司总裁发了一封全员信，把 agentic 开发定为&amp;quot;今后怎么造软件的核心方式&amp;quot;，并定下 AI Retooling Week 的日期：那一周暂停所有非必要会议、推迟交付日期，要求每个工程师和经理都跑通一条完整的 agentic 工作流，从需求到提交 PR。
一周之前：九个人先把&amp;quot;地基&amp;quot;打好 Retooling Week 之前，他们组了一个九人工作组，任务很明确：两周内产出一条可复制的 agentic 工作流，让普通工程师不需要专家知识、不需要定制配置就能自动化掉大部分编码工作。</description>
    </item>
    
    <item>
      <title>Queue-it 播客：autoscaling 什么时候会失效</title>
      <link>/posts/autoscaling-in-production/</link>
      <pubDate>Mon, 01 Jun 2026 09:00:00 +0800</pubDate>
      
      <guid>/posts/autoscaling-in-production/</guid>
      <description>autoscaling 接得住线性、渐进爬坡的流量，接不住瞬时砸下来的尖峰。Queue-it Smooth Scaling Podcast 这期 Autoscaling in Production: When It Works and When It Doesn&amp;rsquo;t 谈的就是这条边界落在哪里。嘉宾是 Queue-it 的 Šimon Bučko（Senior Software Engineer）和 Zaigham Sarfaraz（Engineering Manager），主持人 José Quaresma。他们的经验来自 virtual waiting room（虚拟等候室）这门生意：在抢购、票务、新品发布这类瞬时高并发场景里，把洪峰流量挡在等候室里、按可控速率放行。
一句结论：autoscaling 是必要条件，不是充分条件 整期最值得记的一句是 &amp;ldquo;autoscaling is necessary but not sufficient&amp;rdquo;。autoscaling 擅长应对线性、渐进的流量增长，监控 CPU、内存、请求数等指标，越过阈值就加实例，load balancer 通过 health check 发现新实例并分流。这套机制对&amp;quot;流量缓慢爬坡&amp;quot;几乎是理想方案。
但它有一个关键前提：扩容本身需要时间。新实例从触发到就绪是分钟级的。一旦流量是瞬时、非线性地砸下来，autoscaling 的反应速度就跟不上了。
那次 iPhone 发布的翻车 播客里的一个具体例子，是 2023 年一次 iPhone 发布（播客录制时大约三年前）。流量从 0 瞬间冲到上百万请求。他们当时虽然做了一些 vertical 预扩容，但主要还是指望 autoscaling 去接住尖峰，结果新服务器要 3–4 分钟才能初始化完成，对这种瞬时洪峰来说太慢了，终端用户直接看到了报错。
这个故事点出的边界很清楚：autoscaling 隐含&amp;quot;流量随时间平滑变化&amp;quot;的假设，而他们客户的流量曲线根本不平滑，用 Zaigham 的话说，大意是&amp;quot;零，然后瞬间一百万，然后又归零&amp;quot;。用一个为线性增长设计的机制去接非线性尖峰，差的那 3–4 分钟就是事故。</description>
    </item>
    
    <item>
      <title>GitHub 用 eBPF 限制部署脚本的对外网络访问</title>
      <link>/posts/ebpf-deployment-safety/</link>
      <pubDate>Fri, 22 May 2026 12:00:00 +0800</pubDate>
      
      <guid>/posts/ebpf-deployment-safety/</guid>
      <description>eBPF 最常被拿去做网络加速和可观测性，GitHub Engineering 在 2026 年 4 月那篇文章里用它处理的是另一类更偏平台工程的问题：部署系统本身会不会依赖它正在修复的系统。这篇笔记读的是 InfoQ 对它的新闻总结。
谈 Cloud Native 的可靠性时，常被提到的是多副本、自动扩缩容、健康检查、Service Mesh、GitOps、回滚策略；但当系统真的进入故障态时，一个更朴素的问题往往更实际：修复系统的工具链还能不能工作。
GitHub 这次解决的是什么问题 GitHub 的基本矛盾是一个典型的循环依赖：GitHub 的源码托管在 github.com 上，但 github.com 如果出现故障，修复它的部署动作又可能需要访问 github.com。
这个显性的循环依赖可以通过代码镜像和构建产物镜像缓解。真正麻烦的是部署脚本里的隐性依赖，比如：
直接依赖：部署脚本临时从 GitHub 下载某个 open source 工具。 隐藏依赖：机器上已有的工具启动时自动检查更新，背后访问了 GitHub。 传递依赖：部署脚本调用内部服务，内部服务再去 GitHub 拉取 release 或 binary。 这些依赖平时可能不容易看出来，因为所有服务都健康时它们只是一次普通的网络访问。等到事故发生，才发现部署链路需要依赖一个已经不可用的服务，于是修复动作被卡住，MTTR 被拉长。
GitHub 的做法是把部署脚本放进单独的 cGroup，再用 eBPF 挂到这个 cGroup 的网络出口上，不用每个团队手工审查脚本。这样可以只观察和限制部署进程的 outbound network access，而不影响同一台 stateful host 上继续承载生产流量的其他进程。
GitHub 方案里 eBPF 做了什么 这个方案里 eBPF 有四个关键作用。
第一，按进程边界做网络控制。GitHub 使用 BPF_PROG_TYPE_CGROUP_SKB 这类能力，把规则挂在特定 cGroup 的 egress 路径上。也就是说，它只约束部署脚本这个执行环境，整台机器访问 github.</description>
    </item>
    
    <item>
      <title>Martin Fowler 网站的 SPDD：把 prompt 当一级交付物</title>
      <link>/posts/structured-prompt-driven-spdd/</link>
      <pubDate>Thu, 21 May 2026 22:00:00 +0800</pubDate>
      
      <guid>/posts/structured-prompt-driven-spdd/</guid>
      <description>把 prompt 当成与代码同级的工程工件管理，版本化、评审、复用、迭代。这条主张不新，Structured Prompt-Driven Development 的贡献是把它具体化成了一组流程、一份七维度模板（REASONS Canvas）和一套配套 CLI（gszhangwei/open-spdd），外加一个完整示例项目（gszhangwei/token-billing）。文章 2026-04-28 发在 Martin Fowler 网站，作者 Wei Zhang 和 Jessie Jie Xia 都来自 Thoughtworks。本文只聚焦 SPDD 这一篇文章本身。
文章主张：prompt 是一级交付物 文章开头给的一句话很直接：
Instead of relying on ad hoc chats, SPDD turns prompts into assets that can be: version controlled, reviewed, reused, and improved over time.
这句话把 SPDD 和临时 chat 式交互区分开来：prompt 不只是一次性输入，而是可以被版本化、评审、复用和持续改进的资产。SPDD 想解决的问题文章写得很具体：
模糊的需求被快速翻译成代码，误解随之扩散 评审里要处理的改动越来越多 集成 / 测试问题增加 难以推理生产风险 它给出的答案是：把&amp;quot;意图&amp;quot;从 chat 历史里拎出来，写成可追溯的工件。
REASONS Canvas：把 prompt 拆成七层 文章的核心是 REASONS Canvas 这个概念，它把一份&amp;quot;提示词&amp;quot;拆成七个维度，分到三个层次：</description>
    </item>
    
    <item>
      <title>梳理 kubernetes-best-practices 仓库，补上 Gateway API 等新特性</title>
      <link>/posts/kubernetes-best-practices/</link>
      <pubDate>Sat, 16 May 2026 10:00:00 +0800</pubDate>
      
      <guid>/posts/kubernetes-best-practices/</guid>
      <description>从集群基础配置、安全、网络一直讲到 GitOps，diegolnasc/kubernetes-best-practices 这份 K8s 实践手册覆盖面很广，但更新停在较早的版本，没跟进近几个版本里已经稳定（或接近稳定）的特性，最典型的是 Gateway API。这篇笔记以仓库内容为骨架过一遍，掺入一些我自己的实践理解，并补上这些新特性。
集群基础：规划要在最前面 这三项的共同点是都得在建集群之前定下来，建完再改代价很大。
网络 CIDR 规划 集群建好之后最难改的就是网络。最好在创建集群之前就把三块地址段算清楚：
节点子网：根据最大节点数预留，留足余量 Pod CIDR：每个节点 maxPods 数量决定每个节点需要多大的子网块。例如每节点最多 110 个 Pod，则每节点需要 /25（128 个地址），256 个节点就需要 /17 Service CIDR：独立规划，避免与内网路由冲突 对于托管 K8s（GKE/EKS/AKS），云厂商通常会额外保留部分地址，规划时要读清楚文档，留出 1.5~2 倍余量。
私有集群 节点和 API Server 不应暴露在公网。控制面通过私有端点访问，节点出流量经过 NAT 网关。这一点在公有云环境下几乎是标配，但在自建集群（K3s/kubeadm）里容易被忽视。
Infrastructure as Code 所有集群配置（节点池、网络、IAM）都应该用 Terraform / Pulumi 管理，而不是在控制台手点。没有 IaC 的集群，两周后就没人知道某个配置是怎么来的。
安全 前两项是这份仓库给出的做法，第三项是它没覆盖、但 K8s 1.30 之后绕不开的。
Pod Security Standards 替代 PSP Pod Security Policy 在 K8s 1.21 被废弃，1.25 彻底移除。现在的替代方案是 Pod Security Admission（PSA），通过 Namespace 标签控制：</description>
    </item>
    
    <item>
      <title>Anthropic 论文：AI 会怎么影响技能形成</title>
      <link>/posts/how-ai-impacts-skill-formation/</link>
      <pubDate>Wed, 08 Apr 2026 10:00:00 +0800</pubDate>
      
      <guid>/posts/how-ai-impacts-skill-formation/</guid>
      <description>**更依赖 AI 的那组，在新知识掌握和调试测试上的表现更弱，而完成时间优势也不明显。**这是 Anthropic 一篇 preprint 论文在自己设计的任务里测到的结果。论文自己也没把它当成定论，给出的是一个值得警惕的观察角度。
实验：模拟“边干边学” 研究者设计了一个比较贴近现实的场景：让 52 位有 Python 经验、但从未接触过 Trio 的 professional / freelance programmers，去学习这个主打结构化并发的异步编程库。
参与者被分为两组：
手动组 (Manual Group)：不能使用 AI，只能依靠任务说明、文档和搜索。 AI 组 (AI Group)：可以使用基于 GPT-4o 的 AI 助手协助编写、调试和解释代码。 核心发现：效率差异有限，能力形成可能受影响 测试成绩差异 在任务结束后的技能测试中，AI 组的得分比手动组约低 17%，论文作者称大约相当于 two grade points。差异主要出现在三个领域：
调试能力（分差最大）：AI 组更难发现代码中的逻辑错误。 概念理解：对 Trio 核心设计理念的掌握不如手动组。 代码阅读：预测代码运行结果的表现更弱。 效率并未显著提升 研究结果显示，AI 组平均完成任务的时间仅比手动组快了不到 2 分钟（23 min vs 24.7 min）。
为什么 AI 没有显著提效？ 这里的隐性成本可以理解为一种 interaction tax。
很多时候，我们以为 AI 帮我们写了代码就提效了，但实际上，程序员为了让 AI 生成正确的代码，需要花费大量时间：
构思和编写精准的提示词（Prompt）。 反复修改需求以纠正 AI 的错误输出。 阅读和验证 AI 生成的大段代码（有时这比自己写还要累）。 有参与者甚至把 30% 以上的时间花在与 AI 对话上。对这类任务来说，AI 并不只是一个“生成器”，它也会变成一个需要管理和校验的外部系统。</description>
    </item>
    
    <item>
      <title>Netflix 的 Java 21 虚拟线程死锁排查</title>
      <link>/posts/java21-virtual-threads-where-is-my-lock/</link>
      <pubDate>Mon, 01 Jul 2024 10:38:32 +0800</pubDate>
      
      <guid>/posts/java21-virtual-threads-where-is-my-lock/</guid>
      <description>一批 Java 21 + Spring Boot 3 应用间歇性挂起，查到最后是虚拟线程在 synchronized 块里被 pin 在 carrier thread 上，把一次 ReentrantLock 的正常释放拖成了死锁。这次排障记在 Netflix 技术博客上。
问题 Netflix 接到了 jvm 间歇性超时、实例被挂起的问题报告。这些报告的共同点是都运行着 Java 21 的 Spring Boot 3 应用，且都使用嵌入式的 Tomcat 来提供服务。这些 jvm 虽然仍然在运行，但却无法提供服务。
Netflix 内部应该还有 Java 17 的技术栈服务，所以可以将以上信息作为问题的公共特征抽取出来。
它们的 metrics 检测到 closewait 状态的 socket 数量持续增加。
排查 五节是一条收敛线，从 thread dump 一路问到谁持着那把锁。
收集信息 closewait 状态出现的原因是连接的对端关闭了连接，但本地还没关闭，仍在等待。这通常意味着本地线程可能因为某种原因挂起了。所以他们先排查了 thread dump。
Netflix 的服务有定期保存 thread dump 数据 他们在告警系统中找到一个这类被挂起的实例，并查看对应的 thread dump 数据。从这些数据，只能看出该 jvm 处于空闲状态，并没有特别的活动。
他们查看了这些服务的最近变更，发现它们都启用了 virtual threads 特性。而 virtual thread 的调用栈并不会出现在 jstack 生成的 thread dump 中。</description>
    </item>
    
    <item>
      <title>Go 官方博客解释 type parameters 的推断规则</title>
      <link>/posts/deconstructing-type-parameters/</link>
      <pubDate>Wed, 01 Nov 2023 10:38:32 +0800</pubDate>
      
      <guid>/posts/deconstructing-type-parameters/</guid>
      <description>标准库 slices.Clone 的签名写成 func Clone[S ~[]E, E any](s S) S，第一次看有点绕：为什么要两个类型参数，为什么要 ~。Go 官方博客的 Deconstructing Type Parameters 就从这个签名讲起，一步步推导它为什么得这么写，并解释 ~ 约束和类型推断的设计取舍。作者 Ian Lance Taylor，2023-09-26 发表。
从 slices.Clone 说起 slices.Clone 函数很简单：拷贝一个 slice，元素类型任意。
func Clone[S ~[]E, E any](s S) S { return append(s[:0:0], s...) } s[:0:0] 会让 append 分配一个新的底层数组来容纳 s 的元素。原文要回答的问题是：这个泛型函数的签名为什么要定义成这样。
朴素版 Clone 如果自己写一个泛型的 slice 拷贝，第一反应大概是：
func Clone1[E any](s []E) []E { // 省略函数体 } Clone1 只有一个类型参数 E：输入一个 E 的 slice，输出一个 E 的 slice，E 可以是任何类型，看上去很直观。</description>
    </item>
    
  </channel>
</rss>
