当前位置: 首页 > 科技观察

Go语言创始人:抄几十亿代码,还不如用别人的轮子!

时间:2023-03-12 11:16:39 科技观察

大家好,我是炸鱼。平时我们经常上网,学习经验,知识,吃瓜。在代码界,有同学调侃我们是c+v(复制粘贴)工程师。我的专用快捷键:在Go语言中,有一句谚语也指出了“复制”的好处,叫做:“Alittlecopyingisbetterthanalittledependency”(复制一点比一点依赖好)。关键关键词是:复制、依赖。稍微复制一下vs引入依赖复制,只要核心能写一些短小精悍的代码就可以了,不需要直接导入一个库来做(只复制核心算法即可)。例如UUID的情况:funcmain(){f,_:=os.Open("/dev/urandom")b:=make([]byte,16)f.Read(b)f.Close()uuid:=fmt.Sprintf("%x-%x-%x-%x-%x",b[0:4],b[4:6],b[6:8],b[8:10],b[10:])fmt.Println(uuid)}虽然UUID的第三方库有很多,但是一般很多函数都堆积在一个库里,会引入很多不必要的新依赖。如果你只是想要一点新功能,你可以简单地自己实现,然后封装成公司内部的方法来引入。可以有效减轻依赖管理的负担,减少二进制文件的体积,带来更大的稳定性、安全性,测试第三方库大多不清楚。引入大依赖容易折腾的副作用是,当我们引用太多依赖它的东西时,会导致一个应用过度依赖的场景:比较经典的是微服务的依赖。更贴近我们的场景,就是Gomodules中自带的第三方组件库的版本相互制衡。最小版本选择下面介绍GoModules最小版本选择的计算规则,会带来版本间的制衡。一个模块往往会依赖很多其他的模块,不同的模块在依赖的时候可能会依赖同一个模块的不同版本,如下图(来自RussCox):上述依赖中,模块A依赖模块B和模块C,而模块B依赖于模块D,模块C依赖于模块D和F,模块D依赖于模块E,同一个模块的不同版本也依赖于相应模块的不同版本。那么此时如何选择Gomodules的版本,选择哪个版本呢?根据提案,我们可以知道Gomodules会整理出每个模块的依赖版本列表,最终得到一个构建列表,如下图(来自RussCox):我们看到粗略列表和最终列表,两者之间的区别是为了重复引用模块D(v1.3,v1.4),最终列表选择了模块D的v1.4版本。真实场景在GoRPC的使用中,gRPC的应用非常广泛。gRPC、grpc-gateway、protoc(含对应语言插件)、etcd版本可能不兼容。例如:gRPC本身会做一些实验性的包,etcd在v3之前对Gomodules没有很好的版本管理。在某些情况下需要库版本。在内部框架或应用程序中,我们经常通过go.mod声明使用的版本。但是,在存在“最小版本选择”的情况下,它遵循版本控制。一旦依赖的另一个库需要更高的gRPC版本,这种平衡就会被打破。上次看到是公司有人用了TIDB库,但是只用了某一个东东,却造成大量依赖版本被动升级。最后这位同学采取了一点点复制的做法,解决了增加很多依赖的副作用。综上所述,Go的谚语“一点点复制胜过一点点依赖”更多的是软件工程中的指导思想。当你只涉及一个非常简单的功能时,你可以自己实现或者复制核心代码。不需要直接导入庞大的第三方库,可能会带来很多奇怪的依赖,让你的编译构建变慢,依赖管理复杂。这是我们都需要思考的问题。