Blog

转自:/mp.weixin.qq.com/s/VlBujq9F9F6yC4N5im4S4g 领域驱动设计DDD在战术建模(后文简称建模,除非特别说明)上提供了一个元模型体系(如下图),通过这个元模型我们会对战略建模过程中识别出来的问题子域进行抽象,而通过抽象来指导最后的落地实现。 这里我们谈的战术阶段实际就是这样一个抽象过程。这个抽象过程由于元模型的存在实际是一定程度模式化的。这样的好处是并非只能技术人员参与建模,业务人员经过一定的培训也是完全可以理解的。在带领不少团队实践建模的过程中,业务人员参与战术设计也是我要求的。 由于已经有不少书籍介绍DDD的元模型,这里我们就不再赘述,转而谈谈这个抽象过程中大家经常遇到的一些困惑。这些比较常见的问题可能是DDD元模型未来演进需要解决的,但我们仍然要注意业务问题和架构设计的多样性,不要过度规范,以至于过犹不及。 业务对象的抽象 通过对业务问题的子域划分,我们找到了一些关键的业务对象。在开始进行抽象前一个必须的步骤就是“讲故事”! 讲什么故事呢?关于这个子域解决的业务问题或者提供的业务能力的故事。既然是故事,就必须有清晰的业务场景和业务对象之间的交互。这件事情看起来是如此自然和简单,然则一个团队里能够站起来有条不紊陈述清楚的却没有几人。读到这里的读者不妨停下来试试,你是否能够把现在你所做的业务在两三分钟内场景化地描述出来? 这么做显然目的是让我们能够比较完整地思考我们所要提炼和抽象的业务对象有哪些。只有当我们能够“讲”清楚业务场景的时候,才应该开始抽象的步骤。对于一个业务对象,我们常见的抽象可以是“实体”(Entity)和“值对象”(Value Object)。 这两个抽象方式在定义上的区别是,实体需要给予一个唯一标识,而值对象不需要(可以通过属性集合标识)。当然另外一个经常引用的区别是,实体应该是有一个连续的生命周期的,比如我们在一个订单跟踪领域里抽象订单为一个实体,那么每个订单应该有一个唯一识别号,订单也应该有从下单创建到最后交货完成的生命周期。 显然,如果不增加其它约束条件,值对象的抽象是没有意义的,都用实体不就行了?但如果我们稍微思考一下一个实体的管理成本,比如需要保证生命周期中实体状态的一致性,那么我们就会发现值对象变得很简单很可爱。当一个对象在我们(抽象)的世界里不能改变的时候,一切都变得简单了,这个对象被创建后只能被引用,当没有引用时我们可以把它交给垃圾回收自动处理。 随着高并发、分布式系统的普及,实际上我们在对业务对象抽象的第一步思考是能否用值对象。如果大家实现的技术架构采用函数范式的语言(类似Closure),那么首先考虑值对象抽象可能就是一个建模原则了。 对象抽象初步完成后,一定要再重复一次之前的故事来审视一下我们的建模。经历这个抽象过程后,参与讨论的每个人都应该发现自己更清晰业务的需求和需要提供的能力了。 聚合的封装 DDD元模型中一个核心概念叫“聚合”(Aggregate)。这个从建筑学来的名词非常形象,建筑学上我们翻译为“骨料”,是形成混凝土的重要元素,也是为什么混凝土如此坚固的基础。 同理,在DDD建模中,聚合也是我们构建领域模型的基础,并且每个聚合都是内聚性很高的组合。聚合本身完成了我们对骨干业务规则的封装,减小了我们实现过程中出错的可能。 以上面那个订单跟踪领域为例,假设我们允许一个订单下存在多个子订单,而每个子订单也是可以独立配送的,这种情况下我们抽象出“子订单”这个实体。显然订单和子订单存在业务逻辑上的一致性,没有订单的时候不应该创建子订单,更新子订单的时候应该同时“通知”所属的订单。这个时候如果采用把订单和子订单聚合起来的封装就很有必要了。 采用聚合抽象的结果就是访问每个子订单都需要从相关的订单入口(i.e., 订单为聚合根),存取时我们都是以这个聚合为基本单位,即包含了订单和订单下面的所有子订单。显然这样的好处是在订单跟踪这个领域模型里,订单作为一个聚合存在,我们只需要一次性梳理清楚订单和子订单的逻辑关系,就不需要在未来每次引用时都考虑这里面的业务规则了。 在建模过程中,很多团队并没有努力思考聚合的存在。封装这个在技术实现领域的基本原则在建模时却很少被重视起来。开篇提到在战术建模过程中强调业务领域人员的参与也是为了解决这个问题,聚合的识别实际是针对业务规则的封装,当我们不理解业务规则的时候是无法做出是否封装的判断的。 一言以蔽之,识别聚合是认知潜在核心业务规则的过程,而定义出来的聚合是在大家共识基础上对核心业务规则的封装。 领域服务的定义 在最初的元模型定义里,领域服务让不少人纠结,一个经典的例子是在账户管理领域里对“转账”这个业务行为的抽象。由于转账本身是作用在至少两个账户上的,所以把转账作为一个账户的行为显然是不合适的。那么如果我们把转账名词化抽象成一个实体呢?感觉也是比较别扭,毕竟转账是依附于账户存在的。 这个时候DDD在元模型里提出了服务(Service)这个抽象,转账被抽象为一个服务感觉就顺畅多了。同样道理,在我们上面的订单跟踪领域里,如果跟踪的过程中需要进行短信的通知,一个比较好的建模就是抽象出一个“通知”服务来完成。 我经常会用静态方法来帮助技术人员理解服务的抽象(虽然服务并不一定用静态方法来实现)。服务本身就像一个静态方法一样,拥有一定的逻辑但不持有任何的信息,从整个领域来看也不存在不同“版本”的同一个服务。 一个经常困扰大家的问题是对Service这个词语的限定,有的分层架构设计里会出现领域服务(Domain Service)和应用服务(Applicaiton Service)。大多数时候应用服务在领域服务的上层,直接对外部提供接口。如果存在这样的分层,那么领域服务就不应该直接对外,而应该通过应用服务。 举个例子,前面的订单消息通知如果是一个领域服务,在完成订单状态变化时创建通知消息,而最后的通知以短信的方式发给设定的人群,这样就应该有一个相应的应用服务,包含了具体的业务场景处理逻辑。之后也可能有一个邮件通知的应用服务,同样调用了这个通知领域服务,但通过邮件渠道来完成最终的业务场景。 由于微服务架构的流行,每个子领域的粒度已经相当细了,很多时候已经没有这样的领域服务和应用服务的区分了。当然从简单性角度出发这是好事情。在整个建模过程中,服务的抽象往往是最不确定的,也是最值得大家反复斟酌的地方。 […]

