大海Online的博客

Looking for Interest

组件版本管理

组件版本管理

任何编程语言, 当组件有依赖关系+版本管理之后, 都会遇到同样的问题, 相依性地狱

常见的问题有:

  1. 循环依赖: A依赖于B, B依赖于C, C依赖于A, 相互循环依赖, 导致解析无法继续
  2. 版本不兼容: A依赖于B,C1, B依赖于C2, C1与C2不兼容时, 导致系统无法运行
  3. 依赖过多: 依赖的深度与广度都比较大, 导致系统过于复杂, 能性能调试带来诸多不便

比如:

  1. DLL, DLL初期缺少规化, 导致当覆盖或升级系统的DLL时, 经常出现冲突的情况
  2. JAR, 百家争鸣, 经常导致版本问题, 甚至象log4j,logback,jcf之间的纠缠
  3. js, 复杂的页面交互, 历史遗留问题, 经常导致loader后的几个js不兼容,而作者可能是同一人

同时也有一些版本库管理器

  1. APT, YUM linux上的软件包管理
  2. npm nodejs的软件包管理
  3. brew mac homebrew软件
  4. sublime 编辑器中的package control也算是
  5. maven jar包版本依赖管理
  6. eclipse-plugins 插件版本管理
  7. bundle ios.app, mac.app, 一种常用的app打包模式
  8. 还有很多很多

从已有的解决方案来思考下这个问题

  1. jar包以及java类都不会因循环依赖而导致问题, 因为依赖与运行解耦合了 考虑js.loader中的依赖, AMD因运行后才能得到依赖的module, 导致循环依赖不得不break 而CMD方案, 则提前将module设定为了{}, 少了点微不足道的功能, 但解耦合了, 从而可以将分析模块依赖与模块运行独立开来, 避免掉break
  2. 可以得出这样一个结论, 一个相互依赖+版本的组件库, 通常具备以下几个功能 a) 一个打包器, 通常由语言方制定好规范, 大家相互遵守 b) 一个版本管理工具, 通常会带有命令行, 可以查看树型依赖 c) 依赖的组件, 有远程仓库, 通过id, 可以通过http直接下载, 有中央仓库, 而大公司也喜欢制造自己软件仓库 d) 敲入安装命令后, 可以自行下载元信息, 分析依赖, 下载依赖, 执行初始化 e) 软件本身不参与自己的版本管理
  3. 版本不兼容的问题, 通常与实际情况有关, 很难有最佳实践, 向下兼容是比较靠谱的, 通常情况下, 一但不向下兼容, 通常都会在事后遇到依赖组件冲突问题, 除非完全统一升级 如果无法向下兼容, 那就另起炉灶吧, 换个名字, 换个命名空间, 换个全局变量
  4. 提前定义好接口规范, 小版本号bugfix, 中版本增加功能, 大版本号表示大幅重构或变更

因此:

  1. 在考虑是否采用版本号时, 首先要确定好, 是否有足够的精力去制造或者寻找一个合适的版本管理工具, 一个代码中央仓库, 一个有氛围的社区
  2. 如果没有, 就还是单版本吧, 一个稳定的核心, 每个组件都尽量只依赖于核心, 独立成单独组件, 不相互依赖, 采用简单代码冗余, 代替复杂版本管理

一句话: 要么简单, 要么复杂, 量力选择, 针对具体情况, 做出选择