问题标签 [hexagonal-architecture]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
2 回答
5264 浏览

architecture - 六边形架构 - 一个简单的用例

我已经阅读了很多关于六边形架构的文章,并且我确实了解了大部分概念(嗯,我希望我这样做了),但我没有找到任何关于该架构用例的示例

假设我的应用领域模型是让人醉的。整个业务逻辑包含在Person位于领域层的类中。

领域层还包含一个PersonRepository

实施者:

假设我想通过访问使一个人喝醉:GET /person/johnDoe/drink。我应该创建一个像这样的用例:

并从控制器调用它?这个提到的案例应该驻留在领域层还是应用层?在这种情况下,什么是端口和适配器?如果我想有办法让这个人喝醉——一种来自 GET 请求,另一种来自某些php console person:drink JohnCLI 命令?我应该如何构建我的应用程序?

0 投票
1 回答
1145 浏览

php - 六边形架构/干净代码:实现适配器模式的问题

我目前正在 Symfony 2 框架上编写一个小型控制台应用程序。我正在尝试将应用程序与框架隔离(主要是在听到一些关于六边形架构/端口和适配器、干净代码和将应用程序与框架解耦的有趣讨论之后作为练习),以便它可以作为控制台应用程序运行,一个 Web 应用程序,或者毫不费力地迁移到另一个框架。

我遇到的问题是我的一个接口是使用适配器模式实现的,它依赖于另一个也使用适配器模式实现的接口。这很难描述,最好用代码示例来描述。在这里,我在我的类/接口名称前加上“My”,只是为了清楚哪些代码是我自己的(我可以编辑),哪些属于 Symfony 框架。

需要注意的另一件事是\Symfony\Component\Console\Output\ConsoleOutput实现\Symfony\Component\Console\Output\OutputInterface.

为了符合MyDialogInterface,该MySymfonyDialogAdaptor::askConfirmation方法必须将 的实例MyOutputInterface作为参数。然而,对 SymfonyDialogHelper::askConfirmation方法的调用需要一个 的实例\Symfony\Component\Console\Output\OutputInterface,这意味着代码不会运行。

我可以看到几种解决方法,但都不是特别令人满意:

  1. 同时MySymfonyOutputAdaptor实现MyOutputInterfaceSymfony\Component\Console\Output\OutputInterface。这并不理想,因为我需要在该接口中指定所有方法,而我的应用程序只真正关心该writeln方法。

  2. 假设MySymfonyDialogAdaptor传递给它的对象是MySymfonyOutputAdaptor: 如果不是,则抛出异常。然后在类中添加一个方法来MySymfonyOutputAdaptor获取底层\Symfony\Component\Console\Output\ConsoleOutput对象,该对象可以直接传递给 Symfony 的DialogHelper::askConfirmation方法(因为它实现了 Symfony 的OutputInterface)。这将类似于以下内容:

    这感觉不对:如果MySymfonyDialogAdaptor::askConfirmation要求它的第一个参数是 MySymfonyOutputAdaptor 的一个实例,它应该将它指定为它的类型提示,但这意味着它不再实现MyDialogInterface. 此外,在它自己的适配器之外访问底层ConsoleOutput对象似乎并不理想,因为它实际上应该由适配器包装。

任何人都可以提出解决这个问题的方法吗?我觉得我错过了一些东西:也许我把适配器放在了错误的地方,而不是多个适配器,我只需要一个适配器来包装整个输出/对话系统?或者也许我需要包含另一个继承层才能实现这两个接口?

任何建议表示赞赏。

编辑:此问题与以下拉取请求中描述的问题非常相似:https ://github.com/SimpleBus/CommandBus/pull/2

0 投票
1 回答
690 浏览

php - 来自 Repository 的数据结构服务于所有目的?

对于我想在下一个(Laravel PHP)项目中实现的存储库服务/用例模式(DDD设计的一部分),我需要一些帮助。

