我曾在《The Old New Thing》上露过脸
原文由 Michael Lynch 于 发布,订阅该博客
我这个人相当谦虚,所以大多数人都不知道我身上有一项极其了不起的事迹:Raymond Chen 曾在经典的 Windows 开发博客The Old New Thing上提到过我。
没错,他既没有提我的名字,也没有留下任何能认出我的线索,但就凭我如此低调地对待这项惊人的成就,我也值得被夸一夸。

2009 年,Raymond Chen 在一期The Old New Thing中提到过我。
我当时想解决的问题
Raymond 在文章里称我是“一位客户”,但其实当时我是他在微软的同事。那年我 23 岁,进微软做开发快两年了,这是我大学毕业后的第一份工作。
我当时在做 BitLocker,也就是 Windows 里给磁盘加密的功能。我们刚开始 Windows 8 的开发,我的任务是改进 BitLocker 的配置体验。
BitLocker 有很多可调节的选项,管理员可以通过组织层面的设置(在 Windows 里叫组策略)来配置。比如,IT 管理员可以在全公司强制执行一条规则,像是“所有人的 BitLocker 密码至少要有 12 个字符”,然后 BitLocker 就会要求用户创建的密码必须满足这一长度。

通过 Windows 组策略编辑器查看 BitLocker 的配置选项
BitLocker 配置上一个让人头疼的地方是错误提示含糊不清。比如你想把密码长度设为至少 1000 个字符,BitLocker 只会报错说“不行,太长了”,却不会告诉你上限到底是多少。
在微软,C++ 代码里不能直接写错误提示,因为所有面向用户的文本都得交给本地化团队翻译成其他语言。所以,所有面向用户的文本都放在 .mc 文件里,长这样:
SymbolicName=ERROR_BITLOCKER_PASSPHRASE_MINIMUM_TOO_LONG
The BitLocker minimum passphrase length is too high.
.
SymbolicName=...
而在 C++ 代码的某处,则会有一段这样的检查:
#define MAX_PASSPHRASE_MINIMUM 20
UINT32 minimumPassphraseLength = ReadGroupPolicy(GP_BITLOCKER_MINIMUM_PASSPHRASE_LENGTH);
if (minimumPassphraseLength > MAX_PASSPHRASE_MINIMUM) {
ShowError(ERROR_BITLOCKER_PASSPHRASE_MINIMUM_TOO_LONG);
}
我想改一下 BitLocker 的错误提示,让它能具体说明出错的原因。也就是说,不再显示这样的信息:
BitLocker 密码的最小长度过长。
而是想让用户看到这样的提示:
BitLocker 密码的最小长度不能超过 20。
我不想直接把 C++ 代码里的 20 这个数值复制到 .mc 文件里,因为以后如果我们改了 MAX_PASSPHRASE_MINIMUM 的值,两边就会不同步,导致错误提示不准确。
Raymond Chen 是怎么牵扯进来的
我对用来处理 .mc 文件的 Message Compiler 工具了解不多。我找不到任何在 .mc 文件中引用 C++ 值的例子,但总觉得应该有办法能做到。
于是我在公司内部的邮件列表里提问,能不能把 .mc 文件写成这样:
SymbolicName=ERROR_BITLOCKER_PASSPHRASE_MINIMUM_TOO_LONG
The BitLocker minimum passphrase length cannot exceed ${MAX_PASSPHRASE_MINIMUM}.
Raymond Chen 经常在这些邮件列表里发言。早在 2009 年,他就已经在微软待了很久,对 Windows 开发相关的方方面面都了如指掌。他的回复既有帮助又很权威,但如果你提问前没做足功课,他也会毫不客气地挖苦几句。
如果我没记错,Raymond 在我的帖子下简短地回复了一句:“又没规定说你不能用预处理器。”还附上了一个用预处理命令生成 .mc 文件的例子。
我花了好一阵子才明白他到底是什么意思。我当时根本不知道还可以让 C++ 编译器只执行预处理这一步。
浪费了 Raymond Chen 的时间
这个故事令人惭愧的地方在于,尽管得到了大神 Raymond Chen 的指点,我最后还是退缩了,没敢照做。
在 Raymond Chen 的博客文章里,他演示了只要在 Makefile 里改几行,就能把源文件从 .mc 文件换成 .mcp 文件。轻轻松松!
可 Windows 的构建系统比 Makefile 复杂了无数倍。我已经记不清它具体长什么样了,只记得当时觉得它又吓人又让人摸不着头脑。
更糟的是,如果你把构建搞砸了,可能要到第二天早上收到邮件才知道——邮件会宣布你弄坏了夜间构建,导致几十甚至上百人那天都拿不到 Windows 的构建版本,而这全是你的错。
所以,我面临一个选择:要么做第一个在构建系统里尝试新花样的人,冒着花上一两周去修复各种意外问题的风险;要么就当作自己从没想过要在 BitLocker 错误提示里加入具体数字,转而去做其他让配置更简单的工作。
我选择了后者。
即便到了今天,我依然不知道该怎么解决这个问题
当时我还想:“哇,我居然不知道 C 预处理器还能这么用,真够笨的。”
大多数时候,回头看多年前让我绞尽脑汁的软件问题,现在都会觉得解法显而易见。通常,我甚至能想出更好的方案。
但 16 年过去了,Raymond 那个对非 C/C++ 文件跑 C 预处理器的解法,至今仍让我觉得出乎意料。就算拥有现在所有的职业经验,唯独抹掉这段关于 Raymond Chen 的记忆,再让我去解一次这个问题,我恐怕还是会和 2009 年时一样束手无策。
不同的是,如今我不再因为不知道怎么解决这个问题而觉得自己笨了。我现在觉得,这是微软内部工具链的一个缺陷。在微软这样旗舰产品上,竟然没有一种标准方式能让开发者在错误提示和 C++ 代码中引用同一个常量值?
作为一名软件工程师,有些问题虽然让人不舒服,但你还是会咬牙坚持、不断练习直到有所长进。而另一些问题,你则会通过谨慎选择工作和项目来刻意避开。
搞懂那些晦涩难懂的构建系统,就属于我选择避开的那类问题,对此我心安理得。除了用 Nix 的时候例外。
随机一篇博客
评论
登录后参与讨论