关于fecmall QQ群里,对fecmall强耦合的问题讨论,整理成帖子讨论

技术分享 · Fecmall · 于 4年前 发布 · 1637 次阅读

声明:仅仅技术探讨。

Frank: 读fecmall代码,全靠经验啊,有ide帮助也效率不高,依赖全靠全局变量注入 深度耦合,我这么说会不会被群友们打,逃/舔一舔

Terry: Fecmall services完全是解耦的设计,何来深度耦合?每一个services都可以通过配置改写,何来耦合?

TerryFecmall services无法通过编辑器查找services文件,这个问题的确存在,不过services的命名都是和文件结构对应,约定式命名,这个问题得通过写phpstorm插件解决,如果有高人,可以写一个分享。

Frank:我说了,最大的耦合就是全局变量$services自身,耦合体现在service之间的依赖全部靠全局变量来获取,而不是靠语言本身类之间构造函数来传递service之间的依赖,所以导致了严重的传染性和污染,导致每个涉及业务的地方都出现了那个全局变量,也就是说写代码的人必须要对全局变量services里面有什么有深刻了解,这种“确信目前具体有什么” 比主流依赖注入的“声明要什么”对于开发者来说心智负担更大。

至于通过配置来改写,这种对于全局变量自身来说确实算解耦了没毛病。

不只是ide找service,还有加了前缀action的魔法方法调用这种

Terry: 1.首先,先看业务问题,fecmall作为一个商城,需要按照业务进行划分功能块,譬如cart功能块,产品功能块,订单功能块,而对于一个业务的操作,需要多个功能块完成,譬如:生成订单,需要生成订单,清空购物车,更新优惠卷,更新产品库存,这必然涉及到多个功能的依赖问题,进行解耦 好了,业务问题是将这些功能块解耦,解决强耦合的问题,也就是 a,b,c,d,e,f,g之间的强耦合问题

2.通过Yii::$service->cart的,通过配置注入,容器生成的方式生成单例模式的对象,就是为了解决a,b,c,d,e,f,g的强耦合问题,该模式属于懒加载模式,使用的时候才会实例化单例模式对象,可以通过重写配置重写任意services来解决,这个是吸收了Yii组件的设计思路,参考了Yii::$app->组件的模式思路实现,来解决依赖问题,可以通过配置,更好的重写已有的功能块,譬如:Fecmall可以通过配置的方式,重写Yii框架的一些功能块,譬如:https://github.com/fecshop/yii2_fecshop/tree/master/yii ,里面都是重写的yii2框架的一些类(并不改动yii2的库包文件)

下面将 Yii::$serviceX 来标识

3.关于耦合:A是零件生产者,B是车企,A生产的零件供货给B,B依赖于A,A的零件的参数变动都会造成B出问题,A和B之间强耦合,现在进行解耦,加入C,c是行业标准,B定义来一个行业标准C给与A,让A必须按照C的标准来进行生产,来实现解耦,由B依赖于A,转变成A依赖于C。

通过行业标准C的加入来实现解耦,那么按照你的思路,加入C,导致了严重的传染性和污染?

4.Fecmall就是通过加入X,解决 a,b,c,d,e,f,g之间的强耦合,你认为X导致了严重的传染性和污染? 请问如果不加入X,如果解决a,b,c,d,e,f,g之间的强耦合?

靠语言本身类之间构造函数来传递service之间的依赖?如何解耦?

通过X的加入,来解决的业务问题是a,b,c,d,e,f,g之间的强耦合,你认为aX存在耦合是问题?按照你这个逻辑,可真没有存在绝对的解耦,解耦的同时,也是加入新的耦合的过程,非常彻底的微服务,通过api来调用各个方法,这个解耦彻底吧?

但是,按照你的逻辑,同样存在耦合,每一个调用api的功能块和API存在耦合, 导致了严重的传染性和污染?

对于这些讨论,希望论坛发帖子讨论,别Q群乱发东西误导大众。

注1:services加入actionXxxx这种函数方式,是为了每一个service的函数调用,可以在架构上插入一个开始和结束,可以记录各个services函数执行花费的时间,当然,你也可以不用,fecmall的核心代码也没有严格按照这个来,有一些用了actionXxxx方法,有的没有用

注2:至于为什么这样设计,你自己先构思一下,做一个产品,要解决产品的自身持续开发,第三方开发者的插件开发,以及用户自身本地开发,这之间的冲突问题,以及fecmall自身需要升级的冲突问题。

注3:你的问题,可以归结于一个问题,phpstorm无法通过代码定位文件。这个的确存在,对于services,譬如Yii::$service->cart必须解析代码,加载所有的初始配置,才能清楚到底是那个类文件。

laravel框架也存在这个问题,是通过写了一个phpstorm插件来解决的,如果有高人,可以写一个phpstorm插件分享一下。

共收到 4 条回复
frank_w#14年前 0 个赞

我QQ上面的回复没有说清楚,而且打错了几个字,

