Glean 拾遗
← All issues
#017 Latest 9/14–9/20 Published Sep 20

What's Worth Keeping

This week's fourteen pieces circle a single question: what survives the passage of time? Fowler reframes internal quality as an investment rather than a cost; technical debt splits into aesthetic, deferrable, and toxic; and "code that's easy to delete" recasts lines of code as lines spent. All three converge on one claim — the cost of change is the real cost of software. Beneath that sits a tug-of-war between abstraction and fundamentals: every non-trivial abstraction leaks, database skills get treated as optional, and microservices turn out to be Parnas's 1971 modules. Code is ultimately written for readers, so the craft here is collaboration — a taxonomy of comments, reviews that treat authors like humans, the skill of asking questions, docs-first habits. The final three return to people: twenty years of experience and its limits, how product instinct compounds, and whether open source should raise its contribution bar.

14 picks 4 sections ~3 hr
Section 01

Change Comes at a Price

3 / 14
martinfowler.com · 15 min
01

High Internal Quality Makes Software Cheaper, Not More Expensive内部质量不是成本:高质量软件反而更便宜

Martin Fowler argues that the familiar quality-versus-cost trade-off does not apply to the internal quality of software. He splits quality into external attributes users can perceive — UI, defects — and internal ones they cannot, such as architecture, naming, and modularity. Customers will pay more for a better interface but cannot judge internal structure, so it is usually treated as a cost to be cut. Fowler's claim runs the other way: internal quality lowers the cost of future change, making software cheaper to produce, not more expensive. A pseudo-graph of cumulative functionality against time shows low-quality projects starting fast and then stalling as cruft accumulates; the developers he canvassed report being slowed within weeks. Even the best teams create cruft — they hold it down with automated tests, frequent refactoring, and continuous integration. He concedes that output cannot be measured, so the crossing point rests on experience rather than data. Written for engineers who need an economic, not moralistic, case for quality.

renegadeotter.com · 8 min
02

A Lannister Always Pays His Technical Debts兰尼斯特有债必偿:先分清三种技术债再动手

