不变的指针–一种模块化设计模式,可帮助实现微服务

模块化设计有很多好处,包括:

  • 使得更容易预测变化带来的影响
  • 帮助开发人员并行工作

但是,这比人们想象的难得多。 首先,抽象必须处于正确的级别。 太高了,它们可能变得毫无意义,太低了,它们不再是抽象了,因为它们最终将具有太多的依赖关系( 传出传入

在最近的一个数字贸易领域的绿色项目中,由于上述原因,并且由于该项目有可能发展为一个平台,我打算在后端实现良好的模块化设计(
多于可能被多个团队使用的微服务 )。 为了实现模块化设计,在白板上将后端拆分为一堆概念组件以实现购物功能。 下面列出了核心组件。

模块化组件

  • 购物组件–核心购物功能,例如购物车管理
  • 用户组件–用户管理,名称,地址等
  • 购买–有关先前交易的详细信息
  • 商家-商家API的网关,以获取有关商家产品等的信息。
  • 收藏夹–类似于亚马逊的愿望清单

现在,每个软件项目都使用不同的词“ 组件” 。 在这个项目中,一个组件被严格定义为具有某些有用功能并包含以下内容的组件:

  • 域类
  • 服务
  • 数据库模式(可以是其自己的数据库,但其想法是将其与任何其他组件持久性隔离)
  • 自己的配置
  • 自己的专用测试
  • 自己的异常代码域

外界可以通过一堆ReSTful端点访问组件。

任何组件都可以单独打包,部署等。现在,精明的想法将在思考:“ 这听起来像微服务 ”,差不多了。 对于此项目,其中一些位于同一位置,但它们经过架构设计,因此可以将它们部署到各个已部署的工件中(因此,微服务方法将很容易)。

好的,重申一下,目标是实现非常干净的模块化设计。 这意味着,我不想从一个组件的数据库方案到另一个组件的任何依赖关系,对于本博文,我们仅关注于如何实现模块化的这一方面。

现在,看看上面的组件,很快就会发现这并不容易。 例如:

  • 购物车(在购物组件中 )将具有对用户的引用(在用户组件中
  • 购物车项目(“ 购物”组件 )将引用产品(“ 商家”组件
  • 购物车(购物组件)将引用送货地址( 用户组件

域

因此,在持久层实现模块化的挑战现在应该变得更加明确。 跨组件的某种引用需要保留。 立即,任何开发人员都会问:“ 等等,如果我们仅将外键用于这些内部架构引用,我们将 免费 获得ACID和参照 完整性! ”是的。 但是,那么您将失去模块化并引入耦合。 假设您想将产品(在Merchant Component中 )从关系数据库中移开,而改用Elastic或Mongo DB之类的东西来利用它们的搜索功能。 那外键现在不是那么有用了吗?

好的,首先在这里寻找解决方案时,我考虑了组件之间的所有引用,以查看它们之间是否有任何共同之处。 显而易见的一件事是,它们本质上通常都是不可变的。 例如:

  • 当购物车项目(购物组件)指向产品(商人组件)时,它仅指向该产品。 它永远不会改变指向另一个产品。
  • 当购物车(购物组件)指向用户(用户组件)时,它也是不可变的。 我的购物车永远是我的,永远都不会变成别人。

所以我现在开始考虑首选项:

  1. 如果可能,请避免跨组件依赖(这应该是显而易见的)
  2. 如果必须使用它们,请争取不可变的引用。

因此,接下来要为这种类型的关系起一个名字-我在设计和体系结构文档中称其为“不可变指针”。 但是,对于实际代码,我需要更简洁的内容。 数据库模式已在主键上使用“ id”,在外键上使用“ {name_other_relationship} _id”。 因此,我决定将所有跨组件关系命名为所指向实体的名称和“ ref”。

因此,一些具体示例:

  • userRef(指向用户的ShoppingCart)
  • productRef(指向产品的CartItem)
  • shippingAddressRef(ShoppingCart指向ShippingAddress)

这意味着任何时候只要有人在代码,架构或日志文件中看到“ xyzRef”之类的东西,他们就知道这是一个跨组件引用。 如果不清楚,Ref是的缩写。
参考

下一步是确定实际参考的格式。 我从称为Internet的东西中获得了一些启发,当然,在抽象方面,Internet也具有类似的概念:
网页的网站包含指向其他抽象的不变的指针:指向其他网站中的网页的超链接

超级墨水

因此,类似于超链接和URL,引用将遵循分层名称间隔格式。 高级技术人员的一些好的团队意见建议继续从Web上汲取灵感,并以cp://开头层次结构名称。 CP for Commerce Platform项目的名称。 这类似于http://,我认为这是个好主意,因为它表明我们的平台已生成参考。 同样,这意味着它们在日志文件等中脱颖而出,并且可以使用分层类型引用,但可以在不同的上下文中与任何下游组件区分开。

引用的关键是生成时当然应该是唯一的。 为此,需要混合使用数据库主键或有关数据的某些独特功能(例如,使用了产品skus)

下面是一些例子:

  • userRef-> cp:// user / {用户的uuid}
  • productRef-> cp://商人/ {商人的uuid} / product / {产品的sku}
  • cardRef-> cp://用户/ {卡的uuid} /卡/ {卡的uuid}

永远是一成不变的?

如前所述,首选是避免交叉引用。 第二个偏好是使用不可变的指针(引用模式)。 但是,关于交叉分量参考可能是可变的边缘情况呢? 这会发生吗? 好吧。 通过示例最容易解释。

每个购物车不仅有一个用户,还具有一个选定的送货地址,所购买的物品将被运送到该地址。 在域模型中,用户地址位于用户组件中。 但是,与其他交叉组件参考不同,送货地址可能会发生变化。 考虑一下您的亚马逊购物车。 想象一下,您正在使用所选卡和所选地址的结帐屏幕上,但是在继续进行结帐之前,请进入用户首选项并删除您的卡和地址。 该项目必须促进类似的情况。 因此,用户删除了购物卡ID指向应该发生的情况的地址?

因此,在这里寻求解决方案的灵感时,我们可以看一下各种NoSQL模式,尤其是最流行的一种是最终一致性。 这说明与ACID不同,您不一定总是一直都需要一致性。 在某些情况下,可以基于系统能够自我协调而允许不一致。

因此,在这种情况下:

  1. 购物车使用addressRef指向特定的购物地址。
  2. 用户通过点击用户组件中的ReST端点来删除该地址。
  3. 这意味着购物车将指向一个不存在的地址。 系统不一致。
  4. 下次用户读取购物车时,在处理购物组件的请求中,用户组件会询问用户组件是否存在具有该地址ref sill的地址,并且是否不删除指针。
  5. 该系统现在是一致的

所以戴上建筑师的帽子确实很重要,我们要做好一切。 否则,模块化设计的目标就无法实现。

在这种情况下,这是值得重申的策略更多的时间

  1. 避免交叉引用。 不管您的模式有多棒,如果您有很多跨组件引用,那么很有可能将组件抽象的级别降低了。
  2. 支持不变性。 通常,不变性意味着更少的代码路径,更少的边缘情况,更少的代码复杂性。
  3. 最终的一致性。

软件构架涉及权衡取舍,并找到适当的平衡。 在这种情况下,这是在干净的模块化设计之间进行权衡,但又不能一概而论,因此无法实现。

对于任何尝试进行微服务的人,我强烈建议尝试先掌握如何在体系结构中进行模块化设计。 如果无法做到这一点,那么当您增加网络的复杂性时,事情就会变得非常复杂。

翻译自: https://www.javacodegeeks.com/2016/05/immutable-pointers-pattern-modular-design-help-achieve-microservices.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值