Questions tagged «domain-driven-design»

域驱动设计(DDD)是一种通过将实现与不断发展的模型连接来开发满足复杂需求的软件的方法。

10
为什么我们在设计模式中需要这么多的类?
我是大四学生中的初级开发人员,并且在理解他们的思维和推理方面付出了很多努力。 我正在阅读域驱动设计(DDD),无法理解为什么我们需要创建这么多的类。如果采用这种设计软件的方法,我们最终将得到20-30个类,最多可以替换为两个文件和3-4个函数。是的,这可能很麻烦,但是它更具可维护性和可读性。 每当我想查看某种EntityTransformationServiceImpl功能时,都需要遵循许多类,接口,它们的函数调用,构造函数,它们的创建等等。 简单的数学: 60行伪代码与10类X 10(假设我们有完全不同的逻辑)= 600行杂乱代码与100类+更多包装和管理它们;不要忘记添加依赖项注入。 读取600行凌乱代码=一天 100节课=一周,仍然忘记哪个课什么时候 每个人都说它易于维护,但是为什么呢?每次添加新功能时,都会添加五个带有工厂,实体,服务和值的类。我觉得这种代码的运行速度比凌乱的代码要慢得多。 假设,如果您在一个月内编写了50K LOC混乱代码,则DDD内容需要进行大量审查和更改(我都不介意在两种情况下进行测试)。一个简单的添加可能需要数周,甚至更多。 一年之内,您编写了很多混乱的代码,甚至可以多次重写它,但是使用DDD样式,您仍然没有足够的功能来与混乱的代码竞争。 请解释。为什么我们需要这种DDD样式和许多模式? UPD 1:我收到了很多不错的答案,请大家在某处添加评论或使用阅读列表的链接编辑您的答案(不确定从哪开始,DDD,设计模式,UML,代码完成,重构,实用性等。) ..那么多好书),当然还有顺序,这样我就可以像你们中的一些人一样开始理解并成为高级。


5
有了所有这些服务,我怎么会变得贫血呢?
我们在委托与封装业务逻辑之间划清界限的地方是什么?在我看来,我们委派的越多,我们变得越贫乏。但是,委派还促进重用和DRY主体。那么什么是合适的委托,我们的领域模型应该保留什么呢? 以以下问题为例: 授权。域对象应该负责维护其访问控制规则(例如CanEdit属性)还是应该委派给另一个单独负责管理访问的组件/服务,例如IAuthorizationService.CanEdit(object)?还是应该将两者结合?也许域对象具有CanEdit属性,该属性委派给内部IAuthorizationService来执行实际工作? 验证。与上述相同的讨论涉及验证。谁维护规则,谁负责评估规则?一方面,对象的状态应该属于该对象,而有效性是一个状态,但是我们不想重写用于评估每个域对象的规则的代码。在这种情况下,我们可以使用继承... 对象创建。工厂类与工厂方法与“更新”实例。如果我们使用单独的工厂类,则可以隔离和封装创建逻辑,但要以将对象的状态打开给工厂为代价。如果我们的域层在单独的程序集中,则可以通过公开工厂使用的内部构造函数来进行管理,但是如果存在多个创建模式,这将成为一个问题。而且,如果工厂所做的所有工作都在调用正确的构造函数,那么拥有工厂的意义何在? 类上的工厂方法消除了打开对象内部状态的问题,但是由于它们是静态的,因此我们无法像通过单独的工厂类那样通过注入工厂接口来打破依赖关系。 坚持不懈。有人可能会争辩说,如果我们的域对象要在向另一方委派执行授权检查的职责时将CanEdit公开给他人(IAuthorizationService),为什么在我们的域对象上没有执行相同操作的Save方法呢?这将使我们能够评估对象的内部状态,以确定是否可以在不破坏封装的情况下执行操作。当然,这要求我们将存储库实例注入到我们的域对象中,这对我来说有点气味,那么我们是否应该引发域事件并允许处理程序执行持久化操作? 看看我要去哪里? Rockford Lhotka对他为什么选择CSLA框架中的班级主管路线进行了精彩的讨论,而我对该框架有一些了解,可以看到他的业务对象以多种方式与域对象并行的想法。但是,我试图成为更好的DDD理想的坚持者,我想知道何时协作变得过多。 如果最终以聚合根为IAuthorizationService,IValidator,IFactory和IRepository,还剩下什么?是否具有将对象状态从“草稿”更改为“已发布”的Publish方法足以将类视为非贫血领域对象? 你的意见?

