Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Go 应用程序设计标准

Go 应用程序设计标准

作者头像
frank.
发布于 2022-05-17 03:47:50
发布于 2022-05-17 03:47:50
23400
代码可运行
举报
运行总次数:0
代码可运行

01

介绍

众所周知 Go 语言官方成员 Russ Cox 曾向 Go 社区回应并没有 Go 应用程序设计标准。但是,为什么本文还要使用这个标题呢?

因为团队达成一个共识(标准),制定一些团队成员都要遵循的规则,可以使我们的应用程序更容易维护。本文介绍一下我们应该怎么组织我们的代码,制定团队的 Go 应用程序设计标准。

需要注意的是,它不是核心 Go 开发团队制定的官方标准。

02

定义 domain 包

为什么需要定义 domain 包?因为我们开发的 Go 应用程序,可能不只是包含一个功能模块,并且可能不同的功能模块之间还需要互相调用,所以,我们需要 domain(领域)包,例如我们开发一个博客应用程序,我们的 domain 包括用户、文章、评论等。这些不依赖我们使用的底层技术。

需要注意的是,domain 包不应该包含方法的实现细节,比如操作数据库或调用其他微服务,并且 domain 包不可以依赖应用程序中的其他包。

我们可以定义 domain 包,把结构体和接口放在 domain 包,例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package domain

import "context"

type User struct {
 Id       int64  `json:"id"`
 UserName string `json:"user_name" xorm:"varchar(30) notnull default '' unique comment('用户名')"`
 Email    string `json:"email" xorm:"varchar(30) not null default '' index comment('邮箱')"`
 Password string `json:"password" xorm:"varchar(60) not null default '' comment('密码')"`
 Created  int    `json:"created" xorm:"index created"`
 Updated  int    `json:"updated" xorm:"updated"`
 Deleted  int    `json:"deleted" xorm:"deleted"`
}

type UserUsecase interface {
 GetById(ctx context.Context, id int) (*User, error)
 GetByPage(ctx context.Context, count, offset int) ([]*User, int, error)
 Create(ctx context.Context, user *User) error
 Delete(ctx context.Context, id int) error
 Update(ctx context.Context, user *User) error
}

type UserRepository interface {
 GetById(ctx context.Context, id int) (*User, error)
 GetByPage(ctx context.Context, count, offset int) ([]*User, int, error)
 Create(ctx context.Context, user *User) error
 Delete(ctx context.Context, id int) error
 Update(ctx context.Context, user *User) error
}

细心的读者朋友们可能已经发现,以上代码在「Go 语言整洁架构实践」一文中,它是被划分到 models 包。是的,因为当时我们的示例项目是 TodoList,它仅包含一个功能模块。

但是,当我们开发一个包含多个功能模块的应用程序时,为了方便功能模块之间相互调用,更建议将所有功能模块的结构体和接口存放到 domain 包。

03

按照依赖关系划分包

在「Go 语言整洁架构实践」一文中,提到在 Repository 层存放操作数据库和调用微服务的代码,我们可以在 Repository 层按照依赖关系划分包,比如我们的应用程序需要操作 MySQL 数据库,我们可以定义一个 mysql 包。

示例代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package mysql

import (
 "context"
 "go_standard/domain"
 "xorm.io/xorm"
)

type mysqlUserRepository struct {
 Conn *xorm.Engine
}

func NewMysqlUserRepository(Conn *xorm.Engine) domain.UserRepository {
 _ = Conn.Sync2(new(domain.User))
 return &mysqlUserRepository{Conn}
}

func (m *mysqlUserRepository) GetById(ctx context.Context, id int) (res *domain.User, err error) {
 // TODO::implements it
 return
}

func (m *mysqlUserRepository) GetByPage(ctx context.Context, count, offset int) (data []*domain.User, nextOffset int, err error) {
 // TODO::implements it
 return
}

func (m *mysqlUserRepository) Create(ctx context.Context, user *domain.User) (err error) {
 // TODO::implements it
 return
}

func (m *mysqlUserRepository) Delete(ctx context.Context, id int) (err error) {
 // TODO::implements it
 return
}

func (m *mysqlUserRepository) Update(ctx context.Context, user *domain.User) (err error) {
 // TODO::implements it
 return
}

