短信应用设计备忘录

 

转载时请注明出处

作者:Li XianJing 

 

 

短信是手机最重要的功能之一,也是最复杂的应用之一。在前一家公司,我曾参与改造短信应用的架构,里面有近三万行的C代码,累计BUG超过500个,开发周期历时超过18个月,负责人换了几个,最后的负责人也被折磨得焦头烂额。这其实不是负责人的水平问题,而是实现太复杂了。

 

有人会说,短信应用不就是一个编/解码的问题吗,很简单啊。那我只能说你和我一样都是外行,手机应用程序的复杂度从来都不是算法引起的,像音/视频这类复杂的算法都有现成的代码可用,短信编/解码也有很多代码可以参考。手机应用程序的复杂度,不是单一的因素引起的,而是众多因素掺杂在一起,结果复杂度远远超过各种因素的总和。

 

前事不忘,后事之师。让我们回顾一下上次短信应用的问题出在哪儿:

1.         缺乏基础函数库。这主要是管理上的问题,每个人都只顾自己的,没有人去考虑全局代码重用的问题。短信应用不得不自己去实现诸如,动态数组、双向链表和排序/查找这些基本的代码。后来我在整理公共函数库时,从整个项目中找到N套这类代码的实现。

 

2.         平台问题。平台组提供的平台功能欠缺,而稳定性比较差。提供的数据库,甚至连数据库最基本的特点都没有,应用程序要自己去实现查找、排序和建立索引等本该由数据库完成的功能。为了弥补平台的缺陷,短信应用为此做了大量的工作。GUI也不太稳定,动不动就死锁了,短信应用花了不少时间去调试平台的BUG

 

3.         架构问题。短信应用的负责人无疑是嵌入式方面的高手,不过他们都是从写汇编开始编程生涯的,在任何情况下,性能都是他们首要考虑的问题。面对短信这样的复杂应用时,没有人去考虑它的架构,在编程中引入的一些奇技淫巧,让短信应用的架构更加脆弱。比如,短信应用有多个界面,同步更新造成的BUG就有几十个,我后来把短信应用改造成MVC模型才解决这个问题。

 

4.         交互问题。和短信有交互的模块很多,记事通过短信发送、桌面查看短信、从名片中发短信、短信播放铃音、短信查名片、短信转发彩信通知、短信接收/发送Vcard/Vcalendar、短信存为记事、短信存为集锦、短信与PC同步等等。交互多是正常的,但如果没有良好的架构,没有把交互接口定义好,那就麻烦了。别的不说,单是交互引起的同步和重入就造成很多BUG。加上开发人员之间的友好关系,短信应用提供很多本不该短信应用提供的功能。

 

5.         管理问题。记得有人说过,很容易制定实现软件功能的计划,但谁也不知道功能完成到软件稳定要多长时间。这话很有道理,在管理上一味强调快速完成功能,结果是大量没有测试的代码过早的集成到一起了,这让后期的调试非常困难,软件迟迟无法稳定,甚至到了不可控的程度。在进度第一的情况下,一些BUG并没有彻底解决,只是隐藏起来了,这会造成更严重的问题。

 

6.         其它原因。到我插手整理短信架构时,短信应用已经几易其手,部分代码的可读性很差。这也为它的维护带来很大困难。

 

我不知道大家是否有这样的经验,一个数万行代码的模块和和整个项目的数十/上百万行代码耦合在一起,代码有点乱,架构不太好(甚至没有时间去弄清楚架构在哪里,长什么样的)debugdebug还是debug,最后都麻木了。项目结束时间遥遥无期,大家都在做明知没有希望的事情。这样的事情我经历了两次,希望不会有第三次了。

 

可能有人马上会说,不会吧,我以前做过啊,短信没有你说的那样复杂啊。我只能说你是个幸运儿,你遇上了好的平台、好的架构、好的团队、还有其它一些好的运气。或许好运气这次轮到我们了,至少我们具备不少有利因素:

 

1.         非富的基础函数库。glibcglib提供了非富的功能,字符串操作、各种容器和算法和配置存取等等。还有其它像expatzlibpng等很多函数库,都会或多或少的派上用场。不用再浪费时间在这上面了。

 

2.         功能强大的数据库。我们采用sqlite3作为DBMS,并把它改造成C/S模型,在客户端采用面向对象的封装。更重要的是通过DBUS,支持数据变化通知,某个表变化时,可以通知相应的订阅者。

 

3.         良好的架构。基于MVC模型和插件式设计,让各种耦合减到最少。

 

4.         明确定义各种交互的方式和接口。公共函数提取到公共函数库中,公共控件提取到公共控件库中,而不是在应用程序之间互相调用。能用插件方式的就用插件,减少不必要的耦合。必要时以DBUS服务方式提供服务。

 

下面我们探讨一下短信应用及MMI的基本架构:

1.         短信应用相关组件及其关系。

短信应用设计备忘录_工作

短信应用并不直接与MMI服务进程交互, 而只与数据库交互。

 

桌面的新事件桌面项监听数据库的变化,新短信到来时会得到通知。新事件桌面项也可以通过短信应用查看短信内容,这是通过DBUS服务实现的。

 

数据库是系统的中心。我们实现了的数据变化通知机制,关心数据库变化的模块,可以订阅特定数据表的信息,对应数据表发生变化时会收到通知。

 

短信插件在MMI服务进程中运行,它与数据库和短信工作线程交互。

 

短信工作线程则通过内核的提供串口与GSM模组交互。

 

2.         发送短信的过程。

 

短信应用设计备忘录_平台_02

发送短信时,短信应用只是把新短信存在数据库中,并置为即将发送的标志。

 

数据库存好短信后,通知相应的订阅者,而短信插件是其中之一。

 

短信插件发现有要发送的短信,于是取出这些短信,通过短信工作线程发送。

 

短信工作线程通过串口发送短信给GSM模组。

 

短信插件把发送成功的短信的信箱类型置为已发信箱,把发送失败的短信置为发件箱。

 

数据库通知相应的订阅者,短信应用是其中之一。

 

短信应用提示用户短信发送成功还是失败。

 

3.         接收短信的过程。

 

短信应用设计备忘录_mvc_03

GSM模组收到短信后,上报给短信工作线程。

 

短信工作线程调用短信插件注册的函数。

 

短信插件把新短信存入数据库。

 

数据库通知相应的订阅者,其中包括短信应用和桌面的新事件项。

 

短信应用可能更新相应的短信列表。

 

桌面的新事件项提示用户有新短信。

 

上述架构是同事设计的,我只是做了些改善,欢迎大家提出建议。

 

~~end~~