Normal view

There are new articles available, click to refresh the page.
Yesterday — 2 January 2025Main stream

基于 Go 语言谈软件开发效率

By: kuanat
2 January 2025 at 19:11
kuanat:

基于 Go 语言谈软件开发效率

这个帖子的目的不是对比不同编程语言开发效率的高低。

这个帖子实际上讨论的是以下内容:

  • 软件工程中生产力消耗的占比

  • 语言层面如何改善生产力的利用率

  • Go 有何特殊之处

0x10 定义和量化生产力

以代码行数来衡量程序员的产出是非常可笑的指标,同理,以代码复杂度、语法糖支持来评价开发效率也很离谱。

如果一定要找一个量化指标来评价开发效率,那就是相同开发需求下所消耗的总人力。

实际上,从理解业务需求开始,到构思实现方式和架构占据了写代码这个过程中绝大部分时间。

如果考虑团队协作的一般场景,沟通成本又占据了团队人力消耗的一半(个人估计)。

也就是说,纯代码层面的效率提升即便优化到极致,对于整个开发成本的改善贡献可能远低于 10%。

0x20 编程语言真正的生产力

0x21 沟通成本

能看代码不求人才是最节省沟通成本的方式。

这里的反例就是互联网与工程化兴起之前的各种语言,需要通过外部工具、团队规则才能保证有效协作的各种脚本语言。

开发者讨厌屎山的深层原因还是代码不好读、不好改。

0x22 可读性

影响可读性的因素很多,这里简单列举几个:

  • 在没有 lsp 辅助的情况下,快速定位到方法的实现,即代码结构组织

  • 隐式控制流,在某些地方隐藏着初始化 init 逻辑,或者有非直接可见的构造、析构方法

人脑的栈空间是非常有限的,间接、隐藏信息越多,理解成本越高。

0x23 复用性

往小的方面说,直接复制其他代码引入项目算是复用。往大的方面说,包引入机制也是复用。

这里的重点是语言的官方仓库和工具链系统来一致化、规范化这个过程。

缺少官方包管理、没有官方工具链的各种语言都深受其苦。

0x24 编程范式与思想

面向对象的思想就是某个阶段编程语言带来的巨大进步。

在工程化成为现代语言标配的今天,组合替代继承也是巨大进步。

关于这一点我在其他帖子里有零散的论述,这里就不展开了。

0x30 Go 与生产力

我觉得这个部分是误解最多的,大多数的讨论都没有关注到真正的重点。

0x31 并发原语

Go 最重要的贡献之一是基于 chan 的思维模型:Share memory by communication

日常反复被强调的 goroutine 其实不重要,很多语言也可以有样学样。

通过 chan/goroutine 的结合,初学者即便不理解 race/signal/thread/shared memory 等等概念,一样可以快速、准确地写出并发逻辑。

0x32 显式控制流

没有魔法就是编程语言对开发者最大的尊重。

Debug 浪费的生产力往往会远超写代码的节省。

0x33 原生 tls

在网络编程的时代,原生 tls 才是真正的跨平台。

技术上跨平台的核心是交叉编译,工程上,保证一条命令构建全平台、全指令集,最后的障碍就是原生 tls 。

这里节省的是构建系统,一旦有了外部依赖,语言自身的工具链就不够用了。

0x34 快速编译

Go 从非常早期就是手搓编译器,而不是转换成 IL 交给通用编译器。缺点是各种语言特性、语法糖都会影响编译器的编写,优点是编译很快。

人类的多线程能力很差,现实任务频繁上下文切换会极大降低工作效率。

如果你曾经被 webpack 构建或者 rust 编译支配,你会理解快速编译、即时反馈的意义。

PS

这个帖子实际价值也就最后一个章节,还没有展开说。权当抛砖引玉,欢迎斧正。特地放到 Go 节点也是不想让话题沦为口水争论。

Before yesterdayMain stream

求教: golang error 和 log 的最佳实践思路

31 December 2024 at 13:40
Ayanokouji: 用 go 写业务时,遇到 error 时,大多数情况只能一路向上 return err ,我们基于这个场景讨论。

这个场景,和 java 写业务遇到的 checked exception 很类似,写代码时,只能一路向上 throw (或者 catch 住 throw new unchecked exception ),最终由框架统一处理。

如果遇到 go 遇到经验不足的开发者(比如以前的我),就会看到这样的错误日志:

Error: unexpected '>' at the beginning of value

Error: EOF

Error: wrong argument value

嗯。。。这 tm 是啥啊,到底是哪一行代码出错啊。

调用链越长,问题越难排查。

比较通用的 web 业务调用链,一般是 handler -> service -> 中间件(数据库/redis/第三方 api 等)

随着坑踩的多了,现在遇到 err, 一般是 return fmt.Errorf("xxx:%w", err)

日志一般在 handler 层 slog.log("xxx", slog.Any("request", req), slog.Any("err", err))

但是缺少了调用栈,总觉得少了点什么。

请教下各位,如何平衡 error 和 log ,主要是服务于问题排查。

看过 echo 和 huma 的框架 error 处理,都是自定义 err ,框架统一处理

------

ps:那些上来只踩一脚 java 的,还是去多写写代码吧,这种 err ( unexpected '>' at the beginning of value ) 真的比 excetiop (含调用栈) 强吗。

go 没有异常 怎么判断逻辑以外的错误 全局的处理

By: dzdh
28 December 2024 at 14:17
dzdh:

比如数据库服务吧。

程序启动,先连 db 。连成功。启动 web 服务。然后 setup 路由啥的一堆。

好,服务启动成功了。

现在接受 http 请求,此时数据库崩了。

gorm 返回了 err 。比如代码如下

// userRepository.go
func GetUser(uid int64) (*User, error) {
    user:=new(User)
    if err :=db.model(user).Find(user).err; err != nil {
        return nil,err
    } else { return user, nil }
}

按照 java/php 这种的逻辑。我可以抛出个异常。然后有个地方是处理这个特殊的异常。返回 500,db no connection 。

go 里边咋做呢?现在数据库崩了以后,被业务中间件拦截到了 返回 401 unauthorized 。

repository 由 http 服务调用。我要直接 panic 吗 0.0 http 的中间件 recover 住判断 err 是哪种错误? 这么粗暴的吗?

❌
❌