API设计的金科玉律
API设计是很困难的,特别是要大规模使用时。如果你正在设计的API有成百上千的用户,你就该考虑在将来怎样修改以及修改是否会破坏客户代码。另外,你还要想想API的用户是怎么影响你的。如果一个API类在内部调用了一个它自己的方法,你该记住用户可能会继承你的类并重写它,这可能导致灾难的结果。你没法修改那个方法,因为有些用户给了它不同的含义。你未来的内部实现的选择就受到用户的支配。
API的开发者用各种各样的方法解决这个问题,但最简单的方法是锁定API。如果你用的是Java,可能会尝试将大部分类和方法设定为final。c#中,你可能会让类和方法成为sealed的。不管用的什么语言,你都可能倾向于通过单件或者静态的工厂方法来表现API,以免别人覆盖行为或者以日后可能约束你的选择的方式来使用你的代码。这些看起来很合理,但是真的吗?
过去几十年来,我们逐渐意识到单元测试是实践中非常重要的一部分,但是这种认识并没有完全渗透到行业中。我们周围都是证明。随便拿一个没有测试的使用第三方API的类,尝试为它写单元测试,大多数时候都会有困难。你会发现使用API的代码像胶水一样粘在它上面,没有办法冒充API类来与自己的代码交互,或者提供测试用的返回值。
随着时间的推移,情况可能好转,但是只有在我们开始在设计API时把测试作为一个真正使用的场景。不幸的是,这不止是测试我们的代码,于是就有了API设计的金科玉律:仅为你开发的API写测试是不够的;也需要为使用API的代码编写单元测试。这样做了,就会得到用户在尝试独立地测试他们的代码时需要面对的第一手结果。
让开发者更容易测试使用你的API的代码,方法不是唯一的。static,final和sealed本身不是不好的结构,它们有时也会很有用。但是明白测试中的问题是很重要的,而且你必须亲自体验才能做到。一旦你做了,你可以任何其它的设计挑战中使用这种方法。