READ MORE

re-repair

By : -

转自 /mp.weixin.qq.com/s/hGN3umfQ3aZU_Gq-fY8tOg Any fool can write code that a computer can understand. Good programmers write code that humans can understand. 普通的工程师堆砌代码,优秀的工程师优雅代码,卓越的工程师简化代码。如何写出优雅整洁易懂的代码是一门学问,也是软件工程实践里重要的一环。笔者推荐三本经典的书籍《代码整洁之道 》、《编写可读代码的艺术》、《重构:改善既有代码的设计》,下文重点将从注释、命名、方法、异常、单元测试等多个方面总结了一些代码整洁最佳实践,大部分是笔者总结于以上三本书中的精华,也有部分是笔者工程实践的总结。篇幅有限,本文将总结性给出一些实践建议,后续会有文章来给出一些代码整洁之道的事例。 注释 不要给不好的名字加注释,一个好的名字比好的注释更重要 不要“拐杖注释”,好代码 > 坏代码 + 好注释 在文件/类级别使用全局注释来解释所有部分如何工作 […]

wok

开发人员如何能够胜任测试?工程效能团队如何赋能开发人员,帮助开发人员高效地完成高质量测试? 现在包括 Google、Facebook 和 eBay 等一线互联网巨头公司都在逐渐推行“没有专职测试,测试工作由开发人员完成”的全新模式,原本专职的业务功能测试团队的规模逐渐缩小,有些甚至已经完全没有了,而原本的测试开发团队逐渐在向工程效能(Engineering Productivity)团队转型。这些互联网巨头之所以能够很好地落地这种全新的模式,是因为他们都较好地解决了这个模式的两个最大的难题: 开发人员如何能够胜任测试? 工程效能团队如何赋能开发人员,帮助开发人员高效地完成高质量测试? 本文会围绕这两个问题来展开讨论。 首先让我们一起看一下开发人员自己做测试都会遇到哪些问题和阻碍。 开发人员自己做测试会遇到哪些问题 人性角度引发的问题 首先从人性的角度来看,开发人员通常是属于“创造性思维”,自己开发的代码就像是亲儿子一样,怎么看都觉得实现很棒;而测试人员则属于“破坏性思维”,测试人员的职责就是要尽可能多的找到潜在的缺陷,而且专职的测试人员通常已经在以往的测试实践中积累了大量典型的容易出错的模式,所以测试人员比起开发人员,往往更能客观且全面做好充分的测试。 思维惯性的问题 刚才是从人性角度上来讲的,如果从技术层面来看,由开发人员自己测试,会存在严重的“思维惯性”,通常开发人员在设计和开发过程中没有考虑到的分支和处理逻辑,在自己做测试的时候同样不会考虑到。比如对于一个函数,其中有一个 String 类型的输入参数,如果开发人员在做功能实现的时候压根没有考虑到 String 存在 Null 值得可能性,那么代码的实现里面也不会对 Null 值做处理,连带结果就是测试的时候就更不会设计 Null 值得测试数据,这样的“一条龙”缺失就会给代码的质量留下了缺陷隐患。更糟糕的是,对于这种情况,即便启用了代码覆盖率指标去衡量测试完整程度,也不能有效暴露这类问题,因为处理 Null 值得代码压根没有写,又何来代码覆盖率一说呐。 被测试环境和测试执行环境的复杂性问题 有专职测试的时候,测试工作是专职测试人员完成的,专职测试人员通常会负责搭建被测试环境以及管理测试执行环境。被测试环境好理解,就是 […]

