Posts List

Go 版本不一致?别慌,这是特性!

故事的开端:一场“奇葩”的争论 最近,我和一位可爱的同事,因为一个项目的 go.mod 文件,产生了一点小小的“学术分歧”。文件长这样: // go.mod go 1.21.1 toolchain go1.22.9 同事认为这种配置“非常奇葩”,并抛出了一个灵魂拷问:“你本地用 go1.22.9 的工具链编译,线上服务器(CI/CD 环境)用的却是 go1.21 的基础镜像来构建,这能不出问题吗?这不就是经典的‘我电脑上好好的’吗?” 说实话,我一开始还没 get 到他说的“线上版本”是啥,后来才明白他指的是我们项目构建镜像所基于的 golang:1.21。他的核心论点是:开发环境和生产环境的 Go 版本不一致,是危险的。 为了说服我,他甚至搬出了“AI 军师”,进行了一场“人机对话”。 AI 的“第一次接触”:危言耸听 同事提问: go.mod 中 Go 版本与 Toolchain 版本不一致会带来什么问题? AI 回答(摘要版): 哇,这可不得了!当 go 版本和 toolchain 版本不一致时,会引发一系列灾难性后果: 语言语义和编译行为不一致:编译器优化策略不同,二进制文件体积和性能会有差异。 API 可用性错配:旧工具链编译不了新代码,新工具链用了新 API 在旧环境也跑不起来。 依赖解析差异:go mod tidy 的结果可能不一样,go.sum 文件会在不同开发者之间反复横跳。 构建标志和行为变化:CI/CD 和本地产物的可复现性降低。 安全与合规隐患:你可能会错过新工具链里的重要安全修复。 团队协作噩梦:开发者 A 和 B 构建出的二进制文件性能、大小、告警都不同,定位问题难于上青天。 AI 总结: 为了天下太平,请务必保持版本统一!CI 用什么,你就用什么! 好家伙,这说得头头是道,一套组合拳下来,差点就把我打懵了。如果真如 AI 所说,toolchain 这玩意儿不就成了“潘多拉魔盒”? 我冷静下来,心中升起一个巨大的问号:如果版本不一致是原罪,那 Go 团队费那么大劲引入 toolchain 指令,难道是为了好玩吗?

NilAway:实用的 Go Nil Panic 检测方式

原文:NilAway: Practical Nil Panic Detection for Go 译者:madneal welcome to star my articles-translator, providing you advanced articles translation. Any suggestion, please issue or contact me LICENSE: MIT Uber 由于 Go 语言的高性能,广泛采用其作为实现后端服务和库的主要编程语言。Uber 的 Go monorepo 是 Uber 最大的代码库,包含 9000 万行代码(并且还在增长)。这使得编写可靠 Go 代码的工具成为我们开发基础设施的重要组成部分。 指针(保存其他变量的内存地址而不是其实际值的变量)是 Go 编程语言的一个重要组成部分,有助于高效的内存管理和有效的数据操作。因此,程序员在编写 Go 程序时广泛使用指针,出于多种目的,如原地数据修改、并发编程、数据共享优化、内存使用优化以及支持接口和多态性。虽然指针功能强大且被广泛使用,但必须谨慎和明智地使用它们,以避免诸如空指针解引用导致的 nil panic 等常见陷阱。 nil panic 问题 nil panic 是指程序尝试解引用一个 nil 指针时发生的运行时 panic。当一个指针为 nil 时,意味着它不指向任何有效的内存地址,尝试访问它指向的值将导致 panic(即运行时错误),错误信息如图 1 所示。 图 2 显示了在实现 Go 标准库(特别是 net 包)中发现并解决的最近一次 nil panic 问题 的示例。由于在第 1859 行直接调用了方法 RemoteAddr() 的返回值上的 String() 方法,假设它总是非 nil 的,如图2所示,从而引发了 panic。当接口类型 net.Conn 的字段 c.rwc 被分配给结构 net.conn 时导致了这个问题,因为如果发现连接 c 异常的话,它的 RemoteAddr() 的具体实现可以返回 nil 值(如图 3 所示)。具体来说,RemoteAddr() 可以在 L225 返回一个 nil 接口值,当被调用方法(.String())时,由于 nil 值不包含任何指向可以调用的具体方法的指针,从而导致 nil panic。

如何使用 Git 撤消(几乎)任何操作

原文:How to undo (almost) anything with Git 译者:madneal welcome to star my articles-translator, providing you advanced articles translation. Any suggestion, please issue or contact me LICENSE: MIT 任何版本控制系统最有用的功能之一就是能够“撤消”错误。在 Git 中,“撤消”可能意味着许多略有不同的事情。 当你进行新的 commit 时,Git 会及时存储你的仓库在该特定时刻的快照;之后,你可以使用 Git 返回到项目的早期版本。 在这篇文章中,我将介绍一些你可能想要“撤消”所做更改的常见场景,以及使用 Git 执行此操作的最佳方法。 撤销一个“public”修改 场景: 你刚刚运行了 git push,将你的修改 push 到 GitHub,现在意识到有一个 commit 有问题。你想把这个 commit 撤销。 撤销: git revert <SHA> 结果: git revert 将创建一个与给定 SHA 相反的新 commit。如果旧 commit 是“matter”,则新 commit 是“anti-matter”——旧 commit 中删除的任何内容都将添加到新 commit 中,而旧 commit 中添加的任何内容都将在新 commit 中删除。

