范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

产品代码都给你看了,可别再说不会DDD系列(四)代码工程结构

  这是一个讲解DDD落地的文章系列,它以一个真实的并已成功上线的软件项目为例,系统性地讲解DDD在落地实施过程中的典型实践,以及在面临实际业务场景时的各种取舍。
  本系列包含以下文章: DDD入门 DDD概念大白话 战略设计 代码工程结构(本文) 请求处理流程 聚合根与资源库 实体与值对象 应用服务与领域服务 领域事件 CQRS 案例项目介绍
  既然DDD是"领域"驱动,那么我们便不能抛开业务讲技术,为此让我们先从业务上了解一下贯穿本文章系列的案例项目 —— 码如云(不是马云,也不是码云)。如你已经在本系列的其他文章中了解过该案例,可跳过。
  码如云是一个针对二维码场景应用的SaaS软件平台,采用"一物一码"的业务模式,可以为每一件"物品"生成一个二维码,并以该二维码为入口展开对"物品"的相关操作,典型的应用场景包括固定资产管理、设备巡检以及物品标签等。
  在使用码如云时,首先需要创建一个 应用 ,一个 应用(App) 包含了多个 页面(Page) (也可称为表单),一个 页面 又可以包含多个 控件(Control) (比如单选框控件)。 应用 创建好后,可在 应用 下创建多个 实例(QR) 用于表示被管理的对象(比如机器设备)。每个 实例 均对应一个二维码,手机扫码便可对 实例 进行相应操作,比如查看 实例 相关信息或者填写页面表单等,对表单的一次填写称为 提交(Submission) ;更多概念请参考码如云术语。
  在技术上,码如云是一个无代码平台,包含了表单引擎、审批流程和数据报表等多个功能模块。码如云全程采用DDD完成开发,其后端技术栈主要有Java、Spring Boot和MongoDB等。 代码工程结构
  在码如云,我们经常会受邀去给其他公司或组织分享DDD的落地实践经验,分享期间听众一般会问很多问题,被问得最多的反倒不是限界上下文如何划分,聚合如何设计等DDD重点议题,而是DDD工程结构该怎么搭,包该怎么分这些实实在在的问题。
  事实上,DDD并未对工程结构做出要求,在码如云,我们结合行业通用实践以及自身对DDD的认识搭建出了一套适合于自身的工程结构,我们认为对于多数项目也是适用的,在本文中,我们将对此做详细讲解。
  在上一篇战略设计中我们提到,码如云是一个单体项目,其通过Java分包的方式划分出了3个限界上下文,即3个模块。对于正在搞微服务的读者来说,可不要被"单体"二字吓跑了,本文所讲解的绝大多数内容既适合于单体,也适合于微服务。
  以上是码如云工程的目录结构,在根分包 src/main/java/com/mryqr  下,分出了core  、integration  和management  3个模块包,分别对应"核心上下文"、"集成上下文"和"后台管理上下文",对于微服务系统来说,这3个分包则不存在,因为每个分包都有自己单独的微服务项目,也即DDD的限界上下文和微服务存在一一对应的关系。与这3个模块包同级的还有一个common  包,该包并不是一个业务模块,而是所有模块所共享的一些基础设施,比如Spring的配置、邮件发送机制等。在src  目录下,还包含test  、apiTest  和gatling  三个目录,分别对应单元测试,API测试和性能测试代码。此外,deploy  目录用于存放与部署相关的文件,doc  目录用于存放项目文档,gradle  目录则用于存放各种Gradle配置文件。分包原则:先业务,后技术
  在以上提及的各种模块包中,程序员们最为关注的估计是 core  包之下应该如何进一步分包了,因为core  是整个项目的核心业务模块。
  在做分包时,一个最常见的反模式是将技术分包作为上层分包,然后在各技术分包下再划分业务包。DDD社区更加推崇的分包方式是"先业务,后技术",即上层包先按照业务进行划分,然后在各个业务包内部可以再按照技术分包。
  在码如云的 core  模块包中,首先是基于业务的分包,包含app  、 assignment  等几十个包,其中的app  对应于应用聚合根,而assignment  对应于任务聚合根,也即每一个业务分包对应一个聚合根。在每个业务分包下再做技术分包,其中包含以下子分包:command  :用于存放应用服务以及命令对象等,更多相关内容请参考应用服务与领域服务;domain  :用于存放所有领域模型,更多相关内容请参考聚合根与资源库;eventhandler  :用于存放领域事件处理器,更多相关内容请参考领域事件;infrastructure  :用于存放技术基础设施,比如对数据库的访问实现等;query  :用于存放查询逻辑,更多相关内容请参考CQRS。
  在这些分包下,可以根据实际情况进一步分包。
  这种"先业务,后技术"的分包方式有以下好处: 业务直观:所有的业务模块被放在一起,并且处于一个分包级别中,让人一眼即可全景式地了解一个软件项目中的所有业务。事实上,Robert C. Martin(Bob大叔)提出了一个概念叫尖叫架构(Screaming Architecture)讲的就是这个意思。尖叫即"哇的一声"的意思,比如当你看到一栋房子时,你会说"哇,好一栋漂亮的房子!",也即你一眼就能识别出这是一套房子。 便于导航:当你要查找一个功能时,你首先想到的一定是该功能属于哪个业务板块,而不是属于哪个Controller,因此你可以先找到业务分包,然后顺藤摸瓜找到相应的功能代码。 便于迁移:每一个业务包都包含了从业务到技术的所有代码,因此在迁移时只需整体挪动业务包即可,比如,如果码如云以后要迁移到微服务架构,那么只需将需要迁出的业务包整体拷贝到新的工程中即可。
  在以上子分包中, domain  分包应是最大的一个分包,因为其中包含了所有的领域模型以及业务逻辑。在码如云项目的app  业务包下,各个子分包所包含的代码量统计如下:
  可以看到, domain  包中所包含的代码量远远超过其他所有分包的总和。当然,我们并不是说所有DDD项目都需要满足这一点,而是强调在DDD中领域模型应该是代码的主体。
  接下来,让我们来看看各个子分包中都包含哪些内容,首先来看 domain  分包:
  在 domain  分包中,最重要的当属App  聚合根了,除此之外还包含领域服务AppDomainService  ,工厂AppFactory  和资源库AppRepository  。这里的AppRepository  是一个接口,其实现在infrastructure  分包中。基于内聚原则,有些密切联系的类被放置在了下一级子分包中,比如attribute  和page  分包等。值得一提的是,用于存放领域事件的event  包也被放置在了domain  下,因为领域事件也是领域模型的一部分,不过领域事件的处理器类则放在了与domain  同级的eventhandler  包中,我们将在 领域事件中对此做详细讲解。
  command  包用于放置应用服务以及请求数据类,这里的"command"即CQRS中的"C",表示外界向软件系统所发起的一次命令。
  在 command  包中,应用服务AppCommandService  用于接收外界的业务请求(命令)。AppCommandService  接收的输入参数为Command对象(以"Command"为后缀),Command对象通过其名称表达业务意图,比如CopyAppCommand  用于拷贝应用(这里的"应用"表示业务上的应用聚合根),CreateAppCommand  用于新建应用。
  eventhandler  用于存放领域事件的处理器类,这些类的地位相当于应用服务,它们并不是领域模型的一部分,只是与应用服务相似起编排协调作用。
  infrastructure  用于存放基础设施类,主要包含资源库的实现类:
  query  用于存放与数据查询相关的类,这里的"query"也即CQRS中的"Q",我们将在本系列的CQRS中对此做详细讲解。
  自动化测试
  自动化测试包含单元测试、API测试和性能测试。在API测试中,数据库和消息队列等基础设施均通过本地Docker完成搭建,测试时先启动整个Spring进程,然后模拟前端向各个API发送真实业务请求,最后验证返回结果,如果遇到有需访问第三方系统的情况,则通过Stub类进行代替。码如云采用的是 "API测试为主,单元测试为辅" 的测试策略,其API测试覆盖率达到了90%,所有的业务用例和重要分支都有API测试覆盖,单元测试主要用于测试领域模型,对于诸如应用服务、Controller以及事件处理器等结构性设施则不作单元测试要求,因为这些类并不包含太多逻辑,对这些类的测试可以消化在API测试中。 总结
  本文主要讲解了DDD代码工程的典型目录结构,我们推荐通过"先业务,后技术"的方式进行分包,这样使得项目所体现的业务更加的直观。此外,在DDD项目中,领域模型应该是整个项目的主体,所有的领域对象和业务逻辑均应该包含在 domain  包下。在下文请求处理流程中,我们将对DDD项目中请求处理的全流程进行详细讲解。

