启蒙软件[译]

原文地址:https://mmapped.blog/posts/28-enlightenmentware.html

身为程序员,我们每天都会与各种软件工具打交道。大多数工具只能勉强完成任务,但偶尔我们会发现一些超越实用性的工具。这些工具激发我们的想象力,开启新的可能性,并影响我们设计系统的方式。我将这类软件称为“启蒙软件”。

对于程序员来说,最常见的启蒙源是他们在工作中或作为爱好使用的编程语言。我从折腾各种语言,如masm、C、Prolog和Idris中获得了许多启示。不过,我不会过多讨论语言,因为语言学习对思维扩展的影响已经是老生常谈(例如,参见Peter Norvig的《十年学会编程》)。本文,我将赞扬那些对我启发最大的软件。

UNIX

UNIX 是用户友好的,只是对朋友的选择很挑剔。大约在 2008 年,我在家乡下诺夫哥罗德上大学时,开始寻找我的第一份真正编程工作。几乎所有的职位都要求了解被称为 UNIX 和 SOCKET 的神秘事物。我的课程没有 UNIX 或操作系统课程,所以我决定自学。

Andrey Robachevsky 等人编写的《UNIX 操作系统》(在俄罗斯被称为“乌龟书”)向我介绍了类 UNIX 操作系统的世界。UNIX 成为了我可以理解、探索和编程交互的东西。所有拼图的碎片——文件系统接口、进程模型、环境和权限、分叉、套接字和信号——都拼合在一起,展现出一个连贯而美丽的画面。

Discovering Mandriva Linux 是一种进入平行宇宙的感觉,在那里你不必盗版软件或花四十分钟安装 IDE 来编译 C 语言程序。在这里,人们出于乐趣开发软件并自由分享。我当时无法理解为什么有人会使用 Windows(自大学早期以来,我对 Windows 的容忍度提高了很多;Windows NT 是一个很棒的操作系统,我甚至在我的游戏电脑上安装了它,尽管我从不玩游戏)。

UNIX 伴随着我生活的各个阶段,从跟上 Ubuntu 最新版本的步伐,到为 Thinkpad T61p 编译自定义内核和在 Gentoo 上构建 @world,再到回归 Ubuntu LTS 并延迟升级到第一个点版本,最后成为快乐的 macOS 用户。UNIX 也是我职业生涯中的重要组成部分,因为大多数我编写的软件都在 UNIX 环境中运行,我仍然偶尔会参考《UNIX 环境高级编程》

Git

Git 很容易让你误入歧途,但也容易让你回到正轨。我在 2009 年初接触了版本控制系统,当时公司使用 Rational ClearCase,这是一款令人困惑且令人望而生畏的工具。大约一年后,我加入了一家使用 Subversion 的公司。我提前投入学习,一口气读完了《使用 Subversion》。Subversion 易于理解和使用,我无法想象还能有什么改进。然而,我仍然觉得它只是一款工作工具,因为设置仓库的摩擦阻碍了将其用于小型个人项目。那时,Google 提供了 Google Code 的托管服务,但我当时不愿意将我的实验分享给全世界。

然后我发现了 Git。

Git 完全不同于 Subversion。它的学习曲线陡峭,起初让人困惑,但这种困惑与 ClearCase 的不同。ClearCase 像是一部俄罗斯小说,角色名字奇怪,情节复杂,结局不佳。Git 像是数学,它慢慢熔化你的大脑,塑造你的思维,让你进入更高维度。

Git 去除了使用版本控制的摩擦,再也没有借口不为有价值的东西创建版本。使用 Git 合并分支不会引发焦虑症。被称为“索引”的暂存区成为了我的工作流程中不可或缺的一部分。但我最喜欢的功能是 Git 设计的惊人身手,它巧妙地融合了分布式系统、无环图和内容寻址存储。

