领域模型的应用

概述

领域驱动设计DDD在战术建模(后文简称建模,除非特别说明)上提供了一个元模型体系(如下图),通过这个元模型我们会对战略建模过程中识别出来的问题子域进行抽象,而通过抽象来指导最后的落地实现。
DDD构建的元模型元素脑图
这里我们谈的战术阶段实际就是这样一个抽象过程。这个抽象过程由于元模型的存在实际是一定程度模式化的。这样的好处是并非只能技术人员参与建模,业务人员经过一定的培训也是完全可以理解的。在带领不少团队实践建模的过程中,业务人员参与战术设计也是我要求的。
由于已经有不少书籍介绍DDD的元模型,这里我们就不再赘述,转而谈谈这个抽象过程中大家经常遇到的一些困惑。这些比较常见的问题可能是DDD元模型未来演进需要解决的,但我们仍然要注意业务问题和架构设计的多样性,不要过度规范,以至于过犹不及。

More...

如何实现系统解耦

为什么要解耦

在软件开发领域,解耦这个词相信大家都不陌生。在面向对象的语境下,我们会应用SOLID原则来构建高内聚低耦合的应用,实现模块间的解耦;在复杂业务系统分析和建模时,会通过DDD的战略和战术设计帮助划分领域并实现分布式系统中服务的解耦;当我们在组织大型敏捷开发团队协同工作时,通过组建自治团队来减少摩擦,从而实现团队级别的解耦。

可以看到解耦无处不在,并且以此为目的投入,大家都会觉得是无比的政治正确,因为实现了解耦,我们的系统和应用就能更快速的扩展和演进,我们的团队就能更顺畅的合作并能更加快速的实现业务价值。

但是,当我们暂时抛开将得到的种种好处,思考要如何去实现它时,却发现解耦这个词表达的意义过于抽象和模糊,它既没有描述最终的状态也没有提供实现的方法。那当我们谈解耦的时候,具体内容是什么呢?

从字面上理解的所谓耦合,通常是指两个或两个以上的物体或者体系之间相互作用彼此影响,对应到软件研发的以上场景,我们可以转换成是指两个或两个以上的模块/系统/团队之间相互作用彼此影响

在软件需要解决的业务问题越来复杂的今天,单个的系统或者团队很难在不依赖外部的情况下去实现业务目标,所以我理解的解耦并不是要消除耦合(彼此的作用和影响/依赖),而是指我们应该如何通过一定的方式和规则,来设计和管理以上提到的多个元素之间的依赖,降低耦合程度来使整个系统有序顺畅的运转。

本文将从服务间上下游的思维来讨论如何在系统架构演进过程中,持续的保持服务间的松耦合,实现解耦的目标。

More...

DDD中的上下文映射

什么是上下文映射

上下文映射,对应的英文单词是Context Map,代表的是领域驱动设计中,多个限界上下文之前的关系。方便设计者和开发者能够一目了然地看到每个限界上下文和其它限界上下文之间的关系,最终的产出可能是一张映射图,或者映射卡片。实际上的限界上下文映射的设计,不只是跟设计决策和技术实现有关,还跟企业文化、组织架构有关。

有哪些上下文映射

分离方式

分离方式(separate way),分离方式指的是两个限界上下文没有任何关系,没有关系其实就是一种非常好的设计,因为它们可以独立变化,互相影响。
但在实际的开发过程中,可能两个限界上下文会有一些耦合。如果设计者认为这两个限界上下文解耦的价值远远大于复用的价值(比如分属于两个差异很大的团队),那可以通过引入少量的重复来彻底解耦开来。
比如:在电商场景中,支付上下文,就和库存上下文没有任何关系。

客户-供应

客户-供应(customer/supplier)是我们最中间的一种上下文映射方式。一方提供服务,另一方去调用服务。我们类比水流,上游发生变化可能会影响下游,所以我们把提供服务的一方称为“上游”,使用服务的一方称为“下游”。这与调用关系刚好是相反的。
比如:在电商场景中,订单上下文依赖库存上下文,所以库存上下文就是订单上下文的上游。

发布-订阅

