程序员阅读清单:我喜欢的 100 篇技术文章(21-40)

程序员们也许是互联网上最爱分享的群体之一,他们不仅喜欢开源自己写的软件,也爱通过写文章来分享知识。从业以来,我阅读过大量技术文章,其中不乏一些佳作。这些佳作中,有些凭借深刻的技术洞见令我深受启发,也有些以庖丁解牛般的精湛手法解释一项技术,让我读后大呼过瘾。

作为“爱分享”的程序员中的一份子,我想当一次推荐人,将读过的好文章分享给大家。我给这个系列起名为《程序员阅读清单:我喜欢的 100 篇技术文章》

受限于本人的专业与兴趣所在,清单中的文章对以下几个领域有所偏重:程序员通识、软件工程、后端开发、技术写作、Python 语言、Go 语言

下面是阅读清单的第二部分,包含第 21 到 40 篇文章。

系列索引:

  • 第一部分(1-20):链接
  • 第二部分(21-40):链接

清单

21. 《人生短暂》

人生很短,到底该如何花费自己的时间?传奇投资人、程序员 Paul Graham 在文章中给出了他的建议。总结起来,一共 3 条:尽你所能地避免 bullshit 类事务,比如无用会议、网上吵架;对重要的事情不拖拉,意识到有些东西不会永远停在原地等你;珍惜你所拥有的每一滴时间。

从任何角度看,上面这些建议都称不上有多新奇。但是,作者通过真诚地分享自身经历和感受,给内容注入了不一样的灵魂。或许你会像我一样,读后能获得一些新的感悟。

22. 《有“产品意识”的软件工程师》

从事程序员越久,你大概率会越来越频繁地听到一个词:“产品意识”。人人都说产品意识好,但是它看不见摸不着,到底是个什么东西?是指程序员该自己画线框图?还是说程序员应该写用户故事?

本文作者以软件工程师的视角,对“产品意识”做了全面的解读。简单来说,产品意识就是关注产品、对产品拥有好奇心、对用户拥有同理心;有产品意识的人在做技术方案时,不光思考工程角度,更能靠全局的“产品+工程”视角思考决策。

“产品意识”——工程师们最为强大的思维杠杆之一。

23. 《Python 的 range 不是迭代器》

range 是 Python 语言中最常用的内置对象之一,功能是生产一段数字序列,比如 range(10) => 0, 1, ..., 9。作为循环语句中被迭代的常客,range 常被误认为是一种迭代器(iterator)。但是,正如文章标题所说,虽然可被迭代,但 range 却并不是迭代器。

可如果不是迭代器的话,range 究竟是什么?在文章中,作者用精要的说明和代码片段做出了解答。看起来像咬文嚼字,实则是相当重要的 Python 基础概念。

😊 有关迭代器和可迭代对象这个主题,我也很推荐另一篇自己写的内容:《Python工匠》第六章 6.1.1 “迭代器与可迭代对象”

24. 《有关 TLS/SSL 证书的一切》

一篇和证书有关的科普文。

虽是科普,但这篇和其他科普文章不太一样。你除了能读到一些轻松愉快的小故事,还会被一些不知从哪里冒出来的 shell 命令和大段伪代码“突然袭击”。看似不协调的素材,在作者的精心编排下,却如交响乐团般演奏出一段优美流畅的乐章,让人读来如沐春风。

25. 《让困难的事情变容易》

也许是胡说八道,但我还是想说:技术人普遍有一种“复杂崇拜”情结。实践一门技术,人们常常会踩进许多坑、遇到很多困难,但大部分人对此绝口不提,仿佛抱怨一门技术过于复杂,会显得自己能力不足似的。

尤其,当这些技术是大家口中公认的“基础技术”(比如 DNS、HTTP)时,更是如此。技术人接受复杂、理解复杂,最终认同复杂为理所当然。

正因如此,我很喜欢 Julia Evans 的这个分享。它指出在许多所谓的“基础技术”背后,隐藏着太多难以掌握的复杂元素。不少人都会在它们上面栽跟斗,但并非所有人都会站出来,改善现状。

所以,我们需要让复杂事物变得更容易。针对这一点,文章挑选了几种有代表性的技术,比如 DNS、BASH、SQL 等,提供了切实可行的建议,包括:分享有用的工具和参考文档、从大的功能列表中筛选你真正使用的、展示不可见的内容,等等。

26. 《The Hiring Post》

作者在一家名为 Matasano 的安全公司任职。一天,他接到一份报告,其中描述了一种针对 DSA 的新型攻击手法。由于步骤复杂、条件苛刻,作者认为这种攻击方式有些不切实际,难以实施(时间以月为单位计算)。不过,他还是把报告分享到了团队中(忘了提及“不切实际”)。

两天后,团队里一位名叫 Alex 的新人找到他,说自己完成了一个可工作的漏洞利用程序。

Alex 非常优秀,但是,如果把时间拨回几年前,他根本不会被招进公司。他的简历平平无奇,而当时公司依赖简历和面试来招聘人才。直到后来,Matasano 公司优化了招聘策略,才挖掘出越来越多像 Alex 的人才。