4
富域模型-行为如何准确地适应?
在Rich与Anemic领域模型的辩论中,互联网充满了哲学上的建议,但缺乏权威的例子。这个问题的目的是找到适当的领域驱动设计模型的明确指南和具体示例。(理想情况下为C#。) 对于一个实际示例,这种DDD实现似乎是错误的: 下面的WorkItem域模型不过是属性包,由Entity Framework用于代码优先数据库。按照福勒的说法,这是贫血的。 WorkItemService层显然是对域服务的常见误解。它包含WorkItem的所有行为/业务逻辑。Per Yemelyanov等人认为,这是程序性的。(第6页) 因此,如果以下内容是错误的,我该怎么做呢? 该行为,即AddStatusUpdate或Checkout,应该属于WorkItem类吗? WorkItem模型应具有哪些依赖关系? public class WorkItemService : IWorkItemService { private IUnitOfWorkFactory _unitOfWorkFactory; //using Unity for dependency injection public WorkItemService(IUnitOfWorkFactory unitOfWorkFactory) { _unitOfWorkFactory = unitOfWorkFactory; } public void AddStatusUpdate(int workItemId, int statusId) { using (var unitOfWork = _unitOfWorkFactory.GetUnitOfWork<IWorkItemUnitOfWork>()) { var workItemRepo = unitOfWork.WorkItemRepository; var workItemStatusRepo …

4
非英语域中的编程和通用语言(DDD)
我知道这里已经有一些与该主题紧密相关的问题,但是没有一个以泛在语言为起点,因此我认为这是合理的。 对于那些不知道的人:泛在语言是定义(口头和书面)语言的概念,该语言在开发人员和领域专家中均会使用,以避免因翻译问题和误解而引起的不一致和误传。您将看到相同的术语出现在代码中,任何团队成员之间的对话,功能规范以及诸如此类的内容中。 因此,我想知道的是如何处理非英语领域中的泛在语言。 就个人而言,我极力主张完全用英语编写编程代码,包括注释,但当然不包括常量和资源。 但是,在非英语域中,我不得不做出以下决定: 用域的自然语言编写反映通用语言的代码。 将无处不在的语言翻译成英语,并停止以该领域的自然语言进行交流。 定义一个表,该表定义无所不在的语言如何翻译成英语。 这是基于这些选项的一些想法: 1)我强烈反对混合语言代码,即使用非英语的类型/成员/变量名称等进行编码。大多数编程语言都在很大程度上“促进”英语,并且大多数技术文献,设计模式名称等也是英语。因此,在大多数情况下,根本无法完全使用非英语语言编写代码,因此您最终还是会使用多种语言。 2)这将迫使领域专家开始以与UL等效的英语进行思考和交谈,这对他们而言可能并非自然而然,因此会严重阻碍沟通。 3)在这种情况下,开发人员以其母语与领域专家进行交流,而开发人员则以英语进行相互交流,最重要的是,他们使用UL的英语翻译编写代码。 我确定我不想选择第一个选项,并且我认为选项3比选项2更好。我是否缺少其他选择? 更新 今天,大约一年之后,我每天都在处理这个问题,我不得不说,选择3对我来说非常有效。 这并没有我最初担心的那么乏味,在与客户交谈时进行实时翻译也不是问题。 根据我的经验,我还发现以下优点是对的。 翻译UL使您更加关注定义UL甚至域本身,尤其是当您不知道如何翻译术语并且必须开始浏览词典等时。这甚至使我重新考虑了域建模决策几次。 它可以帮助您使您对英语的了解更加深刻。 显然,您的代码看起来更令人愉悦,而不是让人讨厌。


5
当最终用户的命名法改变时,我们应该在多大程度上重命名代码和数据?
很久以前,我们添加了一项功能,使用户在将图像添加到工作流队列后可以“接受”图像。原来,我们使用了错误的术语,并且用户实际上“批准”了该图像。 在我们的界面上更改“接受接受”很容易,只需替换一个单词即可。但是,我们从CSS类名称到数据库值都使用“ accept”一词对所有层进行了编程。 使按钮变为绿色的CSS类:“ .accepted”; 验证并绑定DOM节点上的类属性的模型方法:“ isAccepted”; JavaScript状态属性:具有“未审阅”,“已接受”和“已发布”的数组; Mysql状态列:ENUM,具有“未审阅”,“已接受”和“已发布”; 测试名称; 替换大多数出现的接受批准很简单(特别是在进行测试时)。迁移数据要困难一点,特别是因为它需要与部署同步。 这个特定的案例很简单,但是在我的职业生涯中,我遇到过类似但更复杂的案例。当文件也被重命名并且在数十台服务器上进行部署时,或者当代理缓存时,将涉及memcached和mysql。 除了接口之外,在所有其他层上都保留“接受”是一个坏主意,因为加入该团队的新程序员可能无法了解导致该决定的历史原因,并且如果接受->赞成,则在含义上是相近的词语被重命名为“排队参加管理层下次地位会议”,这当然没有任何意义。而且,如果我们在这里和那里折衷,就会感觉到,在一些迭代中,用户界面的概念不会影响系统内部,并且我当然不希望在其中一半输出与其内部没有关系的系统上工作。 那么,您是否总是在需要时重命名所有内容?如果这发生在您身上,并且您认为这种权衡不值得,那是不是又回来咬了您?代码注释或开发人员文档是否足以避免此问题?

7
应用层还是领域层?
我正在阅读Evans的“域驱动设计”,并且正在讨论分层体系结构。我刚刚意识到应用程序层和域层是不同的,应该分开。在我正在从事的项目中,它们是混合在一起的,直到我读完这本书(我现在不能说对我很清楚)之后,我才能分辨出它们之间的区别。 我的问题是,由于这两个问题都涉及应用程序的逻辑,并且应该不涉及技术和表示方面,因此,将这两者划定界限有什么好处?

7
系统可以100%进行数据驱动吗?
我的新老板已经在这个项目上工作了很多年。我只来过这里几个星期,但我不确定是否有可能。他想设计一个“ 100%数据驱动”的系统。 因此,如果我们输入足够的数据,则可以定义并生成任何应用程序。我至少设法让他承认某些事情,例如用户,或者应用程序应该具有预定义的值,但是他喜欢系统结构,用户界面和逻辑都存储为数据的概念。 这里有一些简单的演示,他基本上重新发现了一些面向对象编程和基本模板系统的简单想法,但总的来说,我认为这个目标实际上是不可能的。 我不知道如何在不使系统变得如此复杂以至于无法进行实际编程的情况下使用数据定义逻辑。 我认为从理论上讲,这不是因为解释数据的内容最终需要完整描述应用程序,因此您只是将问题上移了一层,甚至没有任何净收益。 这样的100%数据驱动应用程序有可能吗?

11
在域丰富的应用程序中检索报告和仪表板数据的最佳实践或设计模式
首先,我想说这似乎是一个被忽略的问题/领域,因此,如果这个问题需要改进,请帮助我将此问题变成一个有益于他人的好问题!我正在寻求实施解决方案的人员的建议和帮助,而不仅仅是尝试的想法。 根据我的经验,应用程序有两个方面-“任务”方面,这主要是域驱动的,用户可以在其中与域模型(应用程序的“引擎”)进行丰富的交互,而报告方面则是用户根据任务侧发生的情况获取数据。 在任务方面,很显然,具有丰富域模型的应用程序应在域模型中具有业务逻辑,并且数据库应主要用于持久性。分离关注点,每本书都为此而写,我们知道该怎么做,太好了。 报告方面呢?数据仓库是可以接受的,还是由于将业务逻辑合并到数据库以及数据本身而设计不当?为了将数据库中的数据聚合到数据仓库数据中,您必须对数据应用业务逻辑和规则,并且该逻辑和规则不是来自您的域模型,而是来自您的数据聚合过程。错了吗 我致力于业务逻辑广泛的大型财务和项目管理应用程序。在报告这些数据时,我经常会做很多汇总工作以提取报告/仪表盘所需的信息,并且这些汇总中有很多业务逻辑。为了提高性能,我一直在使用高度聚合的表和存储过程进行此操作。 例如,假设需要一个报告/仪表板来显示活动项目的列表(设想10,000个项目)。每个项目将需要显示一组指标,例如: 总预算 迄今为止的努力 燃烧率 以当前消耗率计算的预算用尽日期 等等 这些都涉及很多业务逻辑。我不仅在谈论乘数或一些简单的逻辑。我说的是为了获得预算,您必须应用一个包含500个不同费率的费率表,每个费率适用于每个员工的时间(在某些项目中,其他项目具有乘数),应用费用和任何适当的加价等。逻辑是广泛的。为了使客户端在合理的时间内获得大量数据,需要进行大量的聚合和查询调整。 应该首先在域中运行它吗?性能如何?即使使用直接的SQL查询,我也无法获得足够快的数据以使客户端在合理的时间内显示。我无法想象如果要重新为所有这些域对象补水,并在应用程序层中混合,匹配和聚合它们的数据,或者试图在应用程序中聚合数据,那么尝试将这些数据足够快地发送到客户端。 在这些情况下,SQL似乎擅长处理数据,为什么不使用它呢?但是,那么您在域模型之外就有了业务逻辑。对业务逻辑的任何更改都必须在您的域模型和报告聚合方案中进行更改。 对于域驱动设计和良好实践,如何设计任何应用程序的报告/仪表板部分,我实在感到茫然。 我添加了MVC标签,因为MVC是jour的设计风格,并且在我当前的设计中使用了它,但无法弄清楚报告数据如何适合此类应用程序。 我正在寻找这方面的任何帮助-书籍,设计模式,谷歌关键字,文章等等。我找不到有关此主题的任何信息。 编辑和另一个例子 我今天遇到的另一个完美的例子。客户需要为客户销售团队提供报告。他们想要看似简单的指标: 对于每个销售人员,他们迄今为止的年销售额是多少? 但这很复杂。每个销售人员参加了多个销售机会。有些人赢了,有些人没有。在每个销售机会中,都有多个销售人员,每个销售人员根据其角色和参与度分配一定比例的销售功劳。因此,现在想象一下要遍历该域...为每个销售人员从数据库中提取此数据所需要做的对象补液量: 获取所有SalesPeople-> 对于每个获取其SalesOpportunities-> 对于每个获取其销售百分比并计算其销售金额, 然后将所有SalesOpportunity销售金额相加。 这是一个指标。或者,您可以编写一个SQL查询,该查询可以快速有效地完成并对其进行快速调整。 编辑2- CQRS模式 我已经阅读了有关CQRS模式的信息,尽管很有趣,但即使是马丁·福勒(Martin Fowler)也说它未经测试。那么BEEN过去如何解决这个问题。每个人在某个时候或某些时候都必须面对这一点。具有成功记录的既定方法或陈旧方法是什么? 编辑3-报告系统/工具 在这种情况下,要考虑的另一件事是报告工具。Reporting Services / Crystal报表,Analysis Services和Cognoscenti等都希望从SQL /数据库获取数据。我怀疑您的数据稍后会通过您的业务。然而,在许多大型系统中,它们和其他类似的对象仍然是报告的重要组成部分。在这些系统的数据源甚至报告本身中甚至存在业务逻辑的地方,如何正确处理这些数据?

8
域驱动设计是一种反SQL模式吗?
我正在研究域驱动设计(DDD),尽管我对此进行了更深入的了解,但有些事情我还是没有。据我了解,主要要点是将域逻辑(业务逻辑)与基础结构(数据库,文件系统等)分开。 我想知道的是,当我遇到非常复杂的查询(例如材料资源计算查询)时会发生什么?在这种查询中,您需要使用繁重的集合操作,这是SQL设计的目的。在域层内部进行这些计算并使用其中的许多集合就像丢弃SQL技术一样。 在基础架构中也无法进行这些计算,因为DDD模式允许在基础架构中进行更改而无需更改域层,并且知道MongoDB不具有SQL Server等相同的功能,这是不可能发生的。 这是DDD模式的陷阱吗?