发布-订阅(publisher/subscriber)也是一种很常见的上下文映射方式,在实际的开发过程中往往是通过消息中间件来实现。
发布-订阅模式源自于设计模式中的“观察者模式”,上下游通过消息去通信,下游注册观察者,上游作为发布者,如果上游发生了变化,会发布一个业务事件,下游收到这个事件后进行后续的操作。
发布-订阅模式与客户-供应模式最大的不同,在于发布-订阅模式,是上游主动发起业务的变化,而不是被动等下游去调用上游。它相较于客户-供应模式而言,耦合程度会低一些。
比如:在电商场景中,订单上下文和物流上下文,就可以通过发布-订阅模式来做。订单完成后,发生订单完成事件,物流上下文监听事件开始物流配送。

More...

什么是维度退化

概念:

维度退化(Degenerate-Dimension,DD):将维度退化到事实表中,减少事实表和维度表的关联,在维度建模的数据仓库中,有一种维度叫Degenerate Dimension,中文一般翻译为“退化维度”。这种退化维度一般都是事务的编号,如订单编号、发票编号等。这类编号需要保存到事实表中,但是不需要对应的维度表,所以称为退化维度。

特点/举例:

退化维度是维度建模领域中的一个非常重要的概念,它对理解维度建模有着非常重要的作用,尤其是对维度建模的入门者。

特点:

  1. 没有对应的维度表的维度。
  2. 存储在事实表中
More...

维度表设计注意事项

1、什么是维度表?

维度是维度建模的基础和灵魂。在维度建模中,将度量称为“事实” , 将环境描述为“维度”。
维度表包含了事实表中指定属性的相关详细信息,最常用的维度表有日期维度、城市维度等。

例如:日期维表:

num 字段名 字段中文名 描述 数据类型
1 date 日期 日期 yyyMMdd格式 bigint
2 week 星期,数字型 星期,数字型 0-6 bigint
3 week_cn 星期中文名 星期中文名 星期一…… string
4 year_weeks 一年中的第几周 一年中的第几周 1 2 3…… bigint
5 mon_dt 本周周一日期 本周周一日期 bigint
6 sun_dt 本周周日日期 本周周日日期 bigint
7 month 年月 年月,yyyyMM格式 bigint
8 month_short 月份简写 月份简写,MM格式1~12 bigint
9 month_cn 月份中文名 月份中文名 一月…… string
10 quarter 季度 季度,yyyyQ1\2\3\4 string
11 quarter_short 季度 数字型 季度 数字型 1-4 bigint
12 quarter_cn 季度中文名 季度中文名 第一季度…… string
13 year 年份 年份,yyyy格式 bigint

2、维度表设计原则

维度的作用一般是查询约束、分类汇总以及排序等,我们在进行维度表设计时,应当提前考虑:

(1)维度属性尽量丰富,为数据使用打下基础

比如淘宝商品维度有近百个维度属性,为下游的数据统计、分析、探查提供了良好的基础。

(2)给出详实的、富有意义的文字描述

属性不应该是编码,而应该是真正的文字。在阿里巴巴维度建模中, 一般是编码和文字同时存在,比如商品维度中的商品 ID 和商品标题、 类目 ID 和 类目名称等。 ID 一 般用于不同表之间的关联,而名称一般用 于报表标签

(3)区分数值型属性和事实

数值型宇段是作为事实还是维度属性,可以参考字段的一般用途。 如果通常用于查询约束条件或分组统计,则是作为维度属性;如果通常用于参与度量的计算, 则是作为事实。比如商品价格,可以用于查询约 束条件或统计价格区间 的商品数量,此时是作为维度属性使用的;也可 以用于统计某类目 下商品的平均价格,此时是作为事实使用的。另外, 如果数值型字段是离散值,则作为维度属性存在的可能性较大;如果数 值型宇段是连续值 ,则作为度量存在的可能性较大,但并不绝对,需要 同时参考宇段的具体用途。

(4)沉淀出通用的维度属性,为建立一致性维度做好铺垫

有些维度属性获取需要进行比较复杂的逻辑处理,有些需要通过多表关联得到,或者通过单表 的不同宇段混合处理得到,或者通过对单表 的某个字段进行解析得到。此时,需要将尽可能多的通用的维度属性进 行沉淀。一方 面,可以提高下游使用的方便性,减少复杂度;另一方面,可以避免下游使用解析时由于各自逻辑不同而导致口径不 一致。

(5)退化维度(DegenerateDimension)

