5

我正在将一个开源 Java 库转换为 C#,其中有许多方法和类标记为已弃用。这个项目是一个从头开始的机会,所以我计划完全删除它们。然而,对于大型项目的工作来说,我很担心这种情况会再次出现。由于大部分敏捷开发都围绕着让某些东西现在工作并在需要时进行重构,所以 API 的弃用似乎是一个普遍的问题。即使我不完全确定项目的未来方向,我是否可以采取预防措施来避免/最大限度地减少 API 弃用?

4

9 回答 9

15

我不确定你能做多少。需求发生了变化,如果您绝对必须确保 API 的客户端不会被更新的 API 版本破坏,那么您将不得不依赖简单的弃用代码,直到您认为没有人使用弃用的代码。

将 [Obsolete] 属性放在代码上会导致编译器在存在对过时方法的任何引用时创建警告。这样,API 的客户,如果他们努力修复编译器警告,就可以逐渐转向新方法,而不会因新版本而导致一切中断。

如果您使用带有字符串的 ObsoleteAttribute 的覆盖,它很有用:

[Obsolete("Foo is deprecated. Use Bar instead for munging widgets.")]

<轻浮>

也许您可以创建一个 TimeBombAttribute:

[TimeBomb(new DateTime(2010,1,1), "Foo will blow up! Better use Bar, or else."]

在您的代码中,反映具有 timebomb 属性的方法,如果在指定日期之后调用它们,则抛出 KaboomException。这将确保在 2010 年 1 月 1 日之后没有人使用过时的方法,并且您可以很好地清理您的 API。:)

</轻浮>

于 2009-07-06T14:31:40.357 回答
5

正如马特所说,该Obsolete属性是您的朋友……但无论何时应用它,请提供有关如何更改调用代码的详细信息。这样你就有更好的机会让人们真正改变。您可能还需要考虑指定您预期在哪个版本中删除该方法(可能是下一个主要版本)。

当然,您应该努力确保不要调用过时的代码——尤其是在示例代码中。

于 2009-07-06T14:33:41.227 回答
2

由于大部分敏捷开发都围绕着让某些东西现在工作并在需要时进行重构

那不是敏捷。这是伪装在敏捷标签下的牛仔编码。

理想的情况是,无论你完成了什么,都是完整的,这取决于你对完成的任何定义。通常,DoD 会按照“功能实施、测试和相关代码重构”的方式陈述一些内容。当然,如果您正在制作一次性原型,您可以拥有更轻松的 DoD。

API 修改是一个困难的野兽。如果它们只是您正在修改的项目内部 API,那么最好的方法是尽早重构。如果您需要更改内部 API,只需同时更改所有 API 客户端即可。这样,重构债务不会变得非常大,并且您不必使用弃用。

对于已发布的 API,您可能需要维护一些源代码和二进制兼容性保证,至少要等到下一个主要版本左右。在保持兼容性的同时,将旧 API 标记为已弃用。与内部 API 一样,您应该尽快修复内部代码,以免使用已弃用的 API。

于 2009-07-06T14:45:00.240 回答
1

马特的回答是中肯的建议。我只是想提一下,最初您可能想要使用以下内容:

[Obsolete("Please use ... instead ", false)]

移植代码后,将 false 更改为 true,然后编译器会将对该方法的所有调用视为错误。

于 2009-07-06T14:41:57.950 回答
1

观看 Josh Bloch 的“如何设计一个好的 API 及其重要性

最重要的 w/r/t 弃用是知道“当有疑问时,将其排除在外”。观看视频以进行澄清,但这与必须永远支持您提供的内容有关。如果您实际上期望该 API 被重用,那么您实际上是在确定您的决定。

我认为 API 设计在敏捷方式中是一件更棘手的事情,因为您希望它可能以多种不同的方式被重用。您必须担心会破坏依赖您的其他人,因此虽然可以做到,但如果没有其他团队的快速转变,很难出现正确的设计。当然,弃用在这里会有所帮助,但我认为YAGNI在 API 方面的设计启发式要好得多。

于 2009-07-06T14:59:26.847 回答
0

我认为弃用代码是敏捷过程(如持续重构和增量开发)不可避免的副产品。因此,如果您在处理项目时最终使用了已弃用的代码,那不一定是坏事——只是生活中的事实。当然,您可能会发现,您最终保留了大量代码,但将其重构为不同的方法、类等,而不是弃用代码。

所以,底线:我不会担心在敏捷开发过程中弃用代码。如果它在一段时间内达到了它的目的,那么你就做对了。

于 2009-07-06T14:36:06.230 回答
0

API 设计的经验法则是关注它做了什么,而不是它是如何做的。一旦你知道最终目标,找出你需要的绝对最小输入并使用它。避免将自己的对象作为参数传递,只传递数据。

将配置与执行分开。例如,也许你有一个图像编码器/解码器。

而不是像这样打电话:

Encoder.Encode( bytes, width, height,  compression_type, compression_ratio, palette, etc etc);

做了

Encoder.setCompressionType(compression_type);
Encoder.setCompressionType(compression_ratio);
etc,etc
Encoder.Encode(bytes, width, height);

这样添加或删除设置就不太可能破坏现有的实现。

于 2009-07-06T15:46:21.420 回答
0

对于弃用,基本上有 3 种类型的 API:内部、外部和公共。

内部是只有您的团队在处理代码时。弃用这些 API 没什么大不了的。你的团队是唯一使用它的人,所以他们的存在时间不长,有改变它们的压力,人们不害怕改变它们,人们知道如何改变它们。

外部是指相同的代码库,但不同的团队正在使用它。这可能是大公司的一些常用库,也可能是流行的开源库。关键是,人们可以选择他们编译的代码版本。弃用 API 的难易程度取决于组织的规模以及它们的沟通情况。IMO,弃用者的工作是更新旧代码,而不是将其标记为弃用并让警告在整个代码库中传播。为什么是弃用者而不是弃用者?因为贬低者是知情的;他们知道发生了什么变化以及为什么发生了变化。

这两种情况很简单。只要存在向后兼容性,您通常可以做任何您想做的事情,自己更新客户端,或说服维护人员这样做。

然后是公共api。这些基本上是客户端无法控制的外部 API,例如 Web API。这些很难更新或弃用。大多数人不会注意到它坏了,不会有人来修复它,不会收到它改变的通知,并且只会在它坏了后才修复它(在他们大喊大叫破坏它之后,当然)。

我不得不做以上几次,这是一件苦差事。我认为您能做的最好的事情就是有目的地提前打破它,稍等片刻,然后再恢复它。当然,您首先发出通常的警告和弃用,但是 - 相信我 - 在某些事情发生之前什么都不会发生。

我还没有尝试过的一个想法是让人们注册运行小型测试的简单应用程序。当您想要进行 API 更新时,您可以运行外部测试并联系受影响的人。

于 2009-07-06T15:51:49.007 回答
0

另一种流行的方法是让客户依赖(Web)服务。有一些结构允许您对服务进行版本控制并允许客户端执行查找。这增加了更多的移动部分和复杂性,但如果您正在考虑转换大量版本并且必须在生产中支持多个版本,这可能会有所帮助。

本文很好地解释了问题和方法。

于 2009-07-06T16:08:00.177 回答