一切似乎都清楚了。DDD 中只有一个令人困惑的部分是来自存储库的数据结构。人们似乎选择了存储库应该返回的数据结构(数组或实体),但这都有缺点。其中之一是回顾我过去经历的表现。一种是您没有简单数据结构(数组或简单对象属性)的接口。

我将首先解释我在以前的项目中的经验。这个项目有缺陷,但我从新项目中学到并希望看到一些好的优势,但解决了一些设计错误。

以往的经验

过去,我使用 Kohana 框架和 Doctrine 2 ORM(数据映射器模式)构建了一个以 API 为中心的网站。流程如下所示:

网站控制器 → API 客户端(HMVC 调用) → API 控制器 → 自定义存储库 → Doctrine 2 ORM 原生存储库/实体管理器

我的自定义存储库使用 Doctrine2 DQL 返回纯数组。Doctrine2 建议将数组结果数据用于只读操作。是的,它使我的网站美观而轻松。API 控制器只是将数组数据转换为 JSON。就那么简单。

过去,我的公司创建的项目完全依赖加载的 Doctrine2 实体,这让我们因性能而感到遗憾。

我的 REST API 支持
/api/users?include_latest_adverts=2&include_location=true
对用户资源的查询。API 控制器传递include_location到直接包含位置关系的存储库。控制器读取latest_adverts=2并调用广告存储库以获取每个用户的最新 2 个广告。数组被返回。

例如第一个用户数组:

事实证明这是非常成功的。我的整个网站都在使用 API。添加新客户端将非常容易,因为该 API 已经在使用 oauth 完美地投入生产。整个网站都在上面运行。

但这种设计也有缺陷。我的控制器仍然包含很多用于验证、邮件、参数或过滤器的逻辑,比如has_adverts=true只为用户提供广告。这意味着如果我创建一个新端口,比如一个全新的 CLI 接口,由于所有验证等原因,我将不得不复制很多这些控制器。但如果我要创建一个新客户端,则不需要重复。所以至少解决了一个问题:-)

我的管理面板完全耦合到了学说 2 存储库/实体管理器,以加快开发速度(有点)。为什么?因为我的 API 具有仅针对网站具有特殊功能的胖控制器(特殊验证、邮寄注册等)。我将不得不重做工作或重构很多。因此决定直接使用实体以仍然有某种清晰的方式来编写代码,而不是重写我所有的 API 控制器并将它们移动到服务(例如站点和管理员)。时间是修复我的设计错误的一个问题。

对于我的下一个项目,我希望所有代码都通过我自己的自定义存储库和服务。一个流动的好分离。

新项目(使用 DDD 思想)和数据结构的困境

虽然我喜欢以 API 为中心的想法,但我不希望我的下一个项目以 API 为中心,因为我认为相同的功能应该在没有 HTTP 协议的情况下可用。我想使用 DDD 思想设计核心。

但我喜欢这个想法,它使用一个仅作为 API 说话并返回简单数组的层。任何新端口的完美基础,包括我自己的前端。我的想法是将我的服务类视为 API 接口(返回数组数据),进行验证等。我可以拥有专门用于网站的服务(注册)和管理员或后台进程使用的普通服务。在某些管理情况下,简单的 CRUD 编辑无论如何都不需要服务,我可以直接使用存储库。控制器会很薄。有了这个,创建一个真正的 REST API 只需使用与我的前端控制器类相同的服务来创建新控制器。

对于像业务规则这样的内部逻辑,拥有实体(清晰的接口)而不是来自存储库的数组会很有用。通过这种方式,我可以从定义一些基于属性执行一些逻辑的方法中受益。但是如果我使用 Doctrine2 并且我的存储库总是返回实体,我的应用程序将遭受很大的性能打击!

