标签 dep 下的文章

Go语言有哪些“劣势”

img{512x368}

本文源于笔者对知乎上的一个问题“Go有哪些劣势?”(https://www.zhihu.com/question/300163211)的一次回答(https://www.zhihu.com/question/300163211/answer/1632229924)。当时随手花几分钟在手机上写了一些点。但事后我觉得应该再做一些系统地思考。在这里我就将更系统地思考后的答案整理并分享给大家。

关于Go语言,我是喜欢的,甚至可以算作“鼓吹者”阵营的一份子。但我一贯秉承“Go并非完美语言”这个观点来尽可能客观地看待Go。每种编程语言都有自己的劣势,Go也不例外,下面我们就来列举一下Go的那些“劣势”:

1. 技术路线选择导致的“性能劣势”

众所周知,Go是带垃圾回收的编程语言,因此不管Go的STW(Stop The World)的时间有多么短,GC的延迟有多么的小,它依然属于GC类编程语言,和Java、C#属于一个阵营,同时天然与C、C++、Rust这样的手动管理内存、没有运行时GC负担的编程语言之间划清了界线。虽然Go语言的初衷是成为系统级编程语言(关于Go语言的诞生语言演化历史,可以参考我的技术专栏文章“Go语言的前生今世” https://www.imooc.com/read/87/article/2320 ),虽然Go的运行时性能可以满足99.99%的场合的需要,虽然百度的万亿流量转发引擎BFE、时序数据库influxdb、分布式关系数据库TiDB等性能敏感的项目都选择了用Go实现,但不能否认的是在一些性能超级敏感的场合,选择Go依然要慎重。

2 坚持自己的设计哲学所带来的“表达劣势”

1) “单一”的表达方法

很多从其他语言转到Go阵营的开发人员抱怨Go能玩的花样太少,套路不多,Go之所以表现出“表达劣势”,源于其设计哲学中的一个原则:“崇尚一个事情只有一个或少数几种写法”。这个原则不符合某些开发人员炫技的心理需求,于是Go就被诟病为是资质平平的程序员才会去用的语言

Go 1.18将加入泛型(类型参数),这算是对此类“劣势”的一个“弥补”。不过对于我们这些对Go价值观和设计哲学认同已久的Gopher而言,我们十分担心大幅提高Go表达能力的泛型将成为奇技淫巧的“滋生地”

2) “过时”的显式的错误处理

Go语言从诞生那天起就没有像C++、Java、Python等主流编程语言那样提供基于异常(exception)的结构化try-catch-finally错误处理机制,Go的设计者们认为将异常耦合到程序控制结构中会导致代码混乱。Go提供了一种简单的基于错误值比较的错误处理机制,这“强迫”每个Go开发人员都必须显式地去关注和处理每个错误,经过显式错误处理的代码会更为健壮,也会让Go开发人员对这些代码更有信心。但这一设计哲学的坚持却被很多来自其他语言的开发者嘲笑为“过时”,被称为“半个世纪前的古老机制”。(笔者注:二十世纪70年代C语言诞生时采用的错误处理机制)