学习 Git 的内部工作原理如此有趣,以至于我对其他版本控制系统的基础知识产生了兴趣。我从 Darcs 到 Mercurial,再到 BitKeeper,最后到 SCCS,一路追溯。我还用 Rust 编写了一个玩具单文件版本控制系统。

Git 会被更好的东西取代吗?就像 Git 出现之前很难想象能超越 Subversion 一样,现在也很难想象能显著超越 Git 的东西。对我来说,Git 的主要缺点是其基于快照的方法,这使得合并变得难以理解。Git、Mercurial 和大多数其他工具使得区分原始代码和合并文件时的决策变得困难。Jane Street 的技术团队也有类似的看法。例如,他们博客文章《补丁审查与差异审查,再议》中提到的。基于补丁理论的系统,如 Pijul 和 Darcs,可能会解决这些问题。

Emacs

任何文本编辑器都能保存文件,只有 Emacs 能拯救你的灵魂。我用 Turbo Pascal 7.0 编写了我的第一个程序,它是一个友好的蓝色窗口。大学的入门编程课程使用 Pascal,所以我用 Turbo Pascal 完成作业。后来的课程引入了 C++ 和 Java,我们使用 Visual Studio 6.0 和 JBuilder。虽然我们学会了从命令行调用编译器,但 IDE 在我早期的代码编辑体验中占据了主导地位。

在第一份编程工作中,我通过 Citrix 连接到远程 Solaris 工作站工作。我们团队几乎都使用 NEdit 编辑代码。有一天,我注意到一个人的编辑器看起来与众不同,背景是黑色的,代码是亮色的。在我看来,这是他们技术知识超群的标志。我需要学习如何定制我的编辑器。

对自定义的追求让我接触了 Vim(工作站上预装了 Vim 6)。毕竟,如果目标是脱颖而出,为什么要停留在颜色方案上呢?我完成了 Vim 教程,立刻就上手了。感觉就像在演奏乐器:既具有挑战性又很有趣。修复错误变成了技能的练习。

虽然我现在正在使用 Visual Studio Code 写这些字,但我总是开着 Emacs。我还有一组 tmux 会话,其中运行着多个 nvim 实例。当我的小指厌倦了按住 Ctrl 键时,我会用它们。许多事情在 Emacs 中更容易,我不认为有任何软件能完全取代它。如果我需要实现扩展,它也是我的首选编辑器。编写 Emacs Lisp 是一种乐趣,尤其是与编写 Vimscript 相比。

Boost.Graph

我也必须承认,我对可重用代码的流行趋势有强烈的偏见。对我来说,可编辑的代码远胜于不可触碰的黑箱或工具包。

2013 年新年前夜,我在一艘穿越波涛汹涌的波罗的海的游轮上,因为晕船无法站立。我躺在床上看书,那是我旅行时带的《Boost 图形库》。大多数算法库要求你承诺特定的数据表示,这使得将它们集成到现有项目中变得非常昂贵。对于图算法尤其如此:顶点和边通常隐式定义并深深嵌入其他数据结构中,所以重新实现算法比使用通用库更容易。

Boost.Graph 库优雅地解决了这个问题,采用了 Alex Stepanov 的泛型编程思想。它使用一系列技巧(类型特征、属性映射、访问者)来实现图算法,只要提供一个适配器告诉库如何将你的数据结构视为图,这些算法就可以与任何图表示一起工作。

虽然我从未在实践中使用过这个库(考虑到我对 Donald Knuth 在本节开头的态度,即使有机会,我可能也不会使用这个库。我宁愿编写一页有趣的代码来遍历图,也不愿编写两页无聊的适配器来调用算法),但它的设计加深了我对 STL 设计和泛型编程的理解。它还帮助我理解了其他编程语言中高级类型级编程功能的动机,如 Haskell 的类型家族。

Bazel

如果 make 不按预期工作,那很可能 makefile 有问题。

