Table of Contents
我看到好多独立的事情被外包或者众包出去,在完成速度和效率上,都非常出色。好多开源的组织也是这样,接纳全世界软件开发着的贡献,然后对这些贡献进行整理,这是众包的过程。项目经理在分派任务的过程中,将系统分割成不同的部分,而这不同的部分又关联的不那么紧密; 让他们齐头并进,这样让项目效率提高不少。
1 高度集中的集权模式
在之前的一家公司,在开发的过程中,当你写完代码,你根本就不能去测试你的代码。首先你的代码没有测试模块,因为电信的业务错综复杂,要调试需要牵扯到很多系统。我发现这些系统是互相关联,少了哪一样都不能正常运行(完全形成不了所谓的插件模式)。还有就是大家在本地写好代码,都会上传到同一个服务器上,编译; 有时候刚好碰到某个人也在上传自己的模块,你要等一下,然后等他编译完成之后,你才能接着你的工作。这就是我要说的中心模式,由于拥有一个中心,你必须排着队去处理任务,当你的模块出现问题,还会影响到其他人工作。
现在不同了,在一家游戏公司,每个人都拥有自己的数据,自己的服务端,自己的客户端; 我开发好自己的服务端。在自己的虚拟机里面运行,完全不会影响其他的人工作。同时,客户端开发人员,也拥有和我一样的部署。当客户端和服务端都开发完之后,只需要将客户端连接上服务端就可以进行联调。联调完成之后,将模块代码归总到工程的svn主干,一般一个模块都会指定一个客户端和一个服务端来做。如果人员比较多,两两配对,可以同时做多个模块,而相互不想干扰。这就是分布式开发模式。
分布式开发模式是基于插件模式的基础之上,模块被分割出来之后,它们是互不相关联的。高度集权模式,就像独木桥一样堵得紧。分布式开发模式则拥有更多车道,八面玲珑。我们很快能够看清分布式开发的好处。
在测试上,分布式也体现其优越性。程序猿分别开发自己的模块,每个人为自己的模块写入测试模块,确保自己的模块运行良好之后; 然后将不同的模块汇总,由测试人员查处各个模块之间的衔接bug。假使每个开发人员不确保自己的模块工作正常,所有的bug汇集到测试人员那里,将是不可开交的。
2 千篇一律的固定框架
每个公司都有一个框架,一个开发人员进入这家公司就必须得按照固定的模式去写这个模块。那种千篇一律的工作会让那些想追求新鲜事物的程序猿们厌烦不已; 于是乎不停的跳槽,不停的换工作,最后还是没有跳出这个尴尬的局面; 这恰是一个码农的真实写照。写重复性代码是必须,我们每个人都是生产线上的工人,做重复性的事情,可以减少工作的难度,提高工作效率。但是软件开发毕竟不是富士康里面的生产线。
插件模式,最后要打造的就是这种方式,减少开发的难度,形成固定的插件开发套路。有没有什么方法来解决这样的问题了?
减少重复性工作的方法,就是让这部分重复性的劳作成果自动产生–做一个代码生成工具。现在一些主流的IDE(eclipse、vim、emacs)都支持插件,大部分公司可以根据自己的框架结构,来开发IDE插件,定制自己的IDE。我以前使用VC开发过MFC程序,我们发现使用它能够很方便的添加消息、类、事件等,这些只需要启动classwizard。我们可以设计插件,与IDE相融合,来创建框架里面的一些组建,以及在刚开始的时候,创建自己的模块模板。VC也是这样做的,它会创建Dialog等模板。插件会在各个组建模板需要添加代码的地方,去添加TODO标志,这样子提醒开发人员去补全代码。
按照这样的方式,可以减少大量的复制粘贴的工作,同时也减少了复制粘贴过程的大量错误。要记住,当你产生了大量的复制粘贴,说明好多东西是可以自动生成的。这样子,程序猿可以专注于自己关心的事情,也就不会觉得很枯燥了。
3 左右逢源的插件模式
上面以及包括前几篇文章里面多次提到插件模式,插件模式其实也是一种弱中心化的过程。它有一个中心,起到统筹的作用,各个插件互不关联,表现出不同的特性。当一个插件工作失常,不会影响其他插件的工作。我所见到大部分编辑器,都拥有很多插件。编辑器是一个中心,它拥有最基本的要素; 插件来丰富其特性。
在windows下面拥有一款编辑工具,notepad++; 我特喜欢,其有丰富的插件,其由C++开发而成的。插件开发所有的特性是:1.插件与插件之间互不依赖; 2.在开发插件的时候不需要去更改主体的代码; 3.主体自动去加载插件。想想,当我们下了notepad++的一个插件,我们并没有去更新或者更改notepad++或者其某个插件; 当我们将notepad++的插件放置到其plugin目录下时,重新启动notepad++,notepad++就能够使用这个插件的特性了。
这种不断的更新模块,并不会导致整个工程的重新的编译生成的特性; 只有动态库才能很好完成这样的工作。notepad++的插件就是一系列的dll文件。
不同的操作系统动态加载dll的API不一样,Poco库,一个跨平台的C++库,为我们解决了不同平台的差异,提供了统一的加载dll的API。在开发我们的插件的时候,我们必须要约定插件的一个入口函数,主体应用通过调用相应dll的入口函数,然后在针对插件的不同特性,来做一系列的操作。
下面是一个例子:
1 //主题程序通过配置文件加载dll,而dll_config.txt配置文件里面包含了所有插件dll的路径 2 bool LoadPlugin() { 3 file.open("dll_config.txt"); 4 while (!iseof(file)) { 5 dll_path = file.readline();//从配置文件读取dll路径 6 HAND hDll = LoadLibrary(dll_path); //加载dll 7 Proc proc = GetProcAddress(hDll, "Init"); //获取函数地址 8 proc();//调用函数 9 } 10 } 11 12 13 //配置文件dll_config.txt 14 xxx/a.dll 15 ... 16 xxx/n.dll 17 18 //插件模式dll,必须要实现Init入口函数,而且使用C,防止产生联编,因为我们要根据函数名称获取dll中的Init函数地址,可以在入口函数里面调用插件的C++接口 19 __declspec(dllexport) void Init() { 20 xxx 21 }
这是主体程序加载插件的模式,还有很多事情要做,主题程序必须提供清晰的程序结构来供插件调用。比如编辑器会有工具条,菜单,编辑框,状态栏等,插件要在这些上产生特性,要对这些组建做操作的。
插件模式让事情变得更加简单化,同时让开发变得没有挑战性; 同时也可以让程序猿关注更重要的事情,抽出更多的时间来做自己喜欢的事情。