在我的青少年时期,我涉猎了编程基础和一些汇编。当我学习了 Turbo Pascal 之后这事更进了一步,它提供了一种最早期的集成开发环境(IDE)。我觉得这下合我心意了。实际上,IDE 是一种让你在一个友好的环境内,方便地编写、编译、调试和运行代码的程序。Turbo Pascal 没有太多的图形界面(它基于文本),但它有菜单和窗口。你可以进入调试模式,跟踪变量的值等等。
然后我转到了 Delphi (一种图形化的 Turbo Pascal),它拥有到今天看来仍然不错的出色 IDE。我用 Visual Basic 设计了一个“会报时的钟”,当时发表在 Bulletin Board Systems(使用 Windows 3.1 的一个系统)。那之后我发现了 Visual Studio。有好几年我的 C++ 编程都是借用的 Visual Studio。以上就是我一直使用的所有 IDE。
早在八十年代初,Smalltalk 就有了著名的强大图形化 IDE(Youtube 视频)。
我认为,使用 IDE 并不代表着“现代化”。现在的 IDE 和过去的 IDE 非常相像。虽然我们编程的内容改变了,但在很多情况下,我们如何编程却没有改变。在我的 Dell 笔记本电脑里装着最新版 Visual Studio。换做 20 年前的我,也能完美地轻松上手它。调试、代码补全、远程代码执行,它和以前很像。事实上,Visual Studio 从未与 Turbo Pascal 相差很大过。而我发现这非常令人沮丧。我以为我们应该取得比这更快的进步。
我提出了现代化编程在桌面外观上难有作为的观点。图形化用户界面(GUI)只是表层。现代化编程技术都是关于流程和实际工具的,而不是它们之上的表层。我不在乎你是否使用 Eclipse 或 Emacs,这和你如何现代化毫不相关。
那么,什么是“现代化”?
编码是社会化的
在 20 年前,要求你公司里的每个人都使用相同的 IDE,并且要唯一依赖于这种 IDE 来构建、测试和部署代码,这是很明智的。但在你公司外有很多聪明的人,他们往往不使用你这种 IDE。如今,你可以触及他们了。这意味着对于所采用的工具和流程你必须明智。
如果你嘲弄使用 Atom 文本编辑器、Visual Studio 或者 Emacs 编程的人,那你就不是社会化的。你需要尽可能的包容,否则就会付出代价。
Go 语言有自己的格式化工具
我不在乎在你保存的时候,是不是自动重新格式化代码,或者有没有点击重新格式化按钮,或者是不是输入 go fmt,这些都一样。但它无疑是一个卓越的现代化的想法。这就是进步。所有的编程语言都应该为用户强加一个唯一的代码格式。别再 bikeshedding(过于关心旁枝末节,而忽视主要问题)。
我们很清楚 Java 拥有规范,但规范是不够的。我们需要一个工具,能把代码作为输入,并生成一个唯一定义了的输出,它能处理从行长度到空格的所有问题。
这个工具的目标是对于应该如何格式化代码,不再有任何可能有的争议,而且产生正确的格式不费吹灰之力。我简直无法告诉你这是多么的重要。
像 Rust、Go、Swift 这样的编程语言有自己的程序包管理系统
因此,例如在 Swift 中,我可以创建一个名为 Package.swift 的小文本文件,并把它放入我项目的根文件,在那里声明我的依赖。
import PackageDescription
let package = Package(
name: "SwiftBitsetBenchmark",
dependencies: [
.Package(url: "https://github.com/lemire/SwiftBitset.git",
majorVersion: 0),
.Package(url: "https://github.com/lemire/Swimsuit.git",
majorVersion: 0)
]
)
然后我可以输入 swift build,软件会自动抓取依赖代码,并构建我的程序。这在 Swift 运行的所有地方通用。你使用哪种文本编辑器和 IDE 都没关系。
你不想使用文本编辑器,而更喜欢图形界面?可以。都没有区别。
为什么那样显得现代化?因为自动地解决依赖关系而不费吹灰之力,对于 20 年前的我来说就像魔术。并且自动地、系统地解决依赖关系是极其重要的。我不想永远都不得不手动安装和部署一个依赖项。我希望其他人能够在几秒内把我的库添加到他们项目中,而不是几分钟或是几小时。
是的,你可以将它添加到现有的语言(如:Java 的 Maven 或是 IED)但需要有一个唯一的方法让它起效。
像 Rust、Go、Swift 这样的编程语言,在一开始就支持单元测试。
比如在 Go 里,创建一个 filemyproject_test.go,然后添加 func TestMyStuff(t * testing.T)这样的函数,然后输入 go test 既可。
在 20 年前,几乎没有人测试他们的代码,而今天已经是一个必要要求,您和它需要以一种唯一的方式来做,这样你就可以在项目之间移动,还总是知道如何测试了。
如果不能在你的代码中立刻认出健全的单元测试,我会设想你的代码严重损坏了。
持续集成
代码更改时,你想要一个远程工具来获取新代码,并测试它,以便可以提前停止回归。人们可以在你的代码上运行测试还不够,他们还需要看到自动化测试的结果,自行检查最终的故障。
持续集成是较大规模计划的一部分:你必须在你编程的时候疯狂地自动化程序。体力劳动应该最小化。有时候这意味着你真的应该只是点击一个按钮,无论是通过一个图形化用户界面,还是命令窗口,但它不意味着需要反复地遵循一系列复杂的命令。
版本控制
20 年前,你在桌面上编写代码,并通过电子邮件发送新代码(作为补丁)是讲得通的。但这只在缓慢的合作节奏中有意义。如今,这么做是愚蠢的。任何差于 Git 的都是落后的。注意,如今甚至微软构建 Windows 也使用 Git。
那么,当你共事于从来没有听过现代编程的聪明学生会发生什么呢?他们看一个类似 go get 的命令,只看得到表层(一个命令行)。他们认为这是落后的。漂亮的图形在哪?
他们使用一个好看的 IDE 工作,像是 Visual Studio 或 Eclipse,并确信自己是现代化的,完全无视 IDE 可以追溯到几十年前的事实。然后并没有使用 IDE 的优势,比如更好的功能可见性和更快的操作,而是在其他地方使用现代化编程技术。他们坚持守旧派编程:
- 没有测试。至少,没有自动化和系统化的测试。
- 在一个具体的设置上难以处理依赖关系。
- 没有自动化。没有持续集成,没有自动化部署。
他们编程就像我几十年前使用 Turbo Pascal 入门的时候。尽管 Turbo Pascal 有图形化用户界面(GUI),但它是非常古老的学校。