早期我在设计系统的时候,尚没有听过Microkernel设计模式。那时候我就在想,如何才能设计出来一个“长青系统”。它能够最大程度的顺应系统的演化,具有极强的扩展性,极好的模块化。
直到前几天读《面向模式的软件架构》的时候,读到了Microkernel设计模式,才恍然发现我之前设计系统采取的一些措施和手段,实际上就是使用了Microkernel设计模式。不过到底缺乏理论支持,那些系统看上去并不够精致。
背景与问题
Microkernel设计模式,其背景原书中写的是:
使用依赖于相同核心功能的编程接口开发多个应用程序
不过对于我这种侧重业务的开发而言,它可以被描述为:
使用依赖于相同核心功能的编程接口接入多个业务
在我所涉及的需求,大多数都是具有良好的通用性——因为我所在的部门,涉及的类目实在过多。很多需求都不能仅为当前类目开发,而要充分考虑到其余的类目。此外就是,我主要负责的一款商业产品,它类似于一个平台,允许各个业务方开发各色功能接入这个平台。这些功能可以被组合成不同的产品,执行不同的售卖策略。尤其特殊的是,有很多功能也是我们开发的。于是我们既扮演了一个平台方的角色,又扮演了一个业务方的角色。
不论是哪种情况,都要求必须能够适应业务的不断发展。
解决方案
早期我思考的一个解决方案就是,保持系统的核心尽量与业务特征剥离。有时候我会把这个称为“业务无关内核”。这其实是我从哲学上收获的一个启发。哲学上讲“内涵越小,外延越大”,而“内涵越大,外延越小”。对于一个系统来说,要想适应不同的业务,也就是要具有很强大的“外延”,那么就必须保持“内涵”小。
我们可以这样想:如果一个内核具有极强的业务特征,那么每次接入一个新的业务的时候,这个内核都要修改,以纳入这个业务的特征。如果我们可以预见到所有要接入的业务的特征,那么,我们就可以让内核具有所有这业务的特征。但是很显然的是,我们并不能做到这一点。很多时候,在设计系统的初期,是基本不可能预见到会接入什么样的业务的。所以这条思路是不行的。
可行的是,让内核不具有任何的业务特征。如果一个内核不具有任何的业务特征,那么它就可以接入各种业务特征。所以其实质而言,所谓Micorkenel,我的理解是:
微内核中实现必不可少的功能,但是这些功能应该与具体业务特征无关,而仅仅与接入各种业务的方式有关。
也可以从《Unix编程艺术》中的“提供机制,而不是策略”来理解Microkernel。我认为,Microkenel设计模式中的内核就是提供机制,剩余的策略都是围绕内核来构建,但是并不是属于内核的一部分。于是所有的接入业务,包括其内部实现,都只是一种策略。
机制是一种更加高层次的抽象,因此也越稳定。
在内核设计了这种机制后,我们自己也可以作为一个业务方,利用这种机制实现自己的策略。我们的实现和别的业务方在抽象层次上是平等的。不过可以利用一些内核所不暴露给第三方的特殊接口,实现一些比较特殊的功能。这样就可以引入了Microkernel设计模式里面的两个其他角色:
- 内部服务器(internal server):扩展了内核提供的功能,是一个提供额外功能的独立组件。微内核通过服务请求调用内部服务器的功能,因此内部服务器可以封装一些与底层硬件或软件系统相关的细节;
- 外部服务器(external server):是使用微内核实现其底层应用领域视图的组件。视图是抽象层,建立在微内核提供的不可分割的服务的基础上。不同外部服务器为特定应用领域实现了不同的策略;
这是一种针对不同平台的说法。就侧重业务而言,并且依据我个人的理解为,它应该被表述为:
- 内部服务器:扩展了内核提供的功能,是一个提供额外功能的独立组件。该组件由维护内核的团队维护,可以利用未被暴露出去的“特权”服务实现某些特性,以支持客户端调用;
- 外部服务器:是利用微内核实现的与业务相关的服务。可以被客户端直接调用;
注意的是,无论是内部服务器还是外部服务器,都是一个独立的组件,并且应该支持可插拔。可插拔意味着,内外部服务器是可以随时增加,减少或者替换的。这是满足扩展性的一个核心要求。
微内核还可以增加一个适配层。但是这个适配层是可选的。对于简单的应用来说,加上一个适配层可能过于复杂,太重了。但是如果需要避免客户端对内外部服务器的直接依赖,那么就需要加上这个适配层。或者说,希望对客户端暴露一个统一的api,那么也需要加上这个适配层。但是直接依赖于内外部服务器,对于大多数应用来说,应该不会出现太大的问题。
于是我们现在可以得到整个系统的划分了:
Microkernel设计模式结构
就图而言,越是往中心,其变化就越少,就越稳定;越是往外边,就越贴近业务,知道最外面的真的业务——客户端。
例子
我想用我在可配置前端页面的解决方案里面的例子来作为一个说明:
我在那里要设计的是一个可配置的页面,它基本上遵循了Microkernel的设计模式(虽然我设计的时候并没有系统的学习Microkernel设计模式的理论)。我在文中提及的一点是,因为我无法预料到将来页面会有多少组件,会有多少预定义的动作。所以我设计了一个小巧而精致的内核,内核里面没有定义任何组件,它提供的是通信模块,事件模块,Module模块和model模块。这些模块的实现里面并不含有任何与业务相关的信息。所以可以将其称为一个业务无关的核心。
于此同时,我预定义了一大批的组件,如输入框,复选框;还预定义了部分事件。这部分预定义的组件组成的预定义Module,其实就是充当了内部服务器的角色。所不同的是,这些组件并没有用到什么“特权服务”,它使用的接口与暴露给自定义组件的接口是一致的。
同样道理,第三方module就是充当了一个外部服务器的角色。注意的是,这个例子里面我并没使用一个适配层。
后记
这只能算是我对于Microkernel的一个简单理解。其实我描述的Microkernel与书中提及的有挺大的差异。一者是我理解可能有偏差,另外一个可能是我在将这个设计模式与具体业务结合起来的时候,其中更改了一些概念。读者应该注意区分。
网友评论