阅读上面这段代码,我们可以发现 mysql 包主要作为 domain 包和操作数据库的方法实现之间的适配器,这种包布局方式,隔离了我们 MySQL 的依赖关系,从而方便了未来迁移到其他数据库的实现。比如,我们未来想把数据库切换为 PostgreSQL,我们可以再定义一个 postgresql 包,提供 PostgreSQL 的支持。

04

共享 mock 包

因为我们的依赖项通过我们的 domain 包定义的接口与其他依赖项隔离,所以我们可以使用这些连接点来注入 mock 实现。可以使用 mock 库生成 mock 代码,也可以自己编写 mock 代码。

05

使用 main 包将依赖关系连接起来

最后,我们使用 main 包将这些彼此孤立的包连接起来,将对象需要的依赖注入到对象中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
 "github.com/gin-gonic/gin"
 _ "github.com/go-sql-driver/mysql"
 _userHttpDelivery "go_standard/user/delivery/http"
 _userRepo "go_standard/user/repository/mysql"
 _userUsecase "go_standard/user/usecase"
 "xorm.io/xorm"
)

func main() {
 db, err := xorm.NewEngine("mysql", "root:root@/go_standard?charset=utf8mb4")
 if err != nil {
  return
 }
 r := gin.Default()
 userRepo := _userRepo.NewMysqlUserRepository(db)
 userUsecase := _userUsecase.NewUserUsecase(userRepo)
 _userHttpDelivery.NewUserHandler(r, userUsecase)
}

06

总结

我们遵循以上 4 个规则设计 Go 应用程序,不仅可以有效帮助我们在编写代码时避免循环依赖,还可以提升应用程序的可阅读性、可维护性和可扩展性。

值得一提的是,本文旨在建议团队制定成员都要遵循的规则,作为团队的 Go 应用程序设计标准,而不是建议大家必须遵循本文介绍的 4 个规则。

