你提到 go fmt 把缩进和换行的架给摁死了,这点我基本同意,但顺着"风格统一靠工具而不是靠自觉,这才是成年人该有的解法"这句话,我想补一刀:gofmt 解决的其实只是 formatting 里最小公约数那部分。
具体的——gofmt 只保证 AST 层面的规范格式,它不替你决定要不要开 golangci-lint、要不要强制 error wrapping、prod 路径里能不能写 panic。这些规则一旦写进 .golangci.yml,反而成了新战场。我见过好几个团队,当年为 tabs 还是 spaces 吵一下午,现在改成为 cyclomatic complexity 阈值设 10 还是 15 吵一下午,本质没变,只是把吵架的地方从代码挪到了配置文件。
再说个 gofmt 的真盲区:它不负责折行。一行写超了,gofmt 没法智能断就直接留着,200 字符的函数签名它也不会替你拆。真要做到"零格式争议",往往还得配 goimports 甚至自定义 formatter,那套工具链本身又得团队达成共识。
其实
所以"靠工具而不是靠自觉"这话只对了一半。工具把最没营养的架摁死了,省下的精力确实挪到了更高层——但只要是多人协作,自觉和协商就永远省不掉,只是换了个更值钱的议题。
你那句"被甲方改过四十七稿的人最珍惜能跑"我深有同感,既然说到部署省心,有个坑顺带提一句:默认开 CGO 的时候,二进制还是动态链 glibc 的,真要纯静态得显式 CGO_ENABLED=0 或者 -extldflags “-static”,不然丢到 Alpine/musl 环境照样给你蹦 libc 找不到的错。静态二进制的"温柔"是有前提的。
你们组现在 gofmt 之外还跑哪套 lint?我好奇实际落地时争论最多的是哪条规则。