在 Golang 中尝试简洁架构

在阅读了 叔叔的 之后,我尝试在 中实现它。我们公司也有使用相似的架构,, 但是结构有点不同。并不是太不同, 相同的概念,但是文件目录结构不同。

你可以在这里找到一个示例项目,这是一个 管理示例文章

免责声明:

我不推荐使用这里的任何库或框架,你可以使用你自己的或者第三方具有相同功能的任何框架来替换。

基础

在设计简洁架构之前我们需要了解如下约束:

独立于框架。该架构不会依赖于某些功能强大的软件库存在。这可以让你使用这样的框架作为工具,而不是让你的系统陷入到框架的限制的约束中。

可测试性。业务规则可以在没有 , 数据库, 服务或其他外部元素的情况下进行测试。

独立于 。在无需改变系统的其他部分情况下, 可以轻松的改变。例如,在没有改变业务规则的情况下, 可以替换为控制台 。

4 .独立于数据库。你可以用 , , 或者其他数据库来替换 或 ,你的业务规则不要绑定到数据库。

独立于外部媒介。 实际上,你的业务规则可以简单到根本不去了解外部世界。

更多详见:

所以, 基于这些约束,每一层都必须是独立的和可测试的。

如 叔叔的架构有 4 层:

实体层( Entities )

用例层( Usecase )

控制层( Controller )

框架和驱动层( Framework & Driver )

在我的项目里,我也使用了 4 层架构:

模型层( Models )

仓库层( Repository )

用例层 ( Usecase )

表现层( Delivery )

模型层( Models )

与实体( )一样, 模型会在每一层中使用,在这一层中将存储对象的结构和它的方法。例如: 。

所以实体或者模型将会被存放在这一层

仓库层( Repository )

仓库将存放所有的数据库处理器,查询,创建或插入数据库的处理器将存放在这一层,该层仅对数据库执行 操作。 该层没有业务流程。只有操作数据库的普通函数。

这层也负责选择应用中将要使用什么样的数据库。 可以是 , , ,,无论使用哪种数据库,都要在这层决定。

如果使用 , 这层将控制输入,并与 服务对接。

如果调用微服务, 也将在这层进行处理。创建 请求去请求其他服务并清理数据,这层必须完全充当仓库。 处理所有的数据输入,输出,并且没有特定的逻辑交互。

该仓库层( )将依赖于连接数据库 或其他微服务(如果存在的话)

用例层( Usecase )

这层将会扮演业务流程处理器的角色。任何流程都将在这里处理。该层将决定哪个仓库层被使用。并且负责提供数据给服务以便交付。处理数据进行计算或者在这里完成任何事。

用例层将接收来自传递层的所有经过处理的输入,然后将处理的输入存储到数据库中, 或者从数据库中获取数据等。

用例层将依赖于仓库层。

表现层( Delivery )

这一层将作为表现者。决定数据如何呈现。任何传递类型都可以作为是 , 或者是 文件,或者是

这一层将接收来自用户的输入, 并清理数据然后传递给用例层。

对于我的示例项目, 我使用 作为表现方式。客户端将通过网络调用资源节点, 表现层将获取到输入或请求,然后将它传递给用例层。

该层依赖于用例层。

层与层之间的通信

除了模型层, 每一层都需要通过接口进行通信。例如,用例( )层需要仓库( )层,那么它们该如何通信呢?仓库( )层将提供一个接口作为他们沟通桥梁。

仓库层( Repository )接口示例:

用例层( )将通过这个接口与仓库层进行通信,仓库层( )必须实现这个接口,以便用例层( )使用该接口。

用例层接口示例:

与用例层相同, 表现层将会使用这个约定接口。 并且用例层必须实现该接口。

测试

我们知道, 简洁就意味着独立。 甚至在其他层还不存在的情况下,每一层都具有可测试性。

模型( Models )层

该层仅测试任意结构声明的函数或方法。 这可以独立于其他层,轻松的进行测试。

仓库( Repository )层

为了测试该层,更好的方式是进行集成测试,但你也可以为每一个测试进行模拟测试, 我使用 作为我的工具来模拟查询过程

用例( Usecase )层

因为该层依赖于仓库层, 意味着该层需要仓库层来支持测试。所以我们根据之前定义的契约接口制作一个模拟的仓库( Repository )模型。

表现( Delivery )层

与用例层相同,因为该层依赖于用例层,意味着改成需要用例层来支持测试。基于之前定义的契约接口, 也需要对用例层进行模拟。

对于模拟,我使用 的 的模拟库:

仓库层(Repository)测试

为了测试这层,就如我之前所说, 我使用 来模拟我的查询过程。 你可以像我一样使用 ,或者使用其他具有相似功能的库。

用例层(Usecase)测试

用于用例层的示例测试,依赖于仓库层。

Mockery 将会为我生成一个仓库层模型,我不需要先完成仓库()层, 我可以先完成用例(),即使我的仓库(Repository)层尚未实现。

表现层( Delivery )测试

表现层测试依赖于你如何传递的数据。如果使用 , 我们可以使用 中的内置包 。

因为该层依赖于用例( )层, 所以 我们需要模拟 , 与仓库层相同,我使用 模拟我的 来进行表现层( )的测试。

最终输出与合并

完成所有层的编码并通过测试之后。你应该在的根项目的 文件中将其合并成一个系统。

在这里你将会定义并创建每一个环境需求, 并将所有层合并在一起。

以我的 为示例:

你可以看见,每一层都与它的依赖关系合并在一起了。

结论

总之,如果画在一张图上,就如下图所示:

在这里使用的每一个库都可以由你自己修改。因为简洁架构的重点在于:你使用的库不重要, 关键是你的架构是简洁的,可测试的并且是独立的。

我项目就是这样组织的。通过评论和分享, 你可以讨论或者赞成,当然能改善它就更好了。

示例项目

示例项目可以在这里看见:

我的项目中使用到的库:

Glide :包管理工具

go-sqlmock from github.com/DATA-DOG/go-sqlmock

Testify : 测试库

Echo Labstack (Golang Web 框架)用于 表现层

Viper :环境配置

进一步阅读简洁架构 :

。 这是种另一个版本的简洁架构。

如果你任何问题,或者需要更多的解释,或者我在这里没有解释清楚的。你可以通过我的或者联系我。谢谢。

via: https://hackernoon.com/golang-clean-archithecture-efd6d7c43047

作者:Iman Tumorang

译者:fredvence

校对:polaris1119

本文由 GCTT 原创编译,Go语言中文网 荣誉推出

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20181210B0BU3800?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区