当使用像 Doctrine 2 这样的数据模式模式(现在或将来)时,一种数据结构确保性能但没有清晰的接口,另一种确保清晰的接口但性能不佳。此外,我最终可能会得到两种令人困惑的数据类型。

我在想类似于这个流程的东西:

Controller(瘦)→ UserService(包括验证)→ UserRepository(只是存储)→ Eloquent ORM

为什么用 Eloquent 而不是 Doctrine2?因为我想坚持一下 Laravel 框架和社区中的共同点。所以我可以从第三方模块中受益,例如生成管理界面或基于模型的类似模块(绕过我的 DDD 规则)。除了使用第三方模块之外,我会设计我的核心内容,因此切换应该总是很容易,并且不会影响数据结构的选择或性能。

Eloquent 是一个 activerecord 模式。所以我很想将这些数据转换为像 Doctrine2 实体一样的 POPO。但是不...如上所述,使用doctrine2 真实模型会使系统变得非常胖。所以我再次回到简单的数组。知道这一点将适用于未来的任何其他实现。

但是感觉不好总是依赖数组。尤其是在创建内部业务规则时。开发人员必须猜测数组上的值,在他的 IDE 中没有自动完成功能,不能像实体类那样有特殊方法。但是用两种方式处理数据也让人感觉很糟糕。或者我太完美了;)我想要一个清晰的数据结构!

构建接口和 POPO 将意味着大量重复工作。我需要将 Eloquent 模型(只是一个表映射器,而不是实体)转换为实现此接口的实体对象。都是额外的工作。最终我的最后一层就像一个 API,从而再次将其转换为数组。这也是额外的工作。数组似乎又是一笔交易。

读入 DDD 和 Hexagonal 似乎很容易。好像很合乎逻辑!但实际上,我在试图坚持 OOP 原则的过程中遇到了一个简单的问题。我想使用数组,因为它是 100% 确定我不依赖于任何模型选择和从我的 ORM 中查询关于性能等的选择的唯一方法,并且在转换为视图或 API 的数组时没有重复的工作。但是对于用户数组的外观并没有明确的约定。我想使用这些模式加速我的项目,而不是减慢它们的速度:-) 所以不是有很多转换器的选项。

现在我阅读了很多主题。一个使符合像 Doctrine2 这样的适当实体的 POPO 和接口可以返回,但要为 Eloquent 做所有额外的工作。切换到 Doctrine2 应该相当容易,但会影响性能如此糟糕,或者需要将 Doctrine2 数组数据转换为这些自己的实体接口。其他人选择返回简单的数组。

有人说服人们使用 Doctrine2 而不是 Eloquent,但他们忽略了 Doctrine2 很重并且您确实需要将数组结果用于只读操作的事实。

我们将存储库设计为可更改的,对吗?不是因为它只是设计上的“好”。那么,如果它对性能或重复工作有如此大的影响,我们怎么能依赖完整的实体呢?即使仅使用 Doctrine2(耦合),由于其性能也会出现同样的问题!

所有 ORM 实现都将能够返回数组,因此那里没有重复的工作。很棒的表演。但我们错过了明确的合同。而且我们没有数组或类属性的接口(作为一种解决方法)......呃;)

我只是错过了我们的编程语言中缺少的部分吗?简单数据结构上的接口??

制作所有数组并让高级业务逻辑与这些数组对话是否明智?因此没有具有清晰接口的类。任何预先计算的数据(通常由 Entity 方法返回)都将位于定义 Service 类的数组键中。如果不明智,考虑到上述所有因素,还有什么选择?

如果有人在考虑性能、不同的 ORM 实现等方面在这个“领域”有丰富经验的人能告诉我他/她是如何处理这个问题的,我将不胜感激?

提前致谢!

0 投票
1 回答
882 浏览

grails - 如何在 Grails 中拆分域逻辑和数据访问

如何在 Grails 中拆分域逻辑和数据访问(这是一个好主意)?

