英文:
Vertical Slice Architecture Feature Dependency
问题
我正在使用干净的架构和不到一年的领域驱动设计(DDD),目前正在考虑使用垂直切片架构来更好地组织我的代码,但我有一个重要的问题:
如果我有这样的功能:
- 获取购物车信息(getCart)
- 获取个人资料信息(getProfileInfo)
- 获取送货地址信息(getShippingAddress)
- 获取支付方式信息(getPaymentMethod)
现在我需要实现一个名为“placeOrder”的新功能,而这个功能依赖于其他功能,比如“getCart”、“getProfileInfo”、“getShippingAddress”和“getPaymentMethod”,在这种情况下,我应该怎么做?我可以在“placeOrder”服务中注入其他功能吗,还是应该在这个功能中复制代码,使其自包含?
英文:
I am using clean architecture and DDD less than one year and currently looking to vertical slice architecture to organize my code better but I have an important question here:
If I have features like this
- getCart
- getProfileInfo
- getShippingAddress
- getPaymentMethod
And now I need to implement a new feature called placeOrder
and this feature depends on some other features like getCart
, getProfileInfo
, getShippingAddresss
, getPaymentMethod
, what should I do in that case, can I inject other features in placeOrder
service, or should I duplicate the code in this feature to be self-contained?
答案1
得分: 1
以下是您要翻译的内容:
主要思想是不要让切片(用例)依赖于其他用例。我不是专家,而且这是我的(也许是有偏见的意见)。为了保持用例解耦,我通常使用以下两种方法之一:
首先,您可以拥有一些通用组件,只要它们保持与用例无关。换句话说,只要它们不包含特定于用例的业务逻辑,您就可以重用数据库网关(或存储库)、一些域实体等等。这也意味着您不能重用用例本身或者与特定用例非常相关的组件。
让我们简化一下问题,只考虑“查看购物车”和“下订单”这两个用例/切片:
正如您所看到的,我们正在重用实体和存储库,但不是“用例”类本身,也不是其传入或传出的请求/响应模型/数据传输对象。
您可以阅读hgraca的这篇文章,深入了解这个概念,尤其是关于“组件之间共享数据存储”的部分。
其次,正如您提到的,您可以尝试完全解耦“购物车”、“个人资料”和“订单”“切片”。通过应用程序内部的“领域事件”可以实现这一目标。
例如,假设每当下订单时,需要更新“个人资料”模块/切片的某些内容。在这种情况下,个人资料模块可以监听订单的下达并相应地做出反应。
最后,请记住总是需要权衡。在这种情况下,涉及到复制与耦合的权衡。正如您所建议的,您可以复制一些代码以避免耦合,或者可以重用一些组件,但这将创建一些间接的耦合(不同的用例将依赖于通用/共享组件)。最终,这总是要比较每种解决方案的优缺点,看看哪个更适用于您的情况。
英文:
The main idea would be not to have slices (use-cases) depending on other use-cases. I am not an expert, and this is my (perhaps biased opinion). In order to keep the use cases decoupled, I usually used one of the following 2 approaches:
Firstly, you can have some common components as long as they stay use-case agnostic. In other words, you can reuse the database gateway (or repositories), some domain entities...etc as long as they do not include use-case-specific business logic. This also means you cannot reuse a use case itself or a component that is very specific to one particular use case.
Let's simplify a bit the question and only consider the view cart
and place order
use cases/slices:
As you can see, we are reusing entity and repository, but not the use case
class itself, nor its incoming or outgoing request/response models/dtos.
You can read this article of hgraca to dive deeper into the concept, especially the section about Data storage shared between components.
Secondly, as you mentioned, you try to completely decouple the cart
, profile
, and order
"slices". One way of achieving this would be through some application-internal domain events
.
For example, let's say that whenever an order
is placed, something about the profile
module/slice needs to be updated. In this case, the profile
module can listen to orders being placed and react accordingly.
Finally, keep in mind that there will always be trade-offs to make. In this case, it's about duplication vs coupling. As you suggested, you can duplicate some lines to avoid coupling, or you can reuse some components, but this will create some indirect coupling (different use cases will depend on the common/shared component). In the end, it's always a matter of comparing the pros and cons of each solution and see what better applies to your context.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论