前端与ddd微服务后端的业务逻辑重复



这是一个具有现实意义的抽象问题。

我有两个微服务;让我们称它们为CreditCardsServiceSubscriptionsService

我还有一个SPA,它应该使用SubscriptionsService,以便客户可以订阅。为此,SubscriptionsService有一个端点,您可以在其中POST一个订阅模型来创建订阅,在该模型中是一个指向应该为订阅付费的信用卡的creditCardId。有一些商业规则规定你是否可以使用上述信用卡进行订阅(到期时间超过12个月,是VISA等)。这些特定的业务规则与SubscriptionsService相关

问题是,从事SPA工作的团队希望在SubscriptonsService中有一个/CreditCards端点,该端点返回用户的所有有效信用卡,这些信用卡可以在订阅模型中使用。他们不想在SPA中实现与SubscriptionsService本身相同的业务验证规则。

在我看来,这似乎违背了微服务设计的核心SOLID原则;特别是关注点的分离。我也在问自己,这将开创什么样的先例?我们是否必须向OrdersService或任何其他可能使用creditCardId作为其模型属性的服务添加/CreditCards端点?

所以主要的问题是:设计这个的最佳方式是什么?是否应该在前端和后端之间复制业务验证逻辑?是否应将此新端点添加到SubscriptionsService?我们是否应该尝试简化业务逻辑?

这是一个完全公平的请求,您应该提供该端点。如果你定义了哪些CC对你的服务有效的规则,那么你也应该提供任何和所有的帮助来处理它。

逻辑不应重复这往往会使系统无法维护。

这与SOLID没有太大关系,尽管SRP也会说,如果你对某件事负责,那么任何相关的逻辑也属于你。这个问题不能与您的服务分开,因为它是在那里定义的。

作为一个解决方案选项,我可能会考虑是否可以通过链接到CC服务来逃脱惩罚,因为您已经有了CC服务。我是否可以使用构造的查询将客户端重定向到CC服务,以获取所有相关的CC,而不必在订阅服务中实际了解它们。

设计这个的最佳方法是什么?业务验证在前端和后端之间复制逻辑?应该这样吗是否要将新端点添加到SubscriptionsService?我们应该试着简化业务逻辑?

从我的角度来看,我会将"Subscription BC"(S-BC)与"CreditCards BC"(CC-BC)集成。CC-BC在上游,S-BC在下游。您可以使用CC-BC中的RESTneneneba API,或者使用消息队列来完成此操作。

但我验证的是CC的操作,而不是CC本身,即验证"此CC对订阅有效吗"。验证在S-BC中。

如果SPA想要检索"用户可以用于订阅的CC",这是S-BC的一项功能。

客户端(SPA)应调用S-BC API来使用该功能,S-BC执行从CC-BC获取CC并进行验证的功能。

在微服务和DDD中,订阅服务应该有一个信用卡端点,如果该端点是与订阅的有界上下文相关的数据。

信用卡端点提供的数据模型可能与信用卡服务本身略有不同,因为在订阅的情况下,信用卡的外观或行为可能不同。订阅服务可能会有一个信用卡表或后备存储,以支持存储自己的信用卡模式,并引用一些事实来源来保持数据的良好状态(例如,关于总线上卡事件的消息,或其他机制)。

这实现了3件事,首先,如果卡坏了一段时间,订阅服务不会被完全淘汰,它可以参考自己的表并无论如何工作。其次,你的域代码将更加专注,因为它只需要处理对解决当前问题真正重要的信用卡属性。最后,如果你的卡商店甚至可以有额外的领域特定的属性,这些属性在商店中计算和具体化。

强制Fowler链接:有界上下文模式

即使事实的来源是域模型,并且最终必须在域模型级别,验证仍然可以在域模型级别(服务器端)和UI(客户端)。客户端验证为用户提供了极大的便利。这节省了他们原本会花费的时间等待可能返回验证错误的往返服务器。在商业方面,即使是少数每天以秒为单位乘以数百次,加起来就是大量的时间、费用和挫败直接和即时的验证使用户能够更高效地工作产生更高质量的投入和产出。正如视图模型和域模型不同一样,视图模型验证和域模型验证可能是相似的,但有不同的目的。如果你关心DRY(不要重复自己的原则),考虑到在这种情况下,代码重用也可能意味着耦合,并且在企业应用程序中,不将服务器端耦合到客户端比将遵循DRY原则。(用于容器化NET应用程序的NET微服务体系结构)

最新更新