我只想说我爱 Go。我用它已经 8 年了,我爱它作为一种语言。我希望能够以 Go 开发人员的身份结束我的职业生涯,我太爱它了。
然而,我接手了很多项目,我觉得 Go 可能不是最合适的。我只是想回顾一下我觉得 Go 不太擅长的事情。
- 业务领域繁重的应用程序:如果你的大部分开发工作是更新应用程序的业务逻辑,我觉得 Go 在这方面表现不佳。这主要是因为你正在更新一些 JSON 模式或转换一个模式。我几乎觉得 Go 在这方面表现不佳。代码看起来非常笨重。这也是我见过的一些最糟糕的 Go 代码的来源。由于 Go 的局限性,我看到了很多难以阅读的临时实现。我在这里看到了很多接口污染
- 前端/Gui:我知道 Go 有一些前端和 Gui 框架。但在大多数情况下,我发现很多 Go 原语在这方面效果不佳。一个是垃圾收集器。我觉得桌面应用程序需要这个。我知道 C# 经常使用这个。但 C# 很好地利用了许多 UI 框架,底层运行时(如 .NET)似乎优化了 C# 代码。Java 有类似的限制,但 Java 在第一天构建时就考虑到了 UI 开发。因此它的运行时对此进行了更多的优化。
- 数据工程:类似于业务规则。这需要大量的数据转换。大量的数据解析。
- 游戏开发:我认为垃圾收集器会在这里成为你的阻碍。简单的游戏可能不是问题。但任何需要使用 OpenGL 或任何其他类型的渲染器的东西都行不通。C# 用于游戏开发,当然它也有 GC。但很多时候 C# 在游戏引擎上运行,因此这些优化是在幕后完成的。如果你不使用引擎,几乎每个人都会使用手动内存管理。
- 嵌入式系统:我知道有 tinyGo。我已经很多年没听说过它了。但仅基于其默认工具包的 Go 似乎在这里无法很好地工作。但这不应该太令人惊讶。
我觉得 Go 非常适合网络编程、API 开发以及需要非常良好和高效的网络 I/O 的东西。但它感觉不像是一种出色的商业语言。
网友:
1、我一直在使用 Go + Templ + HTMX,它对于前端来说非常好,但我认为如果你想做非常复杂的事情,它就有其局限性。
不过,我敢打赌,对于绝大多数网站来说,这已经足够了。而且与 NodeJS 或 PHP 选项相比,性能要快得多。
2、适合Go:
预期会有大量连接的系统:
我经常编写防火墙或代理,它们在用户空间中每个连接的实际工作很少(因为存在 splice)。这意味着来自 goroutines 与无堆栈协程(C++、Rust)的所有额外堆栈空间加起来。
任何进行大量数字运算的事情:
当您将 90% 的运行时间花在函数上时,您确实希望编译器对某些函数进行大量优化。Go 并没有真正做到这一点的编译器杠杆。
大型分布式系统:
如果将 GC 暂停置于微服务长链的深处,则会产生连锁反应,如果 GC 暂停发生在错误的时间,实际上可能会导致故障。Go 在这方面比其他语言更好,但这使得它不那么常见,而不是不存在。
任何分配了大量内存的程序:
如果分配了数百 GB 的内存,GC 的时间复杂度与需要扫描的内存量有关,这一事实非常糟糕。如果跨越 NUMA 节点,情况会变得更糟。
与 ML 系列语言(Rust、Scala、Ocaml)相比,Go 解析数据的能力并不好,速度也不够快(但这并不重要)(C++)。这意味着它的生产力和性能都比其他选择更差。
如果您需要非常高的可靠性。BEAM 语言(erlang、elixir、gleam)在这里是王者,因为 BEAM 运行时设计为 7 个 9,您可以构建基本上不可能完全推翻的系统。Go 从 Elixir 吸取了一些教训,但它错过了对可靠性很重要的其他东西。
3、我想要的商业业务应用程序是:
- 使用 TypeScript 进行 Node.js 开发的速度
- Go 的垃圾收集器和 MPMC 通道
- Rust 的安全可变性和无畏并发性
- Java 中的名义类型
- Scala/Akka 序列化
- 事务对象模型来自...呃,可能是 MUMPS 或者 Virtuozzo 对象 DB?
4、我对 Go 的经验很少,大部分经验都在 .NET 和 JS 方面。我曾在 .NET 中做过 DDD,效果很好。
我对 Go 的体验更多是数据驱动的,但其中有一些领域逻辑,说实话有点乱。不过问题不在于语言,因为我在 Go 中找到了 DDD 示例,看起来很棒。使用 Golang 搜索 DDD,我相信你会找到很棒的例子。
问题是你需要明确并使用抽象和设计模式。我注意到,倾向于使用 go 的人这样做是因为他们不喜欢复杂的抽象或过于抽象的代码。
我认为 golang 可以很好地与业务领域繁重的应用程序配合使用,但这需要非常有目的性。
5、为何Go不适合业务领域重度应用?
我花了十年的时间来编写这种类型的 Go 代码。
问题是人们已经看到了用类型系统(主要是 java)做到这一点的方法,而很长一段时间我都觉得 go 做得不够好。
后来我明白了:
- Go的类型完全是为了程序的执行而存在的,如果类型不对,就会出现问题。
- 而数据是有边界的,是为业务而存在的参数, 如果数据不符合验证要求,则应编写逻辑来处理。