民国才女萧红!与鲁迅先生的二三事一代才女萧红与鲁迅之间的绯闻是否真的存在?故事还得从1942年萧红嘎了后,她的那段遗言说起,其中内容引起广泛的关注,大众对那条被嘎了后想安葬在鲁迅先生身旁的那段话有最大的非议。而后声讨汉奸父亲梅思平的爱国女儿梅爱文梅爱文是梅思平和马志芸的女儿。1926年生于上海爱文义路(今北京西路),即以路名唤作爱文。1976年在杭州退休。梅思平是抗战时期的大汉奸。梅爱文生下仅7天,马志芸因染猩红热病离开人诸葛亮临终前,疯狂提醒姜维预防这3个漏洞,否则蜀汉将提前灭亡诸葛亮是三国演义中最聪明的人,他的存在,给了曹魏极大的压力,而即便他去世,仍然给姜维提了3次醒,让姜维要预防3个漏洞,只可惜姜维没有完全看懂,否则曹魏根本不可能灭亡蜀汉!你知道诸葛郭刚堂儿子回老家结婚,郭威被再度重提,郭威被嘲不如郭振有担当这郭刚堂儿子郭振已经回到老家结婚了,山东聊城这才是郭振的真正的故乡,看到郭振带着妻子一起跪拜父母,我们万千萤火都超级替郭刚堂老两口开心。很多的寻亲人都是来到了山东一起给郭振送上新婚灵山缅怀革命先烈清扫烈士陵园3月17日上午,灵山县双拥办组织县人武部武警灵山中队消防救援大队民政局退役军人事务局医保局青年志愿者到灵山县烈士陵园开展缅怀革命先烈清扫烈士陵园学雷锋志愿服务军民共建活动,用实际行土左旗革命人物革命先行者荣耀先荣耀先像荣耀先,蒙古族,蒙名谦登若宪,别名一介。是我党最早的蒙古族党员。1896年生于归化城土默特旗(今内蒙古呼和浩特市土默特左旗西园村)。祖辈牧商,家境富裕。1911年进入土默特暗箭伤人,究竟是谁伤了谁?东周时期有个郑庄公,郑庄公的爷爷是在周幽王烽火戏诸侯后,当西戎人真的打来,少数还挺身而出保卫周幽王的大将,也正因此郑庄公的爷爷获得封地,做了王公。公元前712年,郑庄公要去打许国,四川绵阳挖出7吨重的钱山,这里曾是一座南宋造假币的工厂花生地里挖出了一座由古钱币粘连成的钱山,专家本以为这是一座古代钱窖,考证后才发现这竟然是一座古代造假币的工厂,专家又是如何推断出来的呢?2003年6月27日,四川绵阳安县(今安州区平定七国之乱汉景帝刘启汉景帝,文景之治的创建者之一,与汉文帝一起开创盛世。当皇帝16年,最大功绩是平定了七国之乱,巩固了中央集权,最大的错误是杀了晁错。汉景帝在位期间,继承其父汉文帝的治国理念,采取开明物理超导与社会超导物理超导,大家都熟悉。有些物质在某个温度以下,突然对电流没有阻力。科学家把这个温度叫作临界温度。通常情况下,临界温度非常低,接近绝对零度,例如最先应用的铌锆合金(Nb75Zr),其重新学习如何做人将在人工智能的繁荣中保护你围绕AI的快速发展有很多世界末日场景。无论你是否喜欢这种猜测,我们都可以同意,基于纯粹的逻辑,事情可能会横向发展,在我们知道之前,我们将生活在最坏的科幻场景中。我的意思是,人类想出
万鸟霜天栖洞庭入冬以来,大批候鸟南飞抵达洞庭湖区。12月13日在屈原管理区东古湖湿地拍摄的小天鹅。新华社记者陈振海摄12月13日在屈原管理区东古湖湿地拍摄的小天鹅。新华社记者赵众志摄12月13日云游山西当古建遇到飞雪人间绝色当如此今年山西的冬天姗姗来迟树上的叶子似乎恋恋不舍挂在树梢上总不肯离去最近的寒潮终于带来了冬天的讯息骤降的温度呼喊的大风但初雪却迟迟没有盼来冬日最值得期盼的就是一场大雪了浪漫唯美梦幻一切多样生物多彩四川四川地处中国西南腹地,在独特的地理位置多样的地貌条件复杂的气候等因素的共同作用下,多类型的自然生态系统在四川得以充分发挥。在四川,你不仅能看到憨态可掬的大熊猫,也能观赏到林间飞跃的中科大旗案例入选2022年成都市元宇宙典型应用场景名单近日,2022年成都市元宇宙典型应用场景入选名单正式公布,共涉及45个案例。其中,由成都中科大旗软件股份有限公司(以下简称中科大旗)申报的元宇宙黄龙景区智慧文旅场景应用案例入选。随江滩20年了,哪个武汉人不是在江边长大的吃完晚饭,去江滩散个步咧。在武汉,去哪儿吃饭,去哪儿消遣,首选江边,总是我和身边人的第一反应。汉口班子选武汉天地或江汉路,武昌伢偏爱中华路,汉阳的伙计吃拦江路的蟹神咩咩。江滩所到之成都大邑面向全球公开征集城市宣传语和LOGO每经编辑赵博渊图片来源成都市大邑县提供为持续提升城市形象及内涵,增强城市影响力和吸引力,增进公众认同感和归属感,12月15日起,成都市大邑县面向全球公开征集城市宣传语及LOGO,邑东汉风云皇甫规自荐不成,张纲单车入贼营东汉风云皇甫规自荐不成,张纲单车入贼营安定人皇甫规,闻马贤不恤军事,料其必败,亦据实上闻,顺帝既不从马融之言,怎肯听信皇甫规?当然搁置不理,惟遣使催促马贤进兵。马贤进抵汉阳,尚是无诸葛亮最不该误杀的两个人,两人任留其一,蜀汉都可能一统三国看三国,多数人都感慨蜀国的寿命之短。原本东汉末年分三国,这三国是三足鼎立的存在。但是自从夷陵之战以后,蜀国的国运开始急剧向下,最终导致了蜀后主在敌营里乐不思蜀。若要比喻来说,蜀国就幸福就是适度贫困带着母亲下馆子,吃完了打包,母亲跟服务员说除了盘子不要,其他我都要。我突然问了自己一个问题我有多久没有饥饿感了?我回答不上来,总是来不及等到饥饿感的光顾,就开始吃东西了。听母亲说,冬日10件套,帮你找到仪式感当雪花散落在空中,就知道冬天来啦。那漫天白雪,那清冷孤寂,都让这个季节,多了一丝冰霜的味道。而雪地里的欢声笑语,总是很多。似乎,在冬日里,也有限定版的欢喜。有人说烤红薯是秋冬的开场我们如此渴望有一场改变命运的东风实力重要还是机遇重要?很多人都会说实力更重要,因为没有实力,就算机遇来了也抓不住。有了实力,就有等待机遇的底气,一待机遇来临,便会开启精彩的人生。而机遇,终归是会来的。并且,它还从