按技术职责还是按领域职责来构建代码? - Reddit

在构建 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:</font><font>"message"</font><font>
    }
)

type (
    DogCreateRequest {
        Name string path:</font><font>"name"</font><font>
    }

    DogCreateResponse {
        Message string json:</font><font>"message"</font><font>
    }
)

@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来模拟接口
  • 更容易调试(根据我的经验,更少的面条,更清晰的责任)。

缺点。

  • 一些重复的代码
  • 转换为实体有时是件麻烦的事
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值