接着开篇的小故事,作者探讨了技术行业在人才招聘方面的一些问题。比方说,许多能力出众的候选人常因招聘环节不合理而无法通过面试。与之相对的是,一些善于面试、对抽象概念总能侃侃而谈的人,却能轻松拿到 offer。针对这些问题,文章给出了一些建议,比如:让候选人热身、使用接近工作场景的测试问题,等等。值得一读。

27. 《13 年后,我如何用 Go 写 HTTP 服务》

一篇 Go 语言方面的最佳实践类文章,只涉及标准库中的 HTTP 基建,不涉及其他第三方 Web 框架或库。作者有十余年的 Go 编程经验,经验丰富。

文章除了展示具体的代码编写与组织技巧,也谈了一些“为什么如此处理”背后的设计考量,包括:长参数列表的函数、请求编解码处理、用闭包结合 http.Handler、E2E 测试和单元测试,等等。透过这些考量,能感受到作者多年经验与智慧的沉淀。

28. 《Rust std fs 比 Python 更慢!?》

一篇精彩的短篇侦探小说。

有一天,Xuanwo 接到用户上报一个奇怪的案件:一段 Rust 实现的 Python SDK 中的文件操作代码,执行起来却比原生 Python 代码更慢。一通排查后,更离谱的事件出现,不止 Rust,甚至同样的 C 代码也比 Python 更慢。但这怎么可能,Python 语言解释器本身都是用 C 写的呀?!

就像任何一篇精彩的侦探小说一样,最后,悬疑气氛推到最高点,凶手身份被揭露时,你会自言自语道:“意料之外,情理之中”。

29. 《选择乏味的技术》

作为技术人员,我们喜欢尝试新技术,这让我们感到快乐。但许多时候,比起闪闪发光的新玩意,“乏味”的技术才是更优的选择。

当我们觉得一项技术“乏味”、痛恨它时,根本原因是我们过于了解它,无法从它身上获得任何新鲜感(比如 Django 之于我)。但别忘了,这同时也意味着我们对这项技术的每个坑都了如指掌。在项目中采用它,能让我们更容易专注在核心业务问题上。

很喜欢本文里的“创新代币”比喻。“创新代币”是一种用来处理创造性任务的有限能力。假设你一共拥有 3 枚“创新代币”,你会如何花费它们?也许,和某个新奇的技术栈比起来,产品核心功能上的创新,更需要那枚代币。

30. 《Python 3.10 中的结构化模式匹配》

在 3.10 版本中,Python 新增了“结构化模式匹配”语法( match ... case)。因为看上去和 switch ... case 语句十分相似,不少人认为“结构化模式匹配”就是 switch 换皮。但事实上,它和 switch 语句有着比较大的差异,用作者的话讲:它更适合被当成“迭代式解包”来理解。

本文发布于 2021 年(Python 3.10 发布前夕),其中简单介绍了“结构化模式匹配”的功能,并列举了一些它最适用的代码场景。在总结中,针对该语法的未来,作者持略为悲观的复杂态度。

和“结构化模式匹配”相关的文章中,除几篇 PEP 之外,我认为这是最值得阅读的一篇。

31. 《你想要的是模块,不是微服务》

文章的开头很有意思。从一篇介绍微服务的文章中,作者摘抄出了微服务架的 10 条优势。随后,他逐条分析这些优势,发现其中至少有一半,可以原封不动地套用在“模块”上。

“只关注一小块代码”、“独立开发”、“版本化”、“独立发布”——以上能力模块无一不具备。对了,此处谈及的“模块”,就是那个诞生于 20 世纪 70 年代的技术概念,也是如今所有编程语言的标配能力。

分析完模块和微服务的相似性后,文章继续层层推进,试着回答一个重要问题:微服务架构解决的本质矛盾究竟是什么?

32. 《我不喜欢 Go 语言默认的 HTTP Handlers》

在编写 HTTP handler 函数时,作者意识到这类函数存在一个设计问题,它会促使人们写出有 bug 的代码。该问题大多数 Go 开发者都知道(也可能犯过):回写响应体后忘记 return,导致代码错误地继续执行。为了优化它,作者提出了一种思路。

技术层面上,这是一篇非常简单的文章,最终方案也无非是“多封装一层”而已。不过,我喜欢作者对细节的关注,也认可文章的价值观:通过优化工具与环境,来杜绝人类犯错的可能性。

33. 《对人类更友好的“超时”与“取消”》

做网络编程时,“超时配置”是一个非常重要但又常常被忽视的细节。不当的超时配置就像是鞋底里的一粒沙,开始你甚至觉察不到它的存在,但随着时间累积,沙子会磨破脚底,产生巨大危害。

“作为最常见的超时配置方式,为什么 get(url, timeout=10) 这类 API 不够好?”

从这个问题出发,作者列举并分析了一些常见的超时 API 设计,最后详细介绍了 trio 库的相关功能。作者认为它是一种“对人类更友好”的设计。

34. 《20 年软件工程师生涯,学到 20 件事》

