Tabs, Spaces, Hand Tools, and Seat Belts
Over the last few months, there has been a good ol’ fashioned flamewar over the migration of Bun from Zig to Rust via extremely heavy usage of Claude Code. Last month, Jarred Sumner, creator of Bun, published an in-depth explanation of how and why Bun was migrated to Rust, akin to something you would find on any corporate blog from any tech company with a big engineering department. Shortly thereafter, Andrew Kelley, creator of the Zig programming language, published a screed for the ages, venting about the apparently long dysfunctional relationship between Zig and Bun as well as his and others’ terrible experience working with Jarred. Andrew referred to Jarred as a “stinky manager” and said that “Jarred was already writing slop well before he had access to LLMs”. Both posts are worth reading, the first for a genuinely new and daring approach to software engineering and the latter as an example of a letter that would have been better off burnt than sent. I am grateful for this fiasco, as it gave me a reason to revisit a question that has been bothering me for most of my software engineering career.
过去几个月里,一场老派的网络论战围绕着 Bun 通过极其频繁地使用 Claude Code 从 Zig 迁移到 Rust 一事展开。上个月,Bun 的创建者 Jarred Sumner 发布了一篇深入解析,解释了如何以及为什么 Bun 被迁移到 Rust,这篇文章就像你在任何拥有庞大工程部门的大型科技公司的官方博客上看到的那样。此后不久,Zig 编程语言的创建者 Andrew Kelley 发布了一篇千古奇文,发泄了对 Zig 和 Bun 之间显然早已存在的长期功能失调关系的不满,以及他和其他人与 Jarred 合作的糟糕经历。Andrew 称 Jarred 为“糟糕透顶的管理者”,并说“早在 Jarred 接触大语言模型之前,他就已经在写垃圾代码了”。这两篇文章都值得一读,第一篇展示了一种真正新颖且大胆的软件工程方法,后者则是一封宁可烧掉也不该寄出的信的绝佳示例。我很感激这场闹剧,因为它给了我一个理由去重新审视一个在我大部分软件工程职业生涯中一直困扰我的问题。
To start with, I believe that the production of most software is an industrial process, not a craft process. We work in large, many-thousand-person organizations, on commodity hardware and systems, our roles largely standardized across departments, companies and even countries. Even before the advent of generative AI, we imposed best practices on the production of software, stripping away much of the discretion the individual might have over the fundamentals of how the software was produced. Many decades ago, it was likely true that the production of software was a craft process, done by hand by a skilled individual punching holes in a card, working late into the night, but it’s abundantly clear to me that now, as it is practiced, the production of software is an industrial process by and large. To me, this is not up for debate, it’s self-evident.
首先,我认为大多数软件的生产是一个工业过程,而不是手工艺过程。我们在拥有数千人的庞大组织中工作,使用商品化的硬件和系统,我们的角色在部门、公司甚至国家之间基本实现了标准化。甚至在生成式 AI 出现之前,我们就在软件生产中强加最佳实践,剥夺了个人在软件生产基本方式上可能拥有的大部分自主权。几十年前,软件生产可能确实是一个手工艺过程,由熟练的个人手工完成,在卡片上打孔,工作到深夜,但对我来说非常清楚的是,现在按照其实践方式,软件生产在很大程度上是一个工业过程。对我来说,这没什么好争辩的,这是不言自明的。
What I have wondered for a long time now is whether the production of software should be a craft process. Does better software come from developers and engineers imagining themselves as craftsmen, whittling away at their masterworks year after year? Or does better software come from the imposition of industrial, repeatable, automated processes, with developers and engineers as nothing more than skilled but replaceable workers in the code factory? Is it better to develop and pursue your own personal standard of craftsmanship when coding, or to seek out and embrace industrial best practices wholeheartedly and produce code dispassionately and impersonally?
我长久以来一直在思考的问题是,软件生产_是否应该_是一个手工艺过程。更好的软件是来自那些将自己想象成工匠、年复一年地雕琢其杰作的开发者和工程师吗?还是说更好的软件来自工业化的、可重复的、自动化的流程,而开发者和工程师仅仅是代码工厂中熟练但可替代的工人?在编写代码时,是发展和追求个人的手工艺标准更好,还是全心全意地寻求并拥抱工业最佳实践,不带个人色彩且客观地生产代码更好?
If you are involved in software development, I would ask that you sit with this a minute and ask your heart how you really feel about the question. Do you want to be creating masterworks or are you fine doing your small part to create commodities? Done? Good. Now, with your newfound perspective, go out and terrorize everyone you meet about it. Anyone who disagrees with you is Wrong and a Bad Person and you are justified in using any and all means necessary to correct their behavior and prevent it from spreading further. Get out there and have some fun!
如果你参与软件开发,我希望你花一分钟坐下来,问问你的内心对这个问题的真实感受。你是想创造杰作,还是满足于做些微小的工作来创造商品?想好了吗?很好。现在,带着你的新视角,去向你遇到的每个人灌输这件事,让他们不得安宁。任何不同意你的人都是错的,是坏人,你有理由使用一切必要手段来纠正他们的行为,并防止其进一步蔓延。出去大显身手吧!
In the meantime, for those not sufficiently moved to immediately proselytize their new, deeply held and eminently correct opinion, allow me to introduce the tabs vs spaces debate as a path into understanding exactly why the Great Bun Migration of 2026 portends so much about the future of craftsmanship in software development.
与此同时,对于那些没有受到足够触动去立即宣传其新近确立的、深信不疑且绝对正确的观点的人,请允许我引入制表符与空格之争,以此作为一条路径,来理解为什么 2026 年的 Bun 大迁徙对软件开发中手工艺的未来有如此多的预示。
Wrong. Tabs are inherently evil.
— Dennis Draheim, “Tabs vs. Spaces”, comp.lang.c, Dec 29, 1988
错。制表符生来就是邪恶的。
— Dennis Draheim,“Tabs vs. Spaces”,comp.lang.c,1988年12月29日
If I had thought this through, I would have known the answer already, but as I sat down to research and write this post, I was genuinely shocked to learn that people have been arguing about tabs vs spaces for longer than I have been alive. I am firmly in my mid-thirties now and I’ve been told that I need to maintain a rigorous exercise regime lest I want problems later on in life, so it’s good to get the heart pumping every once in a while with surprises like this one.
如果我仔细想过这件事,我早就该知道答案了,但当我坐下来研究并撰写这篇文章时,我震惊地发现,人们关于制表符与空格的争论时间比我的岁数还大。我现在三十多岁,有人告诉我必须保持严格的锻炼习惯,免得以后生活中出问题,所以偶尔用这样的惊喜来让心脏加速跳动一下也是好事。
Death to tabs!
Regards,
Dan, who will always use 3-space, er, tabs.
— Daniel Berger, “Using TABs vs. spaces II. (the Philosophy flamewar reloaded ;-))”, RubyTalk, Jul 2007
制表符去死!
致敬,
Dan,永远使用3空格,呃,制表符的人。
— Daniel Berger,“Using TABs vs. spaces II. (the Philosophy flamewar reloaded ;-))”,RubyTalk,2007年7月
For those who have only joined the software industry in the last few years, we used to argue often and loudly about whether code should be indented with spaces or tabs. Nowadays, there are formatters that take care of such things for you automatically, to the point that I couldn’t tell you whether I use tabs or spaces anymore in any of the code I write. There were a couple solid decades where that was definitely not the case though.
I said that braces are redundant information. In other words, if you indent the code correctly, the braces don’t add additional information. In fact, that is tautological: if the braces do add additional information, you’ve indented the program incorrectly. Braces are not Compiler-Fluff.
— T. William Wells, “Braces are not Compiler-Fluff.”, comp.lang.c, Jan 4, 1989
我说过花括号是_冗余_信息。换句话说,如果你正确地缩进了代码,花括号就不会增加额外信息。事实上,这是同义反复:如果花括号_确实_增加了额外信息,说明你程序的缩进不正确。花括号不是 Compiler-Fluff。
— T. William Wells,“Braces are not Compiler-Fluff.”,comp.lang.c,1989年1月4日
When I first joined the industry over a decade ago, I remember being enthralled with discussions of the merits of tabs/spaces over the perceived sins of spaces/tabs. My seniors would sit around during lunch and opine at length about their preferred way of indenting code. And not just tabs or spaces, but where the newlines should go and why. Should a single-line while loop all go on one line if it can? Or should it go across 3 (or, if you had the luxury, 4) lines, making it clear what was going on and allowing easy modification later? Each language had a dozen little places where you could have your opinion about how it should look, and people certainly did!
C code layout is a classic example of rule-governed behavior in which the rules are inexplicit and often less than half-conscious, but evidently very strong.
— Eric S. Raymond, comp.lang.c, Dec 23, 1988
C 代码的布局是受规则约束行为的经典示例,这些规则是不成文的,而且往往不到一半是有意识的,但显然非常强大。
— Eric S. Raymond,comp.lang.c,1988年12月23日
I remember caring about tabs vs spaces, and formatting more broadly, in a profound way. I had long conversations about the merits of my preferred whitespace, and why it mattered deeply and always would. I couldn’t for the life of me tell you which one I thought was better now, and I can’t be bothered to dig up my old code to know for sure.
我记得我曾深切地关注制表符与空格之争,以及更广泛的格式化问题。我有过漫长的对话,讨论我偏爱的空白字符的优点,以及为什么这意义重大且永远如此。但我现在无论如何也说不清我认为哪个更好了,而且我也懒得去翻出我的旧代码来确认。
in the tabs-vs-spaces debate, i see people saying “tabs lets us customize our tab-width”, as though we do this “for fun” — but this is about meeting the real needs of real people who have real impairments — how is this not seen as a simple cut-and-dry accessibility issue?
— ChaseMoskal, “Nobody talks about the real reason to use Tabs over Spaces”, /r/javascript, 2019
在制表符与空格的争论中,我看到人们说“制表符让我们能自定义制表符宽度”,好像我们这么做是“为了好玩”一样——但这是为了满足那些真正有障碍的真正的人的真正需求——为什么这不被看作是一个简单的、明确的无障碍问题?
— ChaseMoskal,“Nobody talks about the real reason to use Tabs over Spaces”,/r/javascript,2019
It wasn’t just a preference, people imbued real meaning to tabs vs spaces! You could be wrong and it would affect people’s opinions of you, as irrational as that may sound today. To put a finer point on the depth of the issue culturally, this entire debate was immortalized in a scene in the Silicon Valley TV show, when Richard, the main character, ends things with a woman he would otherwise want to sleep with because she kept using spaces to indent her code.
这不仅仅是一种偏好,人们赋予了制表符与空格之争真正的意义!你可能会犯错,而这会影响别人对你的看法,尽管今天听起来可能很荒谬。为了更精准地说明这个问题在文化上的深度,整个争论被永久地定格在了《硅谷》电视剧的一个场景中:主角理查德本来想和一个女人上床,但因为她一直用空格缩进代码,最终和她分手了。
[
[


Richard and Winnie sitting on a couch mid-argument in Silicon Valley; she looks at him with narrowed eyes as he talks.
《硅谷》中理查德和温妮坐在沙发上争吵;他说话时,她眯着眼睛看着他。
The tabs-versus-spaces argument, from “Tabs versus Spaces (From Silicon Valley)”, aksonai.
制表符与空格的争论,来自“Tabs versus Spaces (From Silicon Valley)”,aksonai。
I don’t want to hear any more people’s opinions. I think that has been made clear by locking the topic, even though I have been baited into the discussion yet again. I have all the information, every point that can possibly been made has been made. This topic is the bikeshed of all bikesheds, and as the BDFN I get to choose the color.
— Andrew Kelley, Zig GitHub Issues, Oct 28, 2023
我不想再听任何人的意见了。我想通过锁定话题已经说得很清楚了,尽管我再次被引诱参与了讨论。我掌握了所有信息,每一个能提出的观点都已经被提出了。这个话题是所有琐事中的琐事,作为 BDFN,由我来选择颜色。
— Andrew Kelley,Zig GitHub Issues,2023年10月28日
No less than Andrew Kelley has made his position quite clear about how Zig code should be formatted. A Zig program will simply fail to compile if it includes tabs or uses the wrong kind of newline at the end of a line, and zig fmt will not let you use 2 spaces for indentation instead of 4. If you have a problem with this, then you should configure your code editor to handle it for you automatically or use a different language. This has been, apparently, controversial and it takes only half a minute to find long, heated discussion of this all over the place. This was another thing I did not know before I sat down to write this essay, but serendipity provides when one sets out to finally put the Truth to print.
A few years into my career, around 2014, I remember some coworkers arguing about whether we should introduce flake8 into the Python codebase at the place I worked. flake8 checked the Python Enhancement Proposal 8 which detailed how Python code should be formatted. PEP8 was an old proposal, from 2001, and while linters had been around for a while, it was only roughly in the early 2010s that automatic formatters appeared that would tell you where parts of your codebase weren’t formatted “correctly” and then fix it for you. You could use tabs or spaces, it supported both, but I think it would whine if the codebase mixed styles, though it’s been long enough that, again, I cannot exactly recall.
在我的职业生涯开始几年后,大约是2014年,我记得一些同事在争论我们是否应该在工作场所的 Python 代码库中引入 flake8。flake8 会检查Python增强提案8,该提案详细规定了 Python 代码应如何格式化。PEP8 是一个早在2001年就提出的旧提案,虽然lint工具已经存在了一段时间,但直到大约2010年代初,才出现了能够告诉你代码库中哪些部分格式“不正确”并帮你修复的自动格式化工具。你可以使用制表符或空格,它两者都支持,但我认为如果代码库混合了这两种风格,它就会抱怨,不过时间隔得太久了,我再一次无法准确回忆起来了。
All my coworkers and I had one last discussion about tabs vs spaces, picked one after a perhaps overlong discussion, and that was that, and our codebase started to trend towards one static style. We all installed flake8 and mostly stuck by its formatting suggestions, and later embraced autopep8 as well to make it happen automatically. That last debate wasn’t that fun though, not the way all the other ones were. I can’t recall that we ever really talked about tabs vs spaces again, moving on to other well-worn topics of discussion.
我和所有同事进行了最后一次关于制表符与空格的讨论,在一场或许有些冗长的辩论后选定了一种,事情就这样定了,我们的代码库开始趋向于一种固定的风格。我们都安装了 flake8,并且基本遵循它的格式化建议,后来还采用了 autopep8 来自动完成这项工作。不过,那场最后的辩论并不怎么有趣,不像其他所有辩论那样。我回想不起我们后来是否还真正讨论过制表符与空格的问题,而是转向了其他老生常谈的讨论话题。
Looking back on it, I remember codebases having so much more personality before automatic formatting. I remember opening up a file and, without having to use git blame or the like, knowing who was the last person to touch this file because who else would do something so weird with all those and’s! I would spend an extra 30 minutes making sure I got all the formatting right, because the senior engineer on the team would reject the changes outright if they didn’t match his standards for how things should look. Found some good bugs that way too, making sure the code looked right. Half the effort of learning a new codebase was learning how to read the idiosyncratic style the team had developed to format the code, let alone how to write it. I wrote lots of little scripts to make sure I was doing it right, and I remember getting better at writing shell scripts because the fear of being called a noob by my older, more experienced peers for not doing things the Right way kept me up at night.
回首往事,我记得在自动格式化出现之前,代码库有着丰富得多的个性。我记得打开一个文件,不用 git blame 之类的工具就知道最后碰过这个文件的人是谁,因为除了他还有谁会把那些 and 用得这么古怪!我会多花30分钟确保所有的格式都弄对,因为如果格式不符合他对事物外观的标准,团队里的高级工程师会直接拒绝这些更改。通过确保代码看起来正确,这种方式也发现了一些不错的bug。学习一个新代码库,一半的精力花在学习团队为格式化代码而发展出的那种特有风格上,更不用说如何编写它了。我写了很多小脚本来确保自己做对了,我记得我的shell脚本写得越来越好,因为害怕年长、更有经验的同行因为我没有用“正确”的方法做事而叫我菜鸟,这让我夜不能寐。
What I think we lost when we adopted formatters was everyone having an obvious and personal sense of connection to the code and the other people who wrote it. Maybe you didn’t have control over what the code did, but, hey, at least, you and your team had some say over how it looked. Now, any sense of personality, of whimsy, of experimenting with the syntax of the language itself, gets sanded away and buffed out and only the impersonal functionality of it all gets left behind.
我认为我们在采用格式化工具时失去的,是每个人对代码及编写代码的其他人之间那种显而易见且个人的联系感。也许你无法控制代码做什么,但是,嘿,至少你和你的团队对它的外观有发言权。现在,任何个性感、异想天开、对语言语法本身的实验,都被打磨抛光得一干二净,留下的只有这整体中非个人的功能性。
As a senior engineer who is responsible for implementing best practices and what not for my team, the two paragraphs above are juvenile and dumb and if a junior engineer sent them to me justifying why they turned the formatter off, I would give them help channel duty for a month. Off the clock though, I have to ask myself, don’t you ever want to just let it rip?
作为一名负责为我的团队实施最佳实践等工作的资深工程师,上面两段话是幼稚且愚蠢的,如果一名初级工程师把这些发给我,以此作为他们关闭格式化工具的理由,我会罚他们去服务台值班一个月。不过下班后,我不禁要问自己,难道你就不曾想过干脆放飞自我吗?
Someone asked about the code base. “Currently it’s 247 lines of C.” Some expressions of incredulity. Whitney displayed the source, divided between five text files so each would fit entirely on his monitor. “Hate scrolling,” he mumbled.
— Stephen Taylor, “Impending kOS”, Vector, Sep 1, 2014
有人问起代码库。“目前是 247 行 C 代码。”随之而来的是一些难以置信的表情。Whitney 展示了源代码,分为五个文本文件,这样每个文件就能完全显示在他的显示器上。“我讨厌滚动,”他嘟囔着。
— Stephen Taylor,“Impending kOS”,Vector,2014年9月1日
typedef char C;typedef long I;
typedef struct a{I t,r,d[3],p[2];}*A;
#define P printf
#define R return
#define V1(f) A f(w)A w;
#define V2(f) A f(a,w)A a,w;
#define DO(n,x) {I i=0,_n=(n);for(;i<_n;++i){x;}}
I *ma(n){R(I*)malloc(n*4);}mv(d,s,n)I *d,*s;{DO(n,d[i]=s[i]);}
tr(r,d)I *d;{I z=1;DO(r,z=z*d[i]);R z;}
A ga(t,r,d)I *d;{A z=(A)ma(5+tr(r,d));z->t=t,z->r=r,mv(z->d,d,r);
R z;}
V1(iota){I n=*w->p;A z=ga(0,1,&n);DO(n,z->p[i]=i);R z;}
V2(plus){I r=w->r,*d=w->d,n=tr(r,d);A z=ga(0,r,d);
DO(n,z->p[i]=a->p[i]+w->p[i]);R z;}
V2(from){I r=w->r-1,*d=w->d+1,n=tr(r,d);
A z=ga(w->t,r,d);mv(z->p,w->p+(n**a->p),n);R z;}
V1(box){A z=ga(1,0,0);*z->p=(I)w;R z;}
V2(cat){I an=tr(a->r,a->d),wn=tr(w->r,w->d),n=an+wn;
A z=ga(w->t,1,&n);mv(z->p,a->p,an);mv(z->p+an,w->p,wn);R z;}
V2(find){}
V2(rsh){I r=a->r?*a->d:1,n=tr(r,a->p),wn=tr(w->r,w->d);
A z=ga(w->t,r,a->p);mv(z->p,w->p,wn=n>wn?wn:n);
if(n-=wn)mv(z->p+wn,z->p,n);R z;}
V1(sha){A z=ga(0,1,&w->r);mv(z->p,w->d,w->r);R z;}
V1(id){R w;}V1(size){A z=ga(0,0,0);*z->p=w->r?*w->d:1;R z;}
pi(i){P("%d ",i);}nl(){P("\n");}
pr(w)A w;{I r=w->r,*d=w->d,n=tr(r,d);DO(r,pi(d[i]));nl();
if(w->t)DO(n,P("< ");pr(w->p[i]))else DO(n,pi(w->p[i]));nl();}
C vt[]="+{~<#,";
A(*vd[])()={0,plus,from,find,0,rsh,cat},
(*vm[])()={0,id,size,iota,box,sha,0};
I st[26]; qp(a){R a>='a'&&a<='z';}qv(a){R a<'a';}
A ex(e)I *e;{I a=*e;
if(qp(a)){if(e[1]=='=')R st[a-'a']=ex(e+2);a= st[ a-'a'];}
R qv(a)?(*vm[a])(ex(e+1)):e[1]?(*vd[e[1]])(a,ex(e+2)):(A)a;}
noun(c){A z;if(c<'0'||c>'9')R 0;z=ga(0,0,0);*z->p=c-'0';R z;}
verb(c){I i=0;for(;vt[i];)if(vt[i++]==c)R i;R 0;}
I *wd(s)C *s;{I a,n=strlen(s),*e=ma(n+1);C c;
DO(n,e[i]=(a=noun(c=s[i]))?a:(a=verb(c))?a:c);e[n]=0;R e;}
main(){C s[99];while(gets(s))pr(ex(wd(s)));}
typedef char C;typedef long I;
typedef struct a{I t,r,d[3],p[2];}*A;
#define P printf
#define R return
#define V1(f) A f(w)A w;
#define V2(f) A f(a,w)A a,w;
#define DO(n,x) {I i=0,_n=(n);for(;i<_n;++i){x;}}
I *ma(n){R(I*)malloc(n*4);}mv(d,s,n)I *d,*s;{DO(n,d[i]=s[i]);}
tr(r,d)I *d;{I z=1;DO(r,z=z*d[i]);R z;}
A ga(t,r,d)I *d;{A z=(A)ma(5+tr(r,d));z->t=t,z->r=r,mv(z->d,d,r);
R z;}
V1(iota){I n=*w->p;A z=ga(0,1,&n);DO(n,z->p[i]=i);R z;}
V2(plus){I r=w->r,*d=w->d,n=tr(r,d);A z=ga(0,r,d);
DO(n,z->p[i]=a->p[i]+w->p[i]);R z;}
V2(from){I r=w->r-1,*d=w->d+1,n=tr(r,d);
A z=ga(w->t,r,d);mv(z->p,w->p+(n**a->p),n);R z;}
V1(box){A z=ga(1,0,0);*z->p=(I)w;R z;}
V2(cat){I an=tr(a->r,a->d),wn=tr(w->r,w->d),n=an+wn;
A z=ga(w->t,1,&n);mv(z->p,a->p,an);mv(z->p+an,w->p,wn);R z;}
V2(find){}
V2(rsh){I r=a->r?*a->d:1,n=tr(r,a->p),wn=tr(w->r,w->d);
A z=ga(w->t,r,a->p);mv(z->p,w->p,wn=n>wn?wn:n);
if(n-=wn)mv(z->p+wn,z->p,n);R z;}
V1(sha){A z=ga(0,1,&w->r);mv(z->p,w->d,w->r);R z;}
V1(id){R w;}V1(size){A z=ga(0,0,0);*z->p=w->r?*w->d:1;R z;}
pi(i){P("%d ",i);}nl(){P("\n");}
pr(w)A w;{I r=w->r,*d=w->d,n=tr(r,d);DO(r,pi(d[i]));nl();
if(w->t)DO(n,P("< ");pr(w->p[i]))else DO(n,pi(w->p[i]));nl();}
C vt[]="+{~<#,";
A(*vd[])()={0,plus,from,find,0,rsh,cat},
(*vm[])()={0,id,size,iota,box,sha,0};
I st[26]; qp(a){R a>='a'&&a<='z';}qv(a){R a<'a';}
A ex(e)I *e;{I a=*e;
if(qp(a)){if(e[1]=='=')R st[a-'a']=ex(e+2);a= st[ a-'a'];}
R qv(a)?(*vm[a])(ex(e+1)):e[1]?(*vd[e[1]])(a,ex(e+2)):(A)a;}
noun(c){A z;if(c<'0'||c>'9')R 0;z=ga(0,0,0);*z->p=c-'0';R z;}
verb(c){I i=0;for(;vt[i];)if(vt[i++]==c)R i;R 0;}
I *wd(s)C *s;{I a,n=strlen(s),*e=ma(n+1);C c;
DO(n,e[i]=(a=noun(c=s[i]))?a:(a=verb(c))?a:c);e[n]=0;R e;}
main(){C s[99];while(gets(s))pr(ex(wd(s)));}
— Arthur Whitney, “An Implementation of J” (Incunabulum), jsoftware.com, summer 1989
— Arthur Whitney,“An Implementation of J” (Incunabulum),jsoftware.com,1989年夏
The Go programming language was announced by Google in November 2009, after having been worked on internally since 2007. It was designed by Unix and C pioneers and legends like Ken Thompson and Rob Pike. The day after its release, someone posted the following about Go’s gofmt formatting tool that came along with the language.
Go 编程语言于 2009 年 11 月由 Google 发布,在此之前它从 2007 年起就在内部开发。它由 Ken Thompson 和 Rob Pike 等 Unix 和 C 语言的先驱及传奇人物设计。发布后的第二天,有人针对随该语言一同发布的 Go 的 gofmt 格式化工具发表了以下看法。
I think it’s pretty neat that a source code formatting tool is provided along. It’s also a nice thing that the parser/ast/pretty printer are available as mods.
However, I’m not sure that trying to enforce a formatting style by denying the ability to configure the formatter (as the FAQ mentions) is a good idea. It could be good that at least the go/printer package allows more flexible configuration even if the command-line gofmt tool doesn’t.
I don’t think it’s so bad that different C/C++ project use different set of conventions and I doubt that the plans of encouraging everyone to use the same style by making go/printer non-configurable will really work. Instead, I expect that many people will do what I intend to and customize it, even at the cost of pulling go/printer out and including a tweaked version of it in the formatting tool source tree (opening braces at end of if/else/etc. instead of on their own lines drastically reduce readability for me)
— Antoine Chavasse, golang-nuts, Nov 11, 2009
我认为附带提供源代码格式化工具非常棒。解析器/AST/美化打印机作为模块提供也是一件好事。
但是,我不确定通过禁止配置格式化工具(如 FAQ 所述)来强制执行一种格式风格是否是个好主意。如果至少 go/printer 包允许更灵活的配置,即使命令行 gofmt 工具不允许,那也会很好。
我不认为不同的 C/C++ 项目使用不同的约定集有什么不好,我怀疑通过使 go/printer 不可配置来鼓励每个人都使用相同样式的计划是否会真正奏效。相反,我预计很多人会做我打算做的事并对其进行自定义,甚至不惜将 go/printer 拉出来并在格式化工具源代码树中包含它的一个修改版本(将左大括号放在 if/else/etc. 的行尾而不是单独一行,极大地降低了我的可读性)
— Antoine Chavasse,golang-nuts,2009年11月11日
Russ Cox, an early member of the Go team, had this to say in direct response:
Russ Cox 是 Go 团队的早期成员,他在直接回复中这样说道:
We hope that people will accept the output of gofmt precisely because it puts an end to these kinds of style debates. How many different brace styles are there in C? Too many.
Personally I find it liberating to let gofmt format for me, because it means I have more neurons available for attacking interesting programming problems. There are things I don’t like about gofmt’s output, but I love not worrying about them anymore.
— Russ Cox, golang-nuts, Nov 11, 2009
我们希望人们能接受 gofmt 的输出,正是因为它终结了这类风格争论。C 语言里有多少种不同的大括号风格?太多了。
就个人而言,我发现让 gofmt 为我格式化是一种解放,因为这意味着我有更多的神经元可用于解决有趣的编程问题。gofmt 的输出有些我不喜欢的地方,但我喜欢不再为它们操心。
— Russ Cox,golang-nuts,2009年11月11日
In a follow-up post about gofmt a month later, Cox had this to say:
一个月后,Cox 在关于 gofmt 的一篇后续文章中这样说道:
The most obvious benefit of using gofmt is that when you open an unfamiliar Go program, your brain doesn’t get distracted, even subconsciously, about why that brace is in the wrong place; you can focus on the code, not the formatting.
— Russ Cox, “Gofmt”, swtch.com, Dec 15, 2009
使用 gofmt 最明显的好处是,当你打开一个不熟悉的 Go 程序时,你的大脑不会分心,甚至潜意识里也不会去想为什么那个大括号放错了位置;你可以专注于代码,而不是格式。
— Russ Cox,“Gofmt”,swtch.com,2009年12月15日
That post is a worthwhile read; it gets into the benefits of what happens when your programming language has one canonical format for all programs and why that’s worth all the difficulties of making that possible in your programming language compiler. We’ll return to that subject of linting and types later on, don’t you worry. For now, though, here are some more thoughts from the Go team.
那篇文章值得一读;它深入探讨了当你的编程语言对所有程序采用一种标准格式时所带来的好处,以及为什么在编程语言编译器中实现这一点所付出的种种困难是值得的。我们稍后会回到关于 lint 和类型的这个话题,别担心。不过现在,这里是 Go 团队的一些更多想法。
Go is efficient, scalable, and productive. Some programmers find it fun to work in; others find it unimaginative, even boring. In this article we will explain why those are not contradictory positions. Go was designed to address the problems faced in software development at Google, which led to a language that is not a breakthrough research language but is nonetheless an excellent tool for engineering large software projects.
— Rob Pike, “Go at Google: Language Design in the Service of Software Engineering”, 2012
Software engineering A personal definition: To maximize the quality of software a given group of programmers can create. Our programmers are Googlers, not researchers. For a new language, practicality and ease of adoption are critical.
The key point here is that our programmers are Googlers, not researchers. Typically fairly young, fresh out of school, probably learned Java, maybe learned C or C++, probably learned Python. They are not capable of understanding a brilliant language, but we want to be able to use them to build good software. And so the language that we give them has to be easy for them to understand and easy for them to adopt.
— Rob Pike, “From Parallel to Concurrent”, Lang.NEXT, 2014, 20:40
Go 是高效的、可扩展的、且具有生产力的。一些程序员觉得在其中工作很有趣;另一些人则觉得它缺乏想象力,甚至乏味。在本文中,我们将解释为什么这并不是矛盾的立场。Go 旨在解决 Google 软件开发中面临的问题,这使得它不是一种突破性的研究语言,但却是工程化大型软件项目的出色工具。
— Rob Pike,“Go at Google: Language Design in the Service of Software Engineering”,2012
软件工程 个人定义:最大化特定程序员群体所能创造的软件质量。我们的程序员是 Googlers,而不是研究人员。对于一门新语言来说,实用性和易于采纳是至关重要的。
这里的关键点是,我们的程序员是 Googlers,而不是研究人员。通常相当年轻,刚从学校毕业,可能学过 Java,可能学过 C 或 C++,可能学过 Python。他们没有能力理解一门天才的语言,但我们希望能够利用他们来构建优秀的软件。因此,我们给他们的语言必须易于他们理解和易于他们采纳。
— Rob Pike,“From Parallel to Concurrent”,Lang.NEXT,2014,20:40
An explicit design goal of Go was that any Joe Schmo from a second-tier university like Cornell or Columbia could come in and write performant code at Google scale, obviating the need for a PhD in C++ Template Studies that was theretofore required. As well, in reading up on the design documents and listening to these presentations, I found that the Go team placed a large emphasis on huge programs written in Go compiling fast. In point of fact, Go was initially conceived while waiting for a large C++ codebase to compile.
Go 的一个明确设计目标是,让任何来自康奈尔或哥伦比亚等二流大学的普通人都能进来,在 Google 的规模上编写高性能代码,从而免除了此前对 C++ 模板研究博士学位的要求。同样,在阅读设计文档和聆听这些演讲时,我发现 Go 团队非常强调用 Go 编写的庞大程序能够快速编译。事实上,Go 最初就是在等待一个大型 C++ 代码库编译时构思出来的。
I started another compilation, turned my chair around to face Robert, and started asking pointed questions. Before the compilation was done, we’d roped Ken in and had decided to do something. We did not want to be writing in C++ forever, and we—me especially—wanted to have concurrency at my fingertips when writing Google code. We also wanted to address the problem of “programming in the large” head on, about which more later.
— Rob Pike, “Less is exponentially more”, 2012
我开启了另一次编译,转过椅子面向 Robert,开始提出尖锐的问题。编译还没完成,我们就把 Ken 拉了进来,并决定做点什么。我们不想永远用 C++ 写代码,而且我们——尤其是我——想在编写 Google 代码时能将并发信手拈来。我们也想直面“大规模编程”的问题,稍后再详述。
—— Rob Pike,“Less is exponentially more”,2012
I focus on these two things, making it easier to write performant code and speed up the compilation process, because both of them map neatly onto economic terms, specifically deskilling and work intensification. Google spent untold millions to create a programming language that made it possible for them to hire less skilled, cheaper labor while also getting more work out of them in less time.
我将重点放在这两件事上:让编写高性能代码变得更容易,以及加快编译过程,因为这两者都能完美地映射到经济学概念上,特别是去技能化和劳动强化。Google 花费了数不清的数百万美元创造了一种编程语言,使他们能够雇佣技能较低、更便宜的劳动力,同时还能在更短的时间内从他们身上榨取更多的工作量。
In economics, deskilling is the process by which skilled labor within an industry or economy is eliminated by the introduction of technologies operated by semi-skilled or unskilled workers. This results in cost savings due to lower investment in human capital, and reduces barriers to entry, weakening the bargaining power of the human capital. Deskilling is the decline in working positions through the machinery or technology introduced to separate workers from the production process.
— Wikipedia, “Deskilling”, Jul 2026
Work intensification has been defined as “the rate of physical and/or mental input to work tasks performed during the working day”. Work intensity comprises several elements, including the rate of task performance; the intensity of those tasks in terms of physical, cognitive, and emotional demands; the extent to which they are performed simultaneously or in sequence, continuously, or with interruptions; and the gaps between tasks.
— Trades Union Congress, “Work intensification”, Jul 2023
在经济学中,去技能化是指通过引入由半熟练或非熟练工人操作的技术,来消除行业或经济体内部熟练劳动力的过程。这通过降低对人力资本的投资节省了成本,并降低了准入门槛,削弱了人力资本的议价能力。去技能化是通过引入机器或技术将工人与生产过程分离开来,从而导致工作岗位减少的过程。
—— 维基百科,“Deskilling”,2026年7月
劳动强化被定义为“在工作日内执行工作任务时的体力和/或脑力投入率”。劳动强度包含几个要素,包括任务执行的速率;这些任务在体力、认知和情感要求方面的强度;它们是同时还是按顺序、连续执行还是有中断执行的程度;以及任务之间的间隔。
—— 英国工会大会,“Work intensification”,2023年7月
I remember the one and only job I had where I worked daily with a C++ codebase. It sucked. I would hit compile and walk away from the computer for a half hour and go watch the senior developer drive Emacs with a keyboard and a joystick he had jury-rigged with elisp to be hooked up to etags. I still feel my face get red when I recall being that intern and telling him I was pretty good with Emacs and then asking him why he had a joystick on his desk and slowly losing my mind as he flew through the Mathematica kernel like a fucking fighter pilot. Cameron, I hope you are doing well, you are a legend, I learned so much from you, thank you!
我还记得我唯一一份每天处理 C++ 代码库的工作。那太糟糕了。我会点击编译,然后离开电脑半小时,去看那位高级开发人员用键盘和一个他用 elisp 临时拼凑并连接到 etags 的操纵杆来驾驶 Emacs。当我想起自己作为实习生告诉他我很擅长 Emacs,然后问他为什么桌上有个操纵杆,接着看着他像他妈的战斗机飞行员一样在 Mathematica 内核中穿梭,而我却慢慢崩溃时,我仍然会觉得脸红。Cameron,希望你一切都好,你是个传奇,我从你身上学到了很多,谢谢你!
[
[


Two stick figures sword-fight in office chairs while their code compiles; caption: “The #1 programmer excuse for legitimately slacking off: ‘My code’s compiling.’”
两个火柴人在办公椅上击剑,同时他们的代码正在编译;配文:“程序员名正言顺地摸鱼的头号借口:‘我的代码正在编译。’”
— Randall Munroe, “Compiling”, xkcd, Aug 15, 2007.
—— Randall Munroe,“Compiling”,xkcd,2007年8月15日。
Let me be clear, I don’t think it was wrong or anything for Google to make Go. It wasn’t obviously the right choice at the time for Google to invest into building Go, but it is obviously the right choice now after more than fifteen years of success after success with Go. It’s a long-term investment that has enabled Google to grow and grow and grow into one of the most valuable companies in the history of the world. And a big part of that growth strategy was them being able to hire less skilled labor to do more of the work than before, and also being able to extract more work out of them because Go compiled so much faster than C++ by design.
让我澄清一下,我不认为 Google 开发 Go 有什么错。在当时,Google 投资构建 Go 并非明显正确的选择,但在 Go 取得一个接一个的成功、历经十五年之后的今天,这显然是正确的选择。这是一项长期投资,使 Google 得以不断成长,成为世界历史上最具价值的公司之一。而这一增长战略的很大一部分在于,他们能够雇佣技能较低的劳动力来完成比以前更多的工作,同时由于 Go 在设计上的编译速度比 C++ 快得多,他们还能从这些劳动力身上榨取更多的工作。
I was asked a few weeks ago, “What was the biggest surprise you encountered rolling out Go?” I knew the answer instantly: Although we expected C++ programmers to see Go as an alternative, instead most Go programmers come from languages like Python and Ruby. Very few come from C++.
— Rob Pike, “Less is exponentially more”, 2012
几周前有人问我:“在推广 Go 的过程中,你遇到的最大惊喜是什么?”我立刻知道了答案:虽然我们期望 C++ 程序员将 Go 视为替代方案,但实际上大多数 Go 程序员来自 Python 和 Ruby 等语言。很少有人来自 C++。
—— Rob Pike,“Less is exponentially more”,2012
But I also understand why the C++ people didn’t flock to Go. Why would they? It cut their bargaining power in the labor market and workplace! If they used Go, they would have fewer excuses to slack off some during the day, and all that knowledge about C++ performance wouldn’t be so useful to them or their employers anymore, they wouldn’t be as special. Likewise, for the less skilled programmer previously unable to perform a lucrative task like code at Google scale, a technology that deskills a particular economic activity is incredibly empowering. Oh, I never took a proper programming language course and don’t know nothing about the sharp edges of concurrency, but I can write a web server in Go that gets sick performance and maybe gets me a promotion? Sign me up!
但我也理解为什么 C++ 程序员没有涌向 Go。他们为什么要这么做?这削减了他们在劳动力市场和职场中的议价能力!如果他们使用 Go,他们白天摸鱼的借口就会变少,而且所有关于 C++ 性能的知识对他们或他们的雇主来说都不再那么有用了,他们也不再那么特别。同样,对于以前无法执行像 Google 规模的编码这样有利可图的任务的低技能程序员来说,一种能对特定经济活动进行去技能化的技术是令人难以置信的赋权。哦,我从来没上过正式的编程语言课,对并发的棱角一无所知,但我能用 Go 写出一个性能爆表的 Web 服务器,没准还能让我升职?算我一个!
For my part, I never liked Go that much. I could tell that Go was an attack on the humble artisanal C++ templatesmiths, and therefore should be rejected out of hand, out of solidarity, from the start! No, not so much, I tried to love it for a week and just never found anything I liked that much about it. It never made my heart sing.
就我而言,我从来都不怎么喜欢 Go。我看得出来 Go 是对谦逊的手工匠人般的 C++ 模板匠人的攻击,因此出于团结,从一开始就该断然拒绝!不,并非如此,我试着去爱它一个星期,但始终没有发现它有什么让我非常喜欢的地方。它从未让我的心歌唱。
[Development Speed slide on screen] So what kind of runner can run as fast as they possibly can from the very start of a race, right? Only somebody who runs really short races.
But of course we are programmers and we’re smarter than runners apparently because we know how to fix that problem. We just fire the starting pistol, every hundred yards and call it a new sprint.— Rich Hickey, “Simple Made Easy”, 2011, 17:10
[屏幕上显示开发速度幻灯片] 那么,什么样的赛跑选手能从比赛一开始就尽可能快地跑,对吧?只有跑超短距离赛的人。 但我们当然是程序员,显然我们比赛跑选手更聪明,因为我们知道如何解决这个问题。我们只需每跑一百码就鸣一次起跑枪,并称之为一次新的冲刺。
—— Rich Hickey,“Simple Made Easy”,2011,17:10
If you’ve read enough forums about programming and software in the last decade or so, I’m sorry for making you flinch like that, thinking this was going to turn into another Clojure evangelism essay. For everyone else, Clojure is a powerful programming language created by Rich Hickey that turns impressionable minds, young and old, into raving artisans, seekers of simplicity, walking down the path of Decomplection, while never leaving the comfort of your hammock.
如果你在过去十年左右阅读了足够多关于编程和软件的论坛,我很抱歉让你这样瑟瑟发抖,以为这又会变成一篇布道 Clojure 的文章。对其他人来说,Clojure 是一种由 Rich Hickey 创建的强大编程语言,它能把易受影响的头脑,无论老少,变成疯狂的手工匠人、简单性的追求者,走在 Decomplection 的道路上,同时从不离开你吊床的舒适区。
I was one such mind, and I’m grateful for it. Though it’s rare now, when I do write code by hand, no matter what language, I’m secretly writing Clojure, with lots of functions and clean data structures and maps. I’ve been that guy who snuck Clojure into workplaces by way of a microservice here and another over there, justifying it because Clojure has that one special library that makes this one really important thing we really care about so much easier, I promise!
我就是这样一个头脑,我对此心存感激。虽然现在很少见了,但当我确实手写代码时,无论用什么语言,我都在暗中写 Clojure,包含大量的函数、干净的数据结构和映射。我曾经就是那种人,通过这里塞一个微服务、那里塞一个微服务的方式,把 Clojure 偷偷摸摸地带进工作场所,并辩称这是因为 Clojure 有一个特殊的库,能让那个我们非常关心的、非常重要的事情变得容易得多,我发誓!
There’s hundreds of essays across the internet about why you should learn Clojure, even if you never get a job writing it. Broadly, I agree: broadening your horizons is a good thing, and Clojure has some real good stuff in it that most would benefit from encountering and incorporating into their thinking about how to develop software. What you should be careful with though is the ideology that comes along with it.
互联网上有成百上千的文章论述为什么你应该学习 Clojure,即使你永远不会找一份写 Clojure 的工作。总体而言,我同意:拓宽眼界是一件好事,而且 Clojure 确有一些真正优秀的东西,大多数人都会从接触并将其融入关于如何开发软件的思考中获益。不过,你应该小心的是随之而来的意识形态。
Rich Hickey has, bucket for bucket, one of the most impressive records for giving talks that make you want to walk into your company’s codebase and light it on fire. Any senior developer watching “Simple Made Easy” on the company VPN should set off those Kill Bill sirens in the CTO’s office and a katana should drop down from the drop ceiling panels, because that CTO is about to have to defend themselves and their timelines for the next quarter from a dozen meetings about how they need to urgently address the creeping horror that is Mutable State. They should have after school programs like D.A.R.E. for project managers that teach them how to watch out for developers showing signs of enjoying “Hammock Driven Development”.
无论怎么比,Rich Hickey 都有一项最令人赞叹的记录,他发表的演讲能让你想走进公司的代码库并放一把火。任何高级开发人员如果通过公司 VPN 观看 “Simple Made Easy”,都应该在 CTO 的办公室里拉响那些 《杀死比尔》 般般的警报,并且应该有一把武士刀从吊顶天花板上掉下来,因为那位 CTO 接下来将不得不在一打会议中为自己及下个季度的时间表辩护,这些会议都是关于他们需要如何紧急应对名为 可变状态 的蔓延恐惧。他们应该为项目经理提供像 D.A.R.E. 那样的课后项目,教他们如何留意那些出现享受 “吊床驱动开发” 迹象的开发人员。
[
[


A round kids’ sticker: a cartoon cat and dog in rainbow shirts give a thumbs up under the word “FRIENDS”, ringed by the text “DON’T LET FRIENDS TRY IMMUTABLE STATE”.
一张圆形的儿童贴纸:一只卡通猫和一只穿着彩虹色 T 恤的狗在“FRIENDS”字样下竖起大拇指,周围环绕着文字“DON’T LET FRIENDS TRY IMMUTABLE STATE”。
Do not get me wrong, Rich Hickey, and the Clojure community by extension, give great talks about compelling ideas, that’s exactly my point. What I am warning about is that they embody deeply and argue convincingly the idea that the production of software should be a craft process. That you, as an individual, should deeply think about the program you are going to write before writing it, that you should prefer simple, well-understood tools applied in masterful ways rather than complex, magical ones that invite too much complexity and therefore, sadly but obviously, disaster. That an individual armed with a powerful language and honed skills can go so much further, so much faster than a whole team of people who aren’t thinking so deeply, working with tools that aren’t so sharp.
不要误会,Rich Hickey 以及延伸到的 Clojure 社区,发表了关于引人入胜的理念的精彩演讲,这正是我的观点。我要警告的是,他们深刻体现并令人信服地论证了软件的生产 应该 是一个手工艺过程的理念。作为个人,在编写程序之前应该深入思考你要编写的程序,你应该倾向于以精湛的方式应用简单、易于理解的工具,而不是那些会带来过多复杂性、因此可悲但显然会带来灾难的复杂、神奇的工具。一个配备了强大语言和磨炼出的技能的个人,比一整支没有深入思考、使用的工具不够锋利的人能走得更远、更快。
[
[


A cartoon in the style of Gary Larson’s “Cow tools”: a cow stands behind a table of crude implements — a lambda, a cube marked with a list and a tree, a magnifying glass reading “a b c” — with a barn slung in a hammock behind it. Caption: “Functional tools”.
一幅加里·拉森“牛的工具”风格的卡通画:一头牛站在一张摆放着粗糙工具的桌子后面——一个 lambda、一个标有列表和树的立方体、一个读着“a b c”的放大镜——它身后有一座谷仓悬挂在吊床上。说明文字:“函数式工具”。
As someone who has at earlier times in my life struggled to fit into society, there is an underlying appeal to Clojure and other Lisps, and to the idea of software as craftsmanship as a whole, that I wouldn’t have to deal with other people if I could just find the right set of tools and train myself to use them well enough to produce code good enough that nothing else really mattered. If I could just have gotten the parentheses to balance out right then I could have had my solitude and taken on life at my own pace, in my own way.
作为一个在生命早期曾努力融入社会的人,Clojure 和其他 Lisp 语言有一种潜在的吸引力,软件作为一门手艺整体也有一种潜在的吸引力,如果我能找到合适的工具,并训练自己足够好地使用它们,编写出足够好的代码,以至于其他什么都不重要了,我就不必与人打交道。只要能把括号配平,我就能拥有自己的孤独,按自己的节奏、自己的方式面对生活。
Those feelings went away as I got older, got a social life, integrated better into society and generally chilled out as a person. The question that remains though to me, again, is whether we should aspire to be craftsmen and craftswomen of software. Is the Hickeyian mode of production best for software? I urge you to ask yourself this question, and accost friends, family, coworkers, and strangers with your answer.
随着我年纪渐长,有了社交生活,更好地融入社会,总体上作为一个人变得更加平和,这些感觉消失了。但对我来说,遗留的问题依然是,我们是否应该渴望成为软件的手艺人。Hickey 式的生产模式对软件来说是最好的吗?我敦促你问自己这个问题,并用你的答案去搭讪朋友、家人、同事和陌生人。
> — Tim Ewald, “Clojure: Programming with Hand Tools”, ClojureTV, Jan 8, 2014
> — 蒂姆·埃瓦尔德(Tim Ewald),“Clojure:使用手工工具编程”,ClojureTV,2014年1月8日
[
[


All work which would be irksome to do by hand is done by immensely improved machinery; and in all work which it is a pleasure to do by hand machinery is done without.
— William Morris, News from Nowhere, 1890
所有用手做会觉得厌烦的工作都由大大改进的机器完成;而在所有用手做会带来乐趣的工作中,则不使用机器。
— 威廉·莫里斯(William Morris),乌有乡消息,1890年
A desire to return to working with one’s own hands with simple tools making perfect things of their own design is not unique to the Clojure community. Over the years, I have worked with a surprising number of people who enjoyed doing woodworking in their spare time.
渴望回归用自己双手和简单工具制作自己设计的完美之物,这种渴望并非 Clojure 社区独有。这些年来,我与数量惊人的在业余时间喜欢做木工的人一起工作过。
The Machine may be against Life, but it certainly saves one a lot of work.
— Janet Malcolm, “About the House”, The New Yorker, May 13, 1967
机器可能与生命为敌,但它确实为人们省去了大量工作。
— 珍妮特·马尔科姆(Janet Malcolm),“关于房子”,纽约客,1967年5月13日
While listening to my coworkers talk about their latest project in the lull before stand-up meetings, I once detected a debate and pushed on it, and I was surprised to learn that there was a good amount of civil discussion about the use of power tools within the hobby woodworking community. The matter has more or less been settled in industry: they have work to do and money to make, and of course they are using the power tools as much as makes sense.
在一次站会前的间歇听同事谈论他们的最新项目时,我发现了一场辩论并加以追问,我惊讶地发现在业余木工社区中,关于电动工具的使用存在着相当多的文明讨论。这个问题在工业界或多或少已经解决了:他们有活要干,有钱要赚,当然他们会在合理的范围内尽可能多地使用电动工具。
Norm! Norm! Norm! Norm! (crowd goes crazy) Four more years, four more years…
Some of you might have guessed that I’m a bit infatuated with power tools. I’m an engineer (at least the degree says so…), so I see a peculiar beauty in any machine that works well, be it a tool or a camera or an airplane. I just like good tools, and for me that’s a significant part of my enjoyment of this hobby.
That said, I’ve begun to appreciate how people can enjoy using a well-tuned handplane. It’s true what they say, there really is nothing like the sound & feel of a good plane doing it’s job… Not to worry though…I won’t give up my power tools, NEVER!
— Just_George, “Neander or Normite?”, Southeast Michigan Woodworkers Forum, Mar 29, 2004
Norm!Norm!Norm!Norm!(人群疯狂了)再干四年,再干四年……
你们中有些人可能猜到了,我对电动工具有点着迷。我是个工程师(至少学位上是这么写的……),所以我在任何运转良好的机器中都能看到一种独特的美,无论是工具、相机还是飞机。我就是喜欢好工具,对我来说,这是我享受这个爱好的重要部分。
话虽如此,我已经开始理解人们怎么会享受使用调试良好的手刨。他们说的是真的,确实没有任何东西能比得上好刨子干活时的声音和感觉……不过别担心……我不会放弃我的电动工具,绝不!
— Just_George,“尼安德特人还是规范人?”,密歇根东南部木工论坛,2004年3月29日
For the hobbyists though, a line separates the lovers of power tools from those of hand tools, with perhaps a silent majority of hybridists in between, buying maybe, just one or two power tools to cut down on the stuff they really don’t like doing, but never giving fully into the devil’s juice that is electricity.
然而对于业余爱好者来说,一条界线将电动工具爱好者与手动工具爱好者分开,中间可能存在着一个沉默的大多数的混合主义者,他们可能会买,仅仅买一两个电动工具来减少他们真正不喜欢做的事情,但永远不会完全屈服于电这种魔鬼的汁液。
I came to the realization that working with wood is a fundamental human experience. […] Classical woodworking is not the kind of technology that comes and goes; it never becomes dated, or changes and becomes obsolete. It will always be there as long as there are trees and metal and muscles. […] Using a hand tool, you can often accomplish a task in one-tenth the time it would take using a seemingly superior modern tool or technique. Consider the ax. It’s phenomenal, just amazing, what you can do with an ax.
— Roy Underhill, “An Interview With Roy Underhill, Host of The Woodwright’s Shop”, Mother Earth News, Nov 1, 1985
我意识到与木头打交道是人类的一种基本体验。[…] 古典木工不是那种来来去去的技术;它永远不会过时,也不会改变或变得废弃。只要有树木、金属和肌肉,它就会永远存在。[…] 使用手动工具,你通常可以在十分之一的时间内完成任务,而使用看似优越的现代工具或技术则需要那么长时间。想想斧头。你能用斧头做的事情是惊人的,简直令人惊叹。
— 罗伊·安德希尔(Roy Underhill),“《木匠店》主持人罗伊·安德希尔访谈”,Mother Earth News,1985年11月1日
The hobbyists gave themselves and each other names even. The hand tool lovers called themselves “Galoot”, “Neanderthal”, their hero Roy Underhill became “St. Roy”, their best vintage and well-cared-for tools were “Crispy”, and power tools were dismissed as “Tailed Apprentices”. “Normites” of course had their own jargon. It was all pretty copacetic as far as my cursory investigation has revealed. The hobbyists drew their own lines around what they thought was good and fun, while the industry pumped out ever more powerful tools that could take in a raw tree and shit out a whole cabinet.
业余爱好者们甚至给自己和彼此起了名字。手动工具爱好者自称“Galoot”、“Neanderthal”,他们的英雄罗伊·安德希尔成了“圣罗伊”,他们保存最好、最古旧且维护得当的工具是“Crispy”,而电动工具则被贬为“带尾巴的学徒”。“Normites” 当然也有自己的黑话。就我粗略的调查所知,一切都相当和谐。业余爱好者们围绕他们认为什么是好和有趣的东西划定了自己的界限,而工业界则制造出越来越强大的工具,能吞进一棵原木,拉出整个柜子。
Woodworking professionals and hobbyists, after many centuries and rapid, shocking technological advancements, seem to have mostly figured out their stances broadly speaking and exist in a nice harmony. Surely, a young and upcoming field full of bright young minds like the software industry would learn from this history and have peaceful and productive discussions about the state of their industry and the proper use of automated tools.
经过许多个世纪和快速、令人震惊的技术进步,木工专业人士和业余爱好者在总体上似乎已经弄清了自己的立场,并存在于一种美好的和谐之中。当然,一个充满聪明年轻头脑的年轻且新兴的领域,如软件行业,会从这段历史中吸取教训,并就其行业的状况和自动化工具的恰当使用进行和平且富有成效的讨论。
Right?
对吧?
What klutz had the idea of high level languages. Should be retroactively killed. Anyone got an time machine? :-)
— Neil Franklin, alt.folklore.computers, Nov 29, 1998
BBTW, the ‘C’ compiler is a complete piece of shit. It produces some of the worst code I have ever seen (trying to do a matrix multiply in 3210 ‘C’ ran 5 times slower than the host 68k on a Quadra 700 - rewriting the same in assembler ran 7-8 times faster). If you do any serious 3210 programming, you will need to learn 3210 assembler.
— Walter Horat, comp.sys.mac.hardware, Dec 4, 1993
Clearly because the problem this “useless program” so clearly demonstrates is found in virtually every other function that C is used to compile. It is clear evidence that C optimizes like shit.
It is clear that C pushers wish to ignore this fact.
— Scott Nudds, comp.arch.embedded, Dec 29, 1996
However once the specs are out there (or once the chips become well understood) hand coded assembly will beat compilers hands down.
— Paul Hsieh, comp.os.linux.development.apps, Mar 18, 1996
Correct, unless the assembler sees a segment override or a base or index register, it won’t know it’s a memory reference even if there are brackets. This fact is documented somewhere and is an artifact of the fact that the mental incompetants who designed MASM were C geeks and designed the whole assembler ass-backwards with typed data and untyped operations, whereas in fact things are the other way around in assembly language. The fact that it screws up forward references is inexcusable, this is exactly what an assembler is FOR!
— John Wilson, alt.lang.asm, Mar 22, 1994
Btw, the term that “todays compilers beat human assembly code” applies mainly to bloody beginners and people concentrating on pure theory.
— TS, comp.lang.asm.x86, Oct 1, 2000
I prefer avoiding bastard languages like C.
— Scott Nudds, comp.lang.asm.x86, Apr 24, 1997
I think the key here is NEVER trust a compiler when you have time critical code to write. I have written many real time drivers and since I switched to ‘c’ instead of assembly a few years back, I have noticed that compiler technology leaves a lot to be desired.
— rogerc, comp.lang.c.moderated, Apr 11, 1995
I also do assembly language on the 8051 because I’m not convinced that a HLL can do a good job. Flame me if you like.
— Roger Ivie, alt.folklore.computers, Jan 16, 1991
Allowing a hotshot who doesn’t understand how the compiler works to try to hand-optimize is insane.
— Mark C. Carroll, comp.arch, May 13, 1992
是哪个笨蛋想出了高级语言的主意。应该被追溯处死。谁有时光机吗?:-)
— 尼尔·富兰克林(Neil Franklin),alt.folklore.computers,1998年11月29日
顺便说一句,‘C’编译器就是一坨屎。它生成的一些代码是我见过的最糟糕的代码(试图在 3210 ‘C’ 中做矩阵乘法比 Quadra 700 上的宿主 68k 慢了5倍——用汇编重写同样的东西运行速度快了7-8倍)。如果你要做任何严肃的 3210 编程,你需要学习 3210 汇编。
— 沃尔特·霍拉特(Walter Horat),comp.sys.mac.hardware,1993年12月4日
显然是因为这个“无用程序”如此清楚地展示的问题,几乎存在于 C 被用来编译的每一个其他函数中。这是 C 像屎一样优化的明显证据。
显然 C 的推销者希望无视这个事实。
— 斯科特·纳兹(Scott Nudds),comp.arch.embedded,1996年12月29日
然而一旦规范发布(或者一旦芯片被充分理解),手工编写的汇编将彻底击败编译器。
— 保罗·谢(Paul Hsieh),comp.os.linux.development.apps,1996年3月18日
正确,除非汇编器看到段覆盖或基址或变址寄存器,否则即使有括号,它也不知道这是内存引用。这个事实在某处有记录,是设计 MASM 的智障是 C 极客这一事实的伪影,他们设计了整个倒置的汇编器,带有类型化数据和未类型化操作,而事实上在汇编语言中事情恰恰相反。它搞砸了前向引用是不可原谅的,这正是一个汇编器存在的意义!
— 约翰·威尔逊(John Wilson),alt.lang.asm,1994年3月22日
顺便说一句,“今天的编译器击败人类汇编代码”这个说法主要适用于菜鸟和专注于纯理论的人。
— TS,comp.lang.asm.x86,2000年10月1日
我更喜欢避免像 C 这样的杂种语言。
— 斯科特·纳兹(Scott Nudds),comp.lang.asm.x86,1997年4月24日
我认为这里的关键是,当你要编写时间关键型代码时,永远不要信任编译器。我编写过许多实时驱动程序,自从几年前从汇编切换到‘c’以来,我注意到编译器技术还有很多不足之处。
— rogerc,comp.lang.c.moderated,1995年4月11日
我也在 8051 上做汇编语言,因为我不相信高级语言(HLL)能做好工作。想喷我就喷吧。
— 罗杰·艾维(Roger Ivie),alt.folklore.computers,1991年1月16日
允许一个不了解编译器如何工作的高手去尝试手工优化是疯狂的。
— 马克·卡罗尔(Mark C. Carroll),comp.arch,1992年5月13日
Ah, the good ol’ days. The above is a mix of genuine bile that users of Usenet liked to spit at each other, as well as some slightly more substantive discussion of the use of automated tools like compilers. Compilers weren’t new in Usenet’s day, but they also weren’t so good yet, nothing compared to the likes of GCC and LLVM today. So users had legitimate complaints about them, that have largely been resolved with time and much development effort on the behalf of the compiler makers. I would understandably be pissed too if I was trying to use a nail gun and even once the nail shot out the wrong end!
啊,美好的旧时光。以上是 Usenet 用户喜欢互相吐露的真正怨气的混合体,以及关于使用像编译器这样的自动化工具的一些稍微更具实质性的讨论。在 Usenet 的时代,编译器并不新奇,但它们也没有那么好,与今天的 GCC 和 LLVM 相比什么都不是。因此用户对它们有合理的抱怨,随着时间的推移和编译器制作者的大量开发努力,这些抱怨在很大程度上已经得到了解决。如果我使用射钉枪时哪怕有一次钉子从错误的一端射出来,我也可以理解会感到愤怒!
My impression is that woodworkers and software developers are alike in that people engaged in both industries often enjoy doing more of that kind of thing as a hobby in their free time. They were likely good at working with wood/code in the first place and maybe that’s why they pursued a career in doing it full time and professionally. Where I think they differ is that a woodworker would not argue often and perhaps even loudly that they should be allowed to use the hand tools they use as part of their hobby in order to accomplish their professional tasks at work.
我的印象是,木工和软件开发者很相似,因为这两个行业的从业者往往在业余时间也喜欢把这类事情当作爱好来做。他们一开始可能就擅长木工/编程,也许正因如此才选择将其作为全职职业。但我认为他们的不同之处在于,木工不会经常——甚至大声地——争辩说自己应该被允许在工作中使用他们业余爱好中使用的那些手工工具来完成专业任务。
And, yet, many software developers who aspire to create high quality code with good craftsmanship want to bring the tools they use as part of their hobbies, like Clojure, Haskell, Elixir, and other functional and/or esoteric languages, to the workplace and use them instead of the more, shall we say, industrial languages already in use there, like TypeScript, Python, Java, and Ruby.
Why is that? As I’ve said, I’ve felt the impulse myself and so I will only comment on what I was doing and why. Sometimes the work was not inspiring, and I felt that it was perhaps beneath a coder of my caliber. I knew several functional languages! I had read a bunch of books about them! I had a hammock that I sat in sometimes! Why was I having to use Python to write CRUD apps? Sneaking Clojure in was a pressure release valve, one that let me take down the dissonance between my self-image as a craftsman and the fact that the work I was doing did not require high quality code in that way. It was important that the work was done, but how “well” it was done, not so much.
为什么会这样?如我所说,我自己也感受过这种冲动,所以我只谈谈我当时在做什么以及为什么。有时候工作并不令人振奋,我觉得这或许有辱我这种水平的程序员。我懂好几种函数式语言!我读了大量关于它们的书籍!我还有一张有时会躺一躺的吊床!为什么我得用 Python 来写 CRUD 应用?偷偷引入 Clojure 是一个压力释放阀,它让我缓解了作为工匠的自我形象与我实际做的工作并不需要那种高质量代码之间的认知失调。重要的是把工作完成,但做得有多"好",并不那么重要。
I didn’t like what I was doing at times, so I tried to at least be pleased with how I was doing it. It’s embarrassing to admit all this, and I wish I had realized the dynamic in myself earlier on.
我有时候不喜欢自己正在做的事,所以至少试图对做事的方式感到满意。承认这一切令人尴尬,我真希望自己能更早地意识到自己内心的这种动态。
At some point though, I lost that drive up the mountain towards quality. It was a gradual process, starting before I even knew about Clojure or much about software development in general. In college, I installed Emacs and Linux on my laptop as my operating system and dove into learning how it all really worked. I had to install so many packages, and do so much just to be able to do everything else all my peers were doing on their MacBooks and Windows machines. I learned so many macros and key bindings and was flying around my file system looking at everything. I knew I was learning more about how computers really worked and those others were just, I don’t know, learning the things we were supposed to be learning.
At least once a semester I did something that turned my computer into a complete tire fire. I think I uninstalled Python one time because I was trying to install a new version and everything just broke on the spot, couldn’t tell you why. I spent a day or two fixing it, and I learned a lot about Python versions and backups. But I didn’t really do much else for a while and that started to annoy me quite a bit. I had other things I wanted to do besides maintaining my laptop. So I sold out.
每学期至少有一次,我搞出的事情会让我的电脑变成一场彻底的灾难。有一次我想卸载 Python,因为我想装个新版本,结果一切都当场崩溃了,我也说不清为什么。我花了一两天来修复,学到了很多关于 Python 版本和备份的知识。但那之后我好一阵子没怎么干别的事,这开始让我相当恼火。除了维护我的笔记本,我还有其他想做的事。于是我妥协了。
I remember loving my MacBook Air when I first got it. It was so easy to do stuff! I would update the versions of things and nothing would break. I couldn’t look at the source code for the operating system and I found myself not caring in the slightest. I was on to bigger and better things, like learning Clojure!
我记得刚拿到 MacBook Air 时有多么喜欢它。做事太容易了!我更新各种软件的版本,什么都不会出问题。我看不到操作系统的源代码,但我发现自己丝毫不在意。我已经转向更大更好的事情了,比如学 Clojure!
Looking back on it, that was probably the first sign that I was perhaps not a craftsman at heart. How could a craftsman abandon such fine tools just because they don’t know how to use them properly? I had that same feeling of relief later on when I switched from Emacs to VS Code. It was my third job out of college and VS Code was getting really popular and everybody on my team was using it. I wanted to do some pair programming with them, and the VS Code session sharing plugin was a siren call to my ears as a remote worker. Maybe, I could just use VS Code for pair programming and then Emacs for the real serious work I had to get done? Yeah that could work.
Anyway, I just use VS Code now and I haven’t done anything serious in Emacs in years. Likewise, I couldn’t tell you the last time I used Clojure, as I am now a surprisingly content user of Rust, Python, and TypeScript, as well as a disgruntled combatant of Terraform. As I worked more in the industry, on teams and across departments, I came to think of myself as less of a craftsman and more of a better worker.
总之,我现在只用 VS Code,已经好几年没用 Emacs 做过什么正经事了。同样,我也说不清上次用 Clojure 是什么时候了,因为我现在是一个出乎意料地满足的 Rust、Python 和 TypeScript 用户,同时也是 Terraform 的不满的战士。随着我在行业中工作得越来越多,在团队和跨部门之间,我逐渐不再把自己看作一个工匠,而更像是一个更好的工作者。
I caught myself thinking less and less about how to achieve code with the highest quality and more and more about just writing some code to unblock the next person down the line. If I spent too long digging in, chasing perfection, the assembly line and Jira board might get backed up behind me, and we can’t have that now, can we.
我发现自己在越来越少地思考如何实现最高质量的代码,而越来越多地想着写点代码好让流程中的下一个人不被阻塞。如果我花太长时间钻研、追求完美,流水线和 Jira 看板可能会在我这里积压起来,而我们不能让这种事发生,对吧。
I started to learn Rust in my free time, as it seemed interesting, and I found that as I was on call for systems that were impacted by systems other people wrote, I cared more about the reliability of everything as a whole. The systems not crashing and not waking me up in the night mattered way more to me than how good the architecture diagrams looked. Code quality and reliability often go hand in hand, but they are not the same thing at the end of the day.
我在业余时间开始学习 Rust,因为它看起来很有趣,而且我发现,当我要为受别人写的系统影响的系统值班时,我更关心整体一切的可靠性。系统不崩溃、不在半夜把我吵醒,对我来说比架构图看起来多漂亮重要得多。代码质量和可靠性常常形影不离,但归根结底它们不是同一回事。
Pardon me this digression, but did you know that people used to protest the laws that required you to wear your seat belt? No, really!
请允许我岔开一下话题,但你知道吗,人们曾经抗议要求系安全带的法律?不,真的!
Automobiles were invented in 1886 by Carl Benz. Mass production of the automobile began in 1901 by Ransom Olds (apparently the namesake of the Oldsmobile, who knew) and really kicked off with the Ford Model T in 1908. And as cars became more widespread, so did accidents and deaths. Roughly speaking as a nonhistorian not aiming for rigor, with the increased usage of automobiles by the American populace as well as many roadways funded by Congress in 1916, 1921 and 1926, traffic deaths reached their peak in 1937, with about 30 deaths for every 100,000 people in the United States. The subsequent war and ongoing Great Depression seem to have caused per capita deaths to drop sharply, and after climbing back through the 1950s the rate was around 20 deaths per 100,000 by about 1960. However, the passing of the Federal-Aid Highway Act of 1956, along with the buildout of the highway, caused deaths to spike up again to ~26 per 100,000 people in the late 1960s. And then deaths began a slow, gentle glide down towards today’s rate of about 12 per 100,000 people. What happened?
汽车由 Carl Benz 于 1886 年发明。汽车的大规模生产始于 1901 年,由 Ransom Olds(显然是 Oldsmobile 的命名来源,谁知道呢)发起,并在 1908 年随着 Ford Model T 真正起飞。随着汽车越来越普及,事故和死亡也随之增加。作为一个不追求严谨的非历史学者大致来说,随着美国民众汽车使用量的增加,以及国会在 1916 年、1921 年和 1926 年资助建设的众多道路,交通死亡人数在 1937 年达到峰值,美国每 10 万人中约有 30 人死亡。随后的战争和持续的大萧条似乎导致人均死亡人数急剧下降,经过 1950 年代的回升,到大约 1960 年时比率约为每 10 万人 20 例死亡。然而,1956 年联邦公路援助法的通过以及公路的建设,导致死亡人数在 1960 年代后期再次飙升至每 10 万人约 26 例。然后死亡人数开始缓慢、平缓地向今天每 10 万人约 12 例的比率下滑。发生了什么?
There are many reasons why people stopped dying so often in car crashes, it’s a long, complicated history. So, by your leave, I’ll just be focusing on one part of it, namely the invention and diffusion of the miracle that is the three-point seat belt, and the American government’s various interventions to compel its usage onto the unwilling and rebellious general public.
人们不再那么频繁地死于车祸的原因有很多,这是一段漫长而复杂的历史。所以,请允许我只聚焦其中一部分,也就是三点式安全带这一奇迹的发明和普及,以及美国政府为迫使不愿配合、桀骜不驯的公众使用它而采取的各种干预措施。
The modern three-point seat belt was invented in 1959 by Volvo engineer Nils Bohlin. Volvo believed so strongly that they had a responsibility to save human lives that they made the patent free for their competitors to use. A decade or so on, with people still needlessly dying in car crashes around the country every day, the U.S. federal government mandated in 1968 that all cars must have seat belts installed by the manufacturers.
现代三点式安全带由沃尔沃工程师 Nils Bohlin 于 1959 年发明。沃尔沃坚信自己有责任拯救人类生命,因此他们将专利免费开放给竞争对手使用。大约十年后,全国各地每天仍有人在不必要地死于车祸,美国联邦政府于 1968 年规定所有汽车必须由制造商安装安全带。
Even though all new cars had them, people still weren’t wearing them in 1973 and 1974. So the Nixon administration looked at the car fatality statistics and mandated that, starting with the 1974 model year, every new car be fitted with a seat belt ignition interlock: a device that would not let the engine start unless the driver’s seat belt was buckled.
尽管所有新车都配备了安全带,但在 1973 年和 1974 年,人们仍然不系安全带。于是尼克松政府审视了车祸死亡统计数据,并规定从 1974 年款车型开始,每辆新车都必须安装安全带点火互锁装置:一种除非驾驶员系好安全带否则不让发动机启动的装置。
[
[


A still from a 1974 GM dealership training film showing a driver buckling a seat belt in a Chevrolet.
1974 年 GM 经销商培训影片中的一帧画面,展示一位驾驶员在雪佛兰中系安全带。
Buckling up in a 1974 Chevrolet, from “1974 Chevrolet / GM Safety Belt System Dealership Promotional Sales Training Film”, The Emulsion Alchemist.
1974 年雪佛兰中系安全带,出自"1974 Chevrolet / GM Safety Belt System Dealership Promotional Sales Training Film",The Emulsion Alchemist。
Within a year, Congress had passed a law rolling back this mandate by the administration and also forbidding any future presidential administrations from ever trying something like that again. Drivers hated the interlock system so much that they overwhelmed congressional offices with complaints. Oftentimes, the interlock systems were faulty and cars would simply not start despite drivers buckling their seat belts. People hated the ignition interlock system, and the US government backed off, scared.
不到一年,国会就通过了一项法律,废除了政府的这项强制规定,并禁止未来的任何历任总统行政团队再尝试类似的做法。驾驶员极其讨厌这种联锁系统,以至于他们用大量投诉淹没了国会办公室。很多时候,联锁系统本身就有故障,即使驾驶员系上了安全带,汽车也根本无法启动。人们讨厌这个点火联锁系统,而美国政府也被吓得退缩了。
But, people were still dying every day from car accidents, deaths that could have been prevented by seat belts. By the early 1980s, seat belt usage was still pretty low, with only about 11 percent of front-seat occupants actually wearing them. So the Reagan administration launched a campaign to get state legislatures to mandate seat belt usage, enforced by local law enforcement, and over the next few years several states did.
但是,人们每天仍然死于车祸,而这些死亡本来是可以通过安全带来预防的。到了20世纪80年代初,安全带的使用率仍然很低,只有大约11%的前排乘客真正系了安全带。因此,里根政府发起了一场运动,促使各州立法机构强制规定使用安全带,并由当地执法部门执行,在接下来的几年里,有几个州确实这样做了。
That’s when the protests began again. Radio hosts began decrying the mandatory seat belt laws as overreach by distant, authoritarian Big Brother. Many argued that it was safer to be “thrown clear” through the windshield or out the window, than it was being held back by the seat belt during an accident. Incredible, but hey, they didn’t have the internet back then. Some of these movements even won: Massachusetts voters repealed their brand new seat belt law by referendum in November 1986, and the state didn’t get another one until 1994. But mostly, people actually started wearing them and finally people stopped needlessly dying so much. Nowadays, culturally, the only people I would expect to not regularly wear seat belts are stupid teenagers who are reinventing time honored ways to rebel against society.
就在那时,抗议活动再次爆发。广播节目主持人开始谴责强制使用安全带的法律是遥远、专制的“老大哥”的越权行为。许多人争辩说,在事故中被“甩出”挡风玻璃或车窗外,比被安全带束缚住更安全。这令人难以置信,但是嘿,他们当时没有互联网。其中一些运动甚至取得了胜利:马萨诸塞州的选民在1986年11月的全民公投中废除了他们全新的安全带法,直到1994年该州才重新制定了另一项法律。但基本上,人们实际上开始系安全带了,最终人们不再那么无谓地死亡了。如今,在文化层面上,我唯一能想到不经常系安全带的人,就是那些正在重新发明对抗社会传统方法的愚蠢青少年。
In short, though many, many other factors were at play, seat belts have saved hundreds of thousands of lives in America thanks to waves of concerted, paternalistic effort by the public and private sectors explicitly against the will of the American people at times. Seat belt usage is now so common as to be thoroughly unremarkable, somehow surprisingly absent from the raging culture wars in America and abroad.
简而言之,尽管还有许多许多其他因素在起作用,但得益于公共和私营部门一波接一波的、有时公然违背美国人民意愿的家长式努力,安全带在美国拯救了数十万人的生命。如今,安全带的使用已经司空见惯,以至于完全不引人注目,不知怎地竟缺席了美国和国外激烈的文化战争。
[
[


A line chart of the vehicular fatality-risk index for car and LTV occupants from 1960 to 2012, indexed to 100 in 1960, declining steeply and ending far below the comparison index for dying of disease.
一张从1960年到2012年汽车和LTV乘员交通事故死亡风险指数的折线图,以1960年为100点基准,该指数急剧下降,最终远低于疾病死亡风险对比指数。
Vehicular fatality-risk index for car and LTV occupants, 1960–2012 (1960 = 100), plotted against the risk of dying from disease. Source: NHTSA, “Lives Saved by Vehicle Safety Technologies… 1960 to 2012” (DOT HS 812 069).
1960年至2012年(1960年 = 100)汽车和LTV乘员的交通事故死亡风险指数,与疾病死亡风险对比图。来源:NHTSA,“车辆安全技术拯救的生命……1960至2012年”(DOT HS 812 069)。
Safety glasses are my bane. In sixteen years I’ve yet to find a comfortable pair…..almost tolerable maybe but certainly not comfortable.
— sii, “comfortable hard hat”, Mike Holt Forums, May 31, 2012
安全眼镜是我的克星。十六年来,我还没找到一副戴着舒服的……可能勉强能忍忍,但绝对谈不上舒服。
— sii,“舒适的安全帽”,Mike Holt Forums,2012年5月31日
My apologies for the digression. Back to my main point: did you know that some programmers actively don’t use programming languages with strong type systems and other safety features? No, really! Like a moth to the flame, some people bitterly cling to dynamic types and other features of unsafe languages like manual memory management, finding comfort in the familiar warmth of getting regularly burnt by race conditions, buffer overflows and null pointer exceptions.
I’ve been complaining about this of years and I won’t wear them useless I need to or am forced too. When I put some glasses and all of a sudden I can’t cut grade there is a problem.
— Dozerboy, “Improvements in Safety Glasses…”, Heavy Equipment Forums, Jun 16, 2012
我已经为这事抱怨好几年了,除非我需要或者被迫戴,否则我是不会戴的。当我戴上某些眼镜,突然我就没法切坡度了,这就成问题了。
— Dozerboy,“安全眼镜的改进……”,Heavy Equipment Forums,2012年6月16日
How many massive security incidents — Heartbleed, Cloudbleed, Stagefright, EternalBlue — will it take per year before we learn our lesson? How many bugs must we squash that are simply not possible in safe languages, available today and for no cost? Do not mistake me for a Rust supremacist here either. If you want to use any other language like C or Python or whatever, be my guest, I use whatever is best suited for a task too, but why not turn on all the safety features you can!
我们还要经历多少次大规模的安全事件——Heartbleed、Cloudbleed、Stagefright、EternalBlue——每年才能吸取教训?在如今免费提供的安全语言中,那些根本不可能存在的bug,我们还要消灭多少个?也不要把我误认为是Rust至上主义者。如果你想用C或Python或其他任何语言,请便,我也会根据任务选择最合适的工具,但为什么不尽可能开启所有的安全特性呢!
Of course it takes longer to put it on and off the beam than the work I do.
— iwire, “OSHA Policy on Subcontractors”, Mike Holt Forums, Nov 15, 2006
毫无疑问,在横梁上把它戴上去和摘下来的时间比我干活的时间还要长。
— iwire,“OSHA关于分包商的政策”,Mike Holt Forums,2006年11月15日
What I hear when I listen to fundamental arguments against type systems and the other safety features designed into programming languages is the cry of a child with scorched and scarred hands begging to be allowed to lick the stove this time. Where’s the thrill of it, if the computer makes sure that you don’t step on well known, well marked and clearly understood landmines, when you are just trying to go about your everyday business? How dare those authoritarians impose any sort of restriction on my ability to lay traps for myself, my coworkers, and my employer? Types and memory management are pure paternalism, forced on the working man by ivory tower academics who have never done a real day’s work in their lives. Some might say! Not me, though. I like not getting thrown clear of my car and my software when things crash.
当我倾听那些反对类型系统和编程语言中内置安全特性的根本性论调时,我听到的是一个双手被烫伤、留下疤痕的孩子在哭喊着,乞求这次能让他舔一下火炉。如果计算机能确保你在进行日常业务时,不会踩上那些众所周知的、标记清晰且显而易见的地雷,那还有什么刺激可言?那些威权主义者怎么敢对我的能力施加任何限制,不让我为自己、同事和雇主设下陷阱?类型系统和内存管理纯粹是家长式作风,是由从未真正干过一天体力活的象牙塔学者强加给工人的。某些人可能会这么说!但我不会。我喜欢在系统崩溃时,不会从汽车或软件里被甩出去的感觉。
So safety glasses are not all that great, ANSI or not. I doubt the ability of the wussy clip-on side shields to do much other than delaying a malnourished mosquito for a half second.
— JST, “eye protection for eyeglass wearers”, Practical Machinist, Aug 23, 2006
所以安全眼镜没那么好,管它有没有ANSI认证。我怀疑那些软弱的夹式侧护板除了能把一只营养不良的蚊子挡住半秒钟之外,还能有什么用。
— JST,“戴眼镜者的眼部防护”,Practical Machinist,2006年8月23日
Not wanting to use a safety system because it’s slow, buggy, or hard to use, well, I wouldn’t want to use one of those either! I find myself of two minds. I remember the resentment and exasperation I felt when I tried to get lifetimes to work in Rust for the first, fifth, and hundredth time. If you see lifetimes actually working in my code, you got three guesses about who wrote that code, me or the agents, and the first two guesses don’t count. I don’t like writing code that passes the borrow checker in Rust, but I love having code that passes the borrow checker. To put a finer point on it, I believe that everyone should already always be wearing their metaphorical seat belts when programming and I myself would have ripped out the ignition interlock system and its software analogues with my bare teeth if I was forced to use something so faulty and annoying.
不想使用一个安全系统是因为它速度慢、有bug或者很难用,嗯,我也不想用这样的系统!我发现自己在两种想法之间摇摆。我还记得我第一、第五和第一百次试图让Rust中的生命周期正常工作时所感到的怨恨和恼怒。如果你看到我的代码里生命周期确实正常工作,你可以猜三次是谁写了这段代码,是我还是代理,而且前两次猜测不算数。我不喜欢编写能通过Rust借用检查器的代码,但我喜欢拥有能通过借用检查器的代码。更确切地说,我相信每个人在编程时都应该始终系好他们隐喻意义上的安全带,而如果我被强迫使用如此有故障且烦人的东西,我绝对会亲自用牙齿把点火联锁系统及其软件同类给扯出来。
You see a guy complain about hard hats and safety glasses on the job site, and watch them drive home in a ball cap and sunglasses. To a large extent the problem is phsycological. I suffer from it right along with everyone else.
— Strathead, “comfortable hard hat”, Mike Holt Forums, Jun 1, 2012
你看到一个家伙在工地上抱怨安全帽和安全眼镜,然后看着他们戴着棒球帽和太阳镜开车回家。在很大程度上,这是个心理问题。我和其他人一样也在受其困扰。
— Strathead,“舒适的安全帽”,Mike Holt Forums,2012年6月1日
For Bun, correctly handling the lifetimes of garbage-collected values and manually-managed values has been a major source of stability issues - most often small memory leaks and occasionally, crashes. Every memory allocation has to be meticulously reviewed. Where do these bytes get freed? How do we ensure it only gets freed once? Did we check for JavaScript exceptions properly? Is this garbage-collected pointer visible to the conservative stack scanner? Is this garbage collected memory or manually managed memory?
— Jarred Sumner, “Rewriting Bun in Rust”, bun.com, 2026
对于Bun来说,正确处理垃圾回收值和手动管理值的生命周期一直是稳定性问题的主要根源——最常见的表现是少量内存泄漏,偶尔也会崩溃。每一次内存分配都必须经过仔细审查。这些字节在哪里被释放?我们如何确保它只被释放一次?我们是否正确检查了JavaScript异常?这个垃圾回收的指针对保守栈扫描器可见吗?这是垃圾回收内存还是手动管理的内存?
— Jarred Sumner,“用Rust重写Bun”,bun.com,2026年
A major reason that Jarred Sumner pulled the trigger on the rewrite was that Bun was suffering from a swath of bugs that were common in Zig and categorically impossible in Rust. Zig gives you more than enough rope to hang yourself with when you manage memory by hand. Rust was explicitly designed with a borrow checker built in, a central authority figure in your compiler that wags its finger at you whenever you do anything that might cause a race condition or memory mismanagement. You do have to change how you write your software, it’s true, and I say good! I’ve been on call for software written by rugged individualists who argued against safety features, I’ve been woken up because the software they wrote was never quite as high quality as they thought it was, and the post mortems where they meekly fought against the suffocating safety blankets we had to impose on their software to keep them from crashing the business into a wall were immensely satisfying.
Jarred Sumner决定进行重写的一个主要原因是,Bun正饱受一系列在Zig中很常见但在Rust中绝对不可能出现的bug之苦。当你手动管理内存时,Zig给了你足够长的绳子去上吊。而Rust在设计时明确内置了一个借用检查器,它是你编译器中的一个中央权威人物,每当你做出任何可能导致竞态条件或内存管理不当的操作时,它都会对你摇手指警告。确实,你必须改变编写软件的方式,而我认为这很好!我曾为那些反对安全特性的粗犷个人主义者编写的软件值班待命,我曾被半夜叫醒,因为他们写的软件的质量从来都没有他们自认为的那么高,而在事后分析会议上,他们无力地反抗我们不得不强加在他们软件上、以防止他们把业务撞向墙壁的令人窒息的安全毯,这让我感到极大的满足。
Andrew Kelley @ 11:30: You can’t handle memory allocation failure in this language and I picked on JavaScript but this is a problem with Python, Ruby, Perl, PHP, Haskell, Lisp, Swift, NIM, and Go, they’re all hopeless. They all have hidden memory allocations, you can’t write perfect software in any of these languages, like you’re done, like hello world, done.
Questioner during Q&A @ 43:23: I may not have been paying attention but it seems like Rust was conspicuously absent from all of your language comparisons and I was wondering why.
Andrew Kelley: That oh that’s a great question yeah okay so the scoop on rust as far as memory allocation goes. It used to be that the standard library would panic on allocation failure, I don’t know where this is in the nightly releases or stable, but they added some functions to all the containers to try and mitigate this. So you can kind of like reserve memory and the next, if you have a list, reserve twenty spaces and now the next twenty appends won’t fail. So, two answers, one it used to be that the standard library disqualified itself from being used, the core stuff is fine the language is fine. Now they’ve added stuff the standard library that’s kind of like an afterthought, it’s kind of like bike lanes in New York City, but it does the job you know like you can write perfect software in Rust. Rust is a great competitor to Zig. I think Rust is like the main competitor to Zig. That’s all I am going to say about that. Shout out to Steve Klabnik.
— Andrew Kelley, “Zig: A programming language designed for robustness, optimality, and clarity”, Recurse Center, Mar 20, 2018
Andrew Kelley @ 11:30:在这种语言里你没法处理内存分配失败的问题,我拿 JavaScript 举例,但这也是 Python、Ruby、Perl、PHP、Haskell、Lisp、Swift、NIM 和 Go 的问题,它们全都无药可救。它们都有隐藏的内存分配,你没法用这些语言中的任何一个写出完美的软件,就这样,连 hello world 都不行,完蛋。
问答环节提问者 @ 43:23:我可能没太注意,但好像 Rust 在你所有的语言对比中明显缺席了,我想知道为什么。
Andrew Kelley:哦,这是个好问题,好的,关于 Rust 在内存分配方面的情况。以前标准库在分配失败时会 panic,我不知道这在 nightly 版本还是 stable 版本中的哪个阶段,但他们给所有容器添加了一些函数来尝试缓解这个问题。所以你可以先 reserve 内存,比如你有一个列表,reserve 二十个位置,那么接下来的二十次 append 就不会失败。所以,两个回答,第一,以前标准库自己把自己排除在外了,核心部分没问题,语言本身没问题。现在他们在标准库里加了一些东西,算是事后的补救,有点像纽约市的自行车道,但确实管用,你懂的,你可以用 Rust 写出完美的软件。Rust 是 Zig 的有力竞争者。我认为 Rust 是 Zig 的主要竞争对手。关于这个我就说这么多。向 Steve Klabnik 致敬。
—— Andrew Kelley,"Zig:一种为稳健性、最优性和清晰性而设计的编程语言",Recurse Center,2018年3月20日
What surprised me about the migration of Bun from Zig to Rust, was not that they wanted to do it, but that they were able to do it so fast, and for such low cost. We will see if it’s ultimately successful, time will tell, yet so far, Bun seems to keep Bunning on without too many hiccups.
让我惊讶的,是 Bun 从 Zig 迁移到 Rust 这件事——倒不是他们想这么做,而是他们能这么快地完成,而且成本这么低。最终是否会成功,时间会给出答案,但到目前为止,Bun 似乎还在正常运转,没出什么大岔子。
To round it out, I also am not claiming that Rust is categorically better than Zig in every way, or that a language like Haskell with its strong safety systems is better than any other language. Speaking without much experience with Zig, if you actually need that much fine-grained memory control, Zig seems like it would be the better experience. What I do have a problem with is when people who don’t actually need the unsafe features of a language keep getting predictably burnt by those same unsafe features, yet insist that they can write safe code by themselves every time and don’t need to wear their seat belts. Simply put, that is a recipe for you and your program landing face down on the pavement time and again.
话说回来,我也不是在说 Rust 在每个方面都绝对优于 Zig,也不是说像 Haskell 这样拥有强大安全系统的语言就比其他任何语言都好。我对 Zig 并没有太多实际经验,如果你真的需要那种精细的内存控制,Zig 似乎是更好的选择。我真正有意见的是,那些实际上并不需要语言中不安全特性的人,却一次又一次地被这些不安全特性所伤害,而且每次都坚持认为自己能写出安全的代码,不需要系安全带。说白了,这就是让你和你的程序一次又一次脸朝下摔在 pavement 上的配方。
To accelerate down the slippery slope towards programming as one would in 1984, in 2021 I told myself I was going to do every day of Advent of Code in Rust. Advent of Code is an online puzzle platform, where every day from December 1st to December 25th, increasingly harder puzzles are posted and people can submit their solutions and compete with each other to see how fast they can solve it. I am not and never have been a competition programmer, I just wanted to see if I could do it and learn some Rust along the way.
为了加速滑向《1984》中那样的编程方式,2021年我告诉自己要用 Rust 完成 Advent of Code 每一天的题目。Advent of Code 是一个在线谜题平台,从12月1日到12月25日,每天发布难度递增的谜题,人们可以提交自己的解答,互相竞争看谁解得更快。我不是、也从未是一名竞赛程序员,我只是想看看自己能不能做到,顺便学点 Rust。
— Day 22: Reactor Reboot —
Operating at these extreme ocean depths has overloaded the submarine’s reactor; it needs to be rebooted.
The reactor core is made up of a large 3-dimensional grid made up entirely of cubes, one cube per integer 3-dimensional coordinate (x,y,z). Each cube can be either on or off; at the start of the reboot process, they are all off. (Could it be an old model of a reactor you’ve seen before?)
To reboot the reactor, you just need to set all of the cubes to either on or off by following a list of reboot steps (your puzzle input). Each step specifies a cuboid (the set of all cubes that have coordinates which fall within ranges for x, y, and z) and whether to turn all of the cubes in that cuboid on or off.
— Advent of Code, “Day 22: Reactor Reboot”, 2021
—— 第22天:反应堆重启 ——
在这些极端的海洋深度下运行,潜水艇的反应堆已经过载了;需要重启。
反应堆核心由一个巨大的三维网格构成,完全由立方体组成,每个整数三维坐标 (x,y,z) 对应一个立方体。每个立方体可以处于开启或关闭状态;在重启过程开始时,它们全部处于关闭状态。(这会不会是你以前见过的一种旧型号反应堆?)
要重启反应堆,你只需按照一列重启步骤(你的谜题输入)将所有立方体设置为开启或关闭。每个步骤指定一个长方体(即所有坐标落在 x、y、z 范围内的立方体的集合),以及是要将该长方体中的所有立方体开启还是关闭。
—— Advent of Code,"第22天:反应堆重启",2021年
One of my fondest memories in my programming life was spending an entire Saturday cooped up in my room solving the problem for Day 22. It involved calculating things about shapes in space, and I remember having to do some tricky spatial decompression thing or something. The feeling though was incredible, spending many, many hours thinking and bashing my head against the keyboard, trying to figure out the trick. Finally getting the idea for the solution and then spending a half hour coding it up in Rust was such a rush, I was ecstatic when I wobbled out of my apartment to go find a late dinner.
我编程生涯中最美好的回忆之一,就是花了一整个星期六关在房间里解第22天的题目。它涉及计算空间中图形的一些东西,我记得得做某种棘手的空间分解之类的东西还是什么的。但那种感觉太棒了,花了好多个小时思考和脑袋撞键盘,试图想出窍门。最终想出解决方案,然后花半小时用 Rust 写出来,真是让人兴奋不已,我踉踉跄跄地走出公寓去找一顿迟到的晚餐时,简直欣喜若狂。
I couldn’t have known at the time that 2021 was the last possible chance to really do Advent of Code before the coding machines arrived in force and the entire tech industry got swept along and away. So I’m quite grateful I got to do Advent of Code as it was intended to be experienced before ChatGPT showed up and shot all of us into the future.
我当时不可能知道,2021年是真正做 Advent of Code 的最后机会——在编码机器大举到来、整个科技行业被席卷而去之前。所以我非常庆幸,在 ChatGPT 出现并将我们所有人射向未来之前,我能以 Advent of Code 本该被体验的方式去体验它。
My position on LLMs is that I would prefer that somehow the math would not work out, that multiplying the right matrices together enough times would not give a machine the semblance of intelligence. I think we are in for a rough decade or two politically and socially because of the economic changes that generative AI will bring about in the world economy.
我对 LLM 的立场是,我倒希望那个数学上不成立——把正确的矩阵相乘足够多次,不会赋予一台机器智能的外表。我认为,由于生成式 AI 将在世界经济中带来的经济变革,我们将迎来政治和社会上艰难的一二十年。
If the models never got any smarter than they are now, it would still herald a major white collar worker extinction event. If we locked down all the models and never trained another one, and let the current level of intelligence provided by the models diffuse through society, you cannot tell me that society wouldn’t still be ripped up at a foundational level. I know they hallucinate, I know they make mistakes, and I know that businesses simply do not care and want to use AIs for as much as they can get away with in order to replace costly human labor. In this way LLMs have been a big downer for me.
即使模型永远不再比现在更聪明,它仍然预示着一场重大的白领工人灭绝事件。如果我们锁定所有模型,再也不训练新的,任由当前模型所提供的智能水平在社会中扩散,你没法告诉我社会不会在根基层面被彻底颠覆。我知道它们会产生幻觉,我知道它们会犯错,我也知道企业根本不在乎,只想尽可能多地使用 AI 来替代昂贵的人力劳动。从这个意义上说,LLM 对我来说一直是一件很令人沮丧的事。
On the flip side, I’ve never been more excited about working with computers though. I can take a walk, mess around with Claude on my phone a bit, and come back to 20 different PRs ready to review that are at least a good start if not full completion of the tasks I was interested in. Sure, there are Big Implications to me and everybody having access to this technology, but I got a thousand ideas and a billion tokens to burn chasing them down, and who has time to be depressed, I got slop to sling.
Part of the reason I learned Clojure was the promise that working in a higher-level language allowed one to move further faster than in a lower-level one. If you keep true to that spirit and that desire, if that is really your main goal, why wouldn’t you leave manually writing the code behind as well? I want to move fast and make things, me writing the code was incidental to that.
我学 Clojure 的部分原因,是因为有一种承诺说,在更高层的语言中工作能让人比在更低层的语言中走得更远更快。如果你忠于那种精神和那种愿望,如果那真的是你的主要目标,你为什么不也把手动写代码这件事抛在身后呢?我想快速行动、创造东西,我亲手写代码不过是其中附带的部分。
The phrase that made me sit down and write this essay, that really crystallized so many things for me, was when Andrew Kelley said that Jarred Sumner was “writing slop well before he had access to LLMs.” The deeper I thought about it, the juicier it felt. Slop has taken on such a big and new meaning ever since generative AI got on the scene, that I had almost forgotten what it meant before we got thrust wildly into the future. Andrew Kelley said it in a fit of pique but I really believe that sometimes our hearts sing loudest in anger.
让我坐下来写这篇文章的那句话,那个真正为我理清了许多事情的话,是 Andrew Kelley 说 Jarred Sumner "在能用 LLM 之前就在写 slop 了"。我想得越深,越觉得这句话有味道。自从生成式 AI 登场以来,slop 已经被赋予了一个如此巨大而崭新的含义,以至于我几乎忘了在它被猛地推向未来之前是什么意思。Andrew Kelley 在一气之下说了这句话,但我真心相信,有时候我们的心在愤怒中唱得最响亮。
Cmd+s, plus an editor = format on save. You can write slop, never use the tab key to indent, etc, and you hit Cmd+s and things magically snap into place. It saves an enormous amount of energy. And the amount of energy saved, across a given work week, is very significant.
— damassi, “Feature Request: breakBeforeElse”, prettier GitHub repo, 2020
SLOP (slop) n. 1. A one-sided fudge factor (q.v.). Often introduced to avoid the possibility of a fencepost error (q.v.). 2. (used by compiler freaks) The ratio of code generated by a compiler to hand-compiled code, minus 1; i.e., the space (or maybe time) you lose because you didn’t do it yourself.
— “Jargon File”, v2.1.1, eds. Guy L. Steele and Eric S. Raymond, 1990
Cmd+s,加上一个编辑器 = 保存时格式化。你可以写 slop,从不使用 tab 键缩进等等,然后按下 Cmd+s,东西就会神奇地各就各位。这节省了大量的精力。而且在一个工作周中节省下来的精力,是非常可观的。
—— damassi,"功能请求:breakBeforeElse",prettier GitHub 仓库,2020年
SLOP(slop)名词。1. 一种单方面的容差因子(参见 fudge factor)。通常引入以避免发生栅栏柱错误(参见 fencepost error)的可能性。2.(编译器狂人使用)编译器生成的代码与手工编译代码的比率减去1;即,因为你没有亲手做而损失的空间(或者也可能是时间)。
—— "Jargon File",v2.1.1,编者 Guy L. Steele 和 Eric S. Raymond,1990年
At least in common parlance, slop had a meaning prior to its modern LLM-inspired one. And it was low quality output, written by either a machine or a human being. We see in that first quote damassi talking about how one is able to focus on just writing the code instead of focusing on syntax, producing slop that then gets cleaned up in the formatter. And the Jargon File is pointing at the output of the compiler: all that extra assembly code produced by a compiler, that’s the slop; if the hacker had written it himself, it would have been trimmed away.
至少在日常用语中,slop 在其现代 LLM 激生的含义之前就有自己的意思。那就是低质量的产出,无论是由机器还是由人写的。我们在第一段引文中看到 damassi 谈论如何能够只专注于写代码本身而非关注语法,产出 slop,然后由格式化工具来清理。而 Jargon File 指向的是编译器的输出:编译器生成的所有那些额外的汇编代码,那就是 slop;如果是黑客亲手写的,这些多余的东西就会被裁掉。
I’ll offer my definition of slop: a pejorative term for something, created by man or machine, lacking quality. A natural follow-up, what qualities matter? And I’ll offer that what constitutes slop is subjective, depending on the observer.
我来给出我的 slop 定义:一个贬义词,指由人或机器创造的、缺乏质量的东西。一个自然的追问是,哪些质量才是重要的?我要说的是,什么构成 slop 是主观的,取决于观察者。
I noticed a phenomenon when ChatGPT first came out. Everybody I talked to thought it was pretty good at everything besides their particular job, which it obviously lacked the expertise to be able to handle well. Oh, yeah, of course I use it to explore some medical thing for me, or to double-check a contract just in case, or write a poem about Shakespeare if he were a dog. But I would never trust the code it writes, that has to be triple checked before it even gets within a mile of production! My friends all had the same reaction, that yes it has its uses, and they used it every day by then, but the lawyers said I shouldn’t be letting it read contracts, the doctors said I shouldn’t be trusting its medical advice, and the poets all said it was obvious that the poem was written by someone that didn’t understand poetry.
当 ChatGPT 刚问世时,我注意到了一个现象。与我交谈的每个人都认为它在所有方面都表现不错,除了他们自己的工作,它显然缺乏处理这些工作的专业知识。哦,是的,我当然会用它来了解一些医学问题,或者以防万一双查一下合同,又或者写一首关于“如果莎士比亚是一只狗”的诗。但我绝不会信任它写的代码,在它进入生产环境一英里范围之内之前,必须经过三重检查!我的朋友们都有同样的反应:是的,它有其用途,那时他们每天都在用,但律师说我不该让它读合同,医生说我不能相信它的医疗建议,而诗人们都说这首诗显然出自一个不懂诗歌的人之手。
I don’t get that reaction as much anymore, the models have advanced sufficiently that people are more accepting that it maybe, might know what it is talking about when it comes to their field. If you know what to look for, then you can tell that something is low quality, but if you don’t know the signs, you won’t see it.
我现在不太常听到这种反应了,模型已经足够先进,人们更倾向于接受它也许,可能,在自己的领域里是懂行的。如果你知道该留意什么,就能辨别出哪些是低质量的,但如果你不知道这些迹象,你就看不出来。
Now! To address a counterargument right off the bat, aren’t there objective standards that can be used to solely determine whether something has a particular quality? And there are! However, I’ll caution you, that if you walk down that road, quality as a solely objective property of something that you can measure and quantify, then you risk straying into the realm of the coding machines again.
现在!为了立刻回应一个反论,难道没有客观标准可以仅仅用来判定某物是否具备某种特定质量吗?确实有!然而,我要提醒你,如果你走上这条路,将质量仅仅视为某种可测量和量化的客观属性,那么你就有可能再次误入编码机器的领域。
High quality code is well formatted! Great, the agent runs the formatter automatically. High quality code has low cyclomatic complexity! Great, the agent knows to refactor if the scanner flags it. High quality code has comments! Great, the agent writes comments, in fact it loves to write comments. High quality code has “good” comments! Remember, we are being objective and avoiding subjectivity, so tell me in an objective way what constitutes “good”.
We can play this game, and it’s fun, for me at least, because I’ll have a good time boxing you into a corner real quick if you try to define quality in an objective way such that a coding agent could not produce it, without trying to bail out to a subjective measure like “good” comments or the like. I’m not saying something with high quality can’t exist. I’m saying that the perception of that quality is at least in part subjective to each person and cannot be explained in purely objective ways, otherwise, you open the door to the coding agents and computers running those objective functions at each turn.
我们可以玩这个游戏,而且这很有趣,至少对我来说是这样,因为如果你试图以客观的方式定义质量,使得编码代理无法生成它,同时又不试图借助像“好”注释这样的主观标准,我会很快把你逼入绝境。我并不是说高质量的东西不可能存在。我是说对这种质量的感知至少在一定程度上对每个人来说都是主观的,无法纯粹用客观的方式来解释,否则,你就为编码代理和运行这些目标函数的计算机敞开了大门。
In short, slop is in the eye of the beholder. It’s a label someone can apply that is completely colored by their preferences and experience. Everybody wants to think they’re objectively calling something slop, but if we could objectify the identification of slop, then we could tell the agents how to detect and avoid it, and we are left with only the subjective parts of what was once considered slop, if there’s anything left at all besides begrudgingly good output.
简而言之,粗劣作品是观者眼中的产物。它是一个人可以贴上的标签,完全被其偏好和经验所影响。每个人都想认为自己是在客观地将某物称为粗劣作品,但如果我们能把对粗劣作品的识别客观化,那我们就能告诉代理如何检测和避免它,而留给我们的就只剩下那些曾经被认为是粗劣作品中的主观部分,如果除了勉勉强强的优质输出之外还有剩下的话。
Have you ever been in a meeting with two people who consider themselves craftsmen, typically with titles like senior architect or lead engineer, who have two very different and opposing ideas of what high quality code means? I’ve been in the industry long enough now that I’ve sat through a few of these and it’s always fun. And I’m not saying oh one wants to ship high quality code no matter how long it takes, and the other person just wants to get stuff done. No, I’m saying they both want to focus on producing high quality code and they fundamentally disagree about what that looks like. If you ever want to understand why there are various microservice fiefdoms in your company’s systems, look at the various lords and ladies and their respective domains and try to find the transcript for the Zoom meeting where they almost came to blows over whether protobuffers or JSON with schemas would produce the best outcome.
你是否曾参加过这样一个会议:两个自认为是工匠的人(通常头衔是高级架构师或首席工程师)对高质量代码的含义持有截然相反的看法?我在这个行业待得够久了,经历过几次这样的会议,每次都很有趣。我不是说一个人是不惜一切代价交付高质量代码,另一个人只想着把事情做完。不,我是说他们都想专注于产出高质量代码,但他们在本质上对高质量代码应该是什么样子存在分歧。如果你想知道为什么你们公司的系统里会有各种微服务“领地”,去看看那些领主和夫人及其各自的势力范围,试着找找那场 Zoom 会议的记录——在那次会议上,他们差点为了到底是 protobuffers 还是带 schema 的 JSON 能带来最佳结果而大打出手。
I won’t go so far as to say that there is no true craftsman when it comes to software development. But beyond the situation described above, I noticed something about the idea that software should be a craft process done by hand that has started to bother me more and more. I felt it as I watched software craftsmen online try and argue that computers could only ever make low quality slop code, and that coding agents will never work.
我不至于说在软件开发领域没有真正的工匠。但除了上述情况之外,我注意到关于“软件应该是一个完全手工完成的工艺过程”这一观点开始让我越来越困扰。当我看着网上的软件工匠们试图争辩说计算机只能生成低质量的粗劣代码,而且编码代理永远不会奏效时,我就有这种感觉。
I’ll state without evidence, that to be among the best software developers in the world, to pursue and hone your craft, you have to believe that you can write a computer program that can do anything a human can do. Maybe it would take a decade, and a dedicated team working under you, and more resources than it deserves, but you have to believe you could do it. I’ll water it down even, and just say much of the work done by software developers is making computers do tasks that were once done by human beings, and that often the software we write prevents human beings from being hired in the first place. Now, I’ll admit I’ve built up a strawman here, but wrestling is fake too, and it’s still fun to watch, so, now, watch this next move.
我会毫无根据地断言,要成为世界上最顶尖的软件开发者之一,要追求并精进你的手艺,你必须相信你能编写出一个能完成人类所能做的任何事情的计算机程序。也许这需要十年时间,需要一个在你的带领下工作的专门团队,需要投入超出其应有价值的资源,但你必须相信你能做到。我甚至可以退一步说,软件开发者所做的大部分工作就是让计算机去做曾经由人类完成的任务,而且我们编写的软件往往从一开始就阻止了人类被雇佣。现在,我承认我这里树立了一个稻草人,但职业摔角也是假的,看着依然很有趣,所以,现在,看这下一步。
I believe it is an act of supreme hubris for software craftsmen to believe that the only job that cannot and should not be automated is their own. You want me to take at face value the idea that you can write software that takes us to the moon, trades a billion stocks a second, coordinates globe-spanning corporate enterprises, and yet the second it crosses into your area of expertise, it’s obviously impossible and can only invite disaster. What makes programmers so special? Why are we the only ones who should be insulated from automation?
我认为,软件工匠们相信唯一不能也不应该被自动化的工作就是他们自己的工作,这是一种极度傲慢的表现。你想让我毫无保留地接受这样一种想法:你能编写带我们登月的软件、能每秒交易十亿股股票、能协调覆盖全球的企业,然而一旦触及你的专业领域,这就显然是不可能的,只会招致灾难。是什么让程序员如此特别?为什么我们应该是唯一免受自动化威胁的人?
This is where I broke hard with the software craftsmen and the idea that software should be a craft process entirely done by hand. I don’t have the arrogance anymore to believe that what I do is so special that it cannot be done by a machine. Why should we be allowed to point the threat of automation at everyone but ourselves?
正是在这一点上,我与软件工匠们以及“软件应该是一个完全手工完成的工艺过程”这一观念彻底决裂了。我已经不再傲慢地认为我所做的事情如此特别,以至于机器无法完成。为什么我们可以将自动化的威胁指向所有人,却唯独不包括我们自己?
[
为什么代码必须是唯一靠手工完成的东西?


A ThinkGeek t-shirt printed with the slogan “Go away or I will replace you with a very small shell script.”
一件印有“走开,否则我就用一个很小的 shell 脚本替换你”这一标语的 ThinkGeek T 恤。
“Go away or I will replace you with a very small shell script.” — a ThinkGeek t-shirt, circa 2008.
“走开,否则我就用一个很小的 shell 脚本替换你。” —— 一件 ThinkGeek T 恤,约 2008 年。
Why must code be the only thing done by hand?
为什么代码必须是唯一靠手工完成的东西?
Moving beyond the past and present, I do have some predictions about what will happen next with this whole AI thing. Let’s start with Bun, Zig, and Rust.
抛开过去和现在,我确实对这整个 AI 事情接下来会发生什么有一些预测。让我们从 Bun、Zig 和 Rust 开始。
-
I’ll bravely stand on the side of soon to be billionaire Jarred Sumner and say that people will keep happily using Bun. It’ll have some weird new bugs, probably because of the rewrite, but they’ll get fixed amid much discussion that goes nowhere.
-
New projects in Zig are functionally dead at the enterprise level. Any business minded person who is even mildly clued in will look at how Andrew Kelley acted and will think twice before greenlighting a major project or partnership with Zig again. Hobbyists will continue to use it right up until another language comes along that catches their eye in the right way, doesn’t have the baggage Zig does, and has even the slightest chance of crossing the gap into the enterprise.
-
TigerBeetle and Ghostty are going to be targeted for rewrites in Rust by people trying to gain attention for themselves and/or people who hate Andrew Kelley because of the mean things he said about Jarred Sumner. If they are particularly spiteful, they’ll try and do the Zig compiler itself. (I would be shocked if TigerBeetle and Ghostty did a Rust migration themselves though, feels like it would take another couple major missteps in Zigland before that would happen, they seem pretty bought in, in ways that Bun obviously never was).
-
An open source tool that makes it easy, fast and cheap to coordinate a billion agents to rewrite any project in Rust while still passing all the original tests will be released by the end of 2026. Nothing Jarred mentioned in his blog post made me think, barring API costs, that somebody couldn’t implement a tool that would make that easy for anybody to pull off. If they really want to show off, they’ll keep the code up to date in real time as pull requests get merged on the original project on an ongoing basis.
-
我将勇敢地站在即将成为亿万富翁的 Jarred Sumner 这一边,说人们会继续愉快地使用 Bun。它会有一些奇怪的新 bug,可能是因为重写造成的,但这些 bug 会在毫无结果的讨论中被修复。
-
在企业层面上,Zig 的新项目实际上已经死了。任何稍微有点头脑的商业人士,看到 Andrew Kelley 的所作所为,在再次批准一个重大项目或与 Zig 的合作之前都会三思而后行。爱好者们会继续使用它,直到另一种语言以正确的方式吸引了他们的眼球,没有 Zig 的包袱,并且有哪怕一点点机会跨越鸿沟进入企业界。
-
TigerBeetle 和 Ghostty 将成为那些试图为自己博取关注的人和/或因为 Andrew Kelley 说了 Jarred Sumner 坏话而讨厌他的人用 Rust 重写的目标。如果他们特别怀有恶意,他们甚至会尝试重写 Zig 编译器本身。(如果 TigerBeetle 和 Ghostty 自己进行 Rust 迁移,我会感到震惊,感觉在 Zigland 再犯几个重大错误之前才会发生,他们似乎很投入,这是 Bun 显然从未有过的)。
-
一个开源工具将能够轻松、快速且低成本地协调十亿个代理将任何项目用 Rust 重写,同时仍能通过所有原始测试,该工具将在 2026 年底发布。Jarred 在他的博客文章中提到的没有任何内容让我认为,排除 API 成本,有人不能实现一个让任何人都能轻松实现这一点的工具。如果他们真的想炫耀,他们会在原始项目合并拉取请求时,实时保持代码最新。
Now, let’s talk about the future of craftsmanship in software.
现在,让我们来谈谈软件工艺的未来。
-
The models will keep getting smarter, faster and cheaper.
-
The coding agents will keep getting better.
-
The AI financing bubble might pop, loudly and with much chaos even, but for our purposes, the coding agents are here to stay. They’re not going to go away, they’re part of the software development process, in some form or another, permanently now.
-
There will continue to be large pressure from the markets and executives on software developers to use coding agents as much as possible, with the explicit goal of deskilling and intensifying the work being done by those developers. Why shouldn’t Marketing be able to open pull requests? Why do engineers get to have all the fun with code changes?
-
Language and framework lock-in for small to medium sized projects is evaporating and will be dead by end of 2027.
-
A “good” Linux kernel entirely rewritten in Rust won’t exist until 2028 though.
-
The wary acceptance of using hobbyist hand tools in the workplace born during ZIRP in order to keep programmers around and happy will be wiped away. Professional projects written in hobby languages like Zig, Clojure, Elixir and Haskell that don’t have a really, really good reason to be written in those languages, those will be swept out and automatically rewritten into something that is more in distribution for the models, like Python, Ruby, TypeScript and Rust.
-
The code produced by coding agents, and software developers still working by hand, will be put further and further into straitjackets. I have my own ideas about what that looks like as well, and I think generally there will be concentrated effort across the industry to quantify what quality looks like and automate the production of it as much as possible.
-
I’m split about the proliferation of type systems. I think TypeScript is winning out over JavaScript, but I think that’s because people hated writing JavaScript mostly. I am not sure if agents and people will actually benefit from turning type systems on for Ruby, Python and the like yet. We’ll see if we can get past the ignition interlock stage of stronger safety system rollouts and have usage of them be as common as seat belts today.
- 模型将继续变得更聪明、更快速且更便宜。
- 编程智能体将继续变得更好。
- AI融资泡沫可能会破裂,甚至伴随着巨大的喧哗和混乱,但就我们的目的而言,编程智能体会一直存在。它们不会消失,无论以何种形式,它们现在已经永久地成为软件开发过程的一部分。
- 市场和高管们将继续对软件开发者施加巨大压力,要求他们尽可能多地使用编程智能体,其明确目标是降低这些开发者的技能要求并加剧他们的工作强度。为什么市场部不能发起拉取请求?为什么工程师要独揽修改代码的所有乐趣?
- 中小型项目的语言和框架锁定正在消散,并将到2027年底彻底消亡。
- 不过,直到2028年,完全用 Rust 重写的“优秀” Linux 内核才会出现。
- 在 ZIRP 时期产生的、为了让程序员留下来并保持快乐而在工作场所勉强接受使用业余手工工具的现象将被抹去。用 Zig、Clojure、Elixir 和 Haskell 等小众语言编写的专业项目,如果没有非常非常充分的理由使用这些语言,将被淘汰并自动重写为模型更常用的语言,如 Python、Ruby、TypeScript 和 Rust。
- 由编程智能体以及仍手工编写代码的软件开发者产出的代码,将被置于越来越严苛的约束之中。我对此也有自己的想法,我认为整个行业通常会集中精力量化什么是质量,并尽可能实现其生产的自动化。
- 我对类型系统的普及持矛盾态度。我认为 TypeScript 正在击败 JavaScript,但我认为那主要是因为人们大多讨厌编写 JavaScript。我不确定智能体和人类是否真的能从为 Ruby、Python 等语言开启类型系统中获益。我们将拭目以待,看我们是否能跨过更强大的安全系统推广的点火互锁阶段,并让它们的使用像如今的安全带一样普遍。
All in all, what I see happening is a further continuation of software becoming an industrial process, the same way it has been for decades now. People who want to solve tricky programming problems by hand can do so on their own time, at home outside working hours, as a hobby. But at work, the expectation will increasingly be to let the coding agents do as much as possible as often as possible.
总而言之,我看到正在发生的是软件进一步成为一种工业过程的延续,就像过去几十年那样。想在工作之余在家里用自己的时间手工解决棘手编程问题的人,可以将其作为一种爱好。但在工作中,期望会越来越多地让编程智能体尽可能多地、尽可能频繁地完成任务。
My last prediction, and the answer to my original question, is that the further industrialization of software development via coding agents will increase the “quality” of code far beyond what any one craftsperson could produce. The models will keep getting smarter, and the automated tools we use to ensure quality in code will continue to get cheaper and better. Most software should not be created via a craft process, by hand or by individuals, and it’ll be increasingly less economically viable to do so in a competitive, global marketplace.
我的最后一个预测,也是对我最初问题的回答,是软件开发通过编程智能体进一步工业化,将提高代码的“质量”,远远超过任何单个工匠所能产出的水平。模型将继续变得更聪明,而我们用来确保代码质量的自动化工具将继续变得更便宜、更好。大多数软件不应该通过手工或个人以工匠工艺的方式来创建,在竞争激烈的全球市场中,这样做的经济可行性将越来越低。
Software engineering, software development, programming, whatever you want to call it, has been constantly eating itself for as long as the field has existed. To expect that it would settle into a staid industry that never threw everyone for a total loop again is to deny the nature of this beast. Every 10 years or so, the industry gets turned upside down and there’s not anything anybody can do about it. Why should we expect the cycle to stop now? We keep thinking we have hit the End of History when it comes to working with computers, that a new tool or hardware or new something won’t ever happen again and upend everything all at once. Hell, we are still inventing new ways of working with wood after several millennia of working with it! We’re not even done with figuring out how to produce wood, how could we have already found the exact right way to produce code?
软件工程、软件开发、编程,不管你想怎么称呼它,自从这个领域存在以来就一直不断地吞噬自身。期望它会安顿为一个再也不会把所有人都彻底搞晕的沉闷行业,就是否认这头野兽的本性。大约每 10 年,这个行业就会发生天翻地覆的变化,任何人都无能为力。为什么我们应该期望这个周期现在停止?在涉及与计算机打交道时,我们一直以为自己已经到达了历史的终结,以为新工具或新硬件或什么新事物不会再发生并一举颠覆一切。见鬼,我们与木头打交道了几千年,却仍然在发明处理木头的新方法!我们甚至还没弄清楚如何生产木头,怎么可能已经找到了生产代码的确切正确方法?
To finish this overly long essay up, the other day I merged a PR I didn’t even try to read. It was a tiny one, just one file changed, a little configuration setting, I knew exactly what should have been in there, and I was in the middle of doing a million other things. Claude knew what she was doing, we had talked through the change, it was to unblock something important, I’m sure she did it right, it’s pretty hard to mess up. All the tests passed, the linter was happy, everything looked the way it was supposed to look in CI. So why should I have looked at the code? And I went back and checked just now and it was fine, really, nothing to worry about. It’s just one little change in one little file. What’s the worst that could happen? I still read the important stuff, I promise!
为了结束这篇过长的文章,前几天我合并了一个我甚至都没尝试去读的 PR。那是个很小的 PR,只改了一个文件,一个微小的配置设置,我确切地知道里面应该有什么,而且我当时正忙于处理无数其他事情。Claude 知道她在做什么,我们已经讨论过这个变更,这是为了解除某个重要工作的阻碍,我确信她做对了,这很难搞砸。所有测试都通过了,linter 也很满意,在 CI 中一切看起来都像它应该有的样子。所以我为什么要去看代码呢?而且我刚才回去检查了一下,它很好,真的,没什么好担心的。只是一个小文件里的一个小改动而已。最坏能发生什么?我发誓我仍然会读重要的东西!
We live in interesting times, and all I can do is suggest you find your joy in that, wherever it might lie. For me, I smell a new type of craft in the promise of ensuring and imbuing quality in the output of coding agents, and I am very curious to see how deep it goes.
我们生活在一个有趣的时代,我所能做的就是建议你从中寻找你的乐趣,无论它可能在哪里。对我来说,我在确保和赋予编程智能体产出质量的过程中嗅到了一种新型工艺的味道,我非常好奇它究竟能有多深。
At least my hands don’t hurt anymore, not the way they used to. That’s been nice.
至少我的手不再疼了,不像以前那样。这挺好的。