Go开发团队也曾“动摇过”,Go开发团队在发布Go2计划后曾发布过多版Go错误处理的新机制草案。Go社区也针对此问题做过长时间的讨论甚至是“争吵”,知名Gopher Dave Cheney发声、Rob Pike发声,著名Go培训师、《Go语言实战》联合作者之一的威廉·肯尼迪(William Kennedy)更是在Go团队try 提案公示之后,发表了对Go社区的公开信反对try方案(更多内容可参考笔者的专栏文章“if err != nil 重复太多可以这么办”(https://www.imooc.com/read/87/article/2434),最终坚持Go设计哲学的一派占据了上风,try提案被否决,没有加入到Go 1.13版本中!

3. 背离主流的“小众劣势”

Go早期设计的包依赖管理机制的确存在不小的“瑕疵”,这源于Google内部大单一代码仓库与基于主干的开发模型的影响。走出Google的Go语言听到了不同方面的声音,Go包管理机制长期无法满足社区的需求。于是先后出现了vendor机制dep等对包依赖管理的改进尝试。

2018 年初,正当广大gopher们认为dep将“顺理成章”地升级为go官方工具链的一部分的时候,Go核心团队的技术负责人,也是Go 核心团队早期成员之一的Russ Cox在个人博客上连续发表了七篇文章,系统阐述了Go团队解决“包依赖管理” 的技术方案: vgo,即go module的前身。

vgo的主要思路包括:语义导入版本 (Semantic Import Versioning)、 最小版本选择 (Minimal Version Selection) ,这些都与当前主流编程语言的包依赖管理的规则相悖,尤其是最小版本选择(MVS),算是另辟蹊径,背离主流!(更多关于go module最佳实践的内容可以参考我的专栏文章“与时俱进!使用module管理依赖包”(https://www.imooc.com/read/87/article/2476))。

4. Go核心团队的“民主集中制”导致的“社区劣势”

和Rust团队广泛采纳社区建议“猛加语言特性”不同,Go像是另外一个极端:Go核心团队对语言演化的把控力十足,不是社区多数人赞同的就一定会被采纳而加入Go语言,我这里将其戏称为“民主集中制”吧,即真正的投票权其实在Go核心团队的代表社区的少数人手中。

2018年初的dep与vgo之争就是这一“劣势”的典型表现。社区费劲一年多努力精心打造的dep项目被Russ Cox等少数人集中花掉一些时间设计出的vgo给“挤出”了Go包依赖管理工具标准的位置,成为了Go module成功的“垫脚石”。即便最终证明Go团队使用go module的决策的结果是正确的,但 这导致的Go社区与Go核心团队的“裂痕”是确确实实存在的,以致于这两年Go核心团队极力改善与Go社区的关系,规范化和透明化Go proposal的提出、review和接纳流程。

5. 全面出击失败后,期望的落空导致的“功能孱弱劣势”

Go 1.5发布之后,由于实现了自举和GC延迟的大幅下降,Go受关注程度逐渐升高,直至2017年初第二次拿到TIOBE年度最佳编程语言,让Go语言有些“膨胀”,甚至狂热的Go鼓吹者曾一度希望Go一统江湖:不仅牢牢把持住自己的云原生市场,占领Java的企业级市场,还要在终端(android. ios)、前端(js)上击败现有对手。

有人可能觉得我的上述说法可笑,但这些说法并非空穴来风。Go语言在终端、前端方面还真的曾经发过力,了解Go历史的都知道,Go团队曾经有全职开发人员参与gomobile项目(http://golang.org/x/mobile),该项目旨在构建在Android和iOS上的Go技术栈,实现用Go语言编写终端应用的目的。

在前端方面,gopherjs项目(https://github.com/gopherjs/gopherjs)可以将go代码编译为js代码并运行于各大浏览器中。后来gopherjs的作者又帮助go项目原生支持webassembly,支持将go编译为webassembly运行在浏览器中。

但上面的尝试最终没能“得偿如愿”,现状是在终端、前端应用领域,使用Go编码的人少之又少。于是Go又逐渐冷静下来,回到自己擅长的主力战场,回归到了企业级应用、基础设施、中间件、微服务、命令行应用等领域,并且在这些领域取得了越来越多开发者的青睐。

但曾经的全面出击失败给很多开发者留下了“Go功能孱弱”的口实,甚至有人说亲爹Google也没能让亲兄弟Android给Go走个后门。

小结

记得有人问过Go核心开发团队这样一个问题:未来Go语言演化之路上最困难的事情是什么?Go团队的回答是:使Go语言一直保持简单

在本文列出的几点“劣势”中,除了第一点的性能劣势和最后两点有待商榷外,其他几点对于不爱Go的开发人员来说,这些的确都是“劣势”。但对于真正认同Go价值观和设计哲学的开发者而言,这些难道不正是Go语言的“优势”吗!


“Gopher部落”知识星球开球了!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!星球首开,福利自然是少不了的!2020年年底之前,8.8折(很吉利吧^_^)加入星球,下方图片扫起来吧!

Go技术专栏“改善Go语⾔编程质量的50个有效实践”正在慕课网火热热销中!本专栏主要满足>广大gopher关于Go语言进阶的需求,围绕如何写出地道且高质量Go代码给出50条有效实践建议,上线后收到一致好评!78元简直就
是白菜价,简直就是白piao! 欢迎大家订阅!

我的网课“Kubernetes实战:高可用集群搭建、配置、运维与应用”在慕课网热卖中,欢迎小伙伴们订阅学习!

img{512x368}

我爱发短信:企业级短信平台定制开发专家 https://51smspush.com/
smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。

2020年4月8日,中国三大电信运营商联合发布《5G消息白皮书》,51短信平台也会全新升级到“51商用消息平台”,全面支持5G RCS消息。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

我的联系方式:

  • Gopher Daily(Gopher每日新闻)归档仓库 – https://github.com/bigwhite/gopherdaily
  • 微博:https://weibo.com/bigwhite20xx
  • 微信公众号:iamtonybai
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • “Gopher部落”知识星球:https://public.zsxq.com/groups/51284458844544

微信赞赏:
img{512x368}

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

vendor目录是否需要提交到代码库中?答案全在这一篇

img{512x368}

如果您还在使用vendor机制管理依赖包,那么说明您肯定是处于下面两种情况之一!

  • 还工作在传统的GOPATH模式下(使用Go 1.10及之前版本;或Go 1.11及之后版本,但GO111MODULE=off),利用vendor管理目标包的特定依赖;
  • 工作在go module模式下,但仍然利用vendor管理目标module的特定依赖并使用go build -mod=vendor来构建。

那么我们是否应该将项目中存储依赖包的vendor目录提交到源代码仓库进行管理呢?如果让笔者给出答案,那就是:应该

要想理解为什么“应该”,我们看看下面Go语言包依赖管理的演化过程就知道了。

Go语言在构建设计方面深受Google内部开发实践模型的影响。

img{512x368}

Google内部基于主干的开发模型:
– 所有开发人员基于主干trunk/mainline开发:提交到trunk或从trunk获取最新的代码(同步到本地workspace)
– 版本发布时,建立Release branch,release branch实质上就是某一个时刻主干代码的快照;
– 必须同步到release branch上的bug fix和增强改进代码也通常是先在主干上提交(commit),然后再cherry-pick到release branch上

Go最初的构建管理以及go get就采用了基于Google内部单一代码仓库(single monorepo)和基于主干(trunk/mainline based)的开发构建模型。具体逻辑是:在Go 1.5版本之前,go get获取的都是各个Go包所在仓库的trunk/mainline的最新代码。go get会将获取的最新代码放在\$GOPATH/src下面,而go build会在\$GOROOT/src和\$GOPATH/src下面按照包导入路径(import path)去搜索这些包并执行构建操作。

我们看到1.5版本之前Go编译器都是基于目标Go程序依赖包的trunk/mainline上的最新代码去编译的,这样的机制带来的问题是显而易见的,至少包括几点:

  • 因依赖包的trunk的变化,导致不同人获取和编译你的包/程序时得到的结果实质是不同的,即构建结果不能重现;
  • 因依赖包的trunk的变化,引入不兼容的实现,导致你的包/程序无法通过编译;
  • 因依赖包演进而无法通过编译,导致你的包/程序无法通过编译。

为了实现可重现的构建(reproduceable build),Go语言于1.5版本引入了vendor机制:即Go编译器会优先在vendor目录下搜索依赖的第三方包,这样如果开发者将特定版本的依赖包存放在vendor下面并提交到代码仓库,那么所有人理论上都会得到同样的编译结果,从而实现可重现的构建。

在Go 1.5发布后的若干年,Gopher们把注意力都集中在如何利用vendor解决包依赖问题,从手工添加依赖到vendor、手工更新依赖,到一众包依赖管理工具的诞生:比如: govendorglide以及当时号称准官方工具的dep,都在努力地尝试着按照当今主流思路解决着诸如:“钻石型依赖”等难题。

但Go核心开发团队没有走寻常路,而是另辟蹊径地在Go 1.11中引入了采用了最小版本选择(mvs)的go module。至此,Go的构建模式被一分为二:gopath mode和module-aware mode。在module-aware mode下,Go构建工具链默认不再使用传统GOPATH下或顶层vendor下面的包了,而是使用\$GOPATH/pkg/mod下面的第三方依赖Go module的local cache。理论上,go module真正实现了“可重复的构建”,我们无需再使用Go 1.5引入的vendor机制了。但社区的反馈让Go核心开发团队将module顶层目录下的vendor目录保留了下来,主要考虑vendor还能在下面场合“发光发热”:

  • 保持Go1兼容性

可继续支持Go 1.5以后,Go 1.10之前的Go版本编译Go 1.11后续版本的源码(仅限于:启用了module并带有vendor)。

  • 支持离线构建(offline build)

module/包构建所需的全部依赖都放入了vendor目录,这样即便在无网络连接的情况下,我们依然可以进行module的构建。这尤其适合企业内部执行CI/CD的那些可能没有外网访问权限的主机。

  • 提高构建性能,缩短CI/CD时间

在CI/CD时,由于每次都是重新构建,在module-aware模式(非vendor)下,每次都需要重新下载依赖的module到本地,这样十分耗时。而采用vendor方式则无需下载依赖module,提高了构建性能,缩短CI/CD的时间。

  • 解决“消失的包/module”的问题

一些module/包在经年岁月后可能被从github等托管站点删除了,这时我们如果依赖这些module/包,我们将遇到构建错误(Go Proxy的存在显然让这种可能行极大的降低了)。而使用vendor已经将包/module存放到了本地(以及自己的代码仓库中),可以解决“包/module消失”的问题。

  • 快速分发module的所有依赖包

vendor目录下存放了当面module的所有依赖包(及版本),易于打包并分发。尤其对一些无法通过go get获取到的依赖包/module,这尤为适用。

上述“演化简史”反复提到了“可重复构建”,这就是Go核心团队先后推出vendor、go module所基于的核心“痛点”。并且“可重复构建”不单单是个人行为,更多是一个“团队(可以扩展到整个Go社区)”行为:让团队所有人拿到同样的代码并构建出同样的成果物。这样来看,如果不将vendor提交到源码仓库,我们就无法实现这一目标

在将vendor提交到代码仓库过程中,你也许会抱怨依赖的代码包太多、依赖变化频繁的问题。但go module所使用的“最小版本选择”已经将依赖变动降低到不能再低的程度了,至少比采用主流“依赖管理”思路的其他语言,比如js,构建时面临的变动要少很多了。另外降低依赖的代码包的数量也是你自己的责任,Go是“自带电池”的编程语言,其标准库中有很多优秀的包可用,尽量使用标准库包以降低过多的“依赖”。

更多关于Go module和包依赖管理的内容,请查看技术专栏《改善Go语言编程质量的50个有效实践》


“Gopher部落”知识星球开球了!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!星球首开,福利自然是少不了的!2020年年底之前,8.8折(很吉利吧^_^)加入星球,下方图片扫起来吧!

我的Go技术专栏:“改善Go语⾔编程质量的50个有效实践”上线了,欢迎大家订阅学习!

img{512x368}

我的网课“Kubernetes实战:高可用集群搭建、配置、运维与应用”在慕课网热卖中,欢迎小伙伴们订阅学习!

img{512x368}

我爱发短信:企业级短信平台定制开发专家 https://51smspush.com/
smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。

2020年4月8日,中国三大电信运营商联合发布《5G消息白皮书》,51短信平台也会全新升级到“51商用消息平台”,全面支持5G RCS消息。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻)归档仓库 – https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博:https://weibo.com/bigwhite20xx
  • 微信公众号:iamtonybai
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • “Gopher部落”知识星球:https://public.zsxq.com/groups/51284458844544

微信赞赏:
img{512x368}

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! 图片广告位1 图片广告位2 图片广告位3 商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats