Go语言本身并不推崇框架,但团队仍然需要框架。
Go 语言功能强大,以其简洁性、速度和并发模型而闻名。但 Go 社区历来强烈反对框架和集中式约定——而这正是许多团队,尤其是那些来自 Rails、Django 或 FastAPI 等结构化环境的团队,遇到瓶颈的地方。
本文探讨了 Go 开发中的结构性缺陷,以及它存在的原因,并阐述了 Encore 如何通过约定驱动的框架来填补这一空白,从而为后端开发带来清晰度、一致性和生产力。
Go:功能强大、设计简约且不带任何主观色彩
虽然没有明确的风格指南,但围棋确实存在一种可辨识的“风格”。——
围棋官方网站 - 常见问题解答
Go 从诞生之初就旨在避免大型框架通常带来的复杂性。它的创建者有意省略了许多东西——项目结构、路由、迁移、后台处理——以便赋予开发者更大的自由度和灵活性。
这种理念确实有很多好处。Go 语言的简洁性使其易于学习。它的并发原语(goroutine 和 channel)优雅且高效。而且它的标准库也十分完善且高效。
但许多团队已经亲身体验到:语言层面的极简主义并不会轻易扩展到团队层面。
框架存在的意义
Ruby on Rails 或 Django 等框架的存在是有原因的:它们编码了最佳实践,减少了样板代码,并通过为你做出数千个决定(关于命名、文件夹结构、路由、测试以及如何将所有内容粘合在一起的决定)来帮助团队更快地前进。
他们提供的正是 Go 刻意避免的东西:观点。
使用 Rails 或 Django,您可以获得现成的结构、默认设置和集成工具。而使用 Go,您则需要从零开始构建。
而这种空白的状态既可以让人感到自由,也可以让人感到无所适从。
问题:Go 留下了太多自主权。