从业 20 年后,软件工程师 Justin Etheredge 回顾自己的职业生涯,总结出了 20 条经验。这些经验短小精悍、富有洞见,我读后对其中大部分都很有共鸣。

比如其中的第 5 条:“最好的工程师像设计师一样思考”。有许多次,我在一个问题卡住,苦思冥想,寻不到最优解。但当我转换思路,学着像设计师一样站在用户(或调用方、依赖方)角度思考时,答案呼之欲出。再比如其中的第 9 条:“问‘为什么‘,永远不嫌多”——旺盛的好奇心和求知欲,正是助我们精进技术的最佳催化剂。

35. 《为什么你的 mock 不工作》

用 Python 写测试代码时,经常会用到 mock 模块。初次接触 mock,不少人都遇到过 mock 不生效的问题。明明用 mock.patch(...) 替换了模块,代码执行时,引用到的却依旧是原始值。

Ned Batchelder 的这篇文章细致解释了“mock 不生效”问题。因为写的是个常见问题,所以文章中的知识点对你来说可能并不新鲜。但即便如此,我还是很推荐它。文章结构清晰、措辞准确,里面的每张示意图和每段代码,都出现得恰到好处。哪怕不为学知识,略读一遍后,也让人心情舒畅。在技术写作方面,能从中学到不少。

同时推荐作者的另一篇文章:《Python 的名字和值》,内容与 mock 这篇有关联。

36. 《实用的 Go:来自真实世界的编写可维护 Go 程序的建议》

互联网上,“Go 代码可读性“方面的资料不算太多,这篇或许是你能找到的最好的之一。

本文包含数十条与提升 Go 代码可维护性有关的建议,覆盖从变量命名到 API 设计等多项主题,十分全面。我喜欢它最重要的原因,除了其写作质量上佳之外,还在于作者为每条建议精心搭配了示例代码,这些代码使得文章内容非常容易阅读,知识很好消化。一篇干货满满的经典之作,值得每位 Go 工程师阅读。

37. 《编写系统软件:代码注释》

在“代码注释”这个主题上,Redis 作者 antirez 的这篇文章是我的最爱之一。通过整理 redis 项目里的所有注释,antirez 将注释一共划分成 9 类,各自承担不同功用。

本文的独到之处,在于立足“用注释解释代码中的 ‘why?’”这条共识上,重点介绍了“教学性/指引性注释”这类不太常规的注释。文章提到,指引性注释是 redis 中数量最多的注释,充斥整个项目,人们认为 Redis 的源码可读性佳,指引性注释功不可没。

某种程度上,这篇文章影响了我的编码习惯。再次回顾它,脑海闪过那句人们重复提及的老话: “代码主要是写给人看的,顺便被计算机执行。”

38. 《编写易于删除,而不是易于扩展的代码》

程序员们有一条朴素的共识:“重复代码坏,复用代码好“。这篇文章站在另一个角度,反思了这条共识。人们习惯于讨论复用的好处,却往往忽视了它的缺点:一段代码被复用越多,意味着它与更多的使用方产生了耦合关系,自然也导致它更难被修改。

代码写出来后便需要被维护,而业务发展又会让旧代码不断过时。以这个为前提,重新思考软件项目的可维护性,会发现“易于删除”变成了一个形容代码的好特征。这篇文章或许写得没那么易读,但个中观点确能引发思考。

39. 《如何提出好问题》

在人际沟通中,“善于提问”是一种顶级技能( 评级:SSR✨)。在关键时刻提出一个好问题,能让沟通事半功倍,事情水到渠成。

Julia Evans 的这篇文章,囊括了与提问有关的若干条经验和技巧,比如:向对方陈述并确认你所知道的现状;选择向谁提问;通过提问让不够显而易见的概念变得明确,等等。文章不止内容好,写作风格也是一如既往的友善、清晰易读,强力推荐。

40. 《每天写代码》

程序员 John Resig (JQuery 库作者) 遇上了一件烦心事。他想完成一些兴趣项目(side projects),却发现在保证全职工作效率的前提下,很难推进。他常在每个周末疯狂赶工,力求完成更多,但压力和焦虑感总是爆棚,状态难以维系。

有一天,在他人启发下,John 决定换一种策略:每天写代码。原本用整个周末投入兴趣项目,如今拆分到每一天,花不少于 30 分钟编程。半年后,他发现新策略产生了神奇的效果,他取得了超多成果:开发多个新网站、重写若干个框架、完成大量新模块。更重要的是,曾经困扰他的焦虑感,也烟消云散。

我很喜欢这篇文章,它是程序员版本的“日拱一卒”,John 也是一位极好的榜样。

结语

以上就是“程序员阅读清单”第二部分的全部内容,祝你阅读愉快!

题图来源:Photo by Roman Kraft on Unsplash

😊 如果你喜欢这篇文章,也欢迎了解我的书: 《Python 工匠:案例、技巧与工程实践》 。它专注于编程基础素养与 Python 高级技巧的结合,是一本广受好评、适合许多人的 Python 进阶书。