大约在 2009 年,我在为学位的计算数学研究项目编写我的第一个 Makefile。那时我在工作中已经使用过 make,但我不需要理解它的工作原理。这次,我需要编译一个混合了不同语言标准的 Fortran 程序:从古老的 Fortran 77 到时尚的 Fortran 2003。为了更深入地了解这个工具,我参考了 Robert Mecklenburg 的《使用 GNU Make 管理项目》。

大多数技术书籍都会让我兴奋:我变得对主题充满热情,并想在实践中尝试。但这本关于 make 的书却产生了相反的效果。构建正确且易用的构建所需的复杂性让我渴望更好的工具。另一本让我有同样感觉的书是 Andrei Alexandrescu 的《现代 C++ 设计》。这本书写得深入且精彩,但第二章中可怕而丑陋的巧妙技巧让我对所选择的编程语言产生了疑问。另一本是 John Calcote 的《Autotools》。

深入研究 make 之后,我经常在工作中折腾构建系统:我将我的第一个 C++ 项目中的复杂且错误百出的 Makefile 文件替换为 CMake,将一个基于 Ant 的 500kloc Java 项目中的不灵活构建系统替换为任何人都可以贡献的 Gradle 脚本。但我尝试过的所有工具,包括 CMake、Ant、Maven、Gradle、SCons 和 autotools,都让我深感不满。它们笨拙、别扭且难以扩展和组合。

2016 年,我加入了位于苏黎世的 Google。我听说了 Google 的内部构建工具 blaze,并迫不及待地想尝试。令人惊讶的是,我没有机会折腾 blaze,也不需要理解它的工作原理。我可以复制一些构建目标并编辑依赖列表,构建就能按预期工作。blaze 使正确且快速的构建变得不仅容易,而且无聊(以好的方式)。直到几年后,当我尝试为一个玩具个人项目使用 Bazel(blaze 的开源版本)时,我才需要理解其底层模型。

Bazel 是拼图的最后一块,与 Haskell 的类型类、Flume 管道接口和 TensorFlow 1.0 执行模型一起,让我理解了普遍的计划-执行模式。Andrey Mokhov、Neil Mitchell 和 Simon Peyton Jones 的《按需构建系统》文章解释了各种构建系统设计如何映射到 Haskell 类型类。Thomas Leonard 的博客文章《CI/CD 管道:Monad、Arrow 还是 Dart?》也是关于这个主题的精彩读物。

我对这个工具的了解达到了真正的亲密程度,当时我帮助 dfinity 的构建系统过渡到 Bazel。尽管在这个过程中遇到了许多挑战,但 Bazel 仍然是我最喜欢的构建系统。它快速、正确、易于使用,并且与语言无关。

引用 Bjarne Stroustup 的话,我认为一个更小、更简单、更干净的构建系统正在 Bazel 中挣扎着要出来。我希望有一天这个核心会向世界展示,并成为构建所有软件的标准工具。

总结

在阐述了我的论点后,我忍不住要寻找一个共同的主题。什么是好的启蒙软件?对我来说,关键点是:

  1. 这些工具都解决了深层次的问题,而且是那种我每天都会遇到的问题,比如让计算机上的程序协同工作、管理并发工作流或泛化代码。
  2. 它们是圆润的:它们在最小的表面积内包含最多的体积。UNIX 的表面积很小,但它解锁了巨大的力量。Emacs 和 Git 无处不在,但它们的核心很小,甜美且易于欣赏。
  3. 它们邀请并鼓励你探索其内部。这不仅仅是关于自由和开源;掌握它们也是值得的投资。

▶ 可以在首页置顶文章找到我的联系方式。
▶ 本网站的部分内容可能来源于网络,仅供大家学习与参考,如有侵权请联系我核实删除。
我是小章,目前全职提供电脑维修和IT咨询服务。如果您有任何电脑相关的问题,都可以问我噢。


启蒙软件[译]
https://itxiaozhang.com/enlightenment-software-inspiring-tools/
作者
小章
发布于
2024年5月23日
许可协议