公司新来的阿里P7大牛,只用十分钟就教会了我实现高层次的复用

最新互联网大厂面试真题、Java程序员面试策略(面试前的准备、面试中的技巧)请移步GitHubgit


做为开发人员,你对复用这个概念必定不陌生。在开发过程当中,咱们把系统中通用的代码逻辑抽取出来,变成公共方法或公共类,而后在多个地方调用,这就是最简单的技术上的复用。程序员

但一开始,咱们不会过多地考虑复用,当一个新项目过来,咱们会选择最直接的方式来实现,结果每每是欲速而不达,好比说:github

好不容易搞定了一个项目,接着又有新的相似项目过来,咱们又要从头再来;项目的代码是定制的,项目结束后,系统维护的噩梦刚刚开始。面试

若是项目缺少沉淀,每一个项目都是全新的开始,出现这些状况,一点都不意外。而要想解决这个问题,咱们一开始就要考虑系统的复用性。算法

复用,它可让咱们站在巨人的肩膀上,基于现有的成果,快速落地一个新系统编程

那么,咱们在作架构设计时,如何实现系统的高可复用呢?架构

今天,我就针对复用这个话题,首先和你介绍一下,复用具体都有哪些形式;而后,我会针对最有价值的业务复用,带你了解如何划分服务的边界,让你可以在工做中,设计一个能够高度复用的系统。框架

复用的分类

复用有多种形式,它能够分为技术复用和业务复用两大类。技术复用包括代码复用和技术组件复用;业务复用包括业务实体复用、业务流程复用和产品复用。ide

从复用的程度来看,从高到低,咱们能够依次划分为产品复用 > 业务流程复用 > 业务实体复用 > 组件复用 > 代码复用。微服务

公司新来的阿里P7大牛,只用十分钟就教会了我实现高层次的复用

接下来,我就按照复用度从低到高,对这些复用方式进行一一分析,帮助你更好地理解架构的可复用性。

技术复用

首先是代码级复用,这部分应该是你最熟悉的了。这里包括你本身打包的类库,第三方提供的 SDK,还有各类算法封装等。咱们的代码能够直接调用它们,物理上也和咱们的应用打包在一块儿,运行在同一个进程里。代码级复用是最低层次的复用,你能够把它看成你本身源代码的一部分。

再往上,是技术组件复用。这些组件有咱们本身封装的,更多的是大量开源的中间件,好比Redis、MQ、Dubbo 等;组件也包括各类开发框架,好比 Spring Cloud。这些基础组件技术复杂度很高,它们的存在,极大地简化了咱们的开发工做。

值得注意的是,代码级复用和技术组件复用都属于工具层面,它们的好处是在不少地方均可以用,但和业务场景隔得有点远,不直接对应业务功能,所以复用的价值相对比较低。

业务复用

咱们知道,系统最终是为业务而服务的,若是可以实现直接的业务复用,那系统开发的效率就更高。在前面的课程中,咱们讨论架构的演进过程时,不少地方谈到了业务能力的复用,好比说,微服务强调单个业务实体的封装和复用,而中台进一步实现了企业级业务能力的复用。

因此接下来,咱们就从比较简单的业务实体复用开始提及。

业务实体复用针对细分的业务领域,好比订单、商品、用户等领域。它对各个业务领域的数据和业务规则进行封装,将它变成上层应用系统能够直接使用的业务组件。

业务流程的复用针对的是业务场景,它能够把多个业务实体串起来,完成一个端到端的任务。好比说,下单流程须要访问会员、商品、订单、库存等多个业务,若是咱们把这些调用逻辑封装为一个下单流程服务,那下单页面就能够调用这个流程服务来完成下单,而不须要去深刻了解下单的具体过程。相比单个的业务实体复用,业务流程的复用程度更高,业务价值也更大。

最高层次的复用是对整个系统的复用,好比说一个 SaaS 系统(Software-as-a-Service),它在内部作了各类通用化设计,容许咱们经过各类参数配置,获得咱们想要的功能;或者说一个 PaaS(Platform-as-a-Service)平台,它会提供可编程的插件化支持,容许咱们“嵌入”外部代码,实现想要的功能。

这种产品级的复用,它的复用程度无疑是最高的。这样的系统,在落地的时候,它无需核心的开发团队进行开发,只由外围的实施团队负责就能够了,这样,一个项目的上线就能简化为一次快速的实施,不但上线周期短,系统也更稳定。

固然,实现这样的复用,难度也是很大的,你既要对所在行业的业务有很全面的理解,又要有很强的抽象设计能力。这类系统中,比较典型的有 Salesforce 的 CRM 系统和 SAP 的ERP 系统。

如今,咱们先对复用作个总结。从技术复用到业务复用,越往上,复用程度越高,复用产生的价值也越大,但实现起来也越复杂,它能复用的场景就越有限。在实际工做中,技术层面上的复用相对比较简单,咱们对这部分的认知也最多,并且因为开源的普及,如今有丰富的中间件让咱们选择,咱们能够基于它们,逐步构建适合本身的技术体系。

但若是咱们能进一步打造业务中间件,并在这个基础上,造成业务平台,这样,咱们就能实现更高的业务级复用,能够更高效地支持系统的快速落地

