耦合与解耦
“分久必合,合久必分”是亘古不变的道理。一个简单的应用从诞生的那天起,就开始不断承载新功能,功能越来越多也越来越强大,于是就产生了从原来的大应用中拆出部分子功能以形成另一个独立的应用的需求。
在产品经理眼中,应用的每个功能都像一块积木,可以组合也能拆分,感觉并不复杂,但将拆分需求告知开发人员的时候,往往会看到一张为难的脸。当然,要他们硬着头皮做也不是不可以,但你打探进度的时候经常会听到“还在解耦”。
“解耦”和“耦合”是对立的,产生了耦合才需要解耦。耦合是代码结构设计中产生的问题。当公司需要开发一个应用时,往往会将应用中的各个功能分配给不同的程序员,但各个功能在联动时会直接互相调用对方提供的方法,这就是耦合的温床。比如A模块的支付功能需要用到B模块中扫描二维码的功能,于是A模块的代码中就出现了“B.scanQRcode”。
B模块扫描结果的代码中就会出现以下代码:
if(resultIsPayCode)
{
A.doPay();
}
这看起来好像没问题。但假设有一天产品经理突然要将扫描二维码的功能单独包装成一个应用,A模块的支付功能不能跟着拆分出去,可是A模块有代码写在B模块中,必须要删除B模块中与A模块相关的代码。实际上,不止A模块的代码,C的、D的……全都写到一起了,这就是耦合。虽然从外部看应用是由各个功能组合起来的,但各个模块之间早已如同血和肉一般你中有我,我中有你地紧紧连在一起。
但功能不能不拆,这里就需要解耦了。换个角度想,一个应用的功能再大再全,对宿主系统来说都是一个独立的模块,在宿主系统中多个应用也是可以交互的,它们的代码之间肯定没有办法互相引用,但是它们依然可以互相协同完成一些任务。例如,一个二维码扫描程序扫描到网址后,打开了浏览器程序;用户在一个需要登录才能使用的应用中单击“微信快速登录”按钮,应用调用微信程序,并使用微信账号登录。如果把宿主系统提供的开发SDK看作一个框架,那么不同应用之间通过框架提供的标准接口进行交互,就可以避免直接的代码耦合。这个想法对单个 APP 内部也是适用的,这是一种利用框架解耦的方式。
当然,还有各种设计模式也是可以帮助解耦的,原则就是避免直接交叉,不将A功能的代码写在 B 功能的代码中。如果两者之间需要交互,可以通过接口、通过消息,甚至可以引入框架。
很多时候需求紧迫,开发人员也没看到功能独立化的趋势,为了快速开发,直接互相引用代码是很常见的现象(这会增加后期解耦的工作量)。如果产品经理能够预见未来独立化的趋势,在初期提醒开发人员也未尝不可。