The author sorts technical debt into three buckets: aesthetic (import order, naming — annoys you but doesn't touch users or velocity, and tooling can fix it), deferrable (contained, to be crossed off methodically inside normal sprint work), and toxic (a half-finished thing that turns into a workaround magnet, with every new feature built on top of it). Missing tests and missing docs are called out as toxic debt: without an integration suite you won't dare swing a sledgehammer at the codebase, and without READMEs and runbooks every bug repro starts with reverse-engineering the system at real dollar cost. The related advice: TODO comments mean you will never do it, so turn them into actual cards on the board, and tag debt stories so the ratio of features to debt stays visible. The debt column will never be empty — just don't let it run away.

programmingisterrible.com · 20 min
03

Write code that is easy to delete, not easy to extend.好代码容易删掉,而不是容易扩展

The thesis: treat lines of code as lines spent, not lines produced. Every line carries a maintenance cost, and abstractions built for reuse bind callers to both the intended and unintended behaviour of an implementation, making later change more expensive. The goal should be disposable code, not reusable or extensible code. The author walks through tactics: don't write code at all; copy-paste a few times before extracting a function; keep stateless, application-agnostic helpers in a util directory with one utility per file; accept boilerplate so static library code stays away from fast-changing business logic; layer policy over protocol the way requests wraps urllib3; let one big ball of mud hold things together; split modules by what they don't share rather than by shared functionality; use uniform interfaces, HTTP caches/CDNs and feature flags as replaceable seams; handle errors at the outer edges (end-to-end principle), as Erlang's supervision trees do by restarting instead of recovering in place. Aimed at engineers maintaining long-lived codebases.

Section 02

The Ground Beneath the Abstraction

4 / 14
www.joelonsoftware.com · 12 min
04

The Law of Leaky Abstractions抽象必漏:TCP、SQL 与 C++ 字符串的同一课

Joel Spolsky's classic essay starts with TCP, which promises reliable, ordered, uncorrupted delivery on top of IP, a protocol that guarantees none of those things. TCP is an abstraction, and like every non-trivial abstraction, it leaks. The examples span the stack: iterating a 2D array column-wise can trigger far more page faults than row-wise; logically equivalent SQL queries can differ by orders of magnitude in runtime; no C++ string class can make "foo" + "bar" compile, because string literals are char*; an NFS server outage silently drops mail that depended on a .forward file; ASP.NET fakes form submission from a hyperlink with generated onclick JavaScript, breaking when JavaScript is disabled. The practical consequence: abstractions save time writing code, not time learning. As tools get higher-level, debugging them still requires knowing what was abstracted away, so proficiency gets harder, not easier.

renegadeotter.com · 14 min
05

Your Database Skills Are Not 'Good to Have'数据库技能不是加分项:从 2006 年 MySQL 分面搜索说起

A MySQL war story from 2006: a three-person team builds faceted search for New York Magazine's Fashion Week portal, with exact per-tag counts, before Solr facets or Endeca existed. The author tunes MySQL 4 by timing queries and reading EXPLAIN output. Twenty years later he sees the opposite trend: engineers reach for "planet-scale" databases while barely knowing the relational engine they already run. He recounts an e-commerce incident where a product listing page took over 10 seconds even with no traffic, caused by three mistakes at once: no index, ORM loops firing 200-500 queries per page, and SELECT-ing every column. The argument: a modern RDBMS is innocent until proven guilty, and the burden of proof is on you. Includes a troubleshooting runbook and anti-patterns (exotic databases, unnecessary caching, data landfill). For backend and data engineers.

kevinmahoney.co.uk · 9 min
06

My Principles for Building Software写软件的十一条原则:先数据,后代码

A practitioner's list of principles for building software, most aimed at making systems simpler: make invalid states unrepresentable, enforce data consistency, design data before code, measure before trading away simplicity. The appendix shows what inconsistency costs — split two Boolean variables x and y that must stay equal into separate databases and the data gains two more states, leaving the toggle function with no correct answer. The author argues consistency is the most undervalued property in software engineering and that most bugs are data failing an expectation. Other principles: avoid trading local simplicity for global complexity (smaller services often do this), don't optimize without measurement, keep code consistent even when the consistent thing isn't the "correct" thing, and learn concepts — the relational model, algebraic data types, borrow checking — rather than surface details of React or Kubernetes. Aimed at backend and data engineers weighing service splits and schema design.

blogs.newardassociates.com · 15 min
07

You Want Modules, Not Microservices拆开微服务,里面是 Parnas 1971 年的模块

Ted Neward argues the microservices pitch is recycled: of six quoted benefits, two come from microservices literature, two from twenty-year-old EJB material, and two from Oracle Tuxedo, forty-year-old technology. Strip the branding and what remains is the module — an independently built, versioned, deployed and reusable unit of code, the concept Parnas defined in 1971 and Unix pipes-and-filters delivered in the 1970s. What organizations actually bought was organizational clarity: small teams owning their own analysis, testing, data and deployment dependencies instead of waiting on DBA, QA or infrastructure groups, at the cost of full-stack staffing and on-call duty. Technically, in-process module calls become network calls, adding five to seven orders of magnitude of latency and running into the Fallacies of Distributed Computing, which more nodes only worsen. Neward's advice: any decomposition behind a common API convention works; fix organizational dependencies directly. Suited to architects and tech leads.

Section 03

Code Written for Readers

4 / 14
antirez.com · 31 min
08

antirez on code comments: a nine-part taxonomy from Redisantirez 拆解 Redis 源码:代码注释的九种类型

antirez works through the Redis source (unstable branch, 32e0d237) to argue that comments are not a crutch for weak code. He sorts comments into nine kinds, namely function, design, why, teacher, checklist, guide, trivial, debt and backup, judging the first six useful and the last three suspect. His two reasons: many comments carry information the code cannot express, such as why a statement is there instead of a more natural alternative, and comments lower the reader's cognitive load, as when scripting.c annotates the Lua stack layout after every call. Each category comes with real examples: the replication code that swaps replication IDs before freeing the backlog, the expire.c loop that increments current_db early, the trigonometry behind LOLWUT, the checklist duty created by Redis's 4-bit type field, and the TODO left in t_stream.c. Reading and writing comments, he argues, is bug hunting and design review in disguise.

vadimkravcenko.com · 11 min
09

Healthy Documentation: A CTO's Case for Docs-First Engineering把知识写下来:一位 CTO 的文档优先实践

A CTO's field notes on running a docs-first engineering culture: replace half-hour check-ins with a one-page memo, budget documentation time explicitly in estimates, and require a short "why X over Y" paragraph on every merged feature. He is candid about the failure modes — stale pages are worse than none, and some workarounds should be fixed in code rather than explained in three paragraphs of handbook. Concrete mechanisms include a lightweight CI check that fails the build when a new analytics event ships without a matching wiki entry, ADR and post-mortem templates, the Diátaxis split between tutorials and reference, and a part-time "docs gardener" who prunes dead links.

mtlynch.io · 23 min
10

How to Do Code Reviews Like a Human (Part One)代码评审不只是找 Bug:像对待人一样给反馈

Michael Lynch argues that most code review writing obsesses over finding bugs and ignores the social half of the process, turning reviews into judgments of the author rather than the code. Drawing on his own review experience, he offers concrete practices: push whitespace, build, test, and lint checks into CI and formatters so humans review logic; settle style disputes with a style guide instead of arguing mid-review; start reviews immediately and keep each round under one business day; stay under roughly 20-50 notes per round and lead with high-level design feedback; include runnable code examples but cap them at two or three per round; never write "you" in a comment, preferring "we", subject-less shorthand, or questions; phrase feedback as requests rather than commands; and tie every note to a stated principle with links to the team style guide or library docs. Aimed at engineers who want reviews that improve code without damaging the team.

jvns.ca · 13 min
11

How to ask good questions about software提问的技术:先说清你已知什么,再问可回答的事实

Julia Evans argues that asking good questions is a trainable software engineering skill, not a personality trait. Her core technique: state what you already understand, then ask 'is that right?'. She rewrites vague questions ('how do SQL joins work?') into questions with factual answers — is joining N and M rows O(NM) or O(NlogN)+O(MlogM), does MySQL always sort join columns first. She shows the rkt-dev mailing list question where she first wrote down how rkt and Docker store container images differently, then asked why; and the term dictionary she built for Hadoop, Scalding, Hive, Impala and HDFS when joining a data team. She also covers choosing whom to ask (a 5-minute answer that saves you 2 hours is a good trade; the most senior person is not always the right target), stopping an explanation to ask what a term like optimistic locking means, and reading the Etsy Debriefing Facilitation Guide for questions that surface hidden assumptions. She is explicit that asking dumb questions is fine, and criticizes ESR's 'How To Ask Questions The Smart Way' for putting an unreasonable burden on askers. Aimed at engineers ramping up on unfamiliar systems.

Section 04

Judgment and the Bar

3 / 14
www.simplethread.com · 14 min
12

20 Things I've Learned in my 20 Years as a Software Engineer20 年工程生涯的 20 条经验,作者先标注了适用边界

A Simple Thread co-founder distills 20 years of engineering into 20 opinions, prefaced by an honest account of his context: small teams and startups first, then consulting inside large companies, then growing his own firm from 2 to 25 people. The list runs against received wisdom: building the right thing is harder than building it well; the best code is code you never write; every system eventually rots, so aim for continuous improvement rather than elegance; the 10x programmer is a myth and the real win is keeping 0.1x programmers off the team; data outlives your codebase; interviews predict almost nothing about teammates; prefer durable "shark" technologies to fashionable ones. Aimed at working engineers who want to sanity-check their own judgment, with the caveat that all advice is contextual.

blog.pragmaticengineer.com · 12 min
13

The Product-Minded Software Engineer: 9 Traits and How to Grow Them产品意识型工程师的 9 个特质与养成方法

The author breaks "product-minded" down into observable behaviors: these engineers do not take a spec and start coding, they ask why first, challenge requirements, and evaluate product and engineering tradeoffs together. Nine traits are listed, including digging into business and user data, building relationships with non-engineers, applying a minimum-lovable-product lens to edge cases, and following user behavior metrics for weeks after launch before drawing conclusions. Product instinct, the author argues, compounds across repeated project cycles of questioning, proposing, validating fast, and debriefing gaps. Written for engineers on user-facing teams who work with PMs; it closes with six concrete habits to build the muscle.

stitcher.io · 5 min
14

No More Issues: Laravel Asks for PRs InsteadLaravel 关掉部分仓库的 issue,改要 PR:门槛该升还是降

Laravel disabled issue creation on several package repositories — including Socialite and Scout — and now asks contributors to open pull requests instead; the main framework repo is unaffected. Brent Roose, an open source maintainer, walks through the trade-offs. Forcing a PR can cut maintainer triage time, and duplicate fix attempts are easier to close. But in the AI era, opening a PR is nearly as cheap as filing an issue, and LLM-written patches demand more review effort than ones a contributor reasoned through. Duplicate PRs also trigger far more CI runs than duplicate issues. Requiring PRs raises the contribution bar rather than lowering it, and shuts out contributors without AI access or enough experience — even though many people, the author included, started out writing Laravel issues. He draws no firm conclusion, but finds the change hard to square with the idea that every contribution is a learning opportunity. Aimed at OSS maintainers and contributors.