关于使用第三方库、代码复用的一些思考
不管是不要重复造轮子
,还是站在巨人的肩膀上
,对于软件开发来说,代码复用都是最基本的原则之一。
代码复用,可能是DRY(dont repeat yourself),也可能是使用别人的代码,或者是开源项目,或者是其他团队提供的组件、服务,或者是团队内他人实现的公共模块,这些复用大大减少了项目的开发周期和成本。
但怎样才算是高效、正确的第三方代码使用姿势呢?在实操中,也会出现一些使用第三方代码导致失控的情况,比如使用了一些第三方代码,但年久失修,当线上事故貌似与第三方代码有关时,无法快速定位、解决问题。
本文是阅读《clean code》的第八章边界(Boundaries)
时的一些思考。
本文地址:https://www.cnblogs.com/xybaby/p/11372846.html
本文将复用的代码分为两类:
- 一类是团队外的代码,具体指第三方库、开源库、公司内其他团队的通用组件,其特征是,这样的代码往往需要做的比较通用,大而全;项目团队只是使用者,很难从根本上影响其设计或实现。
- 另一类则是团队内的代码,即项目团队成员自行封装的一些通用模块、通用组件,其特征是核心为项目服务,比较方便协商修改。
如何复用第三方库代码
这里的复用,不局限于代码,也包括可供远程调用的服务。一般来说,项目会调研、选择一些开源框架,也会使用公司内基础服务部门或者云计算上的一些服务,我觉得这都算复用。
最小化、集中化代码复用
第三方库往往追求功能(服务)的普适性,这样代码就能在多个环境中工作,吸引更多的用户。而使用者往往只需要满足特定需求的部分接口,对于不需要的功能(以及不建议的使用方式),对项目来说反而是负担,控制不当反而会带来风险。
比如redis,既能做内存数据库,也能持久化;既支持单点部署,也能通过sentinel、cluster提供高可用以及水平扩展;而且还支持pub-sub(以及比较新的stream)。但在我们的项目中,只用来内存缓存,而且对可用性、伸缩性也没有太大需求。
原则上,使用第三方库时,使用到的接口(服务)越少越好,将其封装到单独的文件(类、模块),在其他地方不能直接使用第三方库。通过适配,只将需要的部分功能纳入,不需要的功能(接口)不要暴露出来。
这样的好处在于入口统一,将所有对第三方库的使用集中到最少量的代码里面,便于维护。同时,这也是分层的思想,将业务代码与第三方库解耦合,便于替换实现。
learning tests
要将一个开源项目引入自己的业务代码,需要进行科学的调研和完备的测试。调研包括但不限于:与业务需求的重合度,开源社区的成熟度、活跃度等。而测试应包含以下几个方面
- 功能测试
- 性能测试
- 压力测试
- 故障测试
前两项是最基础的测试,主要判断是第三方库是否符合业务的功能、性能要求,同时掌握正确的使用姿势。而后两者,则常常是第三方库以单独的服务部署运行时的测试要点。
为了进行测试,我们会有一些测试代码,也许会参考项目自带的unittest、 code sample、tutorial、benchmark。但问题在于,这样的测试代码经常用完就扔,这样导致
- 如果后面出现问题,我们就需要不断调试,来确定是类库本身的问题,还是我们使用姿势的问题。
- 当地三方库升级之后,应用不敢跟着升级,因为没有手段保证新版本的类库提供了同等契约。
第二个问题我想很多很多人都会遇到,当依赖的第三方库升级的时候,项目是否跟着一起升级你?两种比较极端的策略我都遇到过,一种是始终更新到第三方库的最新稳定版本;另一种是基本不升级,自己维护某个特定版本。
learning test
能解决上述的第二个问题:
我们将所有的测试整理为一整套针对所使用的功能的单元测试,这些测试覆盖了我们对功能、性能、稳定性都诸多方面的需求。当第三方类库的版本更新的时候,我们只要把单元测试再跑一遍,就可以判断新代码的代码是否提供了同等的契约,也就可以比较安全的进行升级。
不难看到,上一小节,“集中化第三方代码使用”是learning test
的基础,让我们很清楚的知道应该对哪些接口进行测试,如果要扩展对第三方库的使用,也能很方便的增加、维护对应的测试。
如何复用团队内的代码
在团队内,也是非常鼓励代码的复用,比较常见的方式是形成各种通用的组件。那么,如果程序员A使用了程序员B提供的公共模块出了问题,那么责任该如何划分?
如果是开源代码,毫无疑问只能责怪使用者,但是在团队中,似乎并不能完全归咎于使用者。公共组件的使用者一般并不会对使用进行完整的测试,也会认为,“都是一个团队的,就应该提供者保证质量,方便快速使用”。
我认为,使用者的责任占主要,使用者应该就使用方式进行测试,如果提供者已经提供了相应的单元测试,而且能通过,那么就可以直接使用。否则应该添加对应的测试case,如果无法通过,则可以找提供者协商解决。对于通用模块、通用组件的提供者,也应该有义务提供高覆盖率的单元测试,一来开发的时候因为本身就会测试,并不会增加额外的工作量;二来是对使用者的一份正式的保证,也能增加自己在团队的影响力。