前段时间,我通关了一个三十多年前的老游戏:《塞尔达传说:织梦岛》。 《织梦岛》是久负盛名的塞尔达传说系列的第四部作品,发售于 1993 年,平台为 Game Boy——任天堂在 1989 年推出的风靡全世界的游戏掌机。 用今天的眼光看,《织梦岛》的游戏画面简陋得吓人。举个例子,游戏的分辨率极低,仅为 160×144,换算下来像素面积不到 iPhone 17 屏幕的 1%。不过,技术过时并未过多损害游戏的可玩性。这部诞生于上世纪的作品,用极具想象力的道具和迷宫,打造出了一个引人入胜的小岛,玩起来依然妙趣横生。 正因如此,在发售后的第 26 年,《织梦岛》在任天堂最新的游戏主机 Switch 上迎来了一次重制。 为了迎合现代玩家,新版《…
阅读全文
02对所有人 谨记 Agent 不对代码担责 多“协作”,少“委派” 拆分你的 PR 善用 Plan 模式,多做前置探索 采纳稳定的库,优于 AI 从零实现 创建 PR 前使用 AI Review 让改动可验证,并总是验证 其他 对初级工程师 质量胜过效率 尝试手动修复 Bug 自己先动脑,在 AI 给出的方案之外寻求 其他 结语 AI 编程发展迅猛,Claude Code、Codex 等 AI Agent 已成为许多软件工程师工作时必不可少的得力助手。然而,对于如何在项目中更好地实践 AI 编程,目前仍然是一副“八仙过海,各显神通”的模样。 假如同一个团队里的工程师,在如何使用 AI 工具的“大问题”上没有达成共识,就会出现协作上的摩…
阅读全文框架的问题 1. 抽象泄露 2. 丧失控制权 认知成本:DRF 的启示 也许,该把 AI 编程当成一种库 使用 AI 类编程工具越多,我便越来越强烈地感觉到:AI 编程是一种“框架(Framework)”。 框架是每位程序员的老朋友,它通常针对特定领域所设计,能极大提升编码效率。以 REST API 服务为例,一些成熟的框架(比如 Django REST Framework)能做到仅需定义数据模型和视图类,便生成一套功能完备的 CRUD API 服务。 AI 编程工具和传统框架一样,都是一种“杠杆”,它们允许人们用少量输入撬动庞大的功能。二者区别仅在于输入类型不同,框架需要代码(或配置),而 AI 仅需一句简单的自然语言提示词——“…
阅读全文
04一个双向链表和另一个字典 小结 有趣的细节 1. 对 weakref 的使用 2. 传入 object() 作为默认值 现在是 2025 年,网上已很少见到 Python 字典有序性的相关讨论。自从 Python 在 2018 年发布 3.7 版本,将“字典保持成员的插入序”写进语言规范后,人们已渐渐习惯有序的字典。那曾经调皮、无序的字典,早已像 2.7 版本一样成为过去,只在某些老登们忆苦思甜时被提起。 而在那个字典无法保持顺序的年代,如果我们要用到有序的字典,我们用什么?答案是:collections.OrderedDict。 但是,随着内置字典已经有序,OrderedDict 似乎也渐渐变得不再必要。不过,截止到目前(3.14…
阅读全文
05kubectl apply 的故事 客户端侧 apply 客户端侧 apply 的局限性 服务端侧 apply 小结 软件设计建议 1. 善用服务端功能零成本复用、变更实时触达的特点 2. 别让服务端因客户端的定制需求过载 烤肉店故事:如何调味? 识别服务端复杂度的过载风险 3. 客户端的计算力是独特的优质资源 烤肉店故事:谁来烤肉? 善用客户端的独特资源 “自助烤肉”的弊端 结语 文末彩蛋 设计软件是一个不断产生疑问、解决疑问的过程。设计者们面对一个需求,会产生许许多多的疑问,在这些疑问中,有一个看似幼稚,却直击灵魂的小问题:“业务逻辑(复杂度)放在哪?” 项目每引入一个新功能,所增加的总复杂度几乎是确定的,但如何把这些复杂度分配…
阅读全文
06清单 41. 《抽象泄露法则》 42. 《如何设计一个好的 API 及其重要性》 43. 《我构建软件的原则+实践“让无效状态不可表示”》 44. 《不,不是编译器的问题,从来都不是》 45. 《关于在除夕前一天换了一个洗衣机的故事》 46.《你的函数是什么颜色?》 47. 《健康的文档》 48. 《如何像人类一样做代码评审》 49. 《关于 Python 3.13 你需要了解的一切 - JIT 和 GIL》 50. 《入行 14 年,我还是觉得编程很难》 结语 程序员们也许是互联网上最爱分享的群体之一,他们不仅喜欢开源自己写的软件,也爱通过写文章来分享知识。从业以来,我阅读过大量技术文章,其中不乏一些佳作。这些佳作中,有些凭借深刻…
阅读全文
07清单 21. 《人生短暂》 22. 《有“产品意识”的软件工程师》 23. 《Python 的 range 不是迭代器》 24. 《有关 TLS/SSL 证书的一切》 25. 《让困难的事情变容易》 26. 《The Hiring Post》 27. 《13 年后,我如何用 Go 写 HTTP 服务》 28. 《Rust std fs 比 Python 更慢!?》 29. 《选择乏味的技术》 30. 《Python 3.10 中的结构化模式匹配》 31. 《你想要的是模块,不是微服务》 32. 《我不喜欢 Go 语言默认的 HTTP Handlers》 33. 《对人类更友好的“超时”与“取消”》 34. 《20 年软件工程师生涯,…
阅读全文
08清单 1. 《开发者应学习的 10 件有关“学习”的事》 2. 《开发者如何管理自驱力》 3. 《用 Go 语言分析 10 亿行数据,从 95 秒到 1.96 秒》 4. 《在开发高质量软件上的花费值得吗?》 5. 《错误抽象》 6. 《谷歌技术写作课:编写有帮助的错误信息》 7. 《深入 Python 字典——一份“可探索”的解释》 8. 《愿意让自己显得愚蠢》 9. 《我们为什么坚持使用 Ruby on Rails》 10. 《ChatGPT 是互联网的一张模糊的 JPEG 图》 11. 《重新发明 Python notebook 时学到的教训》 12. 《断点单步跟踪是一种低效的调试方法》 13. 《作为“胶水”》 14. 《…
阅读全文
09开始“英文写作”的契机 用 LLM 翻译初稿 用 DeepL Write 润色 推广你的文章 ❤️ 我喜欢这种创作模式 结语 时间过得很快,转眼间,2024 年的进度条已经走到了 50% 的位置。作为一名博主,我很惭愧 🥹,过去半年我只写了一篇新文章,算是相当低产。不过,虽然没写太多新文章,但我干了另一件值得记录的大事。 在今年 2 月份,我给博客增加了“英文”板块,并在其中发表了 4 篇英文文章,几乎每一篇都获得了不错的反响: "After 14 years in the industry, I still find programming difficult":Hacker News 217 points(Top 20) 评论…
阅读全文
101. 命名 2. 指引性注释 3. 沟通方式 总结 Code Review(代码评审)是一种流行的软件开发实践。通过在代码合入主分支前引入人工评审,能有效促进成员间的知识交流,提升软件质量。 我以评审者的身份参与过大量代码评审。在评审一份代码时,有些事项长期处在我的关注榜头部,比如设计是否考虑到了边界情况、代码是否有合理的单测覆盖。也有一些事项,因看似无关痛痒一直未引起足够重视,直到最近,我才渐渐发现它们的重要性。 以下是曾被我忽视的 3 件重要的小事。 1. 命名 小女孩千寻误入汤婆婆为神明开设的浴场。为了留在浴场内工作,千寻与汤婆婆签订了一份协议,但协议并非重点,重点是另一件看似无关紧要的小事——汤婆婆给千寻改了个名:从“千寻”…
阅读全文1. 1 行代码与 20 行注释 piglei 说 2. 删掉注释 piglei 说 3. 微服务架构能力 piglei 说 4. 聪明的代码 piglei 说 人物说明: 大师:从事开发工作 20 年有余,精通各类编程语言,有着常人难以匹敌的软件工程经验,说话时惜字如金,有时会让人觉得有些神神叨叨(但人不坏)。 学徒:学习编程的时间不长,热衷于提升自己的软件开发技能,勤学好问。 1. 1 行代码与 20 行注释 一天,学徒问大师:“我每天都写很多代码,实现很多需求,为何编码水平却停滞不前?” 大师回答道:“让我看看你在写些什么。” 学徒打开电脑。大师指着屏幕上一行普通的赋值语句,说:“当你有一天意识到,需要在这前面补充 20 行注…
阅读全文import-linter 简介 在项目中引入 import-linter 修复依赖关系的常见方式 1. 合并与拆分模块 2. 依赖注入 添加类型注解 3. 简化依赖数据类型 4. 延迟提供函数实现 变种:简单的插件机制 5. 由配置文件驱动 6. 用事件驱动代替函数调用 总结 对于活跃的大型 Python 项目而言,维持架构的整洁性是一件颇具挑战的事情,这主要体现在包与包、模块与模块之间,难以保持简单而清晰的依赖关系。 一个大型项目,通常包含数以百记的子模块,各自实现特定的功能,互相依赖。如果在架构层面上缺少设计,开发实践上没有约束,这些模块间的依赖关系,常常会发展成为一个胡乱缠绕的线团,让人难以理清头绪。 这会带来以下问题: 架…
阅读全文
13实现“石头、剪刀、布”游戏 改进“石头、剪刀、布” 相关扩展 良好的命名和结构 引入额外抽象 面向对象编程 领域驱动设计 结语 实现“石头、剪刀、布”游戏 一天,我在一个 Python 技术群里看到一段有意思的讨论。讨论始于这么一个需求: 题目:写代码模拟“石头、剪刀、布”游戏。由玩家 A 和 B 随机进行 10 次游戏并打印结果。要求:用数字 0 来表示石头,1 表示剪刀,2 表示布。 紧跟着的,是一段实现了该需求的 Python 代码。如下所示: import random def game(): """生成一局随机游戏,并打印游戏结果。""" a = random.randint(0, 2) b = random.randin…
阅读全文1. 写代码很简单,但写好代码很难 好代码还是很少 好代码有哪些要素? 写好代码的捷径 2. 编程的精髓是“创造” 3. 打造高效试错的环境至关重要 理想的编程体验≈“刷题” 4. 避开代码完美主义陷阱 5. 技术很重要,但“人”也许更重要 6. 求知若渴是好事,但也要注意方法 关注学习性价比 挑选合适的学习资料 7. 越早开始写单元测试越好 8. 程序员最大的敌人是什么? 复杂度是最大的敌人 减缓复杂度增长的过程 写在最后 很多年前,当我还是一名计算机专业的大四学生时,整天上网浏览各类招聘信息,想找到一个合适的程序员实习岗位。 除了实习岗位外,我偶尔也会点进一些“高级工程师”的招聘帖里。现在回想起那些帖子,抛开让人眼花缭乱的技术名…
阅读全文
15用 ChatGPT 编写程序 编程里的两类乐趣 1. “规划与设计” 2. “解决小谜题” ChatGPT 带来的变化 以《Hades》来类比编程 关于 ChatGPT 的一些疑问 ChatGPT 写的代码真有那么好吗? 不用 ChatGPT 不就完事了? 写在最后 本文完成于 2022 年末,我在其中分享了自己第一次使用 ChatGPT 编写一个 Python 程序的经历。写作时,我选择从“编程中的乐趣”切入,判断 ChatGPT 未来将改变人们从编程中获取乐趣的方式——天平将缓慢由“解决小谜题”向“规划与设计”倾斜。 如今过去了一年多,ChatGPT 等 AI 工具已成为越来越多人的日常(包括我)。我并不怀念 ChatGPT 出…
阅读全文
161. 使用人称代词 2. 搭配使用长短句 3. 大段落与小段落 4. 统一叙事角度 5. 了解规则,打破规则 结语 很多人会把编程比作写作,比如《Thinking in Java》的作者 Bruce Eckel 就说:“程序员就是作家。”二者的确也有许多相似之处,好文章和好代码,都离不精确的结构与优美的表达。写作时,每个人都能用词语拼出句子,组成文章,但并非所有人都能写出好文章,编程也是一样。 不过严格来说,编程和写作虽有少许相似,却仍是两个迥异的技能,在很多方面差别很大。比如我们很少会重写一篇已发表的文章,但重构一段能正常运行的代码实属家常便饭。 不过这一次,我们不妨把编程中那些复杂概念抛掷一旁,来一次奇思妙想:“如果编程就是写作…
阅读全文表达式的特点 海象操作符 1. 用于分支语句 2. 消除推导式中的重复 3. 捕获推导式的中间结果 4. 赋值表达式的限制 其他建议 1. “更紧凑”不等于“更好” 2. 宜少不宜多 让我们从两行最简单的 Python 代码开始。 >>> name = 'piglei' >>> print(f'Hello {name}!') Hello piglei! 这是一个“Hello World”程序,你也许已经见过它无数次,对里面的每个字母都了如指掌。但你可能从未意识到,上面两行代码,刚好对应着 Python 语言里的两个重要概念:语句(statement) 和 表达式(expression)。 具体来说…
阅读全文1. 普通传参 2. 使用参数结构体 3. 藏在可选参数里的陷阱 4. 引入指针类型支持可选 5. “函数式选项”模式 6. 使用接口实现“函数式选项” 问:应该优先使用“函数式选项”吗? 参考 1. 普通传参 Go 语言支持按顺序传入参数来调用函数,下面是一个示例函数: // ListApplications 查询应用列表 func ListApplications(limit, offset int) []Application { return allApps[offset : offset+limit] } 调用代码: ListApplications(5, 0) 当你想增加新参数时,可以直接修改函数签名。比如,下面的代码给…
阅读全文1. 最好不给配置也能用 1.1 预设合理的默认值 1.2 延迟部分配置项 2. 永远别默认“管理员密码” 3. 描述性文本格式优先 配置文件结构 4. 部分或完全支持环境变量 总结 在设计和开发服务端(后端)软件时,配置文件是一个绕不开的话题。 配置文件是一种用于存放各类可配置项的特殊文件。每个软件都会预设一些默认配置,但这些默认值不可能适用于所有情况。因此,到了不同的环境中,我们常常需要用配置文件对其进行扩展和修改。 拿版本控制软件 git 举例。大部分用户的 home 目录(~)都存放着一份 .gitconfig 配置文件,里面写着自己的用户名和邮箱地址: [user] name = piglei email = piglei…
阅读全文
20结缘 Python 为什么写这本书 推荐语 致谢 尾声 我写了一本 Python 语言的编程进阶书:《Python工匠:案例、技巧与工程实践》,本文是关于这本书背后的故事与一些致谢。 我一直觉得编程某种意义上是一门“手艺”,因为优雅而高效的代码,就如同完美的工艺品一样让人赏心悦目。就像一位用锤子敲敲打打了十几年的铁匠,总结出一套“如何锻造出锋利的刀”的经验之谈——我在代码世界也“敲敲打打”了十几年,沉淀下来的便是这本《Python工匠》。 我将自己这些年掌握的技巧、经验与编程建议,去粗取精后悉数写入书中,希望它能帮读者朋友们完成从初学者到工匠的跃迁。 书目前已经正式上市,欢迎点击购买。 本文主要内容来自书中的“前言”部分,略有删改。…
阅读全文