图片来源:cartoonresource / Adobe Stock
对于个人开发者或小型项目而言,Go 语言缺乏结构似乎并非问题。但对于构建复杂系统的团队来说,这会在各个方面带来摩擦和效率低下。
以下是各团队经常遇到的问题:
1. 没有共同约定
项目布局、文件结构、服务边界,甚至HTTP处理程序的编写方式都没有统一的标准。这导致:
- 关于建筑的内部辩论
- 具有自定义布局的“雪花”服务
- 由于每项服务各不相同,因此入驻成本较高。
2. 决策过多,指导不足
在 Go 语言中,许多常见任务(例如后台作业、数据库迁移和路由)都是通过第三方库而非内置工具来处理的。虽然 Go 生态系统提供了许多高质量的选择,但并没有一个统一的“Go 官方认可”的方案或集成框架,因此团队通常需要花费大量时间研究库、将它们集成在一起,并维护不同服务之间的一致性。
3. 基础设施是自己动手做的
由于 Go 的文化刻意反对框架,大多数团队最终都会自己构建所有东西。这通常意味着要把宝贵的开发时间浪费在无法创造任何独特产品价值的任务上:
- 编写样板代码以连接服务并处理诸如追踪和身份验证之类的横切关注点。
- 每个环境中对密钥和配置的管理方式都不同
- 使用 Terraform、Docker 和 CI/CD 脚本等工具手动组装基础设施
4. 团队渐行渐远
如果没有强制性的结构,代码库就会出现分歧。负责不同服务的团队会形成自己的规范。正如一位工程师所说:“每个 Go 服务都像是一个独立的小世界。”
一些团队是如何解决这个问题的:通过 Encore.go 引入结构化方法
Encore.go就是一个旨在帮助团队更顺利地过渡到 Go 语言的框架示例。Encore
为团队提供约定、内置工具和云原生默认设置,从而消除样板代码并降低 DevOps 开销,使开发人员能够专注于构建产品,而不是底层架构。
“如果没有 Encore,我们根本不可能在这么短的时间内开发出我们的电子书产品。它为我们提供了所需的清晰思路、工具和稳定性。”
——Bookshop.org 首席技术官 Mason Stewart
Encore 包括:
- 内置功能:身份验证、路由、数据库迁移、服务间连接处理等。
- 约定驱动开发:定义 API、服务、测试、集成基础设施等的约定。
- 无需配置:只需一条命令即可启动本地环境,包括所有基础设施。
- 可观测性:跟踪、指标和结构化日志记录默认包含在 Encore 的开发仪表板中。
- 云原生设计:支持 Docker 或通过 Encore Cloud 自动部署到 AWS/GCP。
一些团队并没有从零开始使用原生 Go,而是使用 Encore 来逐步采用 Go,而无需放弃他们已经习惯的结构。
以下是它在实践中可能呈现的样子:
代码示例
定义服务
Encore 将 Go 包识别为一项服务。运行或部署应用时,它会自动配置所需的基础设施并生成连接模板。
/my-app
├── encore.app // ... and other top-level project files
│
├── hello // hello service (a Go package)
│ ├── hello.go // hello service code
│ └── hello_test.go // tests for hello service
│
└── world // world service (a Go package)
└── world.go // world service code
更多详情请参阅应用程序结构文档。
定义 API
使用该//encore:api注解,您可以用纯 Go 语言定义 API 端点:
package hello // service name
//encore:api public
func Ping(ctx context.Context, params *PingParams) (*PingResponse, error) {
msg := fmt.Sprintf("Hello, %s!", params.Name)
return &PingResponse{Message: msg}, nil
}
Encore 会自动生成所需的样板代码和文档。
请参阅定义 API 的文档了解更多信息。
本地运行
只需运行:
encore run
Encore 将自动设置本地基础设施和本地开发仪表板,其中包含 API 文档、架构图、跟踪和日志。
云部署
使用 Encore 的开源工具构建 Docker 镜像,或者选择Encore Cloud,实现基础设施的自动配置和部署到您在 AWS 或 GCP 上的云平台。
真正的团队,真正的影响
Bookshop.org
Bookshop.org为了提高可扩展性,开始从 Rails 迁移到 Go。但团队很快意识到 Go 的极简主义是有代价的。
“我们没有沿用以往的约定,这导致我们的应用程序出现不一致的情况。虽然 Go 生成的是单个二进制文件,但仍然需要大量的 Terraform 和定制部署工作。”
——Mason Stewart,Bookshop.org 首席技术官
采用 Encore 后,他们重新获得了 Rails 的结构和生产力,并且通过 Encore Cloud 实现了 Go 和 Google Cloud Run 的自动化,从而节省了大量资金。
“与我们原有的 Rails 应用相比,我们预计每年可节省超过 6 万美元。”
——Bookshop.org 首席技术官 Mason Stewart
奎库普
Quiqup使用 Rails 时遇到了性能瓶颈,希望迁移到 Go,但又不想承担微服务的额外开销。Encore 的模块化单体架构完美地解决了这个问题。
“我非常喜欢Encore的模块化单体架构理念。微服务架构过于臃肿,需要庞大的团队才能管理;而单体架构本身也存在一些问题。Encore完美地平衡了这两者。”
——Danny Hawkins,Quiqup首席技术官
如今,Quiqup 运行着 30 多项服务和 200 多个 API 端点,却没有专门的 DevOps 工程师,这要归功于 Encore Cloud 的自动化基础设施和可观测性。
“如果我们不借助 Encore 就让用户上手 Go,那么他们开始高效工作所需的时间将是现在的 2 到 3 倍。”
——Quiqup 首席技术官 Danny Hawkins
底线
Go 的极简主义是一个强大的特性——但如果它拖慢了团队的进度,那就不是了。
Encore.go提供了 Go 所缺乏的结构、默认值和工具,帮助团队更快地交付产品,减少 DevOps 方面的麻烦和重复工作。
这不是要取代 Go 的优势,而是要避免每次都强迫每个团队重新发明相同的基础。
文章来源:https://dev.to/encore/go-doesnt- believe-in-frameworks-but-teams-still-need-them-2ikm



