
# 三方软件版本管理策略
系统升级、改造过程中，三方软件冲突是最常见的问题。随着软件迭代速度越来越快，传统的软件兼容性管理策略已经不适应软件的发展。
本章节分享三方软件管理的最佳实践，帮助您打造一个持续演进的应用系统。
#### 开源软件选型
主要的开源社区，例如[Spring Boot](https://github.com/spring-projects/spring-boot)、[Spring Cloud](https://github.com/spring-cloud)等都会维护多个版本分支。以Spring Cloud为例，存在Hoxton、Greenwich、2020.0.x等分支，其中大部分分支都已经停止维护。开源软件多数维护的分支存在两个：一个为最新版本的开发分支；一个为最近的稳定维护分支。
在开源软件选型上，应该紧跟社区的版本节奏，使用继续提供维护的分支的最新版本。在选择开发分支和维护分支上，没有严格的定论，需要视具体的产品功能确定。例如产品竞争力严重依赖某个三方软件的特性，那么更倾向于选择开发分支的最新版本；一个产品依赖某个三方软件的特性稳定，不使用新功能，那么更倾向于选择维护分支。
不建议选择社区已经停止维护的分支、以及虽然还在维护但发布时间超过半年以上的分支版本。虽然使用这些版本暂时没有发现功能问题，但是会给产品的持续演进带来严重影响：
1. 软件的安全漏洞得不到及时处理。安全漏洞的发现和利用都有一定的时间周期，长期使用老版本，安全漏洞被利用的可能性变大，使得系统更加容易被攻击。
2. 系统出现故障，更难寻求社区支持。停止维护的版本，或者已经发布超过半年以上的版本，很难得到社区的支持。
3. 系统演进变得更加困难。当系统需要增加新特性，引入新开发工具时，老版本更难与新开发工具兼容。
4. 还有很多的故障，可能在新版本已经修复，新版本在代码可维护性、性能等方面也都优于老版本。
因此，在开源软件选型问题上 ，最佳方案就是选择社区提供维护升级的开发分支或者维护分支，根据问题驱动升级到分支的最新版本，每季度周期性升级到分支的最新版本。
#### 三方软件版本管理
首先通过一个简单的例子，介绍三方件冲突的原理。假设开发一个X项目，该项目需要同时引用项目A提供的组件，也需要引用项目B的组件，并且项目A和项目B同时依赖了项目C，但是版本号不同。
- 项目X的pom：
  ```
  <dependency>
    <groupId>groupA</groupId>
    <artifactId>artifactA</artifactId>
     <version>0.1.0</version>   
  </dependency>
  <dependency>
    <groupId>groupB</groupId>
    <artifactId>artifactB</artifactId>
    <version>0.1.0</version>   
  </dependency>
  ```
  

- 项目A的pom
  ```
  <dependency>
    <groupId>groupC</groupId>
    <artifactId>artifactC</artifactId>
    <version>0.1.0</version>   
  </dependency>
  ```
  
- 项目B的pom：
  ```
  <dependency>
    <groupId>groupC</groupId>
    <artifactId>artifactC</artifactId>
    <version>0.2.0</version>   
  </dependency>
  ```
  
项目X在最终发布的时候，会出现如下几种情况：
- 使用项目C的0.2.0版本。由于项目A是使用0.1.0版本编译和测试的，那么组件A可能无法正常工作。例如0.2.0版本和0.1.0不兼容，并且项目A恰好使用了这些不兼容的接口。
- 使用项目C的0.1.0版本。由于项目B是使用0.2.0版本编译和测试的，那么组件B可能无法正常工作。例如项目B使用了0.2.0提供的新接口。
可以看出，如果项目A和项目B使用的C组件存在接口不兼容的情况，无论怎么调整，项目X都无法正常工作。必须修改项目A的代码，使用和B同样的或者兼容的版本进行测试，发布新的版本给X项目使用。
因此，进行依赖管理的最佳策略是保证公共组件的依赖，都使用较高的版本。尽管如此，通常还是会碰到一系列问题，特别是项目依赖关系非常复杂的情况。
目前主流的复杂项目，都采用dependency management机制管理依赖。使用dependency management已经被验证是比较有效的管理依赖的手段，因此被开源社区广泛使用。例如，Spring Boot、Spring Cloud和Spring Cloud Huawei，开发者可以通过查看Spring Cloud Huawei的源代码目录结构了解dependency management的具体使用。
对于复杂项目，以Spring Cloud Huawei项目为例，和依赖关系管理有关的pom文件包含：
```
/pom.xml # 项目的根目录
/spring-cloud-huawei-dependencies/pom.xml # 项目的主要依赖管理。和项目dependency management有关的声明都在这个文件。
/spring-cloud-huawei-parents/pom.xml # parents既给本项目的子module使用，也给项目开发者使用，类似Spring Boot提供的parent
/spring-cloud-huawei-bom/pom.xml # bom主要用于项目开发者期望将Spring Cloud Huawei自己提供的组件引入项目的依赖管理，而不期望引入Spring Cloud Huawei依赖的第三方软件的版本。
```
Spring Cloud Huawei的这几个pom是相对完整的pom结构，从不同的使用视角给开发者提供了可以引入的pom，比较适用于公共开发组件。
一般的微服务开发项目可能只包含"/pom.xml"，项目的parent和dependency management都在"/pom.xml"声明。引入dependency management以后，项目中的所有dependency声明，都不指定版本号。这样的好处是当需要升级三方软件版本的时候，只需要修改"/pom.xml"里面的dependency management，其他地方都不需要排查修改。
您可以通过[Spring Cloud Huawei的示例项目](https://github.com/huaweicloud/spring-cloud-huawei-samples/blob/master/basic/pom.xml)，直观体会dependency management的原理和作用：
1. 执行命令**mvn dependency:tree**查看项目的依赖关系。
2. 修改"/pom.xml"中"spring-boot.version"，再执行命令**mvn dependency:tree**查看项目的依赖关系的变化。
3. 调整"/pom.xml"中"spring-boot-dependencies"和"spring-cloud-dependencies"的位置，再执行命令**mvn dependency:tree**查看项目的依赖关系的变化。
当项目依赖的三方软件增多的时候，识别软件之间的配套关系是非常困难的。一个比较好的策略是跟随Spring Boot、Spring Cloud的版本配套关系。将spring-boot-dependencies和spring-cloud-dependencies作为依赖关系管理的基础是非常好的选择。因为Spring Boot、Spring Cloud使用比较广泛，社区能够及时修复兼容性问题，开发者只需要升级Spring Boot、Spring Cloud版本即可，而无需关注被其依赖的其他三方软件的版本号。
升级三方软件，能够推动软件的持续改善，但是也需要进行一些工程能力的提升，例如自动化测试能力的建设。
关于三方软件管理的更多内容，请参考[Java Chassis兼容问题和兼容性策略](https://servicecomb.apache.org/references/java-chassis/zh_CN/featured-topics/compatibility.html)。
