关于IoC的的概念提出来已经很多年了,其被用于一种面象对像的设计。我在这里再简单的回顾一下这个概念。我先谈技术,再说管理。
话说,我们有一个开关要控制一个灯的开和关这两个动作,最常见也是最没有技术含量的实现会是这个样子:
然后,有一天,我们发现需要对灯泡扩展一下,于是我们做了个抽象类:
但是,如果有一天,我们发现这个开关可能还要控制别的不单单是灯泡的东西,我们就发现这个开关耦合了灯泡这种类别,非常不利于我们的扩展,于是反转控制出现了。
就像现实世界一样,造开关的工厂根本不关心要控制的东西是什么,它只做一个开关应该做好的事,就是把电接通,把电断开(不管是手动的,还是声控的,还是光控,还是遥控的),而我们的造各种各样的灯泡(不管是日关灯,白炽灯)的工厂也不关心你用什么样的开关,反正我只管把灯的电源接口给做出来,然后,开关厂和电灯厂依赖于一个标准的通电和断电的接口。于是产生了IoC控制反转,如下图:
所谓控制反转的意思是,开关从以前的设备的专用开关,转变到了控制电源的开关,而以前的设备要反过来依赖于开关厂声明的电源连接接口。只要符合开关厂定义的电源连接的接口,这个开关可以控制所有符合这个电源连接接口的设备。也就是说,开关从依赖设备这种情况,变成了,设备反过来依赖于开关所定义的接口。
只要你看过我的那篇《面向对象设计其实和面象对象一点关系也没有》,你就知道这样的例子在生活中太多见了。比如说:
1)在交易的过程中,卖家向买家卖东西,一手交钱一手交货,所以,基本上来说卖家和买家必需强耦合(必需见面)。这个时候,银行出来做担保,买家把钱先垫到银行,银行让卖家发货,买家验货后,银行再把钱打给卖家。这就是反转控制。买卖双方把对对方的直接控制,反转到了让对方来依赖一个标准的交易模型的接口。股票交易也是一样的,证交所就是买卖双方的标准交易模型接口。
2)上面这个例子,可能还不明显,再举一个例子。海尔公司作为一个电器制商需要把自己的商品分销到全国各地,但是发现,不同的分销渠道有不同的玩法,于是派出了各种销售代表玩不同的玩法,随着渠道越来越多,发现,每增加一个渠道就要新增一批人和一个新的流程,严重耦合并依赖各渠道商的玩法。实在受不了了,于是制定业务标准,开发分销信息化系统,只有符合这个标准的渠道商才能成为海尔的分销商。让各个渠道商反过来依赖自己标准。反转了控制,倒置了依赖。
可见,控制反转和依赖倒置不单单的一种设计模式,反而更是一种管理模式。
在大公司中,有很多很多的团队,这些团队开发的软件有很多依赖,跨团队合作是一件挺麻烦的事情,下面是一些比较真实的示例:
1)一个网页会有很多频道,于是,我们的前端工程师进入到各个页面为各种频道开发他们的页面,随着频道越来越多,前端开发工程师的人数也越来越多,每增加一个频道,就要增加一个为这个频道服务的前端团队,于是,人数越来越多,干成了劳动密集型。为什么不反转控制,倒置依赖呢?前端的同学完全可以开发出各种页面的标准组件,布局,模板,以前与后端交互框架,然后,让后端的同学反过来依赖于前端的标准,使用前端的框架,前端的布局,模板,和组件,以向前端接入后端的模块。
2)一个平台需要接入各种各样的业务系统,这些垂直业务系统都有自己的账号体系,于是这个平台为了要兼这些垂直系统的账号体系以做到权限控制,需要做各个系统和自己系统中的账号映射,并为账号和分配出来的资源设置各垂直系统的标识,还要在自己的代码中要写很多很多的依赖于各种账号体系的代码。其实,一个依赖倒置和反转控制就很简单。开发一个权限体系标准,让接入方的账号系统反过来依赖并控制这个标准的权限系统,从而做出一个干净的系统。
3)还有一个云平台中的管理模式,一些底层服务的开发团队只管开发底层的技术,然后什么也不管了,就交给上层的开发人员,在底层团队的开发出来的产品上面开发各种管理这个底层资源的东西,比如:生产底层资源的业务,底层资源的控制台,底层资源的监控系统。这个让底层团队只干纯技术,不干与底层技术无关的东西,看似很科学,其实是做错了。因为,上层为各个云资源控制生产,开发控制台和监控的团队,随着接入的资源的越来越多,完全干不过来了,苦逼得一塌糊涂,因为底层的资源千差百怪,每接一个就要开发一堆这个产品的代码。这个时候依赖倒置和反转控制又可以解决问题了。很简单,上层为各个云资源控制生产,开发控制台,和监控的团队应该制定一个标准,让底层的IaaS云资源开发团队反过来依赖这个标准,统一接入方式,如果开发的云资源不符我的生产控制模型,没有控制台,不把监控数据喂入我的监控系统,对不起,请不要接入我这个PaaS平台。
4)一个集中式的处理电子商务中的订单的流程。各个垂直业务线都需要通过这个平台来处理自己的交易业务,但是垂直业务线上的个性化需求太多。于是,这个技术平台开始出现了黑魔法——“为了害怕改变数据库表结构,不得不在数据库中预留一些字段,里面存把业务方的个性化字段存成如JSON这样的东西”,并为之自豪认为可以快速解决业务问题(WTF)。然而,恶梦并没就此结束,管理这个技术平台的小组开始发现,对来自各个业务方的需求应接不暇,各种变态需求严重干扰系统,各种技术决定越来越不好做,导致需求排期排不过来。于是,不单单得到了各个业务方的各种抱怨,最可怕的是还有高层老大们压过来的Deadline,加班加点,苦逼之极,最后业务方自己要去一个自己的平台。为什么不用依赖倒置和反转控制的思想呢?开发一个插件模型、工作流引擎和Pub/Sub系统,让业务方的个性化需求可以以插件的方式插入我的订单流程中,业务方自的数据存在自己的库中,业务逻辑也不要侵入我的系统,并可以使用工作流引擎或Pub/Sub的协义标准来自己定义工作流的各个步骤(甚至把工作流引擎的各个步骤的Decider交给各个业务方自行处理)。让各个业务方来依赖于我的标准插件和工作流接口,反转迭控制,让他们来控制我的系统,依赖倒置,让他们来依赖我的标准。(这个团队想过把自己的系统内部开源出去让别的团队也进来参与,可以是可以,但一定要用Linux/Git这种方式,允许出现多个分支,多个发行版。但多个版本又造成了多个业务平台,这会上上层垂直业务不知所措)
5)看过《SteveY对Amazon和Google平台的吐槽》的人都知道,Amazon内部系统的SOA架构(这个SOA架构离IBM定义的那个非常变态的SOA还有一定距离),但是这基本上都是依赖倒置和控制反转的思路了—— 与其让我来帮你实现你的业务逻辑,不如把我的业务逻辑开放成服务的方式让你来控制。
6)再说一个我在Amazon经历的例子。有一个项目是在给Amazon的各个商区(Marketplace)做国际出口的业务,我们先把Media类的产品(书,DVD之类的)做国际出口开放,项目不难,就是让商家同意一个法律协议(上传自己的签名),然后后台小改一下。美国的,欧洲的做的都没有问题,物流团队在出口报关单上打的都是Amazon仓库的地址和商家的签名(本来这就是错的,打的应该是商家的地址和商家的签名),但是到了日本,就出了问题,因为日本海关即要日文信息,也要商家的英文名和英文地址,而我们的系统里面只有商家的日文信息。本来,这是一个挺简单的事——数据库里加两个字段,在那个同意条款的网页上收集一下商家的英文名和地址,然后把这些信息传给后面的物流团队。物流团队一看这个,发现搞不了,因为他还要传给仓库,N多的地方都要加这两个字段,还要写下各种if (site == JP)这样的判断。物流团队不蛮干,重新设计自己的系统。做一个Document Template的东西,这个就是那个那个要贴在物流盒子上的单子。再也不让各个业务团队把那些信息传过来,而是把这个Document Template的东西传给上面的业务方,他们想怎么写就怎么写, 写完后,把这个东西传回来。于是,大家依赖了一个标准的协议,而不是一其字段。(当然,这个改动过多,为此改了半年多,不过非常值)
所以说啊,在跨团队的工作中,
- 如果依赖和控制的东西过多了,就需要制定标准,倒置依赖,反转控制。
- 控制欲望最好不要太强,不要想着能干所有的事情,要学会控制反转和依赖倒置原则。否则只会引火烧身。
- 反转控制和依赖倒置是一种智慧。