READ MORE

一、内容概览 本篇将介绍EntityFramework(以下简称EF)CodeFirst中在SQL Server、Oracle中的不同数据关系(一对一、一对多、多对多)的配置方式及效果。 本篇主要目的用于效果演示,所以在代码在编写上无任何实际参考意义。 二、测试环境 1、程序包版本 <?xml version="1.0" encoding="utf-8"?> <packages> <package id="EntityFramework" version="6.2.0" targetFramework="net471" /> <package id="Oracle.ManagedDataAccess" version="12.2.1100" targetFramework="net471" /> <package id="Oracle.ManagedDataAccess.EntityFramework" version="12.2.1100" targetFramework="net471" /> </packages> 2、Oracle版本:Oracle 12c 标准版 3、SqlServer版本:SqlServer […]

READ MORE

一、内容概览 在搭建Hive环境中,我们对Hive有了一个初步的、表面的认识:Hive有点像一个数据库,因为它可以执行SQL脚本;它又有点像MapReduce程序,因为它的执行过程就是一个MapReduce的过程。那么Hive到底是什么?它能给我们解决哪些问题?我们为什么要用Hive?Hive又有哪些基本概念? 阅读前提:稍微了解Hadoop MapReduce概念和数据库基本知识。 二、Hive是什么 说到Hive就不得不提到针对大数据的计算模型——MapReduce:它可以将计算任务分割成多个处理单元,然后分散到许多普通服务器上,从而降低成本并提供足够的横向扩展性。 不过,还有一个问题,那就是用户如何从一个现有的数据基础架构转移到Hadoop上,而这个基础架构是基于传统关系型数据库和SQL的。对于大量的SQL用户(DBA、程序员等)来说,这个问题如何面对? Hive就因此而生。Hive提供了一种Hive查询语言(HiveQL或HQL)的SQL语言,用于查询存储在Hadoop集群中的数据。 即便是一些常见的数据运算,编写底层MapReduce程序对经验丰富的Java开发工程师来说也是非常麻烦的。而Hive可以解决这个痛点。开发或分析人员只需要集中精力关注查询本身就可以了。Hive会在底层将大多数的查询转换为MapReduce任务,这不仅简化了数据分析的操作,同时也提高了Hadoop的可扩展性。 三、Hive的使用场景 No Silver Bullet Hive最适合于数据仓库应用程序,使用这类程序进行相关的静态数据分析,不需要快速反馈结果,而且数据本身也不会经常发生变化。 Hive不是一个完整的数据库。Hive的查询时基于MapReduce任务的,而MapReduce任务的启动过程需要消耗较长的时间,所以Hive查询耗时比较严重。传统数据库秒级可以完成的查询,在Hive中可能都需要几十秒(在搭建Hive环境)的简单例子的输出结果中可以看出来。而且Hive是不支持事物的。 因此,Hive最适合数据仓库应用程序,它可以维护海量数据,并对数据进行分析挖掘,最终形成结果或分析报告等。 传统的数据仓库应用程序中,大多数是基于使用SQL的关系数据库实现的,所以Hive降低了将这些应用程序一直到Hadoop上的难度。 不过,需要注意的是与大多数关系数据库提供的SQL语言一样,HiveQL也没有完全遵守ANSI SQL标准,它和SQL Server、Oracle、MySQL的语法多少都存在差异(与MySQL语法最接近)。 四、Hive体系结构 首先从一张图来了解一下Hive的体系结构: Hive在结构上主要由三块构成:Hive服务、Hive客户端和Hive存储与计算。 4.1 Hive服务 Hive的服务有很多种(通过hive --service --help命令可查),这里只介绍一部分常用的服务。 1、前面我们直接在shell环境下操作Hive,这个shell环境就是Hive服务中的一种:CLI服务,这也是Hive启动时默认的服务。 2、Hive可以承载一个Thrift服务,允许用不同语言编写的客户端对其访问。这就是hiveserver2服务。 […]

