转载

在软件的世界里,菜刀没有“杀人”的接口

  文/余晟

  朗朗上口的“说法”是很容易理解也很容易记忆的,不幸,“说法”也是很容易被误解的。

  存在的就是合理的,这句话多么熟悉,有那么多人振振有辞地引用它来证明事物的正当性,甚至硬生生造出既成事实,再用它来辩护。但是,黑格尔的本意是:“存在”(也就是“事物的本原”)必然是符合绝对精神(历史的推动力)的。或者通俗点说,事物的本原,是有来龙去脉的因果链支撑的。

  权力导致腐败,绝对权力导致绝对腐败,这也是耳熟能详的说法。无数引用的人甚至没有想想,“绝对腐败”到底是什么意思。其实阿克顿勋爵从来没说过“绝对腐败”,原文里的 absolutely 分明是修饰动词的副词,而不是修饰名词的形容词。他的本意是:权力天然有腐化的倾向,不受制约的权力必然会腐化。

  当然,今天我想讲的并不是“存在的就是合理的”或者“绝对权力导致绝对腐败”,而是用得更常见的一个说法:我卖的是菜刀,有人拿菜刀去杀人,难道要怪我吗?

  根据生活经验来看,这个说法相当有力,菜刀一旦卖出去就不受卖家控制,买家随便拿它来干什么,卖家都管不着。尽管大家原本认为这把刀是把菜刀,只应该用来切菜,但这种共识并没有硬性约束。

  不过在软件的世界里,这个说法未必行得通。软件与机械实物不同,软件有智能,还可以不断升级自己的智能。依靠软件的这种特性,软件在开发时的约定,是可以在后续的使用中被严格遵守的。或者换句话说,优秀软件工程师的作品,除了提供客户需要的功能之外,还必须保证“客户只能按照预先约定的方式来使用这些功能”。

  不幸的是,软件的这个特性并不为很多工程师所理解,所重视。这或许是因为现成的编程语言和工具都太强大了,超越了普通人的意识,使用的时候被巨大的快感所蒙蔽,而放弃了认真的思考。

  我们经常在代码里看到这样的例子:接收一个参数作为角度,那么就用 int 吧;接收一段文字作为姓氏,那么就用 string 吧…… 其实 int 也好,string 也好,都只是中立的、不与任何业务场景相关联、也不遵守任何业务约束的基本数据类型而已。

  但是在具体的使用场景中,在用户的共同认知里,“角度”和“姓氏”是有对应的显式或隐式的契约所约束的:角度只能是 0 到 360 之间的数字,“姓氏”通常应该由1-2 个中文字符构成。

  如果我们直接用 int 来承载角度,用 string 来承载姓氏,就破坏了那些显式或隐式的契约,很可能违背用户的共同认知,进而破坏使用场景。最简单的,如果显示出来的角度计只有 0 到 360 的刻度,如果用来显示姓氏的空栏只有 4 个字符的长度,那么这个范围之外的角度,超长的姓氏,就会造成显示的混乱。

  解决的办法就是根据具体的应用场景,把这些显式或隐式的契约以合适的粒度容纳到软件的世界里——角度仍然用 int 来承载,但设定时只能取值在 0 到 360 之间;姓氏仍然用 string 来承载,但设定时最长只有 2 个字符,而且这些字符必须是中文。

  以上举的是最简单的例子,这些知识学校里一般不教,一般团队也不会强调,因此没有经验的工程师常常觉得这是多此一举,只有有经验的工程师能够理解其中的道理:软件一旦开发完放出去,就不知道会在什么场景下,以什么方式来使用。为了保证预期的功能正常运行,避免出现意想不到的情况,软件就需要尽自己所能对使用者和使用方式做出约束,保证自己所处的小环境是可控的,是符合预期的,然后才能正确运转,否则很难预料会发生什么,也未必担得起这个责任。再重复一遍之前的话:优秀软件工程师的作品,除了提供客户需要的功能之外,还必须保证“客户只能按照预先约定的方式来使用这些功能”。

  回到标题,如果你卖的是实物菜刀,或许没办法约束买家拿去杀人。菜刀磨得越快,杀人越容易,这个矛盾是无解的。但如果你是开发软件的工程师,是在软件世界里卖菜刀,只考虑把刀磨得更快是不够的,你还得保证“菜刀”的名副其实——它真的只能“切菜”,绝不可能执行“杀人”的调用。


  这篇文章的灵感来自我近日和软件工程师谈类库设计的经历,与某著名搜索引擎的自辩词没有直接关系。但是,我并不约束大家展开各种联想。

正文到此结束
Loading...