什么情况下使用断言?

最近写代码时考虑的一个问题,从来没有问过大牛,或看过大牛的书,来理清心里的这个疑惑。今天google了下,留个记号方便自己以后复习,为防止Internet链接失效,把看过的内容抄到下面。。

 

http://book.51cto.com/art/201002/182682.htm

 

某一段代码需要对程序状态做出某种假设。

以断言明确表现这种假设。

 

动机

常常会有这样一段代码:只有当某个条件为真时,该段代码才能正常运行。例如平方根计算只对正值才能进行,又例如某个对象可能假设其字段至少有一个不等于null。

这样的假设通常并没有在代码中明确表现出来,你必须阅读整个算法才能看出。有时程序员会以注释写出这样的假设。而我要介绍的是一种更好的技术:使用断言明确标明这些假设。

断言是一个条件表达式,应该总是为真。如果它失败,表示程序员犯了错误。因此断言的失败应该导致一个非受控异常(unchecked exception)。断言绝对不能被系统的其他部分使用。实际上,程序最后的成品往往将断言统统删除。因此,标记"某些东西是个断言"是很重要的。

断言可以作为交流与调试的辅助。在交流的角度上,断言可以帮助程序阅读者理解代码所做的假设;在调试的角度上,断言可以在距离bug最近的地方抓住它们。当我编写自我测试代码的时候发现,断言在调试方面的帮助变得不那么重要了,但我仍然非常看重它们在交流方面的价值。

做法

如果程序员不犯错,断言就应该不会对系统运行造成任何影响,所以加入断言永远不会影响程序的行为。

如果你发现代码假设某个条件始终为真,就加入一个断言明确说明这种情况。

你可以新建一个Assert类,用于处理各种情况下的断言。

注意,不要滥用断言。请不要使用它来检查"你认为应该为真"的条件,请只使用它来检查"一定必须为真"的条件。滥用断言可能会造成难以维护的重复逻 辑。在一段逻辑中加入断言是有好处的,因为它迫使你重新考虑这段代码的约束条件。如果不满足这些约束条件,程序也可以正常运行,断言就不会带给你任何帮 助,只会把代码变得混乱,并且有可能妨碍以后的修改。

你应该常常问自己:如果断言所指示的约束条件不能满足,代码是否仍能正常运行?如果可以,就把断言拿掉。

另外,还需要注意断言中的重复代码。它们和其他任何地方的重复代码一样不好闻。你可以大胆使用Extract Method (110)去掉那些重复代码。

范例

下面是一个简单例子:开支限制。后勤部门的员工每个月有固定的开支限额;业务部门的员工则按照项目的开支限额来控制自己的开支。一个员工可能没有开 支额度可用,也可能没有参与项目,但两者总要有一个(否则就没有经费可用了)。在开支限额相关程序中,上述假设总是成立的,因此:

 

这段代码包含了一个明显假设:任何员工要么参与某个项目,要么有个人开支限额。我们可以使用断言在代码中更明确地指出这一点:

 

这条断言不会改变程序的任何行为。另一方面,如果断言中的条件不为真,我就会收到一个运行期异常:也许是在withinLimit()函数中抛出一 个空指针异常,也许是在Assert.isTrue()函数中抛出一个运行期异常。有时断言可以帮助程序员找到bug,因为它离出错地点很近。但是,更多 时候,断言的价值在于:帮助程序员理解代码正确运行的必要条件。

我常对断言中的条件表达式使用Extract Method (110),也许是为了将若干地方的重复码提炼到同一个函数中,也许只是为了更清楚说明条件表达式的用途。

在Java中使用断言有点麻烦:没有一种简单机制可以协助我们插入这东西 。断言可被轻松拿掉,所以它们不可能影响最终成品的性能。编写一个辅助类(例如Assert类)当然有所帮助,可惜的是断言参数中的任何表达式不论什么情 况都一定会被执行一遍。阻止它的唯一办法就是使用类似下面的手法:

 

如果Assert.ON是个常量,编译器就会对它进行检查;如果它等于false,就不再执行条件表达式后半段代码。但是,加上这条语句实在有点丑 陋,所以很多程序员宁可仅仅使用Assert.isTrue()函数,然后在项目结束前以过滤程序滤掉使用断言的每一行代码(可以使用Perl之类的语言 来编写这样的过滤程序)。

Assert类应该有多个函数,函数名称应该帮助程序员理解其功用。除了isTrue()之外,你还可以为它加上equals()和shouldNeverReachHere()等函数。

 