我们编写的许多软件应用程序都以数据(基础)为中心,在 Grails 中,通常会从服务类或控制器直接持久化到 DataSource.groovy 中配置的数据库。更改数据库很容易,但我们并不是真正独立于代码中的持久性实现。

我正在尝试编写一个为不同的持久性和数据源(不仅是数据库)实现打开的应用程序,并专注于业务领域而不是数据库实体。这也是测试时的一个优点(易于编写假/模拟持久性) 最初我只有一个持久性实现 - Grails 域类,使用 GORM。但有可能我将来希望拥有数据库以外的其他数据源,例如休息服务或其他东西。

目前,我只将数据库作为数据源,并且主要做一些杂乱无章的事情(以及一些域逻辑)。我认为我仍然停留在“旧”思维中,专注于数据库持久性,因为我的大多数业务域类都有一个 Grails 域类等价物,它是它的副本。当要持久化域类时,我只需将属性复制到 Grails 域类。

我对这个解决方案不太满意。我可以想到至少两个可能的改进/更改:

  1. 我的 Grails 域类的组织方式可能与业务域类不同,因此我不只是将属性从一个类复制到另一个类。但是,在从数据库读取或写入数据库时​​,这仍然会涉及从一个类到另一个类的大量属性映射。
  2. 也许有一种方法可以从常规的 src/main/groovy 包中使用业务领域类并用 GORM 东西装饰?或者以其他方式拆分域逻辑和持久性?我已经看到可以通过在域类上使用 hibernate conf 来做到这一点。这是唯一的方法吗?

我看过一些关于 Grails 架构的有趣讨论,包括干净的架构、六边形架构和 ddd,但我还没有找到任何示例。有吗?

在这一点上,正如我所说,大部分功能都是 CRUD 的东西,但不是全部。更进一步,应用程序可能有更多的业务逻辑,所以我不希望使用带有视图、控制器、服务、域的 Grails 的“默认”架构。我想要一个独立于 grails 视图/控制器和域/GORM 的“核心”应用程序

0 投票
1 回答
64 浏览

java - Guice 并限制客户端仅获取某些实例

使用 Guice 时,如何限制客户端从一组特定的类中获取实例(又名Facebook 问题)?

想象一下,我使用端口和适配器来构建我的系统,并且我有一个管理适配器端、一个业务逻辑组件和一个由业务组件使用的数据访问端。如何只允许客户端获取管理适配器端的接口实例?

在代码中:

管理适配器:

业务逻辑:

我想让应用程序级别的注入器只返回Admin接口的实例。

谢谢

0 投票
1 回答
1600 浏览

design-patterns - Windows 服务的六边形体系结构/端口和适配器体系结构。正确的路?

六边形架构的流程

我已经阅读了 Alistair Cockburn 提出的关于端口和适配器架构的不同来源,发现它适合我开发网关服务应用程序的场景,该应用程序从多个源接收消息并处理消息并将消息发送到多个目的地。这是我的详细实现。

  • 目前消息的来源是单一的(JMS Queue)
  • JMS 端口订阅 JMS 消息队列并将其传递给 JMS 适配器,后者又调用相应的消息处理程序。
  • 消息处理程序依次调用与cockburn 建议的消息源或目标无关的业务域层。
  • 由依赖注入容器注入的具有JMS Port、WCF Port、DB Port、TCP Port的消息处理程序依次调用JMS Port、TCP Port和WCF Port来发布/发送域处理的消息。

如果我是否偏离了 Cockburn 提出的架构,我有几个关键问题/疑问。

  1. 单个端口能否同时处理消息的流入/流出(在本例中为 JMS 端口)。或者为消息的流入和流出设置单独的端口是一种好习惯。

2.根据 cockburn 的文章,它说

入站通信:“当事件从外部世界到达端口时,特定于技术的适配器将其转换为可用的过程调用或消息并将其传递给应用程序。”

