如果业务逻辑要发送电子邮件
If business logic wants to send an email
我正在尝试实施 Uncle Bob 的简洁架构:
除了 UseCases/Interactors 之外一切正常。我需要注册一个用户,所以我需要 RegisterUser
个用例。在具体的 interactor 中,我实现了 RegisterUser
用例,它只创建 User
实体并使用 PasswordBroker
端口散列其密码。
创建用户后,我需要发送一封验证邮件。为此,我需要使用框架的组件。而且主要有两个问题。
- 我认为为邮件服务写端口没有意义,因为这个端口只是一个巨大的copy/paste框架服务抽象
- Interactor 不能在用户创建后发送邮件,因为 User 最终会在 Doctrine
flush()
之后存储在控制器中。当我们发送电子邮件但用户未存储在数据库中时,存在风险。一定要一致。
在这种情况下最好的方法是什么?
我认为我们需要某种与具体用例相关的端口,该端口将在用例结束时调用并在中实现Application Layer framework 的 Mailer 和 Doctrine 可用。
这是使用框架的upside/downside。干净的架构有意将您与这样的依赖项隔离开来。这可以让事情从你下面发生变化,而不会受到这种变化的影响。它还允许您针对抽象进行测试(针对框架代码编写自动化测试总是很糟糕)。
您需要做的是决定是否值得牺牲干净的架构来利用框架的优势。这是一种平衡行为,我们都必须在 case-by-case 的基础上做出决定。框架为我们做的越多,我们得到的控制就越少,通常我们的应用程序最终的架构 "pure" 也就越少。但是,如果没有框架,我们必须编写本质上是对现有功能的浪费性重复的代码。
- I think it has no sense to write port for the Mail service, because this port would be just a huge copy/paste abstraction of a framework service
我会创建一个 Notification
接口,然后传递给用例交互器,类似于 EntityGateway
或 EntityRepository
。
我会以一种从具体通知机制中抽象出来的方式设计 Notification
接口,例如e-mail、信使等
Notification
看起来像这样:
public interface Notification {
public void notifyUserRegistered(User user);
}
实现将放在外层,通常是接口适配器层。因为这是调整内层接口的层 - 因此得名。
这样的 Notification
接口可以在测试中轻松模拟,这可以使您的测试快速进行。因此,我不认为通知界面是一个巨大的 copy/paste 抽象。
- Interactor cannot send an email after user creation, because User finally would be stored after Doctrine flush() inside controller. There is a risk, when we've sent an email, but User wasn't stored in a DB. It must be consistent.
首先,我猜你无论如何都不能强制执行,因为发送 e-mail 不参与数据库事务。因此,您仍然会遇到一致性问题。
但您通常可以注册活动交易,以便在交易成功完成时收到通知。这意味着 Notification
实现将只注册一个在事务完成时调用的回调。然后你可以发送 e-mail.
我不知道如何在 php 中完成,也许这是关于 SO 的另一个问题。在 Java 中有几种方法,具体取决于您使用的交易 api。
对于 Spring,请查看 Transaction bound events or JEE's TransactionSynchronizationRegistry。如果 Java 开发人员阅读了这篇文章,请提一下。
我正在尝试实施 Uncle Bob 的简洁架构:
除了 UseCases/Interactors 之外一切正常。我需要注册一个用户,所以我需要 RegisterUser
个用例。在具体的 interactor 中,我实现了 RegisterUser
用例,它只创建 User
实体并使用 PasswordBroker
端口散列其密码。
创建用户后,我需要发送一封验证邮件。为此,我需要使用框架的组件。而且主要有两个问题。
- 我认为为邮件服务写端口没有意义,因为这个端口只是一个巨大的copy/paste框架服务抽象
- Interactor 不能在用户创建后发送邮件,因为 User 最终会在 Doctrine
flush()
之后存储在控制器中。当我们发送电子邮件但用户未存储在数据库中时,存在风险。一定要一致。
在这种情况下最好的方法是什么?
我认为我们需要某种与具体用例相关的端口,该端口将在用例结束时调用并在中实现Application Layer framework 的 Mailer 和 Doctrine 可用。
这是使用框架的upside/downside。干净的架构有意将您与这样的依赖项隔离开来。这可以让事情从你下面发生变化,而不会受到这种变化的影响。它还允许您针对抽象进行测试(针对框架代码编写自动化测试总是很糟糕)。
您需要做的是决定是否值得牺牲干净的架构来利用框架的优势。这是一种平衡行为,我们都必须在 case-by-case 的基础上做出决定。框架为我们做的越多,我们得到的控制就越少,通常我们的应用程序最终的架构 "pure" 也就越少。但是,如果没有框架,我们必须编写本质上是对现有功能的浪费性重复的代码。
- I think it has no sense to write port for the Mail service, because this port would be just a huge copy/paste abstraction of a framework service
我会创建一个 Notification
接口,然后传递给用例交互器,类似于 EntityGateway
或 EntityRepository
。
我会以一种从具体通知机制中抽象出来的方式设计 Notification
接口,例如e-mail、信使等
Notification
看起来像这样:
public interface Notification {
public void notifyUserRegistered(User user);
}
实现将放在外层,通常是接口适配器层。因为这是调整内层接口的层 - 因此得名。
这样的 Notification
接口可以在测试中轻松模拟,这可以使您的测试快速进行。因此,我不认为通知界面是一个巨大的 copy/paste 抽象。
- Interactor cannot send an email after user creation, because User finally would be stored after Doctrine flush() inside controller. There is a risk, when we've sent an email, but User wasn't stored in a DB. It must be consistent.
首先,我猜你无论如何都不能强制执行,因为发送 e-mail 不参与数据库事务。因此,您仍然会遇到一致性问题。
但您通常可以注册活动交易,以便在交易成功完成时收到通知。这意味着 Notification
实现将只注册一个在事务完成时调用的回调。然后你可以发送 e-mail.
我不知道如何在 php 中完成,也许这是关于 SO 的另一个问题。在 Java 中有几种方法,具体取决于您使用的交易 api。
对于 Spring,请查看 Transaction bound events or JEE's TransactionSynchronizationRegistry。如果 Java 开发人员阅读了这篇文章,请提一下。