语言约束和责任感,我们应该信赖谁?

  • Abel Avram
  • 王丽娟

2009 年 7 月 29 日

话题:Ruby方法论编程语言架构语言 & 开发文化 & 方法

语言应该完全灵活、允许开发人员随心所欲地进行调整、并相信他们会对自己的工作负责呢,还是应该从设计阶段就在语言中设置明确的约束集,以避免出现生成糟糕代码、难以维护或阅读的错误?

Bruce Eckel 认为有些功能非常复杂,大多功能最终并没被使用过:

C++ 里一直没有运行时模型(所有内容都编译为原始代码,这是 C 兼容性的另一个遗留问题),之前出现了模板元编程。由于模板元编程确实很难用,它非常复杂,几乎没人知道该如何去做。

Java 有运行时模型,甚至还有动态修改代码的方法,但语言的静态类型检查非常麻烦,以致原始元编程跟 C++ 里一样很难做到。

很显然,需求依旧层出不穷,我们首先看到了面向方面编程(AOP),而事实证明对大多数程序员来说 AOP 又有点儿过于复杂。

跟 Smalltalk 一样,Ruby 中的所有内容都是可替代的(对习惯于静态语言的人来说,这确实让动态语言引起了惊声尖叫)。

Michael Feathers 觉得 Eckel 是在建议对语言进行约束

语言设计者总是坚持这类理由——有些东西不应该被允许。如果你想看这种理由的例子,就去看看 Bruce Eckel 本篇博客的元编程一节吧。

Feathers 提倡信任开发人员,而不是建立安全网,这能促进道德责任,他认为这在 Ruby 社区是存在的:

某些语言里,你会觉得语言设计者在告诉你有些东西非常危险,我们应该防止这些东西,而且应该有可用的工具来防止滥用这些功能。结果整个社区在规范意见和可行方案上花费了大量时间。如果语言不能用人们习惯的方式提供锁定所有这些内容的特性,人们就会非常生气。

在 Ruby 文化里我还没有发现这一点。

你可以在 Ruby 里为所欲为。你能改变库里的任意类,织入方面的(Aspecty)行为,完全用元编程做疯狂的事情。也就是说,一切全在于你。你需要负责任。如果出现问题你只能怪自己。你不能责怪语言设计者没有添加功能,因为你自己可以去做,你也不能因为他没有按你的方式去做而责备他。

那为什么很多人并没有输得很惨呢?我想有一个很好的理由。在你能做任何事情的时候,你必须变得更加负责。你掌握着你自己的命运。而且我认为这能提升责任感。

Coda Hale并不认为 Ruby 社区有更好的责任感,相反,这是一种放任:

我非常想去相信 Ruby 有责任感文化,但我并不觉得是这样。我已经调试了 Ruby 应用中的大量问题,它们都是由擅自采用他人代码的第三方库造成的——把 NilClass 变成一个黑洞,或者使用 alias_method_chain,却没有很好地复写基本的方法签名。对那些引起问题的库,每次都要尽力说服其作者去修复问题,但每次我都不得不在库更新之前自己给代码打热补丁。这并不是积极意义上的责任感;它的责任感只是“如果你不修复,就没人修复”。

我认为 Ruby 文化里放纵多于责任。任何事情几乎都是可以接受的,而不会抗议另一个库的不良行为,由于库自身的不良行为,你要编写自己的版本。

Niclas Nilsson同意 Feathers 的观点,让开发人员不受约束,让他们觉得有责任:

由于某些原因,我总会在各种不同的情形下跟别人结束这个讨论。“这不危险么?”我的答案往往是“是,危险。不过汽车、刀具、药物也是如此。”几乎所有可用的东西都会被滥用,但我们很少这么做,如果这么做了我们很快就会认识到,在软件里,我们具备各种无与伦比的撤销功能。

只要为(虚假)保护付出的代价非常小,尤其是它们可以规避,我就不愿意为它们付出代价。你不能在 Java 运行时改变一个类,所以为了解决这个问题, 人们转向了字节码编织。壁垒打破了,但却是高成本和高复杂性。我还是相信责任,我设置好的习惯和安全网,以保护自己不犯逻辑错误。

自由和责任是并行不悖的。

Keith Braithwaite举了 Lisp 社区的例子,该社区不庇护它的用户,用户也学会了如何避免错误:

从 Lisp 社区的历史中能汲取哪些经验教训呢?Lisp(还有 Smalltalk 和汇编)是不庇护自己用户的。我似乎还能想起来读过 Dick Gabriel 的一些文章,里面说明了 Lisp 程序员如何停止自我检查,认为某些模板的灵巧是不得体的——他们小心翼翼以不让那些灵巧性困扰他人。他们几乎可以做任何事情(还有编写代码本身),但他们选择不去做某些事情。

Glenn Vanderburg 认为,语言约束并不会避免开发人员犯错

差的开发人员会“竭尽所能”地去犯错。你不能通过锁定利器而规避他们造成的破坏。他们会更费劲地挥动钝器去犯错。

如果你希望你的团队有很多产出,并对他们的决定负责的话,就给他们强大的工具。

Aslam Khan认则认为,新手觉得保护机制有必要,但随着他们越来越有经验,这些保护机制就可以移除了:

很多语言设计者假设人们需要被“控制”。事实上,新手们更喜欢基于规则 / 方法 / 准则学习文化和语言,这迫使各种有关“危险”事情的“安全网”很好地为小组服务。当新手不再是新手,这种情况才会结束,然后约束就会变得不合理。

Ward Bell 注意到,人们并不是很负责任:

好的情况下……谁会反对责任和学习呢?但阅读实际已有代码的多年经验告诉我,别人不负责,我们自己往往也会松懈。Ruby 是怎样改变了我们的天性呢?

早在七十年代和八十年代,我用 APL 编写商业应用。非常动态。改变别人写的代码非常容易。你可以编写新的 APL 作为字符串,也可以用烦人的操作符执行它们。几乎没有捕获或警告的解释程序支持(那时还没有编译)。

我们创造了非常好的东西。我们修复的速度几乎和编写的速度一样快,这非常酷。但你必须要非常擅长阅读任何人的代码(包括你自己的)。

T. Powell 认为,不管使用什么语言,开发人员都能吸收,因此问题之所在并不是语言,而是态度:

不论用什么语言,你都能要么举步维艰,要么很优秀……当然,语言有所影响,你也会经常看到设计者或社区适当的作用,但你会成为用 Java、Ruby、Fortran 等语言的白痴……

你对此有何看法呢?我们应该要无约束的语言、信任开发人员呢,还是应该有适当的安全网?

查看英文原文:Should We Rely on Language Constraints or Responsibility?

Ruby方法论编程语言架构语言 & 开发文化 & 方法