混合编程的实践与思考

混合编程

混合编程是指选择择多种编程语言开发应用程序的过程。各种编程语言有各自的优势和劣势,取各自的长处,能显著提升开发效率。

Java和C++混合编程,Java和C++可以通过JNI相互调用。JAVA简单,开发效率很高,完全面向对象,适合做应用程序,C++复杂,运行效率高,难以反编译,适合做底层。Android应用开发时,用Java写应用层,开发效率高,底层关键算法可考虑使用C++,执行效率高,也不容易被反编译,保密性更好。

在游戏行业盛行的Lua+ C++,C/C++这类低级语言写逻辑太不方便,并且逻辑会经常变化,而C/C++必须编译后才能执行,C/C++即使使用了分布式编译,编译时间通常都很长。Lua是一门函数式的脚本语言,脚本语言的最大好处就是无需编译,改完后可立即执行,可显著提升开发效率,因此Lua适合写逻辑,应对各种逻辑变化。C/C++和Lua结合时,由C/C++提供原子操作接口供Lua调用,Lua利用这些接口组织逻辑,可随时改变逻辑规则,而不用改动C/C++代码并重新编译。

豌豆荚用web编程语言实现界面,用C++实现底层逻辑。Android编程时我们实现界面层时,通常直接写xml布局文件,但是遇到复杂的界面,我们不得不写自定义控件,从View或者ViewGroup子类继承,也可以组合多个控件对象。实现复杂动画时也需要写自定义控件进行更精确的控制。同样做Windows客户端程序时,我们也会选择界面引擎,比如说duilib,bkwin,利用这些界面引擎写界面时同样需要编写xml布局文件,遇到复杂的界面以及动画时,同样需要写自定义控件来实现需要的效果。我们知道利用C++实现复杂的界面以及动画非常麻烦,每次开发完之后,必须编译执行才能看到效果,导致开发效率低。而编写Web界面的技术非常成熟,有完善的库,可以利用jquery实现动画,一些简单的渐变动画用jquery来做可能只需要两行代码,如果用原生的C++来做,可能需要好几百行,还可以利用html5技术实现非常炫的效果,并且开发成本也不高。因此使用web编程语言实现界面比原生C++代码开发效率高很多。

让各种编程语言各自发挥自己的长处,比如web编程语言适合写UI,C++适合做底层库,Java适合写应用层。尽可能发挥各种编程语言的长处,可显著提升开发效率,并降低维护成本。

应对软件变化

世界唯一不变的就是变化,在软件开发领域也是如此,因此需要应对各种变化。

面向对象的软件开发有两种变化,一个是扩展,一个是修改。面向对象的软件开发有一个原则:对扩展变化开放,对修改变化关闭。也就是说软件开发时,尽量不要修改已有的代码,避免引入Bug,但是可以随便扩展,因为新扩展不会影响到现有代码。这就要求软件设计时,需要为变化的地方提前设计好接口,隔离变化。面向对象编程时主要通过多态来实现该效果,抽象出接口,接口可有多个实现,进行扩展时可添加新的接口实现,在客户端选用新的实现即可达到扩展的效果,不需要修改框架的代码,这样便实现了对扩展开放,对修改关闭。

通过设计接口隔离变化在框架开发时应对变化非常有用。我们在设计函数接口时,如果函数的参数也很容易变化,我们甚至可以将参数设置成变参类型,甚至map类型,这样也能灵活扩展参数,这也是软件开发时应对变化的一种策略。

但是从软件架构的角度来看,设计接口这样的手段还是不足以应对变化。从软件架构的角度看,客户端发布后,用户会下载客户端,开发者无法随心所欲地修改客户端。开发者一般要完成某个迭代所规划的功能,以及修复一些Bug后,再发新版本,而不是每修改一个小Bug就发一个版本,因为这样频繁升级会引起用户反感,需要保持一定的节奏。每次发完新版,新版覆盖到所有用户也需要一定的时间,因为用户不一定升级,各个渠道的覆盖也需要时间。

从运营的角度看,需要经常做活动或者广告,因此需要经常更换软件的一些界面。客户端可能还要分各种渠道版本,不同的渠道可能需要提供不同的服务。

为了应对这些变化,可以让这些变化的点在服务器端可控制。每次客户端启动时,都和服务器通信,告诉服务器客户端的渠道信息,获取对应渠道所提供的服务。服务端还可配置节日活动所需要的资源,客户端获取这些资源之后,进行节假日活动专题展示。

这样可增强服务端控制能力,因为服务端的修改可以随时影响到所有客户端,也正是基于这个原因,经常变化的因素应该在服务端可控制,这样在服务端修改后可即时影响到所有客户端。

移动软件的开发需要大量适配,比如分辨率适配,安卓版本适配,有些机型支持某一特性,有些机型却不支持该特性。为了能实现针对在不同机型,不同安卓版本的客户端进行控制,可将变化的因素做成配置项放在后台,后台可随时根据机型,安卓版本调整配置项,这样可让不同机型不同安卓版本上的客户端启用不同的特性。比如有些手机可以开启GPU硬件加速,有些手机不能开启,这时便能在服务器灵活控制。

设计成服务端的配置项是应对变化的一种手段,然而配置项的灵活性还是有局限性的:

  • 1) 每次添加新的配置项需要客户端发新版本才能支持
  • 2) 为了兼容旧客户端,即使采用了新的更强大的配置项,所有旧配置项都需要保留,久而久之,配置项的可读性会变得越来越差
  • 3) 有时候软件并没有按预期运行,通过配置项也无法解决该问题,必须让客户端发新版本才能收集错误发生时的现场信息
  • 4) 每个配置项都需要客户端的支持,能实现简单地运行逻辑变换,但是不能象编程语言那样灵活组织运行逻辑

混合编程应对软件变化

混合编程的架构能带来最大的灵活性,可用C++实现客户端,并为Lua提供运行环境,也就说为Lua提供扩展接口。Lua脚本保存在服务器端,客户端每次启动时检查最新的Lua脚本版本,并更新本地缓存的Lua脚本。这样的架构带来的灵活性:

  • 1) 每次变换运行逻辑时,只需更新Lua脚本,客户端启动时会自动获取最新的脚本,这样可以实现不用发客户端版本就能达到切换运行逻辑的目的
  • 2) 因为整个运行逻辑都存储在Lua脚本里,读Lua脚本便可知道实际的运行逻辑,增强了代码的可读性,以及软件的可维护性,不像配置项那样后期维护那边困难
  • 3) 如果软件并没有按预期运行,可以更新Lua脚本,Lua脚本执行逻辑里可以收集没有按预期运行时的现场环境,并上报给服务器,这样可快速定位问题,从而采取有针对性的解决方案,再次更新Lua脚本即可修复该问题
  • 4) Lua脚本因为不需要编译,所以开发效率比C++高。因此可以更快地更新版本,并且采用了即时更新Lua脚本策略,所以在服务端更新Lua脚本后可即时到达客户端。不像客户端的更新,比较打扰用户,而且更新速度也比较慢。

此外,现在也有越来越多的软件采用web+客户端的架构,比如微信,微信的帮助与反馈便是web界面,帮助与反馈功能里有很多常见问题,而常见问题是经常变化的,微信添加新的常见问题,就不需要发布新客户端版本,直接在后台添加一下即可。

当然混合编程也有它的不足。混合编程时,跨语言调试比较麻烦,C++和Lua混合编程时不能给Lua脚本打断点,Lua脚本的问题定位全靠日志。因此混合编程时,尤其需要保证底层接口的可靠性,否则上层开发的效率比较低。

你可能感兴趣的:(混合编程的实践与思考)