基于golang实现报告生成技术方案

最近在做一个基于历史数据生成报告的需求,在做这个需求的时候遇到过一些小坑,所以想在这篇文章分享一下踩坑经验。 最初的需求是基于历史数据来生成一个 word 报告,这种需求其实在大多数应用中也算比较常见的需求。但是由于我们使用的语言是 golang,而 golang 关于 word 方面的轮子是少之又少,只有一个国外的商业产品以及极少的特别不成熟的库,比如做一些简单的文字替换的,这些都比较难以满足需求现状。也不可能为了这么个需求就造一个 word 方面的轮子,况且还不一定造的出来。这种方案实现,如果是使用 java 或者 python 会轻松很多,的确 golang 在某些方面的轮子还是存在缺失。后来想到的方案是,先渲染 html 模板,然后再把 html 转成 pdf。渲染 html 不然,基于 template,理论上可以实现任意文本格式文件的填充,但是转 pdf 又又涉及另外一个轮子,也是一番调研,有一些,但是不太多,看起来也不是特别好用。同时,这个方案也不是很优雅。就在一筹莫展之际时,我想到我们内部其实非常热衷于通过自研的 wiki 平台来分享报告,大家分享的时候也经常通过这个平台来直接链接。(其实中间也看了腾讯文档的开放平台,但是这个开放平台根本就不成熟,都没有开放写入的能力,只开放了创建文档的 API,不能写入,那能有啥用呢。)后来找对应平台的开发聊过,幸好他们提供写入的 API,这样实现报告的方案就实现了。平台支持 markdown 的语法,只需要通过 markdown 的语法来渲染好模板,然后写入就可以了。随便提一句,任何不支持 markdown 语法的编辑器都是极其不友好的,所以非常难理解当初 freebuf 改造 markdown 编辑器居然花了一两年的时间,不知道是如何做到的。其实,我自己都为这个方案拍案叫绝,不过这好像也是唯一能实现的技术方案,但在我看来,也是最优雅的实现方式。 这个需求另外一个小坑就是图标的实现。wiki 平台自身没有提供基于数据实现图表的功能,所欲图表的需求是需要我们自己来实现的。这种最能想到的方式就是基于数据生成图表的图片,然后插入到 markdown 中。在调研图表的方案中,是有看到一个 go-chart 的方案。但是这个库看起来可定制型不是很高。echarts 是前端领域大名鼎鼎的数据可视化方案,可以说的上是百度做的开源精品,现在已经属于 apace 基金维护的开源产品。go-echarts 是一个基于 echarts 的 golang,其本质应该还是通过 echarts 来渲染前端。所以在使用这个库的时候有一个问题,它不会直接生成图片,而是通过 html 来进行渲染的。那么在嵌入图表的时候就不能使用图片,但是正因为之前使用的方案是 markdown,且一般来说大多数 markdown 是兼容 html 的,所以只要将 html 通过 iframe 的形式嵌入,那么这个问题也就迎刃而解了。 <iframe src="%s" frameborder=0 width="1000" height="600"></iframe> 同时得益于 echarts 的灵活,这个方案也可以实现高度定制化的可视化方案。不过这个库并没有丰富的文档,大多数的使用教程都是通过 examples 里面的代码样例来进行说明,这个仓库里面有很多图表的各种形式展现的代码样例。不过在图表的时候也遇到一些问题。比如 x 坐标轴的 label 文字过宽,导致容器容纳有问题,这个一般的做法都是将 label 进行旋转,这在 echarts 里面也是比较常见的做法,在 go-echarts 里面有一定的配置语法。

持续发布 Chrome 插件

Chrome 插件对于 Chrome 浏览器用户来说是必不可少的利器之一。之前我有开发过一款七牛云图床的 Chrome 插件 image-host。后来由于我自己没有自己的域名,所以不太好使用这个插件了。后面,有其他的同学来提交 PR 来维护这一个插件。这样就有一个问题,一旦新的代码发布,就需要自己再重新发布一下插件。虽然发布插件不算特别麻烦,打包成压缩包,上传就可以了,但是对于程序员来说,可以自动做的绝对不要手动做。以下就是通过 CircleCI 来持续发布 Chrome 插件,参考了官方的文章,自己也才了一些坑。 介绍 CircleCI 是一款持续集成产品,和 Travis 非常类似,都属于 Github 上非常流行的持续集成产品。产品有商业和普通版本,开源项目是可以免费使用的。关于持续集成产品的不同,可以参考这篇文章。使用这个工具持续发布 Chrome 插件的原理就是:通过 CircleCI 来使用 Chrome 插件的 API 来持续发布插件,通过 CirecleCI 和 github 的集成可以在特定的时机就可以发布插件。那么下面具体介绍如何使用 CircleCI 来进行 Chrome 插件的发布,主要包括 Google API 的配置以及 CirecleCI 的配置。 Google API 首先,创建一个 Google API 项目,可以直接点击这个链接创建。 在创建项目之后,我们需要开启 “Chrome Web Store API”。在 Library 中搜索这个 API, 并且将其 ENABLE。 在 ENABLE 这个 API 之后,就可以点击 “CREATE CREDENTIALS” 创建口令了。确保你已经选择了对应创建的 project。值得注意的一点是,你创建的应该是 OAuth client ID 类型的,确保你选择了正确的类型。