在维度类型中,有一种重要的维度称作为退化维度。这种维度指的是直接把一些简单的维度放在事实表中。退化维度是维度建模领域中的一个非常重要的概念,它对理解维度建模有着非常重要的作用,退化维度一般在分析中可以用来做分组使用。

(6)缓慢变化维(Slowly Changing Dimensions)

维度的属性并不是始终不变的,它会随着时间的流逝发生缓慢的变化,这种随时间发生变化的维度我们一般称之为缓慢变化维(SCD),缓慢变化维一般使用代理健作为维度表的主健。

缓慢变化维的三种处理方式:

① TYPE1 直接覆盖原值
适用于:不看历史数据,简单粗暴

② TYPE2 拉链表
需要在维度行再增加三列:有效日期、截止日期、行标识(可选)。
在旧的一行数据增加关链时间(end_date),新的一行数据增加开链时间和**关链时间,**多条数据加起来是一个完整的时间周期。

③ TYPE3 增加属性列
保留老字段,把新增的属性放到新的字段。比如 department 变成 old_department and new_department.

关于需求分析和客户沟通

背景

关于需求分析和工期预估一直是老大难问题,Joel 的这篇文章谈到了这个问题,我挑一些记录下来。

客户不知道他们想要什么是问题吗?

通常,在定制项目中,最常见的超支、失败和悲剧的原因总是归结为,基本上,"客户不知道他们想要什么?”
事实上,有一件事是每个初级BA都需要在开展工作前要知道的,那就是:客户其实不知道他们想要什么。不要再期望客户知道他们想要什么。这是不可能发生的。忘掉它吧。
相反,你要假设你将不得不制造一些东西,而客户将不得不喜欢它,但他们将有一点惊喜。你必须做研究,想出一个设计,以一种愉悦的方式解决客户的问题。
设身处地为客户想想。想象一下,你决定装修你的厨房,因此,你聘请了一位专业的设计师,指示要把它弄得高大上一些。你不知道如何完成这个任务,你不知道那些事厨房中必须要装的,哪些事提升体验的,这些都不是你擅长的,你想让设计师帮你完成这个事情,这就是你雇用他的原因。
有一种办法是让客户进入房间,让他们作为开发团队的成员参与到设计过程的每一步。我认为,这有点太 "极端 "了。这就好像我的设计师在设计厨房时让我出现,并要求我对每一个小细节提供意见。这对我来说很无聊,我会觉得这个设计师对我毫无价值。
假设你的客户不知道他们想要什么。根据你对这个领域的理解,你自己设计它。如果你需要花一些时间来学习这个领域,或者你需要一个领域专家来帮助你,这很好,但软件的设计是你的工作。如果你做了领域方面的功课并创造了一个好的用户界面,客户会很高兴。

冰山理论

现在,我答应告诉你一个关于在你的软件的客户(或非技术经理)的语言和程序员的语言之间进行翻译的秘密。
你知道一座冰山有90%在水下吗?那么,大多数软件也是这样的–有一个漂亮的用户界面,需要大约10%的工作,然后90%的编程工作是在盖子下面。如果你考虑到你大约一半的时间是用来修复bug的,那么用户界面只占5%的工作。如果你把自己限制在用户界面的视觉部分,即像素,也就是你在PowerPoint中看到的东西,现在我们说的是不到1%。

More...

Hexo博客安装PlantUML

Hexo 静态 blog 支持 markdown 绘制 plantuml。

安装步骤

  • 进入hexo 目录
  • 安装 npm install --save hexo-tag-plantuml

使用示例

简单时序图:

1
2
3
4
5
6
7
{% plantuml %}
Alice -> "Bob()" : Hello
"Bob()" -> "This is very\nlong" as Long
' You can also declare:
' "Bob()" -> Long as "This is very\nlong"
Long --> "Bob()" : ok
{% endplantuml %}

实现效果:

事实表设计注意事项

概述

在设计事实表的时候,和设计普通的数据库有一些差异,有以下一些注意事项:

graph LR
B(包含完整业务事实)---A(事实表设计)
C(去除多余业务事实)---A
D(分解不可加事实)---A
E(先声明粒度)---A
A---F(避免不同粒度)
A---G(保持单位一致)
A---H(处理null 值)
A---I(退化维度)
More...

请我喝杯咖啡吧~

支付宝
微信