代码架构设计-2.常用的两种web service代码架构

作者: 夜月下 | 来源:发表于2017-12-13 14:40 被阅读206次

    上文介绍了为什么要做好代码架构设计,接下来本文将为大家介绍两种常用的web service的代码架构。
    在开始介绍这两种代码架构之前,先来回答一个问题:什么样的代码架构才是好的代码架构?

    好的代码架构设计

    这个问题的答案其实很简单,如同一份好的代码首先要有很好的可读性,并且能够达到松耦合,高内聚。这样一份代码就是好的代码。
    同样,一个好的代码架构首先要能够便于阅读理解,只需要知道模块名称就知道是做什么的,什么东西应该放在哪里,其次,一个好的代码架构应该能够通过自身的规则,帮助开发人员更容易的写出松耦合,高内聚的代码。
    由此可见,对于一个项目,一个工程来说,无论什么样的代码架构设计,只要能够达到上面的目标就可以了。并且随着项目的膨胀,代码架构也会有着不断地调整以适应现有的项目规模。
    这里也只是列出两种代码架构,仅供大家参考。在大家选择自己的项目架构时,还需要结合自身情况,不建议盲目地照搬硬套。

    基本的三层架构模型

    通常在写web service的项目时,大家都会选择controller/api->service->repository/dao的模型。这里介绍的第一种代码架构就是基于该三层架构,只是对其增加了一些约束和扩展。类似于MVC模型,不过稍微有一些变动:


    基本的三层架构模型
    • controller/api 层负责处理http request的传入参数,将传入参数转换为DTO,传入参数的基本验证以及一定程度的response数据的封装,仅当封装数据的逻辑和业务无关时才可以放在controller层,controller层之间的文件不能有依赖,controller层只能传递到service层。
    • service层主要做业务相关的逻辑业务,service层只接受DTO数据,并且return DTO数据。进入service层的DTO数据如有业务需要,可以进行validation。service层负责调用repository/dao获得Entity实例,简单的DTO<=>Entity转换可以在service层中进行,复杂的则需要单独的Converter
    • repository/dao层负责从数据库操作,只接受和返回Entity实例。repository/dao层不负责处理业务逻辑。
    • Entity只是数据库的字段的映射,只能包含一些简单的和Entity强相关的逻辑。
      这种三层架构的目录结构通常是扁平的:
    .
    ├── controller
    ├── dao
    ├── dto
    ├── model
    ├── job
    ├── validation
    ├── service
    └── utils
    

    由上可知,由于所有的业务逻辑都会在service层处理,service层代码很容易膨胀使得内部代码太多,所以可以选择将原先的service细分为多个小的service,并且将其中的一些通用逻辑代码抽出来,独立一些新的package例如validation或者job等。之间串联关系依旧放在service层中。
    然而随着项目扩张service层的臃肿化终究是一个问题,不过目前的解决方案通常是用划分微服务的方式将整个项目拆分为多个小的子项目,所以并不是一个太大的问题。总之,这种架构设计比较简单,开发人员的适应性也会强很多。
    Note: 在微服务的架构下,上面讲的架构模型需要做一定的调整,本文的第三章将详细介绍这些细节,这里不再详述。

    基于DDD的代码架构模型

    DDD——Domain-driven design,目前可以看到很多人都开始推荐起DDD,对于DDD的概念细节本文并不做详述,DDD作为一种方法论也并非是万能的。基于DDD的代码架构设计有一定的优势之处,所以在这里像大家分享一下:

    DDD的代码架构
    可以看到相对于传统的三层模型,DDD相对要复杂很多,很多开发者在一开始面对DDD的代码架构时,会面临不知如何去写代码的困惑,这里像大家解释下:
    • resource层类似于上文的controller/api 层并没有太多变化,只是与它进行交接的facade
    • facade层不同于上文中的service层,值得注意的是facade层并不做真正的业务逻辑,他只是作为一个粘接层去衔接resourceentityfacade层负责
      1. 接收DTO数据;
      2. repository层读取entity实例,并且将从DTO中提取的纯粹数据或VO传进entity的函数中;
      3. 处理Domain=>DTO的转换(也可以由专门的converter或者factory处理,或者entity自己就直接可以返回自身对应的DTO);
      4. 调用repository层的持久化函数,保存/更新entity
      5. 一些entity到其他层的协调工作
    • repository 从数据库操作,只接受和返回Entity实例。
    • entityDDD概念中的domain的实例,具有业务含义,基本上针对一个domain的业务逻辑(除了它自身的create和delete)都应该放在该entity中去实现。
    • PO(persistent object)是数据库的字段的映射,只应该包含getter``setter方法。
    • factory用来做PO<=>Entity甚至DTO<=>Entity的转换
    • service的主要功能是当一个业务逻辑涉及到两个以上的domain,且这段逻辑不适合放在任何一个domain中时,就可以把该逻辑放在service中,可以说servicedomain之间的侨联。

    可以看出DDD的代码架构比起三层架构的要复杂许多,而文件结构也会相对复杂一些:

    ├── dto
    ├── domain
    │   ├── entity
    │   ├── factory
    │   ├── service
    │   └── vo
    ├── facade
    ├── infrastructure
    │   └── persistence
    │       ├── repository
    │       └── po
    ├── mapper
    └── resource
    

    个人理解,DDD式的代码架构所以流行是因为和restful API的理念非常一致,并且真正用到了面向对象的思想。restful强调所有的一切操作都是对资源的操作,而DDD也非常强调资源的聚合,并且就像面向对象所倡导的一样,设计好抽象,明确地将每个业务行为放在具体的抽象下面(就是domain里面)。
    回忆面向对象编程提出的初衷:因为过程式的代码没有很好的方法去聚合操作,所以会产生出很多的冗余代码。而面向对象通过抽象,将会很好的减少代码的冗余程度,使代码高内聚,低耦合。DDD式的代码架构充分发挥了面向对象思想的优势。好的DDD式的代码架构通常需要新人一定时间的训练其掌握相关业务的所有领域知识,否则很难在现有代码上进行开发,而这也是它的一个好处:强迫所有人了解业务上下文。这点在一个项目上是非常重要的。
    然而在笔者参与的大大小小的项目中,发现一个问题:虽然面向对象思想提出已经许多年,然而如今仍然只有少部分人能掌握其精髓。设计不好的面向对象的代码往往会成为一场灾难。DDD式的代码架构非常依赖每个人有意识地去维护,否则代码腐化速度甚至远超传统MVC模型的代码架构。而且DDD式的代码架构对团队内的每个开发人员的要求都远高于mvc模型。如果团队人员流动性很大,或者项目很急,没有多少code review和refactor的时间的情况下,非常不建议使用DDD式的代码架构。

    我们介绍了两种常见的代码架构,希望大家可以参考并制定符合自己需求的代码架构。这里再多说一句,一套代码架构通常会有一些限制和约束,希望大家在遇到这种情况的时候,可以去多思考下为什么要这样做,这样是否真的有好处,多去思考和总结,总会有更多的收获,谢谢。

    相关文章

      网友评论

        本文标题:代码架构设计-2.常用的两种web service代码架构

        本文链接:https://www.haomeiwen.com/subject/rvldextx.html