电子病历,到底是用BS还是CS
袁永福
2014-8-19
前言:前几天下午去开发医疗软件的S公司,旁听了他们的内部技术讨论会议。他们目前的电子病历是B/S架构,会上一群人讨论起用C/S重构电子病历系统的可行性,于是引出了本文的题目:电子病历,到底是用B/S还是C/S。
电子病历等医疗信息化系统到底是用B/S模式还是C/S模式。这是一个长期以来困扰着许多甲方和乙方的基础性的技术问题。过去困扰了,现在还在困扰,估计将来还会困扰。
这个问题真的是可以花开两朵,各表一枝了。首先说说B/S模式。
B/S模式最为称赞的特点就是部署、维护和升级非常方便,这是一个无与伦比的优点,一俊遮百丑的优势,网络上到处都有歌功颂德的帖子,我内心也是真心认同和赞扬的。很多时候,你若BS,便是晴天。
对于软件开发来说,B/S还有一个好处程序功能模块化。要加个功能,也就新增一个WEB页面,写上服务器端代码,这个操作对已有模块没有任何影响。因此比较容易做出层次明晰,结构合理,[袁永福原创]能持续可控变化的系统。
得益于传奇的Macromedia公司和强大的ADOBE公司,B/S的静态UI展示功能非常好;而随着技术不断发展,B/S的动态UI展示功能也在逐渐增强,比如http://fineui.com就是一个很好的例子。
孙子兵法云:“不知兵之害者,不能尽用兵之利”。同样的,不知技术之害者不能尽用技术之利。对于电子病历等医疗信息化系统来说,B/S还是有着明显的缺陷,此时C/S程序仍然具有相当的优势。在此进行对比。
>>页面状态
由于B/S的基础的HTTP协议的无状态的特性。使得B/S中各个页面数据交换比较困难,数据交换过度依赖数据库,大多数状态数据都需要反复的保存和读取数据库,增加不少代码量。医疗业务流程中的业务数据链路密集复杂,使用B/S处理起来还是很费劲的,相信广大程序猿深有体会。
对于来说C/S程序各个窗体之间交换数据很方便,窗体之间的函数、属性和事件可以*的相互调用,能比较简洁优雅的处理业务数据路由。
>>离线运行能力
B/S程序基本上没有离线运行能力,所有操作都必须在线执行,中途断线了,则页面上的数据全部丢失,用户体验非常的不好。相信大家都曾经遇到过,比如敲字发帖或者发电子邮件,辛辛苦苦敲了几百个字,一提交时才发现网络断了或者服务器当机了,文字全部丢失,肯定会抓狂的。
而C/S 程序具有离线运行能力,[袁永福原创]当网络或者服务器不可用时,可以将用户输入的数据暂存在内存或者临时文件中,等到网络环境好了再上传,这样比B/S程序大大改善用户体验。
>>浏览器兼容性问题
浏览器兼容性问题是B/S程序的老大难问题,过去头疼,现在头疼,未来还是会头痛的。相同的页面,在不同公司的浏览器或者同种浏览器中的各个版本之间存在一定的显示差距。比如在设计时“保存”按钮放在最下面,对于IE8能显示,而对于IE7就不显示,使得应用系统不可用。
规定客户使用指定版本的浏览器也是不可靠的。客户可能会运行多家公司的软件产品,各家公司期望指定的浏览器版本可能不一样,此时会产生冲突,让一家适应另一家都是比较痛苦的过程。
而C/S程序就没有这种浏览器兼容性问题,而且一样的程序,对于不同版本的Windows系统,其界面也差不多,都是能用的。
>>IE嵌控件
医疗软件中一些用户体验使用JS/DHTML实在做不出来,于是采用IE嵌控件的形式,最常见的就是电子病历编辑器控件。
所有的IE嵌控件技术都是不大稳定的,需要配置浏览器的安全性设置、需要设置客户端控件的更新配置,可能存在少数电脑就是无法自动更新控件,需要手动进行更新,而且各种IE插件间会相互影响,[袁永福原创]还会受到360等安全软件的影响。此时B/S系统丧失了部署简单更新方便的优点了。
在这种情况下,还不如使用C/S程序来做。
>>本地数据缓存
希腊神话中,西西弗斯因为在天庭犯了法,被大神惩罚,降到人世间来受苦。对他的惩罚是:要推一块石头上山。每天,西西弗斯都费了很大的劲把那块石头推到山顶,然后回家休息,但到了晚上石头又会自动地滚下来,于是,第二天又要把那块石头往山上推。这样,西西弗斯所面临的是永无止境的推石头。
我们的B/S程序有时候就是西西弗斯在重复又重复的推石头。医疗软件在使用的时候需要调用很多字典类型的数据,比如库存药品清单、ICD编码、各种医学技术名词、可用的知识库等等,这些数据记录都是成千上万的,可是B/S页面无法本地数据缓存,每次刷新页面都需要重新加载这些字典数据,增加服务器的负荷,影响软件的响应速度,即使采用JS动态加载,也只是治标不治本的。JS无法进行本地数据缓存,因为JS没有访问本地文件系统的权限。
而C/S程序可以很方便的进行本地数据缓存,而且事实上笔者见过的所有的C/S医疗软件在启动的时候都会花上一段时间来加载各种字典数据,这样在运行中就直接使用本地缓存的数据,这能提高程序的响应数据,降低服务器的工作量。
>>软件自动升级
B/S程序最大的优点就是部署、实施和更新升级很方便。
C/S虽然这方面差一些,但随着技术的进步,这方面也在逐渐改善。笔者认为在现在的技术条件下,C/S软件的自动安装和自动升级真觉得不是问题。这点网络上泛滥成灾的流氓软件就是很好的证明。再比如QQ客户端软件,几乎每台电脑都会安装,也很好的解决了部署升级问题。
现在客户端绝大多数还是微软的Windows系统,微软针对软件的部署和升级提供了很多底层的支持,包括SmartClient/ClickOne技术等等,[袁永福原创]这些都为C/S软件的自动化部署升级带来很大便利。
>>运行性能
现在的B/S程序大量依赖JS技术。而JS语言是解释方式运行的,很灵活,但容易出错,而且运行速度慢。当JS太多时,比如前头提到的S公司,他们的JS代码量占40%,此时浏览器经常报JS运行超时的警告信息。
而C/S程序都采用编译性语言,会进行严格的语法检查、很多错误都在开发编译阶段能发现,这能提高代码的运行速度。即使遇到耗时的操作,也可以使用多线程操作来改善用户体验。
>>代码规范
B/S程序的客户端编程语言是JS,JS是面向对象的,单不是基于对象的,而且很多公司重视程序代码的质量,但不大重视JS的代码质量,因此造成JS代码的臃肿,出现大量的重复代码。
相对来说主流开发组织对C/S的编程语言是讲究规范的,比如C#/JAVA等,还有专门的语言规范检查工具,而且C/S的编程语言大多是完全的面向对象的,能很好的实现代码重用,重构也很方便。[袁永福原创]主流开发组织也重视代码库的积累和维护。
>>国际化
所谓国际化就是推出软件的多语言版本。比如电子病历系统的简体中文版、繁体中文版、维文版、英文版之类的。
目前中国国内的医疗软件产品基本上不考虑国际化。不过有条件的公司应该还是要考虑到软件产品国际化。
B/S软件比较难于做到软件的国际化,因为WEB页面中的文字都硬编码在HTML代码中,同时维护WEB页面的多语言版本工作量很大,而且JS/DHTML比较难于实现字符串资源的各个版本。
相对来说,C/S程序比较容易实现软件的国际化。比如对于VS.NET的WinForm窗体,可以在设计阶段来配置多语言版本的资源文件。例如下图所示:
这是VS.NET中一个WinForm窗体的相关文件。在这里dlgSpecifyPaste.ar.resx是维文版的资源文件,dlgSpecifyPaste.en.resx是英文版的资源文件,dlgSpecifyPaste.resx是默认的简体中文版的资源文件,dlgSpecifyPaste.zh-TW.resx是繁体中文版的资源文件。
使用这些资源文件,[袁永福原创]可以让窗体在不用的语言环境下显示不同语言版本的内容,不过都表达相同的意思。
编码中需要的字符串也可以另外放在资源文件中方便的实现多语言版本。这样编译结果就是一个主程序配上多个语言版本的资源文件。比较轻松的实现了国际化。
>>用户行为
一些用户行为在B/S中没法很好的处理。最常见的就是直接关闭浏览器。一些浏览器提供窗口关闭事件,JS可以响应这个事件来进行处理,不过这存在浏览器兼容性问题,可能在某些情况某些浏览器中JS无法响应这个事件。
另外就是弹出窗口功能了。浏览器可能会阻止弹出式的窗口。在弹出式的窗口中的JS效果和普通窗体中的JS效果还可能不一样。这些就是需要花不少时间调试和配置的。
而对于C/S程序就没有这种问题了。
从上面分析可以看出B/S也不是完美,C/S也是有其优势的,实际运用中不应该一刀切。
------- 超越B/S和C/S ----------
现在有一种技术流派,想要超越B/S和C/S之争的,笔者也支持这派。笔者长期做UI层开发,那么就从UI层开始说起。
现在所有的医疗软件都是图形化用户界面,对于C/S程序,写C#代码调用DrawString(),DrawLine(),DrawImage()之类的GUI API来绘制用户界面;而对于B/S程序是服务器端写代码输出HTML代码,然后发给浏览器让其解释这个HTML代码来“绘制”用户界面。
因此可以抽象出来看,程序猿都是花大量的代码来绘制图形化用户界面,只不过一部分代码输出图形绘制指令,一部分代码输出HTML代码。但最终目的都是一样的。
另外程序猿还需要写大量的代码来让图形化用户界面和用户互动,都需要响应KeyDown/MouseClick等事件,这点大家的写的代码都很类似。最终目标也一样。
按照这种思想,B/S和C/S的理解可以如下:
C/S程序 |
数据库服务器→应用软件→界面呈现信息(DrawString等指令)→GUI |
B/S程序 |
数据库服务器→应用软件→界面呈现信息(HTML代码)→GUI For Browser |
两者逻辑上的高度相似性可以很容易联想到物理学中引力和电磁力逻辑上的高度相似性。物理学中正在谋求统一场理论,那么我们也可以谋求B/S和C/S的统一。
因此B/S和C/S呈现用户界面的代码虽然语言不同、代码执行的地方不同,但逻辑是相同的,因此逻辑上完全可以统一起来。以此类推,对于业务逻辑执行也是这样的,这就是B/S和C/S统一的理论基础,[袁永福原创]具体表现形式可以是OOP、AOP之类的。
按照B/S,C/S的统一理论,医疗软件可以划分为以下几个部分:
- 数据库服务器。SQL SERVER/ORACLE/NOSQL之类的。
- 业务逻辑执行层。执行医疗业务逻辑的代码,这个层面纯粹执行业务功能,没有用户界面。而且考虑到B/S应用应该是多线程安全的。
- B/S服务器应用层。运行在WEB服务器上的,直接调用业务逻辑执行层来实现业务功能。
- 远程调用包装层。对业务逻辑层执行层的功能进行包装,能方便的进行远程调用,这个远程调用就是基于XML的WebService或者基于二进制的JAVA/.NET Remoting。
- C/S客户端软件。客户端软件通过网络调用远程调用包装层来执行业务逻辑。
对于这种架构模型,如果业务逻辑执行层和B/S服务器应用层编译在一起就是传统的B/S系统;业务逻辑执行层和C/S客户端软件编译在一起就是传统的C/S系统。如果5个部分都分开,那么就是同时支持B/S和C/S的,这样软件具有强大的扩展性和生命力。
回归到笔者的老本行,电子病历编辑器。编辑器控件提供WinForm版本和ASP.NET版本的。WinForm版本支持所有的功能;不过受限于当前技术水平,ASP.NET版本只能只读的阅读病历文档内容,而无法编辑修改。因此建议在开发常规电子病历系统时采用C/S模式,对于互联网应用,比如公卫平台之类的,也是建议新的B/S和C/S统一模式。对于移动应用可以采用传统B/S模式。
最后想总结一下,[袁永福原创]孙子兵法又说了:兵势如水。小平同志的白猫黑猫也是这个理。笔者觉得开发软件也应该“兵势如水”,不必拘泥于B/S,C/S之类的条条框框。怎么适合需求就怎么做,灵活变幻开发策略,以最优的路径做出符合客户需求的软件。
【作者简介:袁永福,微软MVP,资深软件开发专家,著书立作,就职于南京都昌信息科技有限公司(http://www.dcwriter.cn),现从事于电子病历编辑器、时间轴等医疗用软件组件的研发工作。博客网址http://www.cnblogs.com/xdesigner。】