如何处理主要框架/依赖项升级?
寻找一些处理项目内主要依赖项升级的最佳实践,假设使用依赖项管理工具(例如,Maven 2)。
具体来说,我感兴趣的是:
- 如何使继承的应用程序保持最新状态(例如,Spring 1.2.x 到 2.5.x)
- 在进行此类彻底修改后可以采取哪些实践来保持应用程序保持最新状态-date
欢迎您自己的经历或您遇到/发现有用的任何文章/论文。
编辑: 更新依赖项版本号很简单。我更关注如何根据依赖项的更改(弃用、删除、参数/返回值类型的更改等)来处理需要进行的更改。如果有一个好方法可以在将来缓解这些变化,那么保持您的依赖项是最新的应该可以让您随时掌握变化并防止浪费大量时间获得“更安全 x 2.1”功能。
Looking for some best practices on handling a major dependency upgrades within a project, assuming the use of a dependency management tool(e.g., Maven 2).
Specifically, I'm interested in:
- How to get an inherited application up-to-date(e.g., Spring 1.2.x to 2.5.x)
- What practices can be put into place to after such an overhaul to keep applications somewhat up-to-date
Your own experiences or any articles/papers you've come across/found to be useful are welcome.
EDIT:
Updating a dependency version number is trivial. I'm more looking for how you go about tackling the changes you need to make, based on changes to the dependency(deprecation, deletion, changes to types in parameters/return values, etc...). And if there is a good way to ease these changes in the future, as keeping your dependencies up-to-date should allow you to stay on top of changes and prevent a lot of time being wasted just to get feature 'more securer x 2.1'.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
处理依赖项更改的良好实践与应用程序设计的良好实践相同。您希望对架构进行分层并最大程度地减少代码在每个依赖项上的广泛耦合,以便保持更改隔离,以便升级依赖项不会破坏应用程序的每个部分。对接口进行编码,并将业务逻辑与基础设施代码分开。
对于次要升级(依赖项的升级点版本),如果您拥有一套全面的单元测试来检测由于 API 更改而导致的故障,将会有所帮助。这就是为什么编写表面上看起来总是有效的琐碎测试有时会有所帮助的一个重要原因。一个示例是编写一个简单的 JDBC 单元测试来执行简单的查询。这似乎是浪费精力,直到您在数据库升级后发现 JDBC 驱动程序出现运行时问题(我就遇到过这种情况)。
对于较大的更改(例如在 Spring 等框架的不兼容版本之间进行升级),如果您有一些自动化的功能或集成测试,或者至少有一个功能规范供您的 QA 人员运行以验证高级功能,那么它会有所帮助。如果您要升级的框架 API 足够不同,需要进行广泛的代码更改,则单元测试可能不再相关。
管理从一个依赖项版本到另一个不兼容版本的迁移的实际战术部分实际上取决于您正在做什么。成熟的库将提供某种迁移路径,并且希望不需要您重写所有内容。将与框架升级相关的代码更改与与实现新功能相关的更改分开是一个好主意。这样,如果出现问题,您就会知道它与框架升级有关,而不是您在实现新功能时破坏的东西。
造成这一问题如此困难的部分原因是,在运行时,您的 JVM 中只能拥有特定依赖项的一个版本,因此您必须立即更新所有代码。 OSGi 通过允许同一运行中的不同 OSGi 包依赖于不同的依赖项版本来解决这个特定问题,因此您可以在运行时依赖于不同的依赖项版本。这就是 Eclipse 在不破坏其他插件的情况下管理插件依赖关系的方式。
Good practices for handling dependency changes are the same as good practices for application design. You want to layer your architecture and minimize widespread coupling of your code on each dependency in order to keep changes isolated, so that upgrading a dependency doesn't break every part of your application. Code to interfaces and keep business logic separate from infrastructure code.
For minor upgrades (upgrading point releases of a dependency), it helps if you have a comprehensive set of unit tests to detect failures due to API changes. This is one big reason why it sometimes helps to write trivial tests that seem on the surface to always work. An example of this is writing a simple JDBC unit test to perform a simple query. This seems like a waste of effort until you catch a runtime problem with the JDBC driver after a database upgrade (it's happened to me).
For larger changes (like upgrading between incompatible versions of a framework like Spring), it helps if you have some automated functional or integration tests, or at least have a functional specification that your QA people can run through to verify high level functionality. Unit tests will likely no longer be relevant if the framework API you are upgrading is different enough to require broad code changes.
The actual tactical part of managing a migration from one version of a dependency to another incompatible one really depends on what you are doing. A mature library will provide some kind of migration path and hopefully won't require you to rewrite everything. It is a good idea to separate the code changes related to a framework upgrade from the changes related to implementing a new feature. This way if something breaks you will know it has to do with the framework upgrade and not something you broke while implementing a new feature.
Part of what makes this so difficult is that at runtime you can only have one version of a particular dependency in your JVM, so you have to update all of the code at once. OSGi addresses this particular problem by allowing different OSGi bundles running in the same to depend on different dependency versions, so you could depend on different dependency versions at runtime. This is how Eclipse manages dependencies for plugins without breaking other plugins.
根据我的经验,依赖项升级是由于依赖项拥有所需的功能而实现的,作为对直接影响您自己的代码的依赖项中的错误的修复,支持新的 Java 版本,或者保持您的代码符合特定的要求标准(关于影响安全性的依赖关系)。如果您的代码不属于这些必要领域之一,我不会费心使它们保持最新,而是仅根据需要更新它们,因为从一个版本更新到另一个版本实际上可能会给您的应用程序带来错误。
我始终发现,最佳实践始于完成周期内应用程序的生产,将其作为稳定版本发布,并在下一个开发迭代中手动更新依赖项。将您的版本集中在父 POM 中将导致最小的依赖版本修改并提高可扩展性。假设您使用 Maven:
In my experience, dependency upgrades are implemented due to a needed functionality owned by the dependency, as a fix to a bug in the dependency that directly affects your own code, to support a new Java release, or to keep your code compliant to a particular standard (with respect to dependencies that affect security). If your code does not fall into one of these areas of necessity, I wouldn't bother keeping them up-to-date, but instead only update them as necessary as updating from release to release may actually introduce bugs into your application.
I've always found that best practice begins with finishing production on your application for the cycle, releasing it as a stable build, and manually updating your dependencies in the next development iteration. Centralizing your versions in your parent POM will result in minimal dependency version modifications and increased extensibility. Assuming you're using Maven: