领域驱动设计模式是当今的热门话题。

领域驱动设计 (DDD) 是一种软件开发方法,通过将实现连接到不断发展的模型来简化开发人员面临的复杂性。

**这不是一篇解释在 Golang 中实现 DDD 的“理想”方式的文章,因为作者绝不是这方面的专家。本文是作者根据自己的研究对 DDD 的理解。作者

将非常感谢有关如何改进本文的贡献。**

检查 github 存储库以获取更新的代码:

https://github.com/victorsteven/food-app-server

为什么是 DDD?

以下是考虑使用 DDD 的原因:

  • 提供解决疑难问题的原则和模式

  • 基于域模型的复杂设计

  • 发起技术专家和领域专家之间的创造性合作,以迭代改进解决领域问题的概念模型。

领域驱动设计的思想被Eric Evans颠覆了。他在一本书中写到了它,你可以在这里找到一些亮点

DDD 包括 4 层:

  1. 域:这是定义应用程序的域和业务逻辑的地方。

  2. 基础设施:这一层由独立于我们的应用程序存在的一切组成:外部库、数据库引擎等。

  3. 应用:这一层作为域和界面层之间的通道。将请求从接口层发送到域层,域层对其进行处理并返回响应。

  4. 接口:这一层包含与其他系统交互的所有内容,例如 Web 服务、RMI 接口或 Web 应用程序以及批处理前端。

[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s--mhcXpSHR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/zxy4sge2vsk0pv53ik9v.jpg)

要对每一层的术语有一个彻底的定义,请参考这个

让我们开始吧。

我们将构建一个食物推荐 API。

如果您没有时间阅读,您可以获取代码。

在此处获取 API 代码。

在此处获取前端代码。

首先要做的是初始化依赖管理。我们将使用 go.mod。从根目录(路径:food-app/)初始化 go.mod:

go mod init food-app

这就是项目的组织方式:

[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s---SDOlNFy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev -to -uploads.s3.amazonaws.com/i/603kx3hs78n8s7aopood.png)

在这个应用程序中,我们将使用 postgresredis 数据库来持久化数据。我们将定义一个包含连接信息的 .env 文件。

.env 文件如下所示:

该文件应位于根目录(路径:food-app/)

域层

我们将首先考虑域。

该域有几种模式。其中一些是:

实体、值、存储库、服务等。

[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s--v8Z8dxLH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/l8ux2zry0gpcf3moy16o.png)

由于我们在这里构建的应用程序很简单,因此我们只考虑两个 domain 模式:entityrepository

实体

这是我们定义事物的“模式”的地方。

例如,我们可以定义一个用户的结构。将 entity 视为域的蓝图。

从上面的文件中,定义了包含用户信息的用户结构,我们还添加了帮助函数来验证和清理输入。调用哈希方法来帮助哈希密码。这是在 infrastructure 层中定义的。

Gorm用作选择的 ORM。

定义食品实体时采用相同的方法。您可以查找回购。

存储库

存储库定义了基础设施实现的方法的集合。这生动地描绘了与给定数据库或第三方 API 交互的方法的数量。

用户的存储库将如下所示:

这些方法在接口中定义。这些方法稍后将在基础设施层中实现。

几乎同样适用于食物存储库这里。

基础设施层

该层实现了存储库中定义的方法。这些方法与数据库或第三方 API 交互。本文将只考虑数据库交互。

[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s--Sq2VGlgp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/as8nb3zr2oq46tjsrgjq.png)

我们可以看到用户的存储库实现是这样的:

好吧,您可以看到我们实现了在 repository 中定义的方法。这可以使用实现 UserRepository 接口的 UserRepo 结构来实现,如下行所示:

//UserRepo implements the repository.UserRepository interface
var _ repository.UserRepository = &UserRepo{}

进入全屏模式 退出全屏模式

您可以在此处查看有关食物存储库如何实施的存储库。

因此,让我们通过创建包含以下内容的 db.go 文件来配置我们的数据库:

从上面的文件中,我们定义了 Repositories 结构,它保存了应用程序中的所有存储库。我们有用户和食物储存库。 Repositories 也有一个 db 实例,它被传递给 user 和 food 的“构造函数”(即 NewUserRepository 和 NewFoodRepository)。

应用层

我们已经在我们的 domain 中成功定义了 API 业务逻辑。 应用程序连接接口层。

我们只会考虑用户的应用程序。您可以在repo中查看食物的内容。

这是用户的应用程序:

以上有保存和检索用户数据的方法。 UserApp 结构具有 UserRepository 接口,这使得调用 user repository 方法成为可能。

接口层

interfaces 是处理 HTTP 请求和响应的层。这是我们收到身份验证、用户相关内容和食物相关内容的传入请求的地方。

[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s--pNX0gVst--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/o6uj342ppcc7wu232xge.png)

用户处理程序

我们定义了保存用户、获取所有用户和获取特定用户的方法。这些可以在 user_handler.go 文件中找到。

我想让你注意,在返回用户时,我们只返回一个公共用户(在实体中定义)。公共用户没有敏感的用户详细信息,例如电子邮件和密码。

身份验证处理程序

login_handler 负责处理 loginlogoutrefresh 令牌方法。在其各自文件中定义的一些方法在此文件中被调用。最好按照文件路径在存储库中签出它们。

食品加工人员

food_handler.go 文件中,我们有基本的 food crud 方法:创建、读取、更新和删除食物。该文件解释了代码的工作原理。

请注意,在使用 postman 通过 API 测试创建或更新食物方法时,请使用 form-data 而不是 JSON。这是因为请求类型是 multipart/form-data。

运行应用程序

所以,让我们测试一下我们所拥有的。我们将连接路由,连接到数据库并启动应用程序。

这些将在根目录中定义的 main.go 文件中完成。

router(r) 是我们使用的gin包中的 Engine 类型。

中间件

从上面的文件可以看出,有些路由是有限制的。 AuthMiddleware 限制对未经身份验证的用户的访问。 CORSMiddleware 支持从不同域传输数据。这很有用,因为 VueJS 用于此应用程序的前端,并且它指向不同的域。

MaxSizeAllowed 中间件会停止任何大小超过中间件指定的文件。由于 food 实现需要文件上传,中间件会停止将大于指定值的文件读入内存。这有助于防止黑客上传不合理的大文件并降低应用程序的速度。 中间件包interfaces层中定义。

我们现在可以使用以下命令运行应用程序:

go run main.go

进入全屏模式 退出全屏模式

奖金

  • Vue 和 VueX 用于消费 API。在此处获取存储库,您也可以访问url并使用它。

  • 为大多数功能编写了测试用例。如果你有时间,你可以添加它。为了实现处理程序中每个方法的单元测试,我们创建了一个模拟包(在 utils 目录中),它模拟处理程序方法中使用的所有依赖项。

  • Circle CI 用于持续集成。

  • Heroku 用于部署 API

  • Netlify 用于部署前端。

结论

我希望您在构建 golang 应用程序时不会很难遵循这个关于如何使用 DDD 的指南。如果您有任何问题或任何意见,请不要犹豫,使用评论部分。如前所述,作者不是这方面的专家。他只是根据他的用例写了这篇文章。

在此处获取 API 代码。

在此处获取前端代码。

您还可以访问应用程序url并使用它。

在此处](https://medium.com/@victorsteven)查看有关介质[的其他文章。

您也可以关注推特

快乐 DDD。