程序设计中的可维护性

    一个软件产品在release后就会安装到客户的计算机上去运行,在开发过程中出现程序错误我们可以在自己的电脑中利用丰富的工具定位问题,但是一旦程序到了客户的环境,当运行出现问题时,则不是开发组说想怎么调试就怎么调试了,可能因为生产环境管理制度,也可能是系统内已经存在保密信息,在客户的机器上装个调试器、诊断工具什么的一般是不太可行的,这个时候如果事前缺乏相关设计,则可能陷入一摸黑的境况,没有相关环境信息,无法定位故障原因,就引起客户不满。因此,每个程序在事前都应该有充分的可维护性设计,包括日志、转储以及获取相关信息的既定计划。

界面提示

    对于有人操作的程序,在出现错误时最好直接在界面上打印出错误信息,包括引起错误的原因和恢复方法,注意一定要显示对应错误的恢复方法,比如用户的某个操作不要求,则除了要告诉用户这样操作是不对的以外,还要告诉用户怎样操作才行,否则用户就一头雾水,结果用户还是打电话给我们的技术支持,而这个可能只是一个很简单的小错误。
    像这样的提示就是不好的:“无法保存文件”,我知道你保存不了问题,可是怎样才能让保存?
像这样的提示就是好的:”保存文件失败,请检查是否在该位置已经存在一个只读文件”,这样用户可能自己就能修复问题。
    千万不要小看界面直接出现的错误提示,另一个界面直接提示的好处是你可以在用户求助的时候直接在电话里询问用户,在出错时界面上显示什么错误信息,虽然有时用户可能不理解错误提示信息,可是你理解,这样就可以省去了现场支持的奔波了。

日志

    程序的运行日志应该是对定位问题最灵活的方法。日志还可以分为系统日志和应用日志,系统日志就是windows里的事件查看器里面看到的那些信息,他通常是一些系统级别的事件,比如身份验证失败、系统组件异常等,程序可以通过API往这里记录信息,但是这个日志是整个系统共用的,不是很方便自动获取,而且因为跟其他程序混杂在一起也不是很方便定位问题,所以应用程序的日志还是建议自己写自己的日志文件。
    应用日志是存在磁盘上的(当然你也可以直接通过网络发回日志中心),你可以自由在日志里打印各种信息,基本上不用考虑屏幕宽度限制、语言习惯等限制,我曾经跟我们的技术支持讨论日志里面该用什么语言,得到的意见是‘随便,只要你告诉我怎样定位错误,我不管你用符号标记还是暗号’。
一般来说你可以在程序启动和退出时打一行日志做标记,这行日志可以在确定用户在充气软件后是否错误依旧,因为有时出错时把程序重启一下就好了,如果你打印了程序启动和退出,那么日志可以帮助你确定错误是否跟持久状态有关。像下面这样

* * * * * XXX Application started * * * * * *
...log something
----------xxx application quit----------

    另外日志应该记录程序运行的逻辑处理路线,可以在各个逻辑分子打印分支选择结果。也可以在一些重要业务过程中的里程碑点打印一些信息,比如记录一下某一个业务环节已经完成的信息,则如果在这行日志后面出现了一条异常信息,则可以确定错误发生在刚才那行记录业务环节完成的日志之后的那些代码里,这可以提高定位问题的效率。像下面这样就可以通过日志确定是因为step 3里面建立进程时没找到可执行文件
start doing something...
step 1 ok
step 2 ok
error: failed to create process...error code: 2 error msg: file not found
do something failed...

    日志记录应该考虑一下磁盘空间的问题,要是不断向同一个日志文件追加信息可能会产生巨大的日志,一是可能把磁盘塞满,二是客户不好通过网络把日志发给你分析,三是即使日志发回来了,你自己也不好操作这么庞大的文件。所以日志是寻要循环流转的写的,对于C程序推荐使用log4c模块,C++程序推荐使用log4cplus模块(log4cpp和log4cplus是2个不同的日志模块),JAVA推荐log4j,这些日志模块都可以做到循环日志。

