Kwa*_*adz 11 architecture domain-driven-design directory-structure
在做了一些研究之后,我确认在大多数情况下,逐特征结构优于逐层结构。为了获得一些论点,我们可以阅读以下文章甚至这个答案。
包通过的功能,没有层
功能文件夹在VS技术文件夹
的功能包,没有层
的层为Spring项目已过时套餐
但是,我发现的所有 DDD 项目示例都是使用package-by-layer 制作的,大部分时间都遵循如下结构:
???申请
???配置
???域
???基础设施
???接口
所以我的问题是:为什么 DDD 社区即使在大多数情况下明显优越,也不遵循按功能打包的功能?
我们是否应该使用package-by-feature在 DDD 中吗?如果是这样,该怎么做?
我提到我不是在谈论微服务架构的特殊情况,其中显然逐层包更相关。
我对这个课题的理解和看法如下:
按功能打包是关于垂直切片(根据领域概念构建源代码)而不是水平分层(根据技术概念构建)。
但是说“代替”并不完全正确,因为有时您必须区分这些技术概念。最好先按功能打包,然后在每个功能内部逐层打包。
在战略 DDD 中,每个有界上下文 (BC) 都是一个垂直切片(一个完整的应用程序、完整的堆栈……具有 UI、应用程序、域模型和基础结构层)。
然后,在BC内部,tactical DDD提倡先按业务概念,再按技术概念(tactical patterns)打包领域模型代码。所以你有模块(紧密结合和松散耦合的聚合组),并且在每个聚合内部你有实体、值对象、工厂、存储库。其他层(UI、应用程序、基础结构)也可以由模块构成。
因此,作为总结 DDD 确实遵循混合方法:
按不同粒度级别的业务概念打包:BC、模块、聚合。
在 BC 中逐层打包:UI、应用程序、域、基础设施。
PD:这个主题(源代码结构)在 Vaughn Vernon 的书“Implementing DDD”的第 9 章(模块)中有解释。
DDD 与域有关,因此将所有内容分组到实体文件夹中。但在非常高的层次上保留了 4 个六边形架构层。这可以是简单的包,也可以是具有严格相互依赖关系的最佳单独模块(如 Android Instant Apps 中)。
\nsrc/main/java\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 Domain\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 Entity1\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ... (entity & DTO files)\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 Entity2\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ... (entity & DTO files)\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 Service\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 Entity1\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ... (port interfaces, application service files)\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 Entity2\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ... (port interfaces, application service files)\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 UserInterface\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 Entity1\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ... (controllers, routers, MQ-consumers, other adapters files)\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 Entity2\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ... (controllers, routers, MQ-consumers, other adapters files)\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 Infrastructure\n \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 Entity1\n \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ... (repositories, 3-rd party server clients, MQ-publishers files)\n \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 Entity2\n \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ... (repositories, 3-rd party server clients, MQ-publishers files)\nRun Code Online (Sandbox Code Playgroud)\n这是一篇很好的文章,有清晰的解释。
\n为什么 DDD 社区不遵循逐个功能包
我想你会发现好的项目确实遵循逐个功能的包。
在示例中,您可能会发现它没有被遵循。慷慨的解释是,作者试图让人们更容易认识关注点的分离和依赖箭头的方向。
不那么慷慨吗?作者没有注意到,或者不知道更多。
我们应该将按功能包与 DDD 一起使用吗?如果可以的话,该怎么办呢?
是的,如果您不使用 DDD ,则与按功能打包的方式几乎相同。它们是正交的关注点。