在构建 REST api 时,您会选择: 选项 A: controllers order.go region.go user.go models order.go region.go user.go repos order.go region.go user.go 选项 B: order order_controller.go order_entity.go order_repo.go region region_controller.go region_entity.go region_repo.go user user_controller.go user_entity.go user_repo.go 这是如何在不妥协的情况下在松散耦合和高内聚之间找到平衡。 第一个选项适用于非常小范的项目,其中类型很少,"处理程序"很多,像"ToDo"应用程序,演示,单一职责命令行工具这样的幼稚项目适合这种情况,因为凝聚力不会受到太大影响,因为有每个包中的东西很少。 现第二个适用于其他一切: 如果一旦您在这些目录中拥有大量相同命名的.go文件,那么寻找单一类型的实现和跟踪代码将变得非常笨拙。 两打目录和几个文件比几个文件夹更容易推理,每个文件夹中有两打文件,每个文件夹都命名相同。 这就是为什么我从不选择第一种方法,因为随着熵的增加,它几乎总是蜕变为第二种方法,而且当我可以从那里开始的时候,重新构建所有的东西是浪费时间的。 按团队划分 下面是我们团队的标准布局,我们有一个工具可以保证这一点。 我们的布局是这样的: etc pet-api.yaml internal config config.go handler cat_create_handler.go dog_create_handler.go routes.go logic cat_create_logic.go dog_create_logic.go svc service_context.go types types.go pet.go etc是yaml配置文件的文件夹config包含配置的 Go 定义handler包含路由的 HTTP 处理程序logic包含每个处理程序的 biz 逻辑svc是从外部传入处理程序的服务上下文,例如数据库实例。types是定义请求和响应类型的文件夹 为什么我把逻辑文件夹和handler处理程序分开,是因为我希望我们的团队尽可能少地把HTTP请求的信息传递给逻辑处理函数。 另外,所有文件夹的布局是由goctl从下面的API定义文件中生成的,命令是goctl api go -api demo.api -style go_zero -dir .type ( CatCreateRequest { Name string `path:"name"` } CatCreateResponse { Message string `json:"message"` } ) type ( DogCreateRequest { Name string `path:"name"` } DogCreateResponse { Message string `json:"message"` } ) @server( prefix: v1 ) service pet-api { @handler CatCreateHandler post /pets/cats/:name(CatCreateRequest) returns (CatCreateResponse) @handler DogCreateHandler post /pets/dogs/:name(DogCreateRequest) returns (DogCreateResponse) } 前缀:v1将/v1添加到服务中的所有路由,它是可选的。 对于单体服务,我们会在内部下添加模型文件夹,用于数据访问代码。 另外,goctl支持自定义生成行为的选项,比如命名风格、将请求分组到不同的包中,甚至将处理程序和逻辑分别压缩到一个文件中。 安装:go install github.com/zeromicro/go-zero/tools/goctl@latest 六边形架构 对于微型服务来说,拥有如下软件包:- cmd — service_name — mock_service - internal — entities — errors — repositories —— database —— fxrates_provider — server —— http —— grpc — usecases cmd - 持有启动你的服务的方法http/grpc等在/server目录下--你的服务的进入点usecases--领域/业务逻辑层mysql/firestone/其他一些api在/repositories目录下--来自外部的任何数据entities--创建并通过各层传递的模型errors--全局错误,使错误检查更容易。 优点。没有循环的依赖关系非常清楚地将逻辑分离出来只要满足预期的接口,就可以互相替换层(你的老板决定明天要支持http? 没问题!)。更容易测试更容易用gomock来模拟接口更容易调试(根据我的经验,更少的面条,更清晰的责任)。 缺点。一些重复的代码转换为实体有时是件麻烦的事 原文:按技术职责还是按领域职责来构建代码? - Reddit