1.关键是接缝
接缝的概念:从接缝处可以抽取出相对独立的一部分代码,对这部分代码进行修改不会影响系统的其他部分。
那么什么样的接缝才是好接缝呢?限界上下文就是一个非常好的接缝,因为它的定义就是组织内高内聚和低耦合的边界。
2.分解MusicCorp
想象,现在有个巨大的后台单块服务,其中包含了MusicCorp在线系统所需要的所有行为。
假设识别出这个单块后台系统包含以下四个上下文。
- 产品目标 - 与正在销售的商品相关的元数据
- 财务 - 账号,支付,退款等项目的报告
- 仓库 - 分发客户订单、处理退货、管理库存等
- 推荐
3. 分解单块系统的原因
决定把单块系统变小是一个很好的开始。
增量的方式可以让你在进行的过程中学习微服务,同时也可以限制出错所造成的影响。
接下来考虑一些指导因素。
3.1 改变的速度
接下来,我们可能会对库存管理方面的代码做大量修改。
所有如果现在把仓库接缝抽出来作为一个服务,使其成为一个自治单元,那么后期开发的速度将大大加快。
3.2 团队结构
MusicCorp的交付团队事实上分布在两个不同的地区,可以把大部分代码分离出来,这样就能对此全权负责。
3.3 安全
可以对独立的服务做监控,传输数据的保护和静态的数据的保护等。
3.4 技术
4. 杂乱的依赖
当你已经失败出一些备选接缝,另一个要考虑的点是:这部分代码与系统剩余部分之间的依赖有多乱。
我们想要拉取出来的接缝应该尽量少的被其他组件所依赖。
通常时候,你会发现数据库是所有杂乱依赖的源头。
5.数据库
前面讨论了使用数据库作为服务之间集成方式的做法。
但是这种方式需要去找到数据库中的接缝,这样就可以把它们分离干净。但是这会比较棘手。
6.找到问题的关键
第一步是看看代码中对数据库进行读写的部分。
通常这部分代码会存在于一个仓储层中。
把数据库映射相关的代码和功能代码放在同一个上下文中,可以帮助我们理解哪些代码用到了数据库中的哪些部分。
但是,有时候一张表可能会被分离到不同的限界上下文中,对于这种场景比较难回答。
7. 例子:打破外键关系
例如,我们卖了400个产品,挣了3000元钱。
为了做到这一点,财务包中生成报告的代码,需要从行条目表中获取产品标题名称。总账表和行条目表之间可能存在外键关系。
快速的修改方式是:让财务部分的代码通过产品目录服务暴露的API来访问数据,而不是直接访问数据库。
那外键关联了怎么办?我们只能放弃它了。
所以你可能需要把这个约束从数据库移到代码中来实现。
这也就意味着,我们可能需要跨服务的一致性检查,或者周期性触发清理数据的任务。
8. 例子:共享静态数据
这些将共享静态数据存在数据库中的例子非常多。
所以在我们的音乐商店中,如果所有的服务都要从同一张像国家这样的表中读取数据,该怎么办?
有这么几个解决方案可供选择。
第一个方法是为每个包复制一份该表的内容,也就是说,未来每个服务也都会保存这样一份副本。
第二个方法是,把这些共享的静态数据放入代码,比如放在属性文件中,或则简单的放在枚举中。
第三个方法有些极端,即把这些静态数据放入一个单独的服务。
在大部分场景下,都可以通过把这些数据放入配置文件或者代码中来解决问题,而且它对于大部分场景来说都是很容易实现。
9. 例子:共享数据
共享的可变数据对于分离系统来说通常是一个大麻烦。
无论是财务相关的代码还是仓库相关的代码,都会向同一个表写入数据,
有时还会从中读取数据。这种情况下,如何做分离?
其实这种情况很常见:领域概念不是在代码中建模,相反是在数据库中隐式的进行建模。这里缺失的领域概念是客户。
需要把客户概念具象化。作为一个中间步骤,我们可以创建一个新的包Customer。
然后让财务和仓库这些包,通过API来访问此新创建的包。如图
10.例子:共享表
。。。