Unhandled Exception

    Unhandled Exception概念是跟windows的结构化异常处理机制(SEH,就是由VC编译器支持的 __try … __catch 语法)结合在一起的,并且跟windows内核的异常处理机制有关,所以这个方法只适用于windows系统的程序。
    直观上看Unhandled Exception就是在程序里出现异常但却没有对应的异常处理函数时转入的处理过程,他作为程序运行的最后一根稻草出现,如果你没有设置这个unhandled exception的处理函数则进程会崩溃,弹出那著名的dr.watson对话框,就是那个程序崩溃问你是否发送错误报告的对话框。
    可以在程序里用 SetUnhandledExceptionFilter函数设置未处理异常的处理函数,这样当程序里出现未知的异常时,你设置的函数就会被调用,给你最后一个挽救进程的机会。挽救进程只是理论上有这个可能,实际上在这个最后的函数里最好不要做太复杂的操作,因为既然是未处理异常,那一定是出现了你没预料到的情况,这个时候很可能程序已经跑飞了,各个变量的值是否还正确都不知道,所以,我认为在这个地方不应该尝试去挽救进程,而应该记录一些进程的状态,比如当前时间、用户信息、系统环境信息、用户正在进行的操作、关键变量的值等,把这些信息写入磁盘,以便后来分析问题的根本原因,可能的话你可以询问用户是否自动重启进程并发送现场报告,QQ就是这么做的,当QQ崩溃的时候会弹出一个框问你是否发送报告给腾讯,和是否自动重启QQ,这个过程肯定是在SetUnhandledExceptionFilter设置的最终函数里进行的。
    Unhandled exception和 把整个main函数用 try...catch包围起来有什么不同?区别有几点,一是try...catch是线程级别的,你没法跨线程catch异常,所以需要在每个线程里面都把入口函数用try...catch包围起来才能扑获所有异常,而unhandled exception是进程级别的,程序里任何一个地方的异常没有处理都会转到入这里;二是在MFC这类框架下的程序main函数已经被隐藏了,可能在CWinApp::InitInstance前已经出现异常,这时是没法catch的。
    设置unhandled exception的处理函数并在最后关头保留现场信息,在事后根据这些信息分析问题的根本原因可以帮助你逐渐改善软件的质量。但有一个细节要留意一下,就是不要收集私有信息,可不要在收集现场信息时把用户C:/Documents and settings下面的文件打包也收集上来了,我曾经遇到一个软件保留现场信息时把我的屏幕截屏了,我觉得这个也是很不适当的,这个可以参考一下dr.watson的做法,他是主动让用户知道收集了哪些信息,并有一个隐私保护条款,这个在国际化的软件中老外看得比较重。

Core dump转储文件

    转储文件就是在程序运行过程中出现异常时保存的进程映像快照,根据这个快照再结合程序符号可以还原当时进程的运行状态,如果用户愿意把这个转储文件发给你,基本上就跟在本地调试当时在用户那里运行的进程一样了。
    在windows下还是 dr.watson,在默认情况下程序崩溃时dr.watson会弹出崩溃的对话框,并且产生一个转储文件在特定位置,这个转储文件只包含少量信息,不过用来调试也足够了,如果想让dr.watson帮助保留更多现场环境的信息,可以在开始-运行里面输入drwtsn32运行,这是dr.watson的设置程序,可以用来设置dr.watson的行为,包括转储文件中包含哪些信息和转储文件的存放路径,这样当用户跟你说程序崩溃时,就可以让用户到XXX目录下把转储文件发回来分析了。
    可是dr.watson是用户机器上的程序,很难要求每个用户都去设置一下dr.watson以便产生转储文件供我们分析,很幸运Windows提供API让你自己在程序里产生转储文件,用 MiniDumpWriteDump函数可以在程序里自行产生转储文件,最佳的操作时机就是在上文提到的unhandled exception处理函数里面。
    用转储文件进行现场还原时需要对应现场程序的符号文件,符号文件记录了源代码跟转储文件信息的对应关系,这样才能通过转储文件的调用栈对应到源代码的行和函数名,否则转储文件里面仅仅包含线程程序调用栈的内存地址。符号文件就是VC编译时产生的pdb文件。在每个版本程序发布时都应该保存下来。
Unix下也有转储文件,但是没有 API可以自行在程序里产生,只能通过ulimit -c把转储功能打开,打开这个开关后如果发生程序崩溃会在程序所在目录下产生一个叫core的文件就是转储文件。另外gcc默认将符号信息附加在输出的可执行文件里面了,而习惯上release版本我们不会开-g参数,也就是不会产生调试符号,甚至会用strip把符号去掉,还会设置-O2以上的优化级别,优化后符号跟程序转储文件可能对不上。。。

容灾计划

    以上讨论的都是技术上的处理措施,在设计的时候最好也考虑一下非技术性的容灾问题,比如一个功能失效了,用户阻塞在这里无法继续工作,而一时间也无法定位到程序到底哪里出现了问题,如果在出现这种问题的时候再考虑应对方法就会手忙脚乱,所以在程序设计的时候就应该留下一条后路,万一程序小范围失效,个别用户怎样处理,大范围失效,大量用户又怎样处理,这就是容灾计划。比如个别防火墙认证程序失效了,是否有办法让这些用户暂时绕过防火墙继续工作,等问题定位后再启用防火墙认证。

 


以上是这些年软件开发中对可程序可维护性的一些经验,希望对大家有帮助。

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值