READ MORE

duotype

By : -

一、Hadoop 搭建Hadoop伪分布式 HADOOP完全分布式搭建 HADOOP在WINDOWS开发机调式运行错误 二、Hive 搭建Hive环境 Hive基础知识和体系结构 HIVE错误整理

palatoglossus

library case

By : -

一、内容概览 Hive是Hadoop生态系统中必不可少的一个工具,它提供了一种SQL(结构化查询语句)方言,可以查询存储在Hadoop分布式系统(HDFS)中的数据或其他和Hadoop集成的文件系统,如MapR-FS、Amazon的S3和像HBase(Hadoop数据库)和Cassandra这样的数据库中的数据。 本篇介绍如何在Hadoop集群上(这里我有一个现成的Hadoop集群环境,所以这整个过程是在Hadoop集群环境上操作的)搭建一个Hive环境并简单了解一下Hive能做什么。 二、下载安装Hive 首先在/www.apache.org/dyn/closer.cgi/hive/下载一个Hive的二进制tar包。这里我选择的版本是2.2.0。 在/usr/local/hive位置解压tar包 打开/etc/profile在文件底部添加如下内容配置环境变量 export HIVE_HOME=/usr/local/hive export PATH=$HIVE_HOME/bin:$PATH 执行source /etc/profile使配置生效。 此时Hive就安装好了。 三、运行Hive 在运行Hive之前,让我们再执行一个命令:schematool -initSchema -dbType derby,该命令为了初始化Hive的元数据存储服务数据库。 注意,该命令和启动Hive的命令的执行都会在工作路径下生成一个metastore_db目录,所以如果在不同目录下执行该命令会产生多个metastore_db目录,这里建议测试时选择一个统一的路径。本例只适用于测试,后面会有更通用的方式介绍。 初始化metastore完成后就可以真正的启动Hive了。 3.1 Hive的shell环境 在命令行里输入hive即可启动Hive的shell环境: [root@hadoop-namenode-01 ~]# hive which: no hbase […]

