I'm not sure there is much you can do. Requirements change, and if you absolutely have to make sure that clients of the API are not broken by newer API version, you'll have rely on simply deprecating code until you think that no-one is using the deprecated code.
Placing [Obsolete] attributes on code causes the compiler to create warnings if there are any references to the obsolete methods. This way clients of the API, if they are diligent about fixing their compiler warnings, can gradually move to the new methods without having everything break with the new version.
Its useful if you use the ObsoleteAttribute's override which takes a string:
[Obsolete("Foo is deprecated. Use Bar instead for munging widgets.")]
<frivolous>
Perhaps you could create a TimeBombAttribute:
[TimeBomb(new DateTime(2010,1,1), "Foo will blow up! Better use Bar, or else."]
In your code, reflect for methods with the timebomb attribute and throw KaboomException if they are called after the specified date. That'll make sure that after 1st January 2010 no-one is using the obsolete methods, and you can clean up your API nicely. :)
As Matt says, the Obsolete attribute is your friend... but whenever you apply it, provide details of how to change calling code. That way you've got a lot better chance of people actually changing. You might also want to consider specifying which version you anticipate removing the method in (probably the next major release).
Of course, you should be diligent in making sure you don't call the obsolete code - particularly in sample code.
API 修改是一件困难的事情。 如果它们只是您正在修改的项目内部 API,那么最好的方法是尽早重构。 如果您需要更改内部 API,只需同时更改所有 API 客户端即可。 这样,重构债务就不会变得很大,并且您不必使用弃用。
对于已发布的 API,您可能必须维护一些源代码和二进制兼容性保证,至少直到下一个主要版本左右。 将旧 API 标记为已弃用,同时保持兼容性。 与内部 API 一样,您应该尽快修复内部代码,以免使用已弃用的 API。
Since much of agile development revolves around making something work now and refactoring later if needed
That's not agile. It's cowboy coding disguised under the label of agile.
The ideal is that whatever you complete, is complete, according to whatever Definition of Done you have. Usually the DoD states something along the lines of "feature impelmented, tested and related code refactored". Of course, if you are working on a throwaway prototype, you can have a more relaxed DoD.
API modifications are a difficult beast. If they are only project-internal APIs you are modifying, the best way to go is to refactor early. If you need to change the internal API, just go ahead and change all API clients at the same time. This way the refactoring debt does not grow very large and you don't have to use deprecation.
For published APIs you probably have some source and binary compatibility guarantees you have to maintain, at least until the next major release or so. Marking the old APIs deprecated works while maintaining compatibility. As with internal APIs, you should fix your internal code as soon as possible to not use the deprecated APIs.
Most important w/r/t deprecation is knowing that "when in doubt, leave it out." Watch the video for clarification, but it has to do with having to support what you provide forever. If you are realistically expecting that API to be reused, you're effectively setting your decisions in stone.
I think API design is a much trickier thing to do in an Agile fashion because you're expecting it to be reused probably in many different ways. You have to worry about breaking others that are dependent on you, and so while it can be done, it's tough to have the right design emerge without getting a quick turnaround from other teams. Of course deprecation is going to help here, but I think YAGNI is a lot better design heuristic when it comes to APIs.
I think deprecation of code is an inevitable byproduct of Agile processes like continuous refactoring and incremental development. So if you end up with deprecated code as you work on your project, that's not necessarily a bad thing--just a fact of life. Of course, you will probably find that, rather than deprecating code, you end up keeping a lot of code but refactoring it into different methods, classes, and so on.
So, bottom line: I wouldn't worry about deprecating code during Agile development. If it served its purpose for a while, you're doing the right thing.
The rule of thumb for API design is to focus on what it does, rather than how it does it. Once you know the end goal, figure out the absolute minimum input you need and use that. Avoid passing your own objects as parameters, pass only data.
Seperate configuration from execution. For exmaple, maybe you have an image encoder/decoder.
我尚未尝试的一个想法是让人们注册运行小型测试的简单应用程序。 当您想要进行 API 更新时,您可以运行外部测试并联系受影响的人员。
For deprecation, there's basically 3 types of APIs: internal, external, and public.
Internal is when its only your team working on the code. Deprecating these APIs isn't a big deal. Your team is the only one using it, so they aren't around long, there's pressure to change them, people aren't afraid to change them, and people know how to change them.
External is when its the same code base, but different teams are using it. This might be some common libraries in a large company, or a popular open source library. The point is, people can choose the version of code they compile with. The ease of deprecating an API depends on the size of the organization and how well they communicate. IMO, its the deprecator's job to update old code, rather than mark it deprecated and let warnings fly throughout the code base. Why the deprecator instead of the deprecatee? Because the depcarator is in the know; they know what changed and why.
Those two cases are pretty easy. So long as there is backwards compatibility, you can generally do whatever you'd like, update the clients yourself, or convince the maintainers to do it.
Then there are public api's. These are basically external API's that the clients don't have much control over, such as a web API. These are incredibly hard to update or deprecate. Most won't notice its broken, won't have someone to fix it, won't get notifications that its changing, and will only fix it once its broken (after they've yelled at you for breaking it, over course).
I've had to do the above a few times, and it is such a chore. I think the best you can do is purposefully break it early, wait a bit, and then restore it. You send out the usual warnings and deprecations first, of course, but - trust me - nothing will happen until something breaks.
An idea I've yet to try is to let people register simple apps that run small tests. When you want to do an API update, you run the external tests and contact the affected people.
Another approach to be popular is to have clients depend on (web) services. There are constructs out there that allow you to version your services and allow clients to perform lookups. This adds a lot more moving parts and complexity into the equation, but can be helpful if you are looking at turning over a lot of versions, and having to support multiple versions in production.
This article does a good job of explaining the problem and an approach.
发布评论
评论(9)
我不确定你能做多少事情。 需求发生变化,如果您绝对必须确保 API 的客户端不会被较新的 API 版本破坏,那么您将只能依靠简单地弃用代码,直到您认为没有人在使用已弃用的代码。
如果存在对过时方法的任何引用,将 [Obsolete] 属性放在代码上会导致编译器创建警告。 这样,如果 API 的客户端勤于修复编译器警告,他们就可以逐渐转向新方法,而不会因新版本而出现任何问题。
如果您使用 ObsoleteAttribute 的覆盖(它接受一个字符串),它会很有用:
也许您可以创建一个 TimeBombAttribute:
在您的代码中,反映具有 timebomb 属性的方法,如果在指定日期之后调用它们,则抛出 KaboomException。 这将确保 2010 年 1 月 1 日之后没有人使用过时的方法,并且您可以很好地清理您的 API。 :)
I'm not sure there is much you can do. Requirements change, and if you absolutely have to make sure that clients of the API are not broken by newer API version, you'll have rely on simply deprecating code until you think that no-one is using the deprecated code.
Placing [Obsolete] attributes on code causes the compiler to create warnings if there are any references to the obsolete methods. This way clients of the API, if they are diligent about fixing their compiler warnings, can gradually move to the new methods without having everything break with the new version.
Its useful if you use the ObsoleteAttribute's override which takes a string:
<frivolous>
Perhaps you could create a TimeBombAttribute:
In your code, reflect for methods with the timebomb attribute and throw KaboomException if they are called after the specified date. That'll make sure that after 1st January 2010 no-one is using the obsolete methods, and you can clean up your API nicely. :)
</frivolous>
正如马特所说,
已过时
属性是你的朋友...但是每当你应用它时,请提供如何更改调用代码的详细信息。 这样你就有更好的机会让人们真正改变。 您可能还需要考虑指定您预计删除该方法的版本(可能是下一个主要版本)。当然,您应该努力确保不调用过时的代码 - 特别是在示例代码中。
As Matt says, the
Obsolete
attribute is your friend... but whenever you apply it, provide details of how to change calling code. That way you've got a lot better chance of people actually changing. You might also want to consider specifying which version you anticipate removing the method in (probably the next major release).Of course, you should be diligent in making sure you don't call the obsolete code - particularly in sample code.
所以这不是敏捷。 这是伪装在敏捷标签下的牛仔编码。
理想的是,无论您完成什么,根据您对“完成”的定义,都是完成。 通常,国防部会声明类似“功能实施、测试和相关代码重构”的内容。 当然,如果您正在开发一次性原型,则国防部可以更轻松。
API 修改是一件困难的事情。 如果它们只是您正在修改的项目内部 API,那么最好的方法是尽早重构。 如果您需要更改内部 API,只需同时更改所有 API 客户端即可。 这样,重构债务就不会变得很大,并且您不必使用弃用。
对于已发布的 API,您可能必须维护一些源代码和二进制兼容性保证,至少直到下一个主要版本左右。 将旧 API 标记为已弃用,同时保持兼容性。 与内部 API 一样,您应该尽快修复内部代码,以免使用已弃用的 API。
That's not agile. It's cowboy coding disguised under the label of agile.
The ideal is that whatever you complete, is complete, according to whatever Definition of Done you have. Usually the DoD states something along the lines of "feature impelmented, tested and related code refactored". Of course, if you are working on a throwaway prototype, you can have a more relaxed DoD.
API modifications are a difficult beast. If they are only project-internal APIs you are modifying, the best way to go is to refactor early. If you need to change the internal API, just go ahead and change all API clients at the same time. This way the refactoring debt does not grow very large and you don't have to use deprecation.
For published APIs you probably have some source and binary compatibility guarantees you have to maintain, at least until the next major release or so. Marking the old APIs deprecated works while maintaining compatibility. As with internal APIs, you should fix your internal code as soon as possible to not use the deprecated APIs.
马特的回答是中肯的建议。 我只是想提一下,最初您可能想使用以下内容:
移植代码后,将 false 更改为 true,然后编译器会将对该方法的所有调用视为错误。
Matt's answer is solid advice. I just wanted to mention that intially you probably want to use something along the lines of:
Once you have the code ported, change the false to true and the compiler will then treat all the calls to the method as an error.
观看 Josh Bloch 的“如何设计良好的 API 及其重要性
” w/r/t 弃用是知道“当有疑问时,将其排除”。 请观看视频以进行澄清,但这与必须永远支持您提供的内容有关。 如果您确实期望该 API 能够被重用,那么您实际上就是在制定自己的决定。
我认为以敏捷方式进行 API 设计是一件更加棘手的事情,因为您期望它可能以多种不同的方式重用。 您必须担心会破坏依赖您的其他人,因此虽然可以做到这一点,但如果没有其他团队的快速周转,就很难出现正确的设计。 当然,弃用在这里会有帮助,但我认为 YAGNI 在 API 方面是更好的设计启发式。
Watch Josh Bloch's "How to Design a Good API and Why It Matters"
Most important w/r/t deprecation is knowing that "when in doubt, leave it out." Watch the video for clarification, but it has to do with having to support what you provide forever. If you are realistically expecting that API to be reused, you're effectively setting your decisions in stone.
I think API design is a much trickier thing to do in an Agile fashion because you're expecting it to be reused probably in many different ways. You have to worry about breaking others that are dependent on you, and so while it can be done, it's tough to have the right design emerge without getting a quick turnaround from other teams. Of course deprecation is going to help here, but I think YAGNI is a lot better design heuristic when it comes to APIs.
我认为代码的弃用是持续重构和增量开发等敏捷流程不可避免的副产品。 因此,如果您在处理项目时最终遇到了已弃用的代码,这并不一定是坏事——这只是生活中的一个事实。 当然,您可能会发现,您最终并没有弃用代码,而是保留了大量代码,但将其重构为不同的方法、类等。
所以,底线是:我不会担心在敏捷开发期间弃用代码。 如果它在一段时间内达到了目的,那么你就做对了。
I think deprecation of code is an inevitable byproduct of Agile processes like continuous refactoring and incremental development. So if you end up with deprecated code as you work on your project, that's not necessarily a bad thing--just a fact of life. Of course, you will probably find that, rather than deprecating code, you end up keeping a lot of code but refactoring it into different methods, classes, and so on.
So, bottom line: I wouldn't worry about deprecating code during Agile development. If it served its purpose for a while, you're doing the right thing.
API 设计的经验法则是关注它的作用,而不是它是如何做的。 一旦你知道了最终目标,找出你需要的绝对最小输入并使用它。 避免将自己的对象作为参数传递,仅传递数据。
将配置与执行分开。 例如,也许您有一个图像编码器/解码器。
而不是进行像这样的调用:
这样
添加或删除设置就不太可能破坏现有的实现。
The rule of thumb for API design is to focus on what it does, rather than how it does it. Once you know the end goal, figure out the absolute minimum input you need and use that. Avoid passing your own objects as parameters, pass only data.
Seperate configuration from execution. For exmaple, maybe you have an image encoder/decoder.
Instead of making a call like:
Make it
That way adding or removing settings is much less likely to break existing implementations.
对于弃用,基本上有 3 种类型的 API:内部、外部和公共。
内部是指只有您的团队在处理代码。 弃用这些 API 并不是什么大问题。 你的团队是唯一使用它的团队,所以他们存在的时间不长,有改变它们的压力,人们不害怕改变它们,而且人们知道如何改变它们。
外部是指具有相同的代码库,但不同的团队正在使用它。 这可能是大公司的一些常用库,或者是流行的开源库。 关键是,人们可以选择他们编译的代码版本。 弃用 API 的难易程度取决于组织的规模以及他们的沟通情况。 IMO,更新旧代码是弃用者的工作,而不是将其标记为弃用并让警告在整个代码库中传播。 为什么是弃用者而不是被弃用者? 因为卸货者是知情的; 他们知道发生了什么变化以及原因。
这两种情况都很简单。 只要存在向后兼容性,您通常可以做任何您想做的事情,自己更新客户端,或者说服维护人员这样做。
然后是公共 api。 这些基本上是客户端没有太多控制权的外部 API,例如 Web API。 这些非常难以更新或弃用。 大多数人不会注意到它坏了,不会有人来修复它,不会收到它发生变化的通知,并且只会在它坏了之后修复它(在他们对大喊大叫之后) >你打破了它,当然)。
我不得不做几次以上的事情,这真是一件苦差事。 我认为你能做的最好的事情就是有目的地尽早打破它,稍等一下,然后恢复它。 当然,您首先发出通常的警告和反对意见,但是 - 相信我 - 除非出现问题,否则什么都不会发生。
我尚未尝试的一个想法是让人们注册运行小型测试的简单应用程序。 当您想要进行 API 更新时,您可以运行外部测试并联系受影响的人员。
For deprecation, there's basically 3 types of APIs: internal, external, and public.
Internal is when its only your team working on the code. Deprecating these APIs isn't a big deal. Your team is the only one using it, so they aren't around long, there's pressure to change them, people aren't afraid to change them, and people know how to change them.
External is when its the same code base, but different teams are using it. This might be some common libraries in a large company, or a popular open source library. The point is, people can choose the version of code they compile with. The ease of deprecating an API depends on the size of the organization and how well they communicate. IMO, its the deprecator's job to update old code, rather than mark it deprecated and let warnings fly throughout the code base. Why the deprecator instead of the deprecatee? Because the depcarator is in the know; they know what changed and why.
Those two cases are pretty easy. So long as there is backwards compatibility, you can generally do whatever you'd like, update the clients yourself, or convince the maintainers to do it.
Then there are public api's. These are basically external API's that the clients don't have much control over, such as a web API. These are incredibly hard to update or deprecate. Most won't notice its broken, won't have someone to fix it, won't get notifications that its changing, and will only fix it once its broken (after they've yelled at you for breaking it, over course).
I've had to do the above a few times, and it is such a chore. I think the best you can do is purposefully break it early, wait a bit, and then restore it. You send out the usual warnings and deprecations first, of course, but - trust me - nothing will happen until something breaks.
An idea I've yet to try is to let people register simple apps that run small tests. When you want to do an API update, you run the external tests and contact the affected people.
另一种流行的方法是让客户依赖(网络)服务。 有一些结构允许您对服务进行版本控制并允许客户端执行查找。 这会增加更多的移动部件和复杂性,但如果您正在考虑切换大量版本并且必须在生产中支持多个版本,这会很有帮助。
这篇文章很好地解释了问题和方法。
Another approach to be popular is to have clients depend on (web) services. There are constructs out there that allow you to version your services and allow clients to perform lookups. This adds a lot more moving parts and complexity into the equation, but can be helpful if you are looking at turning over a lot of versions, and having to support multiple versions in production.
This article does a good job of explaining the problem and an approach.