出站通信:“当应用程序有东西要发送时,它会通过端口将其发送到适配器,适配器会创建接收技术(人工或自动)所需的适当信号。”

因此,我已将处理后的消息直接传递到端口,该端口又调用适配器根据目标要求转换消息。

  1. 消息处理程序(应用层)可以依赖注入的端口吗?

  2. 根据 Cockburn 的文章,它说

任何一个端口通常都有多个适配器,用于可能插入该端口的各种技术。

我想不出单个端口需要多个适配器的情况。你能给我一个场景,这样我就可以充分利用架构。

0 投票
2 回答
505 浏览

design-patterns - 在哪里应用域级别权限

我认为,许可/授权(不是身份验证)是一个跨领域的问题。

在洋葱架构或六边形架构中,应该在哪里执行权限?所需许可的示例是:

  • 过滤返回到前端的数据(UI、API 或其他)
  • 验证业务操作是否可以执行

理想情况下,通过单一职责原则,执行业务操作和返回数据的代码根本不需要知道用户的权限。该功能的实现应该知道如何执行业务操作或查询存储库或域服务 - 就是这样。

实现与执行业务操作或返回数据的类相同的接口的包装器/外观是否是放置此权限的地方?或者,还有更好的方法?

此外,如果最佳实践是按活动而不是按角色进行许可,那么说许可应该由其目的只是返回数据的服务执行是否仍然有效?

0 投票
2 回答
580 浏览

domain-driven-design - DDD - 管理域和存储库之间的耦合

我的问题很简单:如何将我班级的私有数据保存到存储库中?

不管我们采用何种架构风格,每个人都同意业务对象不应该知道“如何”保存自己——也就是说,它们不应该实现数据库或其他持久性细节。但是,在我看来,业务对象是唯一知道他们需要保存“什么”的对象。Repository 知道如何从数据库中获取,但如果它要知道如何将业务对象翻译成数据库术语,那么它必须知道要翻译什么。

考虑到我可能使用数据库,但我没有用休眠注释标记我的类,因为我可能经常保存到平面文本文件中。

假设我在这里的课程实际上是以特定的业务实体命名的,那么做类似的事情会有什么问题

并像使用它一样

我知道有一些框架可以帮助我,但归根结底,它们都依赖于某种反射。我想知道,在没有反射的情况下,我如何静态组合我的对象以在保持封装的同时公开它们的数据。我能想出的唯一答案是这种访问者模式。

0 投票
1 回答
492 浏览

domain-driven-design - 六边形架构 - 调用序列

我试图理解六边形架构以及域驱动设计,但我对命令处理程序和命令总线感到困惑?这应该属于应用层还是领域层?

我也找不到任何示例类或序列图。欣赏是否有人可以提供还涉及命令总线的示例序列图。

0 投票
1 回答
1482 浏览

php - DDD 和六边形架构 - 服务

自从我开始构建我的 DDD/Hexagonal 架构应用程序以来已经有一段时间了,我对与它们相关的大量概念感到不知所措。

尽管当我发现有必要时,我开始略微尝试并尝试应用概念。我发现仍然有很多我不能甚至我不想应用到我的应用程序中,其中一些是:适配器、命令(CQRS?)、事件..

除此之外,我对与六边形体系结构有关的事情有点卡住了。我试图应用外部行为的定义应该依赖于内部,所以基础设施层 -> 应用层 -> 域层

在我的例子中,我在我的应用层中定义了服务作为 LoginService 的这个例子:

但是,我很确定我在吹嘘六边形架构所代表的依赖声明。因为我的应用层依赖于基础设施层。(在这种情况下,$this->userRepository->findByUsername($userName);是注入到应用程序的 serviceContainer 中的 DoctrineUserRepository 的一部分)

我的 repo 在 github 中完全可用:Malendar Repository

如何处理这个依赖于数据库输出的服务案例?另外,我跳过哪些概念会很好用?

先谢谢你=D