参考资料:

  1. https://medium.com/@benbjohnson/standard-package-layout-7cdbc8391fc1
  2. https://github.com/bxcodec/go-clean-arch/pull/21
  3. https://github.com/golang-standards/project-layout/issues/117
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Go语言开发栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
移除 WordPress 后台“外观-主题” 管理功能
之前在本站 DeveWork.com 分享了《移除 WordPress 后台插件管理的“编辑”与“停用”功能》的方法,禁止让特定的后台管理员使用其中的“编辑”与“停用”入口,最大限度地避免失误操作的影响。今天分享的同样是来自原代码作者的代码,这次实现的功能更绝——直接在WordPress 后台移除“外观-主题” 管理功能,就是让这个查看、更换主题的入口消失,够绝吧? 在主题的 functions.php 文件下加入以下代码: //移除 WordPress 后台“外观-主题” 管理功能(管理员可用) deve
Jeff
2018/01/19
8840
移除 WordPress 后台“外观-主题” 管理功能
WordPress 主题开发之激活主题后显示自定义提示信息
如果你要开发一款WordPress 主题,那么你肯定希望用户在激活主题后能够看到你自定义的提示信息,一般是感谢使用主题之类的话。WordPress 本身在激活主题后会有一句“新主题已启用。查看站点”。我们想要的效果也是这样,不过提示的文字不同罢了。 将下面的代码丢入主题的functions.php 文件即可实现激活主题后显示自定义提示信息: //激活主题后显示自定义提示信息 devework.com add_action('admin_notices', 'admin_notice'); function
Jeff
2018/01/19
9390
WordPress 主题开发之激活主题后显示自定义提示信息
自定义WordPress 密码文章提示文字
WordPress 默认的密码提示文字是这样的:This post is password protected. To view it please enter your password below
Jeff
2018/01/19
1.9K0
自定义WordPress 密码文章提示文字
wordpress自定义文章类型功能添加
公司的自研主题开发,最近几个都需要用到:自定义文章类型 通过自定义文章类型来,来处理和归类不同的内容类型 下面以添加产品中心来举例:
青梅煮码
2023/01/16
5320
WordPress 自定义文章类型(Post Type)终极指南
WordPress 里面内置了两种常用的 Post Type :Post(文章)、Page(页面),分别用来展示两种类型的内容,一种是相对动态的文章,另一种是相对固定的页面。
Denis
2023/04/14
3.2K0
WordPress 自定义文章类型(Post Type)终极指南
自定义(修改)WordPress管理后台界面的字体样式
默认的话,WordPress 后台管理界面的字体样式是“sans-serif”,中文的话直接是宋体了(当然,在Windows的机子上是这样,苹果机可能不同)。不知道是看多了的缘故,总觉得宋体太难看了,想换成微软雅黑。但是苦于WordPress 特殊的文件机制,实现起来并不是加个CSS 样式那么简单(没耐心得直接看折腾三)。 折腾一(fail) Jeff 在本地测试,通过开发者工具查看WordPress 后台样式文件,结果让我蒙了:比如说,某部分的CSS 竟然是通过PHP 文件来加载CSS 的(讲得不明不白,
Jeff
2018/01/19
2.6K0
自定义(修改)WordPress管理后台界面的字体样式
WordPress Ajax 异步加载 自定义评论表情
最近为了考试都复习成狗熊样啦~~我要缓缓折腾折腾WordPress 先。今天带来本人最新的折腾成果: Ajax异步加载自定义评论表情。由于评论表情那22个gif图片加载的话实在是增加了不少的请求数,虽然本站DeveWork.com 的图片都用七牛加速了,但对于Jeff 这种有洁癖的人来说,实在是不舒服。想到可以使用 Ajax异步加载,经过不懈努力,Jeff 终于实现了这个效果,下面分享教程给大家! 这篇教程是建立在 DH博客 的一篇文章思路上面的,但是本文与之非常不同(DH 那篇文章甚至有错误),整个教程经
Jeff
2018/01/19
1.7K0
WordPress Ajax 异步加载 自定义评论表情
WordPress 中强制设置 特色图像 才能发表文章
在开发WordPress 主题的时候,为了丰富网页,常常使用到特色图像功能;这就要求主题使用者为每篇文章都要设置个特色图像,但总有一些用户不会乖乖按要求做;如此一来,主题的实际演示效果就大打折扣了。因
Jeff
2018/01/19
7710
WordPress 中强制设置 特色图像 才能发表文章
简单代码实现“网站维护中”“coming soon” 效果
一般网站要改版或者临时维护一下可能要给访客一个友好的“网站维护中”“coming soon” 提示,之前本站DeveWork.com 也分享了《WordPress“网站建设中/倒计时”主题Launch
Jeff
2018/01/19
2.7K0
WordPress代码实现防止发表重复标题的文章
其实所有的插件这些的就等于放到function.php的代码片段。function.php里面的插件集成出来也可以做成一个插件,反过来插件也可以集成到function.php里面,插件的好处就是方便管理,但也添加了静态的资源请求,所以就导致了,插件越多也会导致网站卡顿的情况,扯得有点远了,直接上代码。
七辰
2023/10/05
4470
DW Replace Open Sans:将WordPress 后台中的open-sans字体加载源从Google Fonts换为360 CDN
针对最近因为Google fonts被墙导致WordPress 打开慢的问题,Jeff 在上一篇《Google Fonts导致WordPress 速度问题的三个解决方案》提出的方案中其中是禁止加载Google fonts ,但是禁止后WordPress 后台的英文字体会变成你当前系统默认的——不好看。为此Jeff 借助网络上的代码开发了这款插件,可一键将WordPress 后台中的open-sans字体加载源从Google Fonts替换为360的CDN 加载源。 2015.2.26更新:Google
Jeff
2018/01/19
8710
WordPress 开发之让浏览器自动加载最新的CSS、JS文件(免刷新缓存)
在开发WordPress 主题的时候,如果频繁更新主题的CSS、JS文件但主题已经上线,如何让访客的浏览器获取最新的CSS、JS文件而非等到浏览器删除缓存后?下面就介绍一个简单的方法。 版本号参数 相信有过开发经验的童鞋都知道是用版本号参数控制。即原来比如说css 文件路径代码是如下面的: http://devework.com/wp-content/themes/Devework/style.csshttp://devework.com/wp-content/themes/Devework/style.c
Jeff
2018/01/19
5.1K0
WordPress 开发之让浏览器自动加载最新的CSS、JS文件(免刷新缓存)
Google Fonts导致WordPress 速度问题的三个解决方案
本来实在是不想写这个的,因为相关方法在圈子里面已经烂大街了。但无奈,一些客户将近期的Google Fonts导致 WordPress 打开速度慢的现象归咎于我的主题——真TM 比窦娥还冤。所以,有必要在这里说下。 2015.2.26更新:Google Fonts 已可正常访问,相关插件可卸,本文已失效 Google Fonts导致WordPress 速度问题之原因 WordPress 自3.8+版本后加入了Google Fonts(别问我Google Fonts是什么了),然后捏,因为近期敏感周期(35号)
Jeff
2018/01/19
2.3K0
让WordPress 在RSS 中Feed 输出支持“More”标签
如果你的主题支持“more”标签,在写文章的时候加上“more”标签,首页就可以截断显示。“more”标签截断文章的意义在于能够随心所欲,想断就断(汗,越写越废~)。但是在RSS 中输出feed 的时候却不支持“More”标签。这么一来,要么全文输出feed,白白流失流量;要么摘要输出feed ,文章惨不忍睹。Jeff 今天决定要解决这个问题。 于是上网查找资料,发现提供的方法都是修改WordPress 核心文件的,这么做当然欠佳。后来用英文一搜,老外那里满大街都是,找了一个改了改用在自己的主题上了,接下来
Jeff
2018/01/19
1.3K0
让WordPress 在RSS 中Feed 输出支持“More”标签
WordPress 注册页面显示自定义提示信息
如果你的WordPress 网站是多用户网站,那么在提供给用户注册的时候,可以自定义一些提示信息,比如说网站协议、版权声明之类的。把下面的代码放到主题的functions.php 文件中: add_action('register_form', 'register_message'); function register_message() { $html = ' <div style="margin:10px 0;border:1px solid #e5e5e5;padding:10px"
Jeff
2018/01/19
9020
WordPress 3.5.1添加后台编辑器按钮
作者:matrix 被围观: 1,911 次 发布时间:2013-04-24 分类:Wordpress 兼容并蓄 | 无评论 »
HHTjim 部落格
2022/09/26
8130
WordPress 3.5.1添加后台编辑器按钮
WordPress 在后台文章和页面列表显示对应的ID
在WordPress 中,每一篇文章及每一个页面都有一个独一无二的id 。在开发主题或者插件的时候可能有需要获取相对应的文章或者页面id,例如在展示特色文章幻灯片,你需要获取对应文章的id。现在教你一个方法快速在后台文章和页面列表显示对应的ID。 将下面的代码添加到主题的functions.php 文件下: add_filter('manage_posts_columns', 'posts_columns_id', 5); add_action('manage_posts_custom_column
Jeff
2018/01/19
1.2K0
WordPress 在后台文章和页面列表显示对应的ID
WordPress免插件仅代码实现文章归档模板 II
不多说了,本站目前使用的效果,可以到我的存档页一览,该方法来自zww,感谢原作者,在这之前,建议你: 1、你的博客存档页面地址后面的应该为/articles,而不是常见的/archives 。在英文中,article表示“文章”,而archive意为“档案”,使用archive貌似不那么规范;2、你的博客存档页面应该禁止搜索引擎访问,因为这会造成内容重复(在你启用站点地图插件的情况下)。 折腾功能:代码实现WordPress归档页面模板[WP原生函数篇] 原创作者:zwwooooo 特点: 1. 按
Jeff
2018/01/19
2.4K0
WordPress免插件仅代码实现文章归档模板 II
使用函数register_post_type()给你的WordPress添加一个说说/心情/动态页面
我们在写博客时,有时候会想写写自己的心情或者觉得好的句子。但是如果特地发一个只有一句话甚至几个字的单章的话总觉得怪怪的。几不利于收录也不美观,所以这里我们搭建一个专门发动态的页面,用register_post_type( ) 函数创建一个新的帖子类型。
Daimon
2022/03/22
7090
wordpress 为自定义类型文章新增自定义字段的方法-文曦博客
wordpress强大之处在于有很强的可自定义性,使得插件、主题的开发变得及其便利。就拿我们今天要说的自定义文章添加自定义字段来说,就很便捷。
雾海梦曦
2022/11/14
1.2K0
wordpress 为自定义类型文章新增自定义字段的方法-文曦博客
推荐阅读
相关推荐
移除 WordPress 后台“外观-主题” 管理功能
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验