""" 最大的耦合就是全局变量$services自身,耦合体现在service之间的依赖全部靠全局变量来获取。正确的做法是应该靠语言本身类之间构造函数或者setter方法等来传递service之间的依赖,每个service应该对全局变量$services保持未知,只声明需要什么依赖。 """

用楼主说的例子,目前fecmall的状态,A、D是同种零件生产者,B是车企,B定义了这种零件的行业标准C,每次B要这种零件时都要先膜拜全知全能的神X来获取符合C标准的零件。

这个神X无处不在,系统里每个想要正常运行的部件都需要先膜拜神X。

不觉得这样很痛苦吗,作为开发者我要写代码就先要了解这个全能的神,把所有对神array merge的配置都看一遍,这些配置还都凌乱在各个地方,然后我写的每个部件,这个部件干每一件事就会大喊“万能的神啊给我一个xxx”。

正确的做法是让每个部件对神X保持未知,他们的依赖在神X创造完他们时他们已经知道了,就比如车企B,只依赖行业标准C,而不依赖零件厂A、D,更不依赖万能的神X。

Fecmall#24年前 0 个赞

@zjsxwc [#1楼](#comment1)

1.你的这个思路,类似于:你通过智联找工作,需要智联给你的每个职位都已知,如果不是,你就说智联的设计有问题!

和吐槽没啥分别,就是吐槽难用,yii2的组件也是这种方式,Yii::$app->db, 你的这个思路同样也是可以吐槽。 是的,很多人吐槽yii2框架垃圾,每个人站的立场角度不同,看问题就不同,很多键盘侠吐槽中国没有人权,现在疫情又说明中国很有号召力,什么东西都是双刃剑。

Yii::$service并不是未知,微服务架构的的每个api都是未知?这个显然不成立!

fecmall的配置文件分布在很多地方,但是fecmall做了一个将N个配置文件生成一个配置文件的功能,无论安装了多少个插件扩展,可以通过这个配置文件进行查看,详细资料:http://www.fecmall.com/doc/fecshop-guide/instructions/cn-2.0/guide-fecmall_config_speed.html

2.如果您仅仅做一个程序,自己用,不考虑扩展,升级等问题,直接一把梭,站在这个立场,你的吐槽的确成立! 直接php代码撸sql代码都一点问题没有,什么框架都也别用,直接一把梭,简单直接有效。

3.说重点,作为产品需要解决很多问题,给你几个问题,你先思考如何解决这些问题,说出来解决方案,才有资质讨论这个问题

3.1fecmall各个功能块, cart , product, order, coupon等功能块的解耦问题

3.2fecmall需要持续升级,低版本的用户进行了二次开发,如何解决冲突

3.3第三方开发者开发了很多fecmall插件,这些插件也需要升级

3.4解决本地开发者,第三方开发者,fecmall核心代码开发,三者直接的持续开发与升级的代码冲突问题。

这是fecmall作为一个产品首页解决的问题,而且是必须解决的问题,解决这些问题的前期下,才有资质思考你的问题。

frank_w#34年前 0 个赞

首先我没有否认全局变量$services的作用,但我觉得它有巨大的改进和提升的空间,你不觉得目前$services对类单例属性仅仅只能配置字符串等标量而不能注入别的依赖类,很弱吗。

如果在array配置每个service时,还能直接把这个serviceA依赖的别的serviceB、serviceC等都直接配置到serviceA的属性上,那么我们就可以玩更多,

比如fecmall对每个service对象调用魔法方法时前后hook这是一个方法,不过我更推荐使用代理模式,在神X创建每个service时可以通过创建代理类来代理这个service,实现hook方法调用。

关于三方开发者插件开发、用户自己开发、fecmall自身升级之间的冲突,我觉得冲突是不可避免的,和包管理那样严格限制允许版本号呗,话说回来如果代码调用都是遵守同一个interface接口,每个service行为没问题就ok,interface依赖没有改变就可以认为没有冲突。

Fecmall#44年前 0 个赞

你的观点:首先我没有否认全局变量$services的作用,但我觉得它有巨大的改进和提升的空间,你不觉得目前$services对类单例属性仅仅只能配置字符串等标量而不能注入别的依赖类,很弱吗。

如果在array配置每个service时,还能直接把这个serviceA依赖的别的serviceB、serviceC等都直接配置到serviceA的属性上,那么我们就可以玩更多

回复:我上面说的,真的是白说了,现在的问题是解耦的问题,将serviceA,serviceB、serviceC进行解耦,你居然要耦合再一起,如果是这样,Yii::$service真的没有必要用了,直接再serviceA中new serviceB,直接调用就行了,还用啥servies?多此一举,直接再model里面写就完事了,mvc框架结构一把梭!

总结

1.该贴结单,不做讨论,你认为你的可行,去实践,可以自己写一个商城,也可以基于fecmall上面二开,做出来你想要的样子,试试就知道了。

2.该说的都说了,没有动力讨论这个问题了,get不到点,讨论的一点意思没有,不在一个水平线。

3.发帖子讨论,也是为了以后有类似的phper扯这些东西,直接基于现有帖子基础上讨论。

添加回复 (需要登录)
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册
Your Site Analytics