3
关于DDD,什么是有界上下文?
在阅读沃恩·弗农(Vaughn Vernon)的《实施域驱动的设计》(Implementing Domain Driven Design)一书时,我无法很好地理解什么是真正的有限上下文。 本书将有界上下文定义为“适用领域模型的概念边界。它提供了由团队说出并以其精心设计的软件模型表达的无处不在的语言”(“本书指南”的开头部分)。此定义听起来似乎是有界上下文是子域的模型和语言,在该子域中,该子域可能恰好是核心域(似乎应该将其称为“核心子域”,但这是另一个讨论...)。对于有限的上下文提供了什么仍然有些含糊。它是一个或多个子域的分组吗?如果只有一个子域对应一个有界上下文,那么有界上下文实际上告诉我们什么? 但是,同一本书的第3章涉及有界上下文之间的集成技术。但是,这似乎暗示着有限的上下文实际上是软件系统或某种人工制品。 马丁·福勒(Martin Fowler)简要讨论了有界上下文的概念(http://martinfowler.com/bliki/BoundedContext.html),但并未真正阐明问题。 归根结底,什么是有限的上下文?它是一组子域吗?子域的模型和语言?执行一个子域?没有这些答案,似乎很难理解如何将现实问题空间分解为有限的上下文。

6
在Web应用程序中DDD聚合真的是一个好主意吗?
我将深入研究领域驱动设计,而我遇到的一些概念从表面上看很有意义,但是当我更多地考虑它们时,我不得不怀疑这是否真的是一个好主意。 例如,聚合的概念很有意义。您可以创建较小的所有权域,这样就不必处理整个域模型。 但是,当我在Web应用程序上下文中考虑此问题时,我们经常访问数据库以拉回小的数据子集。例如,页面可能仅列出订单数量,并带有单击链接以打开订单并查看其订单ID的链接。 如果我理解正确的聚集,我通常会使用存储库模式返回,将包含成员的OrderAggregate GetAll,GetByID,Delete,和Save。好的,听起来不错。但... 如果我调用GetAll列出我所有的订单,那么在我看来,这种模式将需要返回整个汇总信息列表,完整的订单,订单行等...当我只需要该信息的一小部分时(仅标头信息)。 我想念什么吗?还是在这里使用某种程度的优化?我无法想象有人会主张在不需要时返回全部信息。 当然,可以在您的存储库上创建诸如之类的方法GetOrderHeaders,但这似乎违背了首先使用诸如存储库之类的模式的目的。 谁能为我澄清一下? 编辑: 经过大量研究后,我认为这里的脱节之处在于,纯存储库模式与大多数人认为的存储库模式不同。 Fowler将存储库定义为使用集合语义的数据存储,通常存储在内存中。这意味着创建整个对象图。 Evans修改了存储库以包括聚合根,因此截取了存储库以仅支持聚合中的对象。 大多数人似乎将存储库视为美化的数据访问对象,在其中您只是创建获取所需数据的方法。正如Fowler的企业应用程序架构模式中所描述的那样,这似乎并不是目的。 还有一些人认为存储库是一个简单的抽象,主要用于简化测试和模拟,或将持久性与系统的其余部分分离。 我猜答案是,这是一个比我最初想象的要复杂得多的概念。

2
您如何处理微服务架构中的共享概念?
我正在研究我正在开发的应用程序的体系结构模式,微服务方法似乎是一个不错的选择,但是我不确定如何处理服务之间的交互。 该应用程序主要处理用户,用户拥有的配置文件,照片以及代表照片中一对多配置文件的标签。可以想象有一些方法可以返回用户上传的照片,返回包含特定标记个人资料的照片,等等。 这是我设计基于微服务的体系结构的第一步,而我来自于启发式历史的整体式域模型。在那个世界中,控制器会将这些域对象缝合在一起,但是我很难理解如何以微服务方式工作。

5
在函数式编程的背景下谈论贫血模型仍然有效吗?
DDD的大多数战术设计模式都属于面向对象的范式,而贫乏的模型则描述了将所有业务逻辑都置于服务而非对象中的情况,从而使它们成为一种DTO。换句话说,贫血模型是程序样式的同义词,不建议用于复杂模型。 我在纯函数式编程方面不是很有经验,但是我想知道DDD如何适合FP范例以及在这种情况下是否仍然存在“贫血模型”一词。 更新:纽崔里出版了有关该主题的书籍和视频。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.