9789588986

启动Hive CLI报错: Exception in thread "main" java.lang.RuntimeException: org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient at org.apache.hadoop.hive.ql.session.SessionState.start(SessionState.java:614) at org.apache.hadoop.hive.ql.session.SessionState.beginStart(SessionState.java:549) at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java:750) at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java:686) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) […]

READ MORE

某日打开浏览器发现会弹出很多乱七八糟的广告,第一感觉是运营商又fangjian了。仔细看了看广告内容感觉又不太像,运营商胆子没这么大,有些sax的广告也敢放。 观察广告的顶部都有一个Countflix的标识,于是网上找了一下。说可能是安装了什么被捆绑的软件导致的。于是找了下,还真找到个不认识的软件,卸载之。重启后发现还是有广告。 网上有人说是不是DNS已被篡改。于是打开DNS配置界面发现DNS服务器那里是空的,心想,果然是DNS的问题(果然,我还是太天真了),然后把DNS给加上了。可是问题依旧。 最后在cmd下面用ipconfig /all命令打了一下发现猫腻了 起作用的DNS其实是上面两个(82.163.143.176,82.163.142.178)[流汗]。 netsh interface ip set dns "以太网" static 114.114.114.114 ipconfig /flushdns 重启后打开浏览器,再无广告。VV

READ MORE

原文地址 随着Windows Server 2016添加对Docker容器支持,大家一定会想知道Windows容器和Linux容器之间的差别。这里做一个简单的概述。 为了简单起见,我们从这两者相似点和差异点来看: 相似点 Linux和Windows上的Docker容器有以下几点类似之处: 它们都被设计用于作为应用程序的容器。 运行不依赖于虚拟机管理程序或虚拟机。 都可以通过Docker进行管理(在Windows环境下可以使用PowerShell来管理)。 它们仅支持主机操作系统支持的应用程序。也就是说Windows上的Docker只能托管Windows应用程序,而Linux上的Docker仅支持Linux应用程序。 提供了相同的可移植性和模块化功能。 差异点 以下是Docker在Windows上的不同之处: Docker仅支持特定版本的Windows(目前为Windows Server 2016和Windows 10)。相比之下,Docker可以在任何类型的基于Linux(内核不低于3.13)的操作系统上运行。 即便是在Docker支持的Windows版本中,Windows对镜像的兼容性也有更严格的要求。更多相关信息在这里。 Windows上的容器尚不支持的一些Docker的网络功能。在这里的底部有详细说明。 Windows上不支持大多数用于Linux上Docker容器编排系统。Docker Swarm是个例外。(Windows也正在开发对k8s和mesos这类容器编排引擎的支持)。 非Docker容器和Windows 值得一提的是,Docker是目前唯一与Windows兼容的主要容器平台。其他类型的容器,例如OpenVZ和LXD仍然只能在Linux上运行,并且在可预见的将来也是如此。 由于这些容器平台相对于Docker有着不同类型的使用场景,因此Windows对这些容器的支持与否并不影响我们决定是在Windows还是Linux上运行Docker。尽管如此,Docker仍是Windows上唯一的容器选项,这一事实非常重要,因为这一点突出了Windows的容器生态系统现在比Linux容器世界要小得多。

READ MORE
Scroll Up