3.3 对设计的影响
这样的工作组织方式、复杂的决策流程以及大量的参与者会如何影响 C++ 的发展?看看委员会的规模、组成及其流程,我认为,任何建设性成果居然能从中产生,都足以令人惊喜。这已经不只是委员会的设计
了,而是多委员会的联合设计
。
此外,委员会的管理结构非常薄弱,甚至缺乏最基本的管理工具:
- 成员资格、发言或投票没有任何资质要求(例如,学历或实际经验)。支付 ISO 会员费(2018 年美国会员为 1280 美元)并参加两次会议,就能拥有正式投票权。在研究组和工作组中,任何人都可以发言与投票,即使这是他们的第一次参加会议。
- 除了让提案得到采纳,以及看到改进后的标准而感到满足,并没有任何其他回报。不过,满足感确实是一个主要动力。
- 没有真正的办法来阻止破坏性行为。非官方委员会管理人员所能做的只是有礼貌地提醒人们不要做别人认为具有破坏性的事情。然而委员们对于什么是有破坏性的,意见也不一致。
当考虑在一个大型委员会里演化一门语言的各种问题之前,请记住委员会里大部分时间和工作都是为了解决小问题
;就是那些不 会上升到语言设计哲学、学术出版物、或会议演示层面的问题。它们对于防止语言及其标准库被分割成方言,并保证在编译器和平台之间的可移植性至关重要。这些 问题包括:命名、名称查找、重载决策、语法细节、构件的确切含义、临时变量的生存周期、链接,还有其他很多很多。许多问题需要技巧才能解决,而拙劣的解决 方案可能带来让人吃惊而具有破坏性的后果。解决方案往往经过精心设计,以最大程度减少对现有代码的破坏。委员会每年解决数百个问题。我估计委员至少要为此 花费他们时间和精力的三分之一,乃至于三分之二。这项工作往往被忽视和低估。如果你用过计算机或计算机化的设备(例如电话或汽车),你得感谢 CWG 和 LWG 的工作。
当关注由一个庞大的委员会引起的问题时,也请记住,这些问题本质是一种有钱人的烦恼:C++ 的标准化流程由数百位各种不同背景的热心人士所驱动,他们的经验各不相同,但都满怀理想主义。
委员会应起到过滤作用,也就是说,把坏提案挡在标准之外,同时,还要提升最后通过的提案的品质。委员会的存在,是要鼓励大家提出建议,并主动提供帮助。然而,并没有正式的提案征求流程。
不存在全职的 C++ 设计者,尽管有许多全职人员从事 C++ 编译器、库和工具方面的工作。直到最近,委员会中还很少有人从事应用程序开发,这是一个问题,因为它使委员会偏向于语言律师
、高阶特性和实现问题,而不是直接解决大量 C++ 开发者的需求——很多成员只是间接地了解这些需求。最近新成员急剧增加,也许会部分缓解这个问题。
委员会中的教育工作者相对较少。这可能是个问题,因为委员会(理所当然地)高度重视易于学习
,但是委员们对其含义有着非常不同的理念(经常会意见强烈)。这往往使关于简单性
和易用性
的讨论变得混乱。
当思考组织问题对 C++ 发展的影响时,请记住,ISO 流程本不是为 200 人的会议而设计的——典型的 ISO 编程语言委员会只有一二十人。平均而言,我们在某种程度上是通过识别和解决问题来进行管理。考虑下面这些观察到的问题:
延迟:多阶段的流程为延迟、阻止提案和提案变化提供了很多机会。常常出现几十名委员坚持要满足他们的要求的情况,往往是通过阐释、扩展和寻找特例的方式。一个人眼中的过度延迟在另一个人看来却是尽职尽力。
例如:概念(当前方案为 6 年(§6))、契约(从开始到失败花了 6 年(§9.6.1))、网络(15 年,仍在进行中(§8.8.1))和 constexpr(5 年(§4.2.7))。甚至
nullptr
被接受也花费了三年时间(§4.2.6)。孤立特性:大多数委员会成员喜欢特性的添加。另一方面,他们(非常合理地)深刻地担心破坏现有代码的可能性。这给了孤立特性系统性的优势,孤立特性是不影响语言和标准库其余部分的小提案。这样的小提案很少会对语言的使用产生重大影响,但却会增加学习和实现的复杂性。而且,到头来,它们往往还是会和其他特性发生令人惊讶的交互。
例如:大多数在本语言演化总结中不值得提及的特性。结构化绑定(§8.2)和运算符
<=>
(§8.8.4)都需要多次会议去完善。后来者居上:有时经过多年的工作之后,提案已接近投票表决,一些一向未曾关注提案的委员此时进入讨论并提供了替 代提案。这样的提案可能与原始提案有戏剧性的差异,或者只是一系列小的请求。这往往导致延迟、混乱、甚至有时是争执。这种时候,已经议定的问题又重被激 活,而未经尝试(通常也未实现)的新想法和多年工作的成果获得了接近相等的权重。对老提案而言,瑕疵已经被发现过了,相应的技术折中也已经完成。人们很容 易想象新事物的好处而忘记意外后果定律:意外后果总是会出现的。新的和相对未经审查的总是看起来比老的更好。这使得较早提案的拥护者变得具有防御性,从而分散了进一步完善
老提案
的精力。在这里老
可能只是几年,或者就像概念(§6)那样十几年。有时,接受未经尝试的后期变更(所谓改进)是为了安抚反对派;这经常导致意外的后果。后期加入讨论的人们,通常不会认为有冲刺的必要
,而是自然地希望他们自己的想法得到认真考虑(而通常并没有认真考虑老提案的细节和理由)。这就可能会与已经在老提案上投入多年工作的人们产生摩擦。例子:结构化绑定(语法更改,对位域的新增支持,笨拙的
get()
(§8.2))、概念(§6)。数字分隔符(§5.1)、点运算符(§8.8.2)、模块(§9.3.1)、协程(§9.3.2)、契约(§9.6.1)。热情总青睐新事物:唤起对新事物的热情比反对它们容易。每个提案都是为某人解决某事,支持者愿意花大量时间展现其价值。而要反对它们,有人就不得不说像这样的话:
不,这个问题不是那么重要。
不,这种解决方案有缺陷。
不,你还没有充分记录解决方案。
不,你还没有仔细检查替代方案。
不管措辞怎么客气,这都让反对者看起来更像
坏人
,是他们阻碍了进步并否认支持者需求的合理性。更糟糕的是,拥护者总是比 反对者花费更多的时间来准备论文和演讲。大多数人喜欢对自己相信的事物进行建设性的工作,而不是小心地拆除他人的工作。因此,支持者通常都很热情并且准备 充分,而反对者总是显得意见含糊而不懂细节。然而,每项新特性都有其成本:如设计、规范、实现、修订、部署和教学(§9.5)。我害怕在演化工作组度过周四下午。那时,EWG 成员经过几天的大提案工作而感到疲倦,许多老成员(例如我)已经被拖入其他小组,参会者又急于看到有成果。这种时候,小提案就会只经受相对较少的审查而滑入标准。例如:条件中的显式测试(§8.7)、
inline
变量(§8)、结构化绑定的后期更改(§8.2)。过度自信:相对于整个语言及标准库的复杂度,尤其是不同应用领域的 C++ 用户所面临的问题的复杂度,个人在日常工作中能获得的经验总是不足的。并非所有委员会成员都能意识到这一局限,或是能通过质疑自身经验的推广价值加以弥 补。这就导致某些一般性有限的提案被过度推广。更糟糕的是,一些委员强烈反对某些提案,是因为他们不认为有必要解决该提案所针对的问题。语言设计需要一定 的智力上的谦逊 [Stroustrup 2019b]。先想出来的解决方案很少是最好的,而未经进一步认真思考就提出轻率的反对意见和建议很少会带来改进。
例子:出于对犯错者的保护,就不举例了。
实现时机不当:在标准流程中,实现提案晚了有风险:特性出现严重缺陷、有潜在无法实现的部分、以及缺乏使用反 馈;实现早了也有风险:特性以不完整的、次优的且难以使用的形式冻结。委员会中的许多人不会投票赞成尚未实现或以他们不信任的方式实现的提案。另一方面, 许多实现者不愿意为委员会未批准的提案投入实现资源。这是一个困难而现实的两难困境。委员会经常听到
它已经实现了吗?
的问题。通常,它是经过设计的吗?
和要如何使用?
是更重要的问题。人们很容易在细节中迷失。我提出的走出这一困境的方法是,就建议的方向、提案的总体范围达成一致,然后从一个相对较小子集的详细设计和实 现出发,以关键用例为指导前进。这样,我们可以相对较早地获得用户体验,并了解该特性如何与其他特性交互。这需要对这种语言应该是什么有一个长远的看法 [Stroustrup 1993, 1994, 2007](§1),(§11.2),否则语言就会沦为机会主义的零敲碎打。如果这个方法起作用,语言将从反馈和有机增长中受益。例子:模块(§9.3.1)、C++ 0x 概念(§6)和
<=>
(§8.8.4)。特性交互:最难处理的问题之一是特性的组合使用。一定程度上这是规范和实现的技术问题。因此,这会占用大量委员 会时间。从设计的角度来看,更难的问题是要预计新特性在整个语言的语境中如何使用,这些语境包括其他正在考虑中的语言和库的新特性。每个特性都应设计成便 于同其他特性结合使用。我担心这一点没有得到重视。很少有提案书提供详细的讨论,而委员会里关于特性交互的讨论往往简短或混乱。其结果之一是,个别特性趋 于膨胀而只好把它孤立于语言的其余部分才能用起来。
例子:
tuple
(§4.3.4)和<=>
(§9.3.4)。为 lambda 表达式(§4.3.1)中的动作指定专用语法的(失败)提案。篇幅和分心:千头万绪往往同时发生,没有人能全跟得上。那些尝试全部关注的人,就容易失去对真正重要课题的关 注,而把注意力分散在一些事实证明并不那么重要的课题上。如今每年有超过 500 篇委员会论文,有些长达数十甚至数百页。与 2010 年代初相比,文献总篇幅翻了一番。我注意到,2018 年秋天的会前邮件(新论文汇总)的字数是莎士比亚全集的三倍。
电子邮件的泛滥最让人分心,因为许多委员喜欢通过一波一波地爆发短邮件来进行技术讨论。在这样的讨论中掉队意味着失去对问题的跟踪,其结果可能是,共识只是从几个一直能跟得上讨论的人中间浮现。
这种讨论不利于冷静而系统地权衡各种选择。有时候,它会导致不幸的特性滑入标准。有时候,它会导致不一致的设计理念体现于语言和标准库的不同部分,进而损害了互操作性。
例子:
any
、optional
和variant
的不同接口(§8.3)。概念(§6)。精确规范:标准是规范,而不是实现。但是,标准是用英语编写的,因此我们做不到数学般的精度。委员会的许多成员 擅长数学,但不擅长数学的人更多,因此在规范中没办法使用数学式的写法。试图使英文文本精确而详尽,则会让文本变得生硬又难以理解。我常常很难理解标准中 对我自己提案的描述。
大多数委员是程序员,而不是设计师,因此规范有时看起来会像程序——用没有类型系统或编译器的低级语言写成的程序。有详尽的如果、那么、否则的说 明,却很少写出不变量。更糟糕的是,很多词汇继承自 C,而且是基于程序源代码文本中的标记,因此,更高级别的概念仅被间接提出。
奇怪的是,标准库规范在结构上明显比语言规范更为正式。
经院主义:当然有必要大力强调标准文本的正确性和准确性。但是,人们有时会忘记标准本身可能就是错误的,而仅根据标准文本的论证来讨论正确性。这样一来,根据标准文本所应反映的模型和使用上的论证,反倒可能被忽略。
方向:哪些问题是真实的?重要吗?对于谁?哪些紧急?十年后,哪些解决方案仍然有意义?有些事情也许算个问题, 但这并不意味着它必须在语言里有直接的解决方案。尤其是,委员会很难记住这一点:一种语言不可能对所有人来说都是万能的。更难以接受的是,它居然不能解决 每个委员最紧急的问题 [Stroustrup 2018d]。
例子:C++17(§8)和 C++ 20(§9)。
专一关注:一些委员仅关注一个或两个课题,例如语言技术、易用性、
可教学性
、效率、 使用单一编程风格、在单个行业中使用、在单个公司中使用、单个语言特性等。对于专一关注的委员而言,这可能是一种非常有效的技巧,但这样做会让广泛的、平 衡的进展变得困难。过分相信理论或个人经验则是这个问题的另一类例子。一个好的建议在许多领域都会推动进步,但通常不能在所有这些方面都达到完美。原则的不适当应用:将一般原则应用于具体事例通常很困难。有时,我们会不与其他原则进行必要折中,就去严格应用某项原则。折中的必要性是《设计和演化》一书 [Stroustrup 1994] 将设计原则称为
经验法则
的原因之一。有时,似乎没有经验基础就凭空冒出来一个原则。有时,一个提案严格遵循了某一个原则,而另一个提案则忽略它。有原则的设计很困难;它需要品味、经验以及原则。实用的语言设计不只是从第一原理出发进行演绎的练习。通常,多种原则之间必须进行权衡。倾向专家的偏见:想象别人的问题总是困难的。委员会成员几乎都是某方面的专家。在日常工作中,他们通常是处理最细微、最复杂问题的人。这样的问题在
外面
的数十亿行常规 C++ 代码中一般不常见,而且也不是大多数 C++ 程序员所苦恼的问题。但是,对委员会来说,专家级的问题通常就是紧急问题,也是最容易通过流程的问题。例子:支持
enable_if
和类型特征(§4.5.1)在标准库中的使用简直水到渠成,但接受概念(§6)却大费周章。聪明的问题:委员会成员一般是聪明人,他们中许多人无法抵御机灵的解决方案。此外,他们也很难断定,并非每个问 题都值得解决,而拥有解决方案也并不意味着我们必须将其纳入标准。这会带来过于精巧的特性,带来大多数程序员用不着的特性。公平起见,也需要指出,许多程 序员也很聪明,有时也会以使用过分机灵的语言和标准库特性为乐。
例子:在有些提案中,即使简单用法也需要用上严肃的模板元编程。
不愿妥协:大多数委员会成员都有强烈的意见,但要在一个大型团体中达成共识需要妥协。分辨哪些妥协无关紧要,而 哪些妥协事关基本原则,有时会很困难。后一类妥协可能对语言造成破坏,应该避免。不幸的是,当委员们坚信自己所担忧的才至关重要时,他们比起心态开放的委 员就有了有关键的战术优势。有些人能做到从整体上关注语言而不纠结于个别话题,但他们往往得向不能如此的人们屈服。而反过来,那些从不认真质疑自己的原则 或需求的人,倒往往可以向别人视为必要的技术妥协发动猛攻。取得进展需要关注整个社区,有自知之明,并懂得适当的谦逊 [Stroustrup 2019b]。
缺乏优先级:从技术的角度来看,所有问题都是平等的:不精确的规范就是不精确的规范,这一点与它未能正确规定的 内容是什么不相干。任何可能从类型系统的漏洞中混进代码的错误原则上都可能造成死亡和毁灭。但是,现实世界中不同错误的影响可能大不相同。实际上,大多数 晦涩的细节基本上没有破环性。有些人在研究设计细节时很难记住这一点。
例子:在数字分隔符(§5.1)上花费的时间比在范围
for
(§4.2.2)上花费的时间更多。完美主义:一个标准预期会被几百万人用到,并且可以稳定数十年。人们自然希望它是完美的。这会导致特性膨胀(特 性过多),尤其是导致单个特性的膨胀。程序员善于想象出问题,特性在委员会走流程的时候,委员们会坚持要它解决掉所有想象中的问题。这会导致严重的使命偏 离,并导致只有专家才会喜爱的特性。这也可能导致特性一直无法加入标准。
例子:
.
运算符(§8.8.2)、网络库(§8.8.1)和异常规约(§4.5.3)。少数人的阻挠:共识流程可以防止某些类型的错误,尤其是防止多数人的暴政。但是,它很容易受到个人和小团体的阻挠。这可以是好事(避免错误),但是当它在提案流程的各个阶段一再发生,或正好在最后一刻发生时,就会具有破坏性了。
例子:
constexpr
(§4.2.7)、.
运算符(§8.8.2)、模块(§9.3.1)和协程(§9.3.2)。内聚的团体:许多工作组和研究组都拥有稳定的核心人员群体,这些年来他们形成了内聚的技术观、共享的词汇表和特定的运作方式。这会使
外部人员
难以交流和贡献。这也可能使设计跨越 WG 边界的特性(例如同时具有库和语言部分的特性)变得困难。每个小组都往往会设计出适合其自身组织结构领域的内容,再次印证了老格言,即系统的结构总是长得像创造它的组织的结构。例子:范围
for
(§4.2.2)和可能需要更改语言的并发机制(§4.1.3)。any
、optional
和variant
(§8.3)的接口差异。
从积极的一面来看,基于个人敌意或针锋相对的行为非常罕见。从这个意义上讲,委员会是非常专业的。
幸运的是,并非每个提案都受所有这些现象的影响,并且大多数其他大型项目也会遇到这类问题。但是,以其 ISO 标准所代表的 C++ 语言,整体上反映出了这些现象。它们不是新问题,但是自 C++11 起出现得越来越多。我怀疑它们是由以下因素共同造成的
- 委员会人数增加
- 新人的涌入
- 成员的专业化(分散化)
- 成员对 C++ 历史的了解有所减少
尽管存在这些严重的问题,但标准制定流程仍屡屡成功,原因之一是很多人不断努力将负面影响降到最低。方向组(Direction Group)的建立就是这方面的努力的一部分(§3.2)[Dawes et al. 2018; Stroustrup 2018d]。另见(§11.4)。工作组主席、笔记记录员、会议组织者和编辑组的不懈努力是无形的,但却至关重要。例如,Jens Maurer 数十年来一直在 CWG 中做笔记,帮助提案者编写标准文本,安排网络访问,为无法出席的成员安排电话接入,安排会议室,告知成员当地旅行的可能性,等等。
有其他方案吗?在理想的世界里,我会建议限定由一小部分(大约 5 人)的全职受信任专家委员做决定,而由大团队完成(例如超过 350 人的委员会)完成讨论、提案、以及大部分流程。但我不认为 C++ 会发展成这样,因为:
- 没有人喜欢放弃权力(在这种情况下是投票权)。
- 要为固定的全职专家团队保持稳定的资金投入需要非同小可的技能(而这种技能在 C++ 社区还没有出现)。
- 激进的变化不会发生在成功的时候;只有 C++ 使用量的显著下降才能促使委员会进行剧烈的组织创新(到那时多半为时已晚)。
我不认为公司控制是可行的替代方案,因为:
- 公司期望投资回报。
- 公司的支持往往几年后就会消失。
- 公司往往选择差异化的优势,而不是惠及所有人的进步。
我也不认为完全开放的审议流程(由成千上万人投票)是可行的:
- 超过千人的投票就会失去品味。
- 大群体的成员和意见没法在几十年里保持稳定。
对许多大型开源项目起作用的分级审批程序可能至少提供了部分方案,但是在 C 和 C++ 的标准化开始时,这方面的经验很少。当这样一个系统运行良好时,你在审批层级中的地位越高,审批者的知识基础就越广阔,他们关注的领域也就越广泛。在组织 结构顶部,我们会找到一人或多人,他们对所有知识都有所了解、对所有用户都有所关心。而与此相对的是,提案越接近最终批准,ISO 流程就越会稀释专业知识和关注领域:全体会议上,许多委员投票的提案是他们不感兴趣、领域经验有限且没有密切关注的。人们努力想负起责任,但是这真的很 难。还要从大局角度来看待每个提案,把它们当作其中的一部分,那就几乎不可能了。
这样看来,WG21 的工作还不算糟糕。我确实担心这样的工作模式能否使 C++ 长久保持连贯并与时俱进。从另一个角度来看,出席 C++ 标准会议的有 200 多人,比其他标准的团体要大一个数量级,而 ISO 的流程本来就是为那种较小的团体设计的。另外,委员的多样性远远超过了过去的老三样:头发斑白的专家、公司代表、以及国家机构代表。混乱有可能爆发。
我从温斯顿·丘吉尔的格言中得到些许安慰,民主是最糟糕的政府形式,除了所有那些人类一再尝试过的其他形式
。
特别要指出,我不认为经常被建议的仁慈的终身独裁者
模式可以规模化,而且,不管怎么说,该模型从来就没对 C++ 适用过。
在我心目中,启动语言设计项目的理想模式是单个人或一小群密切配合的朋友。但我看不到这种方式可以规模化。一门成熟的语言需要数十甚至数百个人来解决他们必须面对的各种问题。即使只是与相关的标准、行业组织进行协调,也会让一个小规模、紧密配合的团体彻底应接不暇。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论