`

DDD与TDD比较之——DDD

 
阅读更多

 


DDD与TDD比较之——DDD

 

最近承诺要写一篇TDDDDD区别的文章,在比较之前,我这里会先分别给出一个DDD的开发实例和TDD的开发实例。这篇文章主要讲解DDD

 

几年前,曾接手了别人写了一半的一个项目,新加一些功能,然而模型不是很清晰,虽然反映了外部的业务逻辑,但是为了一些新的功能或者特殊案例,我们需要加一些特殊处理。由于模型不够清晰,原本1天能做的的东西,往往需要4-7天才能做完。

 

我们需要简单清晰的模型,这样往往能够清晰的表达业务,可能聪明的程序员往往不在乎这个,总能够想出解决特殊的逻辑处理这些问题,然而随着业务的日渐复杂,特殊逻辑的往往不能完全的表达业务,特殊逻辑越来越多,特殊逻辑之间也产生了很多矛盾,为了解决一个很简单的需求,我们要绞尽脑汁,花费大量的精力和资源,大家忙忙碌碌,甚至非常充实,但是鲜有人能够体会到编程的乐趣。

 

如何建立简单有效的模型呢?简单的模型不是简单的思考,简单的拍拍大脑就做决定,因为,“Simplicity is ultimate sophistication”。简单清晰的模型,需要一个智者“慢慢”摸索才能完成(汲取和消化领域知识,挖掘隐含概念),哪怕你是MF或者是Eric

 

我给出一个真实的故事,详细讲述实践Domain-Driven Design过程的所发生的事情。

 

几年前,我们承接了一个项目,需要做两个系统的集成。刚开始,做该集成开发的有两个人员,过去了一个月多月,后来其中一位离开了公司,但是两个月过去了,仍然没有进展。于是经理派我去着手该事情,其实,我只了解其中一个系统,对另一系统,除名字之外我别无了解。我首先向之前的开发人员索要需求,由于没有正式的需求文档,只有一封潦草的邮件,其中关于此集成的只有一句话:系统A和系统B的集成。看完之后,我一头雾水,由于提供需求的专家暂时不在,为此,我就去咨询那位一直致力于该工具的软件开发人员,想从他那里了解更多信息。

 

我们首先大致进行了如下对话:

开发人员:     我们就需要做个简简单单的映射,根据需求专家的意思。

我:          映射?

开发人员:     根据系统A的发过来的事故(Incident)的信息,在系统B生成一个新的事故(Incident)的记录。

我:          这是在系统B创建一条记录,是这样吗?

开发人员:     是的现在的问题是我们系统B的事故(Incident)添加了新的属性,这些属性是必填项,而发送的过来的信息不全,导致一些新的必填信息为空。

我:          如果B系统记录的属性发生了变化,A系统需要集成,应该在A系统修改和添加这些属性。

……

经过接近半个小时讨论,我得出了以下结论:现在是要发布新版本的系统BB系统新加了一些特性,导致一些属性发生了变化,包括增加,删除和修改,客户要求发布的版本能够和系统A能够集成,但前提是不能修改系统A代码。

 

现在的问题也就是如何决定这些必填项信息的内容,而并非映射的问题。几分钟后,我们继续了我们的讨论:

开发人员:  事故(Incident)记录里还有3个属性是需要特殊处理的,Assignment属性,Urgent属性和Priority属性要根据事故(Incident)所关联的另外一条记录资源(CI)的属性来判断。

我:          怎样决定这三个属性值确定了吗?

开发人员:  关于Incident里有3个属性是需要特殊处理的,Assignment属性和Urgent属性和Priority属性,要根据所关联的出现问题的资源(CI)来判断,打个比方:这个资源是Adobe Reader,那么就应该交由Applications的团队管理来处理这个事故,于是Assignment属性就是Applications;并且Urgent属性是CriticalPriority属性就是high

我:          也就是只有这三个属性需要一些逻辑判断来赋值,其他的如果没有值的话,就是使用配置的默认值了。

开发人员:  3个字段可以由关联的资源(CI)的任何3个属性值来决定。

打个比方:如果Adobe Reader出了事故,那么这个资源就是Adobe Reader,而Adobe Reader是由Applications的团队管理来处理,于是Assignment就是Applications;而Adobe ReaderUrgent值是CriticalPriority值就是high,那么该事故(Incident)的Urgent值是CriticalPriority值就是high

 

我:        CI3个属性的值如何决定Incident3个字段。

开发人员:     这个还要继续和需求专家讨论。

我:          只是用3CI属性够用吗?

开发人员:     目前就是这样要求的.

 

目前看来,我能从开发人员那里得到的信息差不多就是这些了,然而问题还没解决,似乎这位开发人员对于某些需求细节还不太清楚,而他已经动手写完了一部分代码,这部分代码并未反映这些需求的细节。

 

为了对需求有更好全面的认识,我和需求专家预定好了时间,展开了讨论。

我:          新生成的Incident有三个字段需要特殊处理,对吗?

专家:       可以是多个。

我发现前面对需求认识开始出现问题了,我开始继续往下问。

 

我:          能不能给我一个场景?

专家:       如果打印机坏了,A会生成一条信息发送给BB会生成一条Incident记录,这条记录的CI就是Printer,如果不知道应该交由谁处理,即Assignment是空,那么此时,我们就需要找个默认值赋给它。

我:          那么我们需要CI的三个属性来做什么逻辑?

专家:       目前我们最多提供3个条件来判断是否使用这些默认值,如果不符合条件,我们就不使用这些默认值。我们还能提供一个如果不匹配时使用另外一些默认值?

我:          当然可以。

专家:       集成时,不仅可以创建一条Incident记录,还可以更新或者删除(这里指使该条数据状态为Closed,是一种特殊的更新)一条Incident记录。

 

我们进一步讨论的3个条件逻辑:目前使用最简单的相等来判断。我也了解到这个版本目前只是实验性质的,并且这个集成方案由于种种原因,是B软件单方面的做出的,这个方案最终在以后版本遭否决的程度非常大。了解这些对该功能的开发非常重要。至此,我还没有画出来一张模型图出来和他讨论,我承认我在这里犯了一个严重错误,由于未及时画出模型图来,也差点导致我接下来的工作重做。

 

 

此时虽然我没有画出来一张模型图出来,但是我头脑已经有一副,如下所示:

 

 

IncidentConfiguration之间的关系是一对多:可以创建,更新和删除时使用这个配置来。

ConfiurationCriterionMappingDefaultMapping之间的关系是一对一的:一条配置信息

 

正当我准备编写代码之际,我意识到,模型图还未来得及和领域专家进一步深究,于是我又找到他做最终的探讨:

我把我之前脑中的模型图首先展示给了他,和别的领域专家一样,一开始他并不了解这些符号的意思,我用2分钟简单地讲给他多对多的关系和关联关系,他已经明白这张图的意思了。

然后,他迅速指出其中一个细节来:

专家:       ConfiurationCriterionMapping关系不是一对一的,是多对一的。

我:          这个……,为什么?

看来理解是有出入的。

专家:       因为我们可以根据发送过来的事故(Incident)的具体属性,选取不同的Mapping,来填充这些新的属性。

我:          恩,确实不错,更加灵活了。

于是我立即修改了模型图:

 

别看这个小细节的修改,这可关系到用户的体验度和满意度。我们都知道盲人摸象的故事,有的盲人认为它是萝卜,有的却认为它是柱子……,每个盲人对大象的认识是不同的,片面的,要对大象有个全面的认识,需要摸清大象的每个部位。我们认识领域问题要一步一步地深入挖掘,否则会管中窥豹,时见一斑。

 

记得前不久,遇到几位著名公司的“资深”的开发人员,自认为对软件开发了解独到,甚至对“面向切面的编程”及其不满。我们讨论到一个实际问题:

他们问道:我这里有一系统,使用到了workflow,需要通知,当一条记录发生变化时,需要什么模式?

就这么几句,我努力尝试更深一步的交流,然而都是徒劳地,他们认为,你懂得设计模式,那么就不需要了解需求,或者给你及其模糊甚至错误的需求,都应该立马给出令人惊奇的设计,并结合令人惊奇的模式。

 

我真无法得到需要什么模式,因为,我不清楚具体的需求到底是什么,而且,模式并非只与模型有关,模式和现有代码(比如,三种wrapper模式,详见我的书籍)等有关。而且模式的粒度要小于需求问题的粒度。

 

我们在上世纪60年代就提出了,软件必须重视需求,80年代末期,我们意识到,软件问题已经和开发所使用的语言关系并不紧密了,而要解决了实际问题,我们应该关注与问题域(Problem Domain),于是为这些领域建模逐渐兴起。

 

虽然这几位“资深”人士,有的甚至有10年的开发经验,然而并未了解软件的核心,虽然,我不怀疑他是否做过软件设计,但是至少,我想,他们没有真正设计出OO系统,和让用户非常满意的系统。

 

末了,上述系统从需求到设计,以及最终的代码交付,我花了4天时间,而之前,已经过去2个多月仍未有结果,因为他有兴趣的是“两个系统集成的技术”。

 

我希望大家能够明白,软件的核心是模型,不是算法,也不是数据结构,也不是技术。尽管这三个方面及其重要,但它们都称不上是软件的核心。我们需要智慧的程序开发人员,需要脚踏实际,一步一个脚印地去做每一件事,而不是空想自己10分钟可以做别人10年的工作。

 

作者简介:

 

我是一个AgileDDDDomain-Driven Design)的爱好者,关于这两方面的文章书籍非常丰富: 

我非常推荐Eric EvansDomain-Driven Design: Tackling Complexity in the Heart of Software一书,其中探讨了非常全面的关于领域建模艺术的技术,很多关于DDD的文章和书籍都是基于此书展开的。这本书让我对软件设计有了新的认识,很值得细细回味其中某些重要章节。

 Eric Evans的关于Folding together DDD into Agile讲述了如何把他们结合起来,读了之后,我获益甚多

本人著有书籍《漫谈设计模式》

 

 

分享到:
评论

相关推荐

    BusinessAdminstration:此项目的内容包含DDD,TDD,代码优先,异步任务,KISS,DRY,CLEAN CODE Y SOLID

    下面将详细阐述其中涉及的关键技术点——DDD(领域驱动设计)、TDD(测试驱动开发)、代码优先策略、异步任务处理、KISS原则、DRY原则、CLEAN CODE以及SOLID原则。 1. 领域驱动设计(DDD):DDD是一种软件开发方法...

    实现领域驱动设计.pdf

    最后,书中还会讨论如何将DDD与持续集成、测试驱动开发(TDD)以及敏捷开发方法结合,以实现更高效、更灵活的开发流程。 《实现领域驱动设计》这本书是学习和实践DDD的宝贵资源,它通过实例和深入的解释,帮助...

    ThoughtWorks文集II——敏捷实践的秘密

    这包括遵循最佳实践,如SOLID原则、DDD(领域驱动设计)和TDD。 6. **精益思想**:ThoughtWorks将精益理念应用于软件开发,减少浪费,增加价值流的流动。例如,通过最小化等待时间、消除过度设计和优化工作流程,以...

    领域驱动设计

    ### 领域驱动设计(DDD):精简业务模型与实现匹配 #### 一、领域驱动设计概览 领域驱动设计(Domain-Driven Design,简称DDD)是一种面向复杂业务领域的软件开发方法论,旨在通过深入理解业务逻辑来构建高质量的...

    基于Spring的Java平台程序架构研究.pdf

    为了更好地理解上述设计思想和技术的实际应用,我们可以考虑一个具体的案例——中大型B/S结构的应用系统开发。 1. **领域建模**:在这个案例中,可以将业务划分为多个模块,比如订单管理、库存管理等,每个模块都有...

    魂斗罗java源码-it-glossary:IT术语表:purple_heart:

    DDD - 领域驱动设计 开发人员 - 开发人员 HTML - 超文本标记语言 AI——智能人工(人工智能) GCP - 谷歌云平台 JS - JavaScript LESS - 更精简的样式表 Lib - 图书馆(图书馆) OOP - 面向对象的编程 PHP - 超文本...

    POJOs in Action

    而且在理论与实践之间架起了一座桥梁,使读者能够更好地理解和应用领域驱动设计(Domain-Driven Design, DDD)及测试驱动开发(Test-Driven Development, TDD)等最佳实践。 #### 二、主要内容概述 1. **核心概念...

    清洁建筑电影

    通过这个项目,学习者可以了解如何在Dart项目中实施清洁架构,提高代码的可读性和可维护性,并掌握如何在实际项目中运用DDD和测试驱动开发(TDD)方法。同时,这也为其他编程语言的开发者提供了借鉴,让他们了解到...

    程序员简历模板针对架构师

    1. **全面的IT教育基础**:屈小勇毕业于211工程大学——西南大学的计算机科学与技术专业,具有扎实的理论基础。 2. **深厚的行业经验**:他拥有11年的银行和互联网金融信贷系统实践经验,涵盖了咨询、需求分析、...

    软件工程 课外读物 软件工程思想等

    这通常会涉及到软件工程中的最佳实践,如TDD(测试驱动开发)和DDD(领域驱动设计)。 标签“软件工程”和“案例”表明这些资料将深入探讨实际项目中的问题和解决方案,使学习者能够更好地理解和应对可能出现的各种...

    领域驱动设计实践

    同时,领域驱动设计并不排斥其他分析技术,如分析模式或测试驱动开发(TDD),它们可以辅助我们构建和验证领域模型。 领域建模在Rational Unified Process(RUP)中也占有重要地位,采用用例驱动的方法,通过用例来...

    timebus1:控制Agregados

    在领域驱动设计(Domain-Driven Design,简称DDD)中,聚合根是业务逻辑的核心组件,它封装了一组相关的实体和值对象,维护其内部一致性。下面我们将深入探讨Java编程语言中如何实现和控制这类聚合体。 首先,让...

    ReCapProjectCarRental

    为了保证代码质量,项目可能还采用了单元测试和持续集成(CI/CD)策略,通过Visual Studio或其他IDE进行开发,利用TDD(测试驱动开发)和DDD(领域驱动设计)方法来确保代码的健壮性和可维护性。 总结来说,...

    cart:领域驱动设计购物车演示

    这是一个域元素,但必须根据项目需求来实现——通过 API 调用或数据库查询。固定价格一旦我们将产品添加到购物车中,价格可能是固定的。 如果是项目用例,请查看。如何组装实际应用我们必须通过我们的基础设施实现...

Global site tag (gtag.js) - Google Analytics