• 乐
    2019-11-27
    ## 为什么贫血模型盛行

    下面几项自己都中过招(环境问题和个人问题):

    ### 环境问题 ##

    * 近朱者赤,近墨者黑
        * 大多数人都是模仿别人的代码,而别人的代码基本上都是 demo,没有复杂的业务逻辑,基本是贫血模型
        * 找不到好的指导与学习对象
    * 接触不到复杂业务项目
        * 做 web 项目的,很大一部分就是简单的 CURD,贫血模型就能解决
    * 公司以任务数来衡量个人价值

    ### 个人问题 ###

    * 不考虑项目质量属性
        * 只关心当前业务,没有意识去思考后期该如何维护和响应业务变更
    * 求快不求质
        * 个人以任务数来自我满足
        * 没有 60 分和 100 分的概念
        * 需求分析、设计、编码合为一体

    ## 如何理解充血模型

    先推荐一本书:整洁架构设计

    先说一下充血模型中各组件的角色:

    * controller 主要服务于非业务功能,比如说数据验证
    * service 服务于 use case,负责的是业务流程与对应规则
    * Domain 服务于核心业务逻辑和核心业务数据
    * rep 用于与外部交互数据

    ----

    额外说一点,业务开发个人倾向于六边形架构,而非传统的三层架构。六边形架构更能体现当下 web 应用的场景

    六边形项目结构(根据实际情况自行组织与定义):

    * InboundHandler 代替 controller
        * *WebController:处理 web 接口
        * *WeChatController:处理微信公众号接口
        * *AppController:处理 app 接口
        * *MqListener:处理 消息
        * *RpcController:处理子系统间的调用
    * service 服务于 use case,负责的是业务流程与对应规则
        * CQPS + SRP:读写分离和单一原则将 use case 分散到不同的 service 中,避免一个巨大的 service 类(碰到过 8000 行的 service)
    * Domain 服务于核心业务逻辑和核心业务数据
        * 最高层组件,不会依赖底层组件
        * 易测试
    * outBoundhandle 代替 rep
        * MqProducer:发布消息
        * Cache:从缓存获取数据
        * sql:从数据库获取数据
        * Rpc:从子系统获取数据

    ----

    各层之间的数据模型不要共用,主要是因为稳定性不同,各层数据模型的变更原因和变更速率是不同的,离 IO 设备越近的的稳定性越差,比如说 controller 层的 VO,rep 层的 entity。Domain 层是核心业务逻辑和核心业务数据,稳定性是最高的

    ----

    几个不太容易理解的点(我刚开始碰到的时候很费解):

    * use case 和 核心业务逻辑该如何定义与区分
        * 哪些该放到 service 里面,哪些该放到 Domain 中
    * rep 是依赖于 service 的,而不是 service 依赖 rep 层
        * 业务逻辑是最高层组件(最稳定的),rep 层是底层组件
    * 接口能反转依赖关系

    ----

    一剂良药:所有的中间层都是为了解耦
    展开
     15
     136
  • 业余爱好者
    2019-11-27
    一直贫血而不自知
     6
     80
  • 有铭
    2019-11-27
    我个人认为,充血模型在web开发领域不流行的一个根本原因,在于互联网兴起后各种层出不穷的需求变动,以及短命的项目生存周期,充血模型应对复杂业务确实很有优势,但是这是建立在复杂业务本身其实相对稳定上,比如银行的业务,虽然复杂,但是其实很稳定。但是要是换在互联网,今天改需求明天改需求,甚至很多时候根本就是推倒了重来的需求,充血模型面对这种状态,根本是力不从心的
     6
     50
  • 李小四
    2019-11-27
    设计模式_10
    # 问题:
    - 1. 做的Android项目更多,Android开发也是经历了MVC==>MVP(依然是一种MVC架构)==>MVVM的模式演进。类MVC模式比较多,在UI相关的开发中,只用过贫血模式(之前也尝试过使用充血模式,但考虑到不一致带来的成本就放弃了);在UI无关的复杂服务类开发中,也用过充血模型(虽然我不知道它叫充血模型)。我认为贫血模型的优点是更容易看懂,充血模型的优点是更能应对复杂业务。
    - 2. 我认为还是不要放在同一个类中,原因是:成本大于收益。成本:一个复杂的类,在被不同的模块调用时充当着不同的角色,甚至,不同的模块调用不同的字段,需要大篇幅的文档来描述这些差异。稍有修改,复杂度的增加非线性。优点:代码重用。

    # 感想:
    软件开发处理的是工程学问题,解决方案依赖场景,一个新技术的火爆一定是解决了当前主流场景的痛点问题,随着规模和复杂度的变化,场景也随之变化;争论贫血模式更好还是充血模式更好,争论哪个开发语言更好,这样的问题都是伪命题,我们更应该投入精力的是为当前场景选择最合适的解决方案。
    展开
    
     22
  • 墨雨
    2019-11-27
    老师,我平常做web开发都是,entity,dao,service,controller.对vo,bo不是很理解,也没有用到。有没有demo呢?

    作者回复: 我抽空写个demo,放到我的github上吧
    https://github.com/wangzheng0822

     9
     19
  • ╭(╯ε╰)╮
    2019-11-27
    个人感觉业务被贫血模型绑架的另一个原因是以前缓存nosql这些技术不不成熟 刚毕业那会哪有什么redis,机器的内存也不多。都是公司堆在角落的旧机器。一些业务如果在domain里实现可能会hold住数据库中的大部分数据。所以业务上都需要翻译成sql的where和join来减少网络和内存的开销。功能都被sql抢了去,想充血也充不起来。现在随便开个项目不带个redis老板都会质疑一下。mysql的访问也都是能少就少,不行再多加几台云服务器。老板也显得更有面儿。
     4
     17
  • lizi
    2019-11-27
    沙发,不睡觉,听课。哈哈,加班好累,
    
     10
  • Lrwin
    2019-11-27
    我觉得代码架构和业务架构一样,只要将关注点分离就可以。
    简单的系统,困难的不在于领域的拆分,而在于时间成本的控制。从软件工程角度考虑,时间,成本,范围三角理论可以进行分析、。
    我们所说的复杂系统,更看重业务的复杂度,将复杂度降低的方法则是分而治之。这样可以降低复杂度。
    复杂要解决三个问题:规模问题,结构问题和需求变化问题。无论是技术复杂度或业务复杂度,只要能解决这三种复杂度问题就是好的方法。
    DDD模型其实无异,都是将Model层做重。因为业务核心是技术无关的。传统MVC用于C/S模型,也依然是重Model层的。我觉得软件设计的方法没有变化,只是大家看到的视角不同罢了。
    软件架构有两个含义:1.参与的元素有哪些 2.元素间的关系是什么。 从抽象角度来看,非常简单。
    展开
     1
     9
  • Geek_Zjy
    2019-11-27
    看到「领域驱动设计有点儿类似敏捷开发、SOA、PAAS 等概念,听起来很高大上,但实际上只值“五分钱”。」时,不知道引起了多少人的共鸣,O(∩_∩)O~。 做技术的本身就经常会遇到沟通问题,一些人还总喜欢“造概念”,唯恐别人听懂了,争哥这句话无疑说中了我们的心坎儿。
    当然我这里也不是说 DDD 不好(看后面的争哥也没这个意思),但是每个理论都有自己的局限性和适用性,看很多文章在讲一些理论时,总是恨不得把自己的理论(其实也算不得自己的)吹成银弹,态度上就让人很难接受。
    我还是喜欢争哥的风格,逻辑很清晰,也很严谨,很务实。

    关于老师的问题。
    说句实话,我们就没有写过充血模型的代码。
    我们会把 UserEntity、UserBo 混着用, UserBo 和 UserVo 之间转换时有时还会用 BeanUtils 之类的工具 copy 。
    对于复杂的逻辑,我们就用复杂 SQL 或者 Service 中的代码解决。

    不过我在翻一些框架时,比如 Java 的并发包时不可避免的需要梳理 Lock、Condition、Synchronizer 之间的关系。比如看 Spring IOC 时,也会需要梳理围绕着 Context 、 Factory 展开的很多类之间的关系。
    就好像你要“混某个圈子”时,就不可避免的“拜码头”,认识一堆“七大姑八大姨”,然后你才能理解整个“圈子”里的关系和运转逻辑。
    我也经常会有疑问, DDD 和面向对象究竟是什么关系,也会猜想:是不是面向对象主要关注“圈子”内的问题,而 DDD 主要关注“圈子”之间的问题?有没有高手可以回答一下。
    (其实我最近一直都想订隔壁DDD的课,但是考虑到精力的问题,以及担心学不会,主要不是争哥讲O(∩_∩)O~,所以没下手)
    展开

    作者回复: 哈哈,多谢认可,我写这篇文字的时候,还害怕搞DDD的人会来骂我,看来是我多虑了。隔壁的DDD课程可以去学下,管它是不是我写的,看看他咋“吹”的也好。

     3
     8
  • 梦倚栏杆
    2019-11-27
    第一个还没有太多的感受,还需要时间来练习感受
    第二个是否合成一个各有优劣,可能还是和写代码人的功底有关:
    拆分开的优势:各层的防腐隔离,当前层的变化不影响其他层。
    拆分开的劣势:来一个迭代需求,比如需要加一下邮箱等, rd很有可能在三个类里各加一个字段,从上改到下,完全看不出隔离的优势,就看不到了一层层的类转换
    反过来就是不拆分的优劣
    
     8
  • 丶Zero灬
    2019-11-28
    我们公司的ERP系统使用的是贫血模型,支付系统由一个OOP的忠实践行者设计的,使用的是充血模型。两个系统我都有在维护,先说ERP。遇到新需求的时候,就像老师说的SQL驱动。从后往前返回数据。简单的需求还好,像一些复杂的模块。看着service一个方法动辄几百,甚至出现过上千行的。真心感觉改不动。在业务还比较简单的时候贫血模型还够用,但随着业务发展,service层越来越重。这时还不做封装抽象,系统真心不好维护。很多时候都要依靠老员工的讲解。而,支付系统,在开发新功能的时候,因为封装抽象已经做的很好,改动起来还是蛮愉快的。没有那么多的重复性代码。不过,因为封装的太多太深,在刚接手的时候确实不好读。业务逻辑逻辑分散在各处。当然,也可能是本人水平有限。
    
     7
  • grey927
    2019-11-27
    能否用代码表达一下充血模型,其实还是不太理解

    作者回复: 下一节课有的

    
     7
  • 小晏子
    2019-11-27
    基本上经历过的web项目都是基于贫血模型开发模式的,entity,bo,vo不能放在一个类里,每个对象的应用场景不同,entity是映射数据库字段的,bo,vo适合业务和展示相关的,而且entity相对来讲变化不多,bo,vo可能会频繁变化,所以不适合放在同一个类里
    
     7
  • 花儿少年
    2019-11-27
    有本书叫ddd 原则,模式与实践可以翻阅一下
    首先要明白一点ddd适用范围,多数业务就是CRUD就可以搞定,理解起来也没有困难,为啥不继续用贫血模型。
    充血模型就像老师说的需要精心设计,以应对变化,如果没有一个复杂的业务场景就根本用不到,或者说用起来很难受是一个似是而非的东西。
    况且充血模型只建议用在核心域,还有通用域和支撑域呢,不要一上来就ddd
    
     6
  • 深度•仁
    2019-11-28
    一拍大腿,靠,说到心坎里去了,各种细碎的sql,就为了解决某个小功能! 业务熟悉,领域驱动设计就是屠龙刀,业务不熟悉,DDD也就值个半毛钱!茶不思,饭不想,期待后面的文章更新
    
     5
  • 杨树敏
    2019-11-28
    回想起来经历的互联网项目一直都是贫血模型, 究其原因:
    1.互联网项目多采用敏捷开发, 需求多变, 设计充血模型的性价比低;
    2.互联网小产品业务场景相对简单, 业务难点更多的出现在并发, 性能上, 在存储,内存成本急剧下降的当下, 粗暴的横向扩展成为见效更快的选择.
    
     4
  • Lonely绿豆蛙
    2019-11-28
    最近边看边重构自己的项目,感觉真的是从码农视角转到了架构师层次~
    
     4
  • 追风少年
    2019-11-27
    1. 以前做的项目都是基于贫血模型的,这次的话涉及风控业务,也是基于贫血模型,但是各种问题不断,正在考虑优化,这里刚好看到老师的文章,希望能有所借鉴。
    2. Entity是ORM中数据库映射的实体类,BO是业务操作相关实体类,VO是视图层对应实体类。在简单情况下,这三个类可能是一样的,比方说你填写一个登陆注册的表单,此时前端传给后端接口的数据,一般就是VO,而通过业务层Service操作,加入创建时间,IP地址等,就转换成了BO,最后对应到数据层就转换为了Entity,也许一次注册可能需要写多个库,就会生成多个Entity。
    有些复杂业务,还有DO,DTO,PO之类的概念,但是个人感觉很模糊,也不是很了解。这里希望老师能指点一下。

    作者回复: DTO:data transfer object,是一种更抽象的概念,这种数据类型可以是贫血模型的,主要是用在接口之间传递数据。

    其他的两个没听说过:《

    
     4
  • Ant
    2019-12-03
    有哪些同学像我一样,是个移动端开发,也在学设计模式
     1
     3
  • 编程界的小学生
    2019-11-28
    1.一直贫血模型,却没有发现。
    2.充血模型我有点没看懂,我粗糙的理解成把贫血模型的service里面的复杂业务逻辑都搬到了domain,然后service简单调用domain即可。那domain里不也是业务逻辑+bo.吗?还有复杂的sql无法复用问题,我一般写业务都是单表。然后放到service层调用多个dao去组装最终的数据出来。这样可以解决乱七八糟的sqlz吗?希望争哥解答下。
    3.第二道问题,我觉得不能合并,因为首先entity是对应的数据表字段,其次bo可能被多个业务方法所使用,返回的字段可能不同,这就需要vo来限制具体每个接口需要哪些字段来响应给客户端。
    展开
    
     3
我们在线,来聊聊吧