而在实现业务组件化和平台化的过程当中,首要的问题就是基础服务边界的划分。边界划分决定了服务的粒度和职责,在实际工做中,也是很是困扰咱们和有争议的地方。

接下来,我就针对基础服务边界的划分,和你分享我本身在项目开发的过程当中,总结的一些实用的原则和作法。

基础服务边界划分

服务边界划分要解决“我是谁”的问题,它实现了服务和周边环境的清晰切割。

咱们都知道,服务包含了业务数据和业务规则,并提供接口给外部访问,其中,接口是服务的对外视图,它封装了服务的业务数据和规则。

因此从边界划分的角度来看,咱们就是要肯定哪些数据属于这个服务,哪些接口功能由这个服务提供。这里,我总结了 3 个基础服务边界划分的原则,供你设计时作参考。

首先,是服务的完整性原则

你在划分服务的边界时,须要确保服务内部数据的完整性。

举个例子,一个商品服务的数据模型,不只要有商品基本信息,好比商品名称、价格、分类、图片、描述等;还须要包含商品的扩展信息,如商品的各类属性、商品标签等;最后还要包含各类复杂商品类型的定义,好比组合商品、套餐商品、多规格商品等。

另外,你还要保证服务功能的完整性。对于服务使用者来讲,他们是以业务的角度看服务,而不是纯粹的数据角度。好比一个套餐商品,在服务内部,它是多个单品的复杂组合,但从服务调用者的角度来看,它就是一个商品。

那如今问题来了,对于套餐的价格,商品服务是给出一个最终价格呢?仍是给出各个单品的价格,而后让调用方本身算最终价格呢?咱们知道,套餐的价格不是各个单品价格累加的结果,它包含了必定的优惠,若是它的价格由服务调用方来算,这会致使商品的部分业务规则游离于服务外面,破坏了商品服务的功能完整性。

在实践中,有些服务只是存储基础数据,而后提供简单的增删改查功能,这样一来,服务只是一个简单的 DAO,变成了数据访问通道。这样的服务,它的价值就颇有限,也容易被服务调用方质疑。所以,咱们要尽量在服务内部封装完整的业务规则,对外提供完整的业务语义,最大程度地简化服务的使用。

因此,当你在划分服务边界时,要保证服务数据完整、功能全面,这样才能支撑一个完整的业务领域

其次,是服务的一致性原则

也就是说,服务的数据和职责要一致,谁拥有信息,谁就负责提供相应的功能。

服务内部的业务逻辑要尽可能依赖内部数据,而不是接口输入的数据,不然会形成数据和业务规则的脱节(一个在外面,一个在里面),若是服务对外部的依赖性很强,就没法提供稳定的能力了。

不少时候,咱们对一个功能到底划分到哪一个服务,有很大的争议。这时,咱们能够结合这个功能所依赖的数据来判断,若是功能所须要的大部分数据都存储在 A 服务里,那固然由 A服务来提供接口比较合适,这样接口输入的数据比较少,不但简化了服务对外部的依赖,同时也下降了接口调用的成本。

给你举个例子,在订单小票上,咱们常常能看到一些优惠信息,好比说商品原价是多少,其中由于满减优惠了多少,由于商品特价减免了多少。这个优惠计算的结果是订单的一部分,毫无疑问,它须要保存在订单服务里。

但这个订单的优惠计算过程,却不是由订单服务来负责,而是由独立的促销服务负责的。由于优惠计算所须要的优惠规则是在促销服务里定义的,促销服务能够在内部拿到全部的优惠规则,而后完成整个优惠计算。

不然,若是是由订单服务负责优惠计算,订单服务的调用者就须要在接口中提供完整的促销规则,不但调用成本高,并且外部促销规则的改变会影响订单服务的内部实现。

因此在这里,促销服务负责促销规则的维护,以及对应的优惠计算功能;订单服务负责优惠结果数据落地,以及后续的查询功能。这样,每一个服务存储的数据和对外提供的功能是一致的。

最后一个,是正交原则

既然是基础服务,它们就处于调用链的底层,服务之间不会有任何的调用关系,也就是说基础服务相互之间是正交的。好比说会员服务和商品服务,它们表明不一样维度的基础业务域,彼此之间不会有调用关系。

正交还有另一种状况:服务之间有数据的依赖关系,但没有接口的调用关系。

好比说,订单明细里包含商品 ID 信息,但订单服务内部不会调用商品服务来获取商品详情。若是页面须要展现订单的商品详情,针对这个具体的业务场景,咱们能够在上层的聚合服务里,经过聚合订单服务和商品服务来实现。

总结

可复用是架构设计的一个重要目标,今天咱们对复用进行了梳理,包括复用有哪些形式,以及它们有哪些价值,相信你如今对复用已经有了一个总体的认识。业务上的复用比纯粹的技术复用有更高的价值,咱们要尽可能往这个方向上靠。

在实践中,落地基础服务是实现业务复用的有效方式,而基础服务边界的划分,它有科学的成分,但更多的是一种艺术,这里我提供了几个实用的划分原则,你能够在工做中结合实际状况,灵活地运用它们。