关于业务分层的疑惑: 贫血模型 or 领域模型 or 都是扯淡?

2016-08-18 01:42:23 +08:00
 ctrlaltdeletel

LZ 是一个 Python 开发者,在公司做 Python Web 开发。

公司的业务变得越来越复杂,团队也越来越大,感觉“ fat Active Record ORM Model ”的模式有点力不从心: Model 越写越臃肿、有的逻辑不明确应该放在哪里、依赖关系有点混乱、测试困难等等等。

现在觉得需要对业务进行一些分层处理,类似 Java 开发中常见的区分出 DAO 和 service 。

我理解的 DAO 即是只处理数据操作,隔离底层数据操作和逻辑。 service 处理逻辑。

在我的理解里,其中又有两种实现方式:

  1. “贫血模型”。数据对象简单,逻辑实现在类似过程式的“事务脚本”中,操作 DAO 进行数据处理。能想到的缺点是可能仍要写一些 service 间重复的逻辑。
  2. “领域模型”。对业务对象抽象为一个 domain object ,处理自身相关逻辑。上层 service 协调各个 domain object 处理逻辑。对业务理解和抽象的要求更高,感觉 service 和 domain object 在结构的组织上也比较麻烦。

貌似 Rails 开发也有类似的 Service Object 概念,来抽象业务模型间的逻辑。

LZ 对 Java 基本不懂,仅限大学时候“ Hello world ”水平。现在这套分层实践起来并不是很顺手,对于命名和结构都比较模糊。 service 的参数、返回值,以及实现方式也是跟着感觉走。对以上的理解也是来自网上东拼西凑,乱说一气,感觉有时间应该翻来 Martin Fowler 的书看看。

大家有类似的经验、什么好的实践、建议吗?或者有其它的方式解决现在遇到的问题?

6276 次点击
所在节点    程序员
10 条回复
msg7086
2016-08-18 02:56:04 +08:00
和 Java 应该关系不大吧。
可以看看设计模式,然后用你上面提到的关键词去爬谷歌 /帖子去,应该会学到不少经验。
davisz
2016-08-18 04:01:31 +08:00
如果只是解决 FAT ORM 的问题可以用两层 Model 来处理,例如 User 表有 UserActiveRecordModel 、 UserModel , AR 一般是框架自动生成后不再任何修改,逻辑写在 UserModel ,如果处理表单校验等逻辑还可以加入 UserFormModel 。

一家之言,仅供参考。
kitalphaj
2016-08-18 09:00:24 +08:00
你说的这个问题在 Rails 里面挺常见的,特别是 Rails 的 Model 已经默认实现了数据库的一些基本操作不需要你再自己写。这种时候你就只需要考虑到底是把业务逻辑(Business Logic)放在 Service 层还是放在 Model 层。

一种思路是完全把逻辑放在 Service 里面, Model 仅仅是存数据。这种方法的好处是 Model 层会比较轻,就算是以后某个 Model 变了,比方说以前是 FullName ,现在你需要换成 FirstName 和 LastName ,那对于 UI 层的 Controller 或者 View 来说,这个变化是透明的,只需要 Service 里面把获取名字的函数调整一下就好了。但是这个设计的问题也很明显,就像你说的, Service 层会写很多重复代码,比如明明可以直接 Model.Name 的你就需要用 Service 的方法包装一层。

我个人觉得设计模式从来都不是绝对的,对于某些系统来说这种设计可能很适用,但是对别的系统这种设计很可能就太累赘。比如上面提到这种设计,如果你觉得现在系统处于项目早期,很多 Model 都有可能会进行变化,那么你完全可以把易变的那些逻辑在 Service 里面封装,其它一些你觉得长时间都不会变的,比如某个时间的本地化处理,那么完全可以在 Model 层里面实现。

总之一句话总结就是,程序架构没有绝对,只有适合,一定要根据你目前的项目来决定。而且一开始你可以对这些决定拿捏不准,没有关系,因为经历还浅,就算是高级架构师也不可能设计出永久不变的架构。等你以后做的设计多了,架构多了就知道,哦这种逻辑很可能会变要抽象出来,哦这种逻辑不太可能变化等等。一开始要有自信,敢去设计敢去实现,就算是后面要改也不要怕,改了说明你学习了进步了!
feiyuanqiu
2016-08-18 09:26:28 +08:00
企业应用架构模式那本书对 ddd 开发并没有写得很清楚,很多概念其实在日常开发中,在使用 orm 中已经接触并实践过了,看它收获不大

最近在看 implementing domain driven design 这本书,内容挺丰富的


以下是个人的一些牢骚

我之前非常纠结的是采用 DataMapper 类型的 orm 之后,因为会给每个表建立一个对应的实体,我有点不清楚业务逻辑该放在哪好了,普遍推荐的是实体就仅仅是个做数据映射的 pojo ,数据持久化操作放到 repository 里面,领域逻辑放到 service 里面,业务流程逻辑放到 controller 里面…但因为我用的是 php ,在网上找到的一些资料又说 weak object 是种反模式,比如 doctrine 的作者之一,在他的 doctrine 最佳实践的 ppt 里就说,实体应该要有行为,不然和数组有什么区别…

然后找了一些 php 的 ddd 开发实例观摩,发现似乎过于复杂了,几乎把业务里所有东西都对象化了, id 这些不可变元素要做成 value object ,把它的行为都扔到 vo 里面,但是实际上很少会对 id 这些东西有什么复杂的操作,同样还有对 repository 的抽象,单独建了 instruction 这么一层来存放不同的数据存储,但是实际工作中很少会出现更换数据库这种事吧?有必要吗

我觉得像 php , python 这种语言,并不需要全盘地采纳 ddd 的思想,不然还不如直接用 java 算了
tianshiyeben
2016-08-18 09:49:38 +08:00
1>首先,团队越来越大是好事情

2>我是做 java 的,大多数项目都是采用你说的 贫血模型

一般架构根据依赖关系从下到上分为, dao->service>controller->view(页面)
ctrlaltdeletel
2016-08-18 14:10:12 +08:00
@kitalphaj 多谢回答,很棒。
@feiyuanqiu 已标注想读。的确应该是以解决问题为目的出发,单纯模仿就有些过了。
ihuotui
2016-08-19 04:38:17 +08:00
把充血模型当作微服务化就差不多了,把每个方法都是一个微服务,只是这个微服务是在单个应用里面的,而真正的微服务是面向分布式的,记住类似就行了。
chaleaochexist
2019-03-07 09:34:30 +08:00
大佬有很多体会吗?遇到了类似的问题.
waibunleung
2021-05-27 19:31:41 +08:00
我有了同样的疑问,看这个帖子还是没有很好地得到解决呀...题主方便交流一下吗?
waibunleung
2021-05-27 19:32:01 +08:00
@ctrlaltdeletel 我有了同样的疑问,看这个帖子还是没有很好地得到解决呀...题主方便交流一下吗?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/300046

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX