【细品架构8/100】好代码是架构的根基

本文主要是继续研读了资深架构师王概凯Kevin执笔的《架构漫谈》系列的《架构漫谈(八):从架构的角度看如何写好代码》的心得感觉。王概凯Kevin结合本身多年的架构经验,经过不一样的视角,从新审视架构的本质,从而产生一力做《架构漫谈》系列,做者但愿可以抛出本身从实践中得出的一些观点,并引起你们的一些思考,欢迎你们沟通讨论。网络

如须要阅读原文,请关注公众号“聊聊架构”,从历史文章中获取《架构漫谈》系列。架构

本文内容结构图:post

 

好代码是架构的根基

 

  1.  

当咱们有了好的架构,那就须要考虑架构如何落地,而这时候代码就显得无比重要了!千万不要让代码成为架构扩展的瓶颈。性能

在上篇文章中,咱们得出一个结论,软件架构实际上包括了:代码架构,以及承载代码运行的硬件部署架构。实际上,硬件部署架构最终仍是由代码的架构来决定。由于代码架构不合理,是没法把一个运行单元分拆出多个来的,那么硬件架构能分拆的就很是的有限,整个系统最终很难长的更大。单元测试

常常会据说,重写代码,推翻原有架构,从新设计等等说法,来讲明架构的进化。这实际上就是当初为了完成任务,没有充分思考所带来的后果。这也并非架构进化的事情,而是我的对问题领域的逐渐深刻理解的过程学习

因此,本文进一步探讨如何把架构的思考进行落地,细化到咱们代码的实践当中,尽可能不要让代码成为系统长大的瓶颈,下降架构分拆的成本。测试

  1.  

在前面文章提到,软件其实是对现实生活的模拟,虚拟化。这是一个很是重要的前提,直接决定了咱们的代码应该分为几部分。结合每一个部署单元所承担的责任,能够明确的拆分为两个不一样的责任:设计

  1. 表达业务逻辑的代码。不少人把这部分叫作Domain Logic,或者叫Domain Model。这部分实际是来源于生活的,必须保持和现实生活中的切分一致,并不是人为的抽象而成。对象

  2. 对用户提供访问并保存业务逻辑运行结果的代码。计算机的状态保存有一个缺陷,本机保留业务运行结果有很大的问题,通常都在外存储设备上保存,也便于扩展。接口

因此单个部署单元的代码能够分为两个部分,以下图所示:

 

单个部署单元代码架构

 

从这个图中能够看出,软件代码的相关利益人为运行时的访问人员和存储设备。而service的代码是最复杂的,须要服务于三方,代码人员的负担是最重的。为了把这三方的变化对service的影响降到最低,对于service还必须进一步的分拆为三个部分,让每个部分都可以独立的变化,这样这三方的变化就不会产生连锁响应,下降成本。以下图所示:

 

Services拆分代码架构

 

这样,就划分红了几个责任:

  1. Service就专一于user的需求,并组合Glue Code提供的服务完成需求。

  2. Glue Code专一于组合business的调用,管理Business里面对象的生命周期,而且经过Repository保存或加载Business的状态

  3. Business专一于实现业务的核心模型

  4. Repository专一于数据的保存,并和存储设备一一对应。

你们注意看,仍是树形架构。而且左侧的主要须要计算机的相关理论知识,而且要直接面对用户的需求。右侧的更多的须要面对业务的核心。只要这几块的开发人员互相商量好了接口定义,这几个部分的开发就能够并行的进行,极大的提高开发的效率,缩短开发的时间。要作好这几部分,还须要注意,逻辑只容许存在于Business中,Service、Glue Code、Repository都不容许存在业务逻辑。为何呢?首先咱们来看看什么叫业务逻辑。

  1.  

什么叫业务逻辑

首先这个定义的前提是指软件代码中的逻辑,不是现实生活中的逻辑。在软件代码中,不需缩进和计算的顺序调用,包括缩进的代码目的是cache exception的,都不算逻辑,除此之外都是逻辑。如下用严格的顺序调用来指代这种代码。由于顺序调用是计算机的特性,由编译器来决定的,固然最本质的是由于咱们计算的基础都是图灵机。在现实生活中,顺序调用也是逻辑,你们不要和咱们这里说的业务逻辑相混淆。

为何说除了Business代码中有逻辑之外,其余地方不能有逻辑呢? 咱们每一个部分分别分析:

  • 若是service里面不是严格的顺序调用,有不少分支,那么说明这个service作了两件或者两件以上的事情。必须把这个service分拆,确保每一个service只作一件事情。由于若是不这么分拆的话,一旦这个service中的某个部分发生变更,其余的部分的执行一定会受影响。而肯定到底有哪些影响的沟通成本很是高,其余相关利益方没有动力去配合,咱们每每不会投入精力仔细评估。最后上线会出不少不可预料的问题,最终会致使损失用户的利益,而且确定会致使返工,损坏本身的利益。若是是有计算的逻辑的话,好比受益计算,订单金额计算等,那么这部分应该是Business代码须要完成的,不能交给service代码来实现。

  • Glue Code里面若是不是严格的顺序调用,同理会和service同样遇到一样的问题

  • Repository里面若是不是严格的顺序调用,包括存储访问的代码里面(好比SQL),会致使逻辑进入到存储设备中。存储设备的主要目的是拿来存储的,一旦变成了逻辑计算的主体,就会致使存储设备没法经过增长机器的方式横向扩展长大。这个时候就没有架构了,只能换性能更好的机器,这个叫scale up。只有scale out才能算架构。

