传统服务端项目都是使用一种分层架构模式(这里用 MCV 举例):
. ├── Model │ ├── Model_A │ ├── Model_B │ └── Model_C ├── Controller │ ├── Controller_A │ ├── Controller_B │ └── Controller_C └── View ├── View_A ├── View_B └── View_C
这种架构方式会有很多变种,但是大体结构相似,就是相同层级的文件会放在同一目录里。
最近,越来越多的项目使用一种以功能为边界的架构模式:
. ├── A │ ├── Model │ ├── Controller │ └── View ├── B │ ├── Model │ ├── Controller │ └── View └── C ├── Model ├── Controller └── View
有种说法说这种架构模式方便日后微服务化。
如果主要以开发效率、维护成本、可扩展性等,这些核心需求来考虑,哪种架构模式更好更具发展性呢?
![]() | 1 lhx2008 2020-04-21 17:07:45 +08:00 via Android 有啥区别,只是文件夹不同而已。。 |
2 hantsy 2020-04-21 17:08:23 +08:00 小项目用 1 就可以了。 大一点的项目必须用 2 结构,不同的 Domain 分开,也方便以后拆分。 |
3 ben1024 2020-04-21 17:14:27 +08:00 看迭代和人力交互 1.迭代速度快,人力交互略差,扩展性略差 2.迭代速度慢,人力交互方便,内部通信成本增加,扩展性好 |
4 hantsy 2020-04-21 17:16:29 +08:00 1 。不同的 Domain 之前, 一些本来有 Entity 耦合的情况,使用 ContextMapping 概念,用一些 Ref 代替 2 。Domain 之间调用切换到 Message Broker,或者 REST API 等。 |
![]() | 5 Hanggi OP |
![]() | 6 huijiewei 2020-04-21 17:19:36 +08:00 用结构 2 吧 小项目就打包成一个 大项目就分开打包 更加灵活 |
7 gemini767 2020-04-21 17:20:13 +08:00 个人认为没啥区别,团队统一好了 大应用拆应用 |
![]() | 8 opengps 2020-04-21 17:22:18 +08:00 小系统选 1,大系统选 2,2 可以轻松的吧每一个业务板块单独拆出来 |
![]() | 9 janda 2020-04-21 17:23:27 +08:00 第二种挺像 微服务中这样的的了!每个都是完全独立的 |
10 kaiser1992 2020-04-21 17:26:14 +08:00 DDD ? |
![]() | 11 Hanggi OP @janda 实际操作中很难做到完全独立,比如 A 里的一个表跟 B 里的一个表有一对多的关系。那就会有一条依赖从 A 伸进 B 。 这种情况,一般怎么处理呢,到时候要拆的时候怎么拆呢? |
![]() | 12 index90 2020-04-21 17:29:52 +08:00 感觉没有区别啊 |
![]() | 13 Hanggi OP |
![]() | 14 rioshikelong121 2020-04-21 17:38:59 +08:00 前端也是这样的吧。小项目第一种,比较大的项目第二种。 |
![]() | 16 xcstream 2020-04-21 17:59:55 +08:00 混合 A 和 B 的模式 |
![]() | 17 Hanggi OP @index90 一个项目啊,比如 A 是用户模块,B 是文章模块,C 是视频模块,类似这么分,同一个项目怎么可能分在不同的 repo 呢。 |
![]() | 18 lower 2020-04-21 18:22:13 +08:00 ![]() 把两者结合一下:D ├── A │ ├── Model │ │ ├──Model_A1 │ │ ├──Model_A2 │ │ └──Model_A3 │ ├── Controller │ │ ├──Controller_A1 │ │ ├──Controller_A2 │ │ └──Controller_A3 │ └── View │ ├──View_A1 │ ├──View_A2 │ └──View_A3 ├── B │ ├── Model │ │ ├──Model_B1 │ │ ├──Model_B2 │ │ └──Model_B3 │ ├── Controller │ │ ├──Controller_B1 │ │ ├──Controller_B2 │ │ └──Controller_B3 │ └── View │ ├──View_B1 │ ├──View_B2 │ └──View_B3 └── C ├── Model ├── Controller └── View |
19 noobsheldon 2020-04-21 19:19:16 +08:00 ![]() @lower 这不就是 Django 的结构吗 |
20 Kirsk 2020-04-21 19:31:50 +08:00 从 service 开始按模块分 看业务有可能分两层 service 底下就是作为基础层 model 其实用 API 服务化的思维去做服务端我觉得比较合适 view 已经弱化了 这么分的理由是业务共性的东西会逐渐下沉形成比较稳定的层级或功能,service 层之上根据业务来 |
![]() | 22 wangyzj 2020-04-21 22:03:29 +08:00 “服务端架构模式”?????? |
![]() | 23 wizardoz 2020-04-21 22:08:35 +08:00 我只想说第一种很无脑 |
![]() | 24 hello321 2020-04-21 22:09:50 +08:00 果断第二种 |
![]() | 25 janda 2020-04-21 22:20:20 +08:00 @Hanggi 这样每个项目之间进行通讯、需要一个注册中心、把多个集中在一起!这样就相当于 N 个模块、变成一个项目了!不过这样操作成本比较大、维护也比较麻烦的!大项目用这种比较好、小项目用你的 A 方法就行了 |
![]() | 26 siganushka 2020-04-21 22:21:00 +08:00 Symfony Bundles 了解一下 |
27 mitu9527 2020-04-21 22:26:23 +08:00 哪里有什么最优解决方案,只有最合适的解决方案。选择适合当下的方案,然后当需求变化时,改成适合新需求的方案。 |
![]() | 29 Samuelcc 2020-04-21 22:49:02 +08:00 via Android 个人喜欢第二种,通过 package private 的方式解耦各个模块,不会互相耦合,方便拆分和重构,也适合按照功能查找代码。 |
30 mitu9527 2020-04-21 23:00:50 +08:00 @Hanggi 就因为没办法预计,才应该选择最适合当下的。别人的也不见得适合你,就拿微服务来说吧,真正适合的公司就没多少家,服务数量都没上来就开始准备拆分,明显考虑的太早了。Keep It Simple 。 |
![]() | 31 xuanbg 2020-04-21 23:10:40 +08:00 无脑选 2 就行。第一种非常容易写着写着就不清不楚地黏糊在一起了 |
![]() | 32 abcbuzhiming 2020-04-21 23:32:56 +08:00 @xuanbg 选 2 要面对一个预先规定功能边界问题,然而在经常变动的需求下就慢慢的这个边界就模糊了,然后你就发现照样糊在一起 |
![]() | 33 nvkou 2020-04-21 23:40:05 +08:00 via Android 后端不是已经没有 view 了吗。重点应该都在路由和业务了吧。 |
![]() | 34 wweir 2020-04-21 23:50:07 +08:00 2, 不过拆分了 repo 。 整个使的是微服务的套路 |
35 uxstone 2020-04-21 23:50:57 +08:00 没有最优 如果不对需求严加把控,最终都会变成山。 |
36 limingjie138 2020-04-22 00:16:2 +08:00 via Android 个人开发我选择了 1,但后来项目越堆越大,再开其他项目需要共用实体类的时候我就超级头痛,快点但蠢新建一个 project 把 enter 完整的 copy 过去。后悔当时不应该为了自己开发快选 1 。有没有大佬能救救我 1 的方案导致的实体不能多 project 共用的问题 |
![]() | 37 huijiewei 2020-04-22 00:21:13 +08:00 ![]() @limingjie138 你这个问题,最简单地办法就是引入 RabbitMQ 独立事件机制,把关联做成事件关联 |
![]() | 38 zhuzhibin 2020-04-22 00:23:46 +08:00 有区别吧 第二种是按照模块组织 最上层可以抽成通用的壳子 业务按照 modules 来组织 期望这些 module 都是独立可拆分的 这种做法比较难的就是业务解耦了 模块之间不要耦合太严重,否则没啥收益了 |
![]() | 39 imycc 2020-04-22 00:43:28 +08:00 flask 的 blueprint 就是 2 这样的设计思路,每个模块之间各自处理内部的业务,在功能拆分还有迭代上会舒服一些。 不过即使用了 2 的结构,如果在开发时候 ABC 互相引用,到时候拆微服务也拆不开。 |
![]() | 40 zclHIT 2020-04-22 01:17:32 +08:00 via iPhone 来吧拥抱 DDD |
![]() | 41 realpg PRO 抛开项目需求谈架构都是扯 |
![]() | 42 hacson 2020-04-22 01:36:59 +08:00 via iPhone 我来问个题外话,楼主你这个树形结构的图是怎么生成的?有时候分享 ppt 这种图还蛮清晰明了的 |
![]() | 43 akagishigeru 2020-04-22 08:10:05 +08:00 via iPhone 我和楼主同样的 两个模块之间耦合数据层( Model )该怎么办?需要连表的情况下,该如何处理呢?希望求得一知半解 |
44 Leigg 2020-04-22 08:18:56 +08:00 via Android 这个叫代码结构 |
![]() | 45 itechify PRO 毫无疑问选 B |
![]() | 46 AngryMagikarp 2020-04-22 09:05:49 +08:00 这只是代码组织方式而已,前端客户端都可以用。 没有完美的方式,只有最合适的方式,抛开需求谈这个没什么意义。 |
![]() | 47 edk24 2020-04-22 09:09:38 +08:00 我怀疑你在说 tp3 和 tp5 哈哈哈 |
![]() | 48 Jrue0011 2020-04-22 09:10:31 +08:00 初期一个就行了,后期再拆分,遇到困难再想解决方案。。。 |
49 robot1 2020-04-22 09:58:31 +08:00 点链接之前脑子里闪现了分布式 无状态 高可用 一致性 ,点进来原来是代码放哪个文件夹。。。。。 |
![]() | 50 Orenoid 2020-04-22 10:00:37 +08:00 业务划分得清楚,A 也可以重构成 B 。业务互相耦合,用 B 一样给写成 A 。 |
51 Muyiafan 2020-04-22 10:04:23 +08:00 这不就是个文件目录吗? 怎么成服务器架构模式了! |
![]() | 52 Hanggi OP @Muyiafan @robot1 @Leigg @wangyzj 好多人都在纠结为什么叫架构模式,可能翻译的不准确,但是我们平时经常说的 MVC 、微服务都是架构模式,贴个维基百科链接: https://zh.wikipedia.org/wiki/%E6%9E%B6%E6%9E%84%E6%A8%A1%E5%BC%8F 当你改变你的目录结构、代码组织方式、依赖管理方式等这些细节的时候,其实你已经悄然改变了你的架构模式。 |
![]() | 53 baiyi 2020-04-22 10:57:21 +08:00 目录结构是跟着架构走的,还是得看实际需求,所以也谈不上哪种最优 |
![]() | 54 xianxiaobo 2020-04-22 16:09:43 +08:00 混起来用,以 B 为主,A 为辅。 |
55 zypy333 2020-04-22 16:15:49 +08:00 @Hanggi 单回复你那个多表关联下的模块拆分问题,我正好前阵子看过一个房产平台微服务视频,里面提了,说这种跨模块的,最好把关联表放到被依赖关系较小的那个库里,比如说用户表被很多模块依赖,那用户-房产关联表,就放到房产模块的库里 |
56 charlie21 2020-04-22 17:47:07 +08:00 前者不就是后者的细节展开图嘛 ... |
![]() | 57 xuanbg 2020-04-22 20:00:47 +08:00 @abcbuzhiming 功能边界肯定要划分清楚的呀。 我在带团队的过程中一直强调,把代码写对地方比写对代码更重要。代码写错了很快就能发现并修复问题,写错了地方则不然,当时是没问题你好我好大家好,但会让你在后面一直吃屎。。。同时也会在合并分支时产生大量的冲突。 事实上只要在写代码之前稍微思考一下再动手,就很容易解决功能边界的问题,也就能把代码写对地方了。 |
![]() | 58 xuanbg 2020-04-22 20:02:28 +08:00 @JaguarJack A 和 B 之外搞个 Common 就行,AB 都依赖 C |