如果Assert.ON是个常量,编译器就会对它进行检查;如果它等于false,就不再执行条件表达式后半段代码。但是,加上这条语句实在有点丑 陋,所以很多程序员宁可仅仅使用Assert.isTrue()函数,然后在项目结束前以过滤程序滤掉使用断言的每一行代码(可以使用Perl之类的语言 来编写这样的过滤程序)。

Assert类应该有多个函数,函数名称应该帮助程序员理解其功用。除了isTrue()之外,你还可以为它加上equals()和shouldNeverReachHere()等函数。

 

 

 

http://sunxiunan.com/?p=1638

什么时候该用ASSERT?

—————————————————-
Michael to pongba

有下面2种方法:

方法一:Section *pImageSection = new Section(pImage);

assert(pImageSection);

方法二:略

ps:现在项目组代码用第一方法,并且也不写日志,每一次客户端down了,定位问题都要很久,让人很崩溃。并且到处都是assert。

我个人认为,用assert的地方,是比较严重的错误,甚至不能够让程序再运行下去。

如果到处用asset也太残忍了,有的时候应该温柔的跳过,然后写日志,返回。告诉我哪里运行失败了。

—————————————————-

下面是我对这个问题的回答:

首先需要指出一个非常重要、讨论前必须明确的问题,assert一般不应该直接用,而应该包装一下,比如微软就有ASSERT宏,可以跟踪line file这些有用信息,另外可以通过条件编译取消ASSERT。每次定位很久,只能说这种编程common sense还没有建立起来。

原文虽然说得很简单,其实涉及了几个方面,一个是版本管理发布,一个是错误处理机制,一个是如何写日志,我们一个个讨论。

首先是什么情况下用ASSERT,什么情况下应该处理wrong case?

一个成熟的代码里面,大概有百分之三十到七十的代码都是为了查错,fault tolerance。比如你写一个API或者对外使用的函数,别人要调用,你要确保传入的指针不为空,传入的参数合法,这时候都不应该,注意是不应该使用 ASSERT,因为这些情况out of your control。

什么情况可以使用ASSERT,应该是那些绝少发生的例子,而且你可以控制的那些代码段落,比如Object* p = new Object,返回空指针,这种情况下多半是内存申请出错,即使你容错了,后面的逻辑也不会正常,这时候就应该停止运行报错了。还有就是你的内部函数(注 意是你程序的内部哦),因为内部函数的代码责任其实是你自己的,你传错参数只能说水平太差怨不得别人。也许有人会说,同组里别的程序员万一也调用了这个函 数怎么办?这种情况当然是会有的,其实也没法避免,但可以用ASSERT以及Code review这些手段来规范,同一个程序组里面的问题属于内部矛盾好解决多了。

所以,大的原则可以是这样:内部函数尽量简化容错机制,稍微苛刻一些,而对外接口则尽量容忍,出错处理也要温柔。

第二个问题,ASSERT该怎么写?

我已经提到,不要直接使用assert,最好包装一下,加入#ifdef _DEBUG这种条件编译选项,保证Release版本不弹出ASSERT。这里其实也涉及到版本管理问题,一个商业产品发布一般包含两个版本 (Release版以及Debug checked版本),即使是Windows操作系统也是如此。在Release版本要Disasble assert,这时候如果出错可以用后面的Crash Dump机制捕捉跟踪,而且要说明的是Release版本一样要附带PDB文件(或者Linux同类文件),保证Crash Dump可以定位。Debug版本也要发给用户,用户可以通过它返回更详细信息。每个Build出来的Release、Debug都应该妥善备份,将来客 户提交Bug,对应版本以及PDB,就可以准确定位,不会出现很难差错的现象。

另外也可以加入日志log选项。在这里跑一下题,日志记录也是个大问题,要考虑多线程以及性能问题,其实不是加入日志系统就万事大吉了,说句难听 的,对于那些2B Number One的人来讲,任何一个好东西都可能被他们用到烂。一般ASSERT跑出来,对于客户来说就等同于Crash了,所以可以参考一下Google的 Crash Report开源项目,比如Windows下可使用Crash Dump机制来捕捉崩溃时调用栈,这样即使Fail Soon Fail Fast也不会很难看。这些手段都是common sense的东西,一个正常的软件开发公司应该积累下这些代码财富才对。

相关文章

1. 如何去重 #!/usr/bin/perl use strict; my %hash; while(...
最近写了一个perl脚本,实现的功能是将表格中其中两列的数据...
表的数据字典格式如下:如果手动写MySQL建表语句,确认麻烦,...
巡检类工作经常会出具日报,最近在原有日报的基础上又新增了...
在实际生产环境中,常常需要从后台日志中截取报文,报文的形...
最近写的一个perl程序,通过关键词匹配统计其出现的频率,让...