以上都会致使架构没法快速的横向扩展和分拆,而且增长了修改的成本,这些是不符合开发人员以及业务的利益的。

  1.  

这么作的好处有哪些呢?

Service、Glue Code、Repository里面的代码是严格的顺序调用,那么这些代码只要作连通性测试便可,不须要单元测试。由于这些代码都须要和不少上下文打交道,很难作单元测试。这样才算是真正的组合。

Business不访问任何上下文,不访问任何具体的设备,因此这部分代码是很是容易些单元测试的,而且单元测试必须100%覆盖。由于其余地方没有业务逻辑,因此一旦有问题,就能够判定是Model的问题,单元测试确定能够发现。若是单元测试没有发现问题,那么单元测试必定有问题。线上问题的模拟也就变得很是的简单,单元测试也可以获得进一步的补充。

Repository很容易按照存储设备自己的最小访问粒度来完成工做,好比DB,彻底能够作到单表访问。由于这个时候存储设备只关心存取数据,彻底和业务没有关系。作表的分拆也是很是容易的事情,存储设备经过增长机器就能够横向扩展长大。不少人会担忧说,没有了join,访问DB的次数是否是更多了,会致使性能降低? 按照如今网络的条件,网络访问和Disk IO访问的差距已经不大了,合理的设计下,多访问几回DB并不会致使这个问题。另外若是多台DB的话,还能经过并行加速访问。

因为Service、Glue Code、Repository代码简单了,才能够让咱们的开发人员投入更多的时间研究业务,毕竟这部分才是软件所真正服务的对象。

咱们再来看一个实际的例子,以下图所示:

 

实践中代码架构

 

Manager类实际就是Glue Code。有几个注意点须要说明一下:

  1. 不能把Business Model当作数据对象来处理,Model关心的其实是业务行为,数据只是是这些行为的结果。因此Glue Code须要把Model转换为Entity,Entity和存储设备里面的存储粒度一一对应。好比在DB中,每一个Entity对应一张表,而且跟着表的变化而变化,这样就保证存储的变动不会影响Model。一样Service和用户之间的数据交互,也是不会和Model之间相关的,确保用户的需求变化,不会影响到Model。由于用户的需求变化是最频繁的,没有逻辑,可让我快速的知足业务的需求。
  2. 在Service这里,最好不要考虑代码重用。由于当多个不一样的角色访问同一个接口,一旦某个角色的需求发生了变化,就会要求开发人员去修改。而这个修改每每会影响到其余的角色,须要这些角色一块儿配合来肯定是否受影响,可是这些角色由于没有需求,每每不会配合。这样就给开发人员形成了不少没必要要的沟通,成本是很是高的。最终都会致使线上Bug,影响最终的用户。因此尽可能给不一样的角色不一样的Service,避免重用,下降沟通成本。不少人会说这样Service不就太多了吗? 这样Service注册,查找等管理需求就出现了,Service治理中心就是来解决这个问题的。由于Service里面没有逻辑,因此开发和管理很是的简单,能够快速应对业务的变化。咱们只有更快地变,更容易的变,才能更好地应对变。
  3. Business Model是必需要重用的,一旦发现重用出现问题,那么说明Business Model的识别出现了问题,这是一个咱们要从新思考Model的信号。Business Model必须是一个完美的树状,若是不是,也说明Model的识别出了问题。

在实际操做中,Service、Glue Code、Repository不能有逻辑,实际上和不少人的观念是冲突的,认为这个根本作不到。作到这一点须要不少的学习成本,可是必定能够作获得。当发现作不到的时候,能够判定是业务的分析出了问题。好比不应合并的合并了,不应计算的计算了。这个问题必定有办法解决的,作不到都是理由,无非是想早点把本身的工做结束罢了。虽然刚开始会比较困难,一旦把这个观念变成自觉,开发的质量和效率立刻就能高好几个级别。

咱们真正想快速的完成代码工做,就要克服本身对时间的恐惧,真正的去研究业务的问题,相关stakeholder的利益,把这个变成咱们的习惯。写代码的时候让该出现逻辑的地方出现逻辑,让不应出现的地方不能出现。一旦不应出现的地方出现了逻辑,那么要立刻意识到,这个地方是一个坑,这个问题必定和业务的分析不透彻有关系。

以上只是针对单一的Service部署单元的分析,扩展开去,对于其余的部署单元也是相似的。每一个单元的下一级均可以认为是Repository,每一个单元的上一级均可以认为是User。这些实践在项目中都有用到,很是的有效,迭代的速度很是的快。不少人担忧Business Model建很差,其实不要紧,刚开始能够粗糙一点,后续能够慢慢的完善。这个架构架构已经隔离好了每一个部分的变化对其余部分的影响,变化成本都在可控的范围以内。

做者:猿码道 连接:https://juejin.im/post/5b36f6d3e51d4558957dee8d 来源:掘金 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。

相关文章
相关标签/搜索