免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: 77h2_eleven
打印 上一主题 下一主题

[函数] 大家在项目代码中会大量使用断言么?  关闭 [复制链接]

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
81 [报告]
发表于 2008-07-05 11:28 |只看该作者
晕,俺的话就那么难以理解吗?


1、错误必须正确分类
网线断掉、硬件不稳定等等都是正常情况设计师必须预先考虑到这些,设置合理的处理/恢复逻辑。
    代码中的逻辑错误与以上相同,在总体设计层面上也是正常情况,没有为这些东西准备措施的就是面条设计师。

2、不同错误不同对待
    正常情况式的异常将纳入系统异常流程逻辑错误必须立即让它爆发,然后在影响范围之外纳入系统异常流程


举例来说:
     strcpy得到一个空指针,这就是典型的逻辑错误
     对有经验的设计者来说,这意味着如下几种可能:
            1、调用者的上级模块有问题,且调用者本身没有严格检查参数
            2、调用者本身逻辑有问题,比如使用了未初始化的内存或野指针
            3、之前的流程出现了严重故障,内存写越界导致程序跑飞

     如果相关代码继续运行,必然招致如下后果(全部或其中之一):
            1、错误被稀里糊涂的丢弃,业务流向稀里糊涂,最终导致用户数据莫名其妙地消失
            2、后续逻辑继续引用未初始化的内存或野指针,捣毁栈结构甚至导致程序跑飞
            3、跑飞的代码……谁知道它会做什么……这种故障没有任何人能准确界定原因(某责任人满头大汗地“偶发,偶发……”)。

所以,对这种情况的处理不能简单返回一个arg_error了事,而是必须想办法隔离相关模块,在更高的、不受影响的层次上恢复运行。


3、在错误精确分类的基础上再考虑如何恢复
看在下曾用过的这个设计:

WARNING:    程序设计有错,但只影响当前函数的此次调用,可当作失败处理;但必须写调试日志以跟踪错误。
MINOR_ERROR:程序设计错误影响到了整个子模块,此模块应停止一切活动,把这个错误直传上去,让上级模块撤销此次操作。
MAJOR_ERROR:程序设计错误影响到了中间控制模块,此模块应停止一切活动把错误直传上去,让框架撤销操作
CRITICAL_ERROR: 程序设计错误影响到了负责总控的框架,整个框架不应再作任何操作,应结束程序并重新启动服务。
FINAL_FAULT:发生了无法恢复的重大故障,应结束程序且不得重新启动(或重启动后禁止写任何数据以免造成数据无法恢复),等待专业人员修复(这个级别从未被用到过)。

各位觉得这个设计怎样?
如果strcpy空指针问题撞上这个系统,显然不会崩溃,而是在经验老道的程序员手下准确界定范围不触动可能导致无法预料的总爆发的任何东西直线返回,然后在可能恢复错误最低层次重试

如果你们也有这种系统,返回错误码俺没意见;可惜在下看不出各位有使用过类似系统的任何迹象。

在下说过,这是对异常系统的一种模拟。如果你们不打算或不能用异常,只要有这个,效果和异常相差无几
也许有些朋友是在这种系统下工作,那么返回错误无可厚非;但你要站出来说“我们不用assert,我们不用异常”——不客气的说:你们那位可怜的设计师的脸面被你们给丢尽了;同时希望你们回去好好看看设计,不要误导初学者。

在下以前也在华为做过。当时我们的系统也使用了异常,但同时还定义了类似的异常级别系统,如 WARNING MINOR_ERROR 等等。
这样,上层模块接到下层抛出的异常,就可以大致估计影响范围,然后决定在何种层次上恢复正常。
我们同样大量使用assert;但assert被我们定义为 CRITICAL_ERROR,并且会保留在发行代码中。


4、试图恢复无法预知的错误必将导致错误扩散甚至更为严重的伤害;
   并且这种错误几乎无法界定原因

所以,在下更早的项目组宁可放弃原有的错误分类系统,也要迁就新手,让他们把逻辑错误当逻辑错误处理。

换句话说,正规软件开发是要估计代码稳定程度的。
隐藏错误的系统将导致测试经理评估出一个虚假的bug级别;像strcpy空指针伴生野指针之类的bug绝不会无缘无故消失,总有一天它会爆发出来——当然,此时您很可能已经不在公司了,没有人会知道这是您干的。
相反,把所有逻辑错误暴露出来,测试经理给出的bug级别才是准确的。

假设一个未知bug最终导致crash的几率是5%,那么:
不暴露错误的系统里,评估内部约有20个bug;实际是内部还有 200 个bug被隐藏;这220个bug至少有11个会导致crash且无法追踪。
暴露错误的系统里,评估内部约有20个bug,实际就是20个bug;这20个bug则只有1个会导致crash——由于没有隐藏错误,这一个crash会很快被捕获并修正。

于是,半年试运行后,不暴露错误的系统可能会crash 11次,修修补补后修复了8个,同时又引入3个可能导致crash的bug;
暴露错误的系统crash 1次,修正后永远不会crash。


看看Linux、orache他们是怎么做的;他们有没有重写c/c++库,去掉库中的assert(至少,release版的标准strcpy是不检查传入参数的)。



5、请注意讨论范围,不要任意发散

在下已经批评过某“坏人 ”把硬件不稳定这种八杆子打不着的问题扯进来了;有些朋友也不想想,既然我们连错误级别系统都搞出来了,系统可能没有日志吗?如此详细的错误级别,日志可能不细致、准确吗?这种精确错误级别界定机制下,我们的恢复机制粒度会不细吗?

日志不是糊涂账,不是火锅,不能什么都往里写——否则,这本糊涂账就不会有人去认真分析。


日志分很多种,比如访问日志、业务日志、调试日志等等,请注意它们的严格分类以及作用。


正式发布的正规系统都不会写调试日志,除非明确打开——比如Linux、Windows、oracle、ms sql server等等。

为什么?

原因就是: 调试日志中,低级别(TRACE)的记录相当于单步跟踪,这是为整体联调服务代码的无奈之举;高级别(WARNING及以上)记录则用于跟踪逻辑错误。

一个稳定的系统,肯定是不允许逻辑错误存在的。
测试一定要做到可以保证逻辑错误几乎不发生时才敢往出发代码——否则,谁知道会爆出什么炸弹。


为何c/c++标准库有大量 用assert、不检查strcpy参数指针等等“恶心” 行为?同样用着这些东西,为何别人就能写出真正稳定的代码?

原因很简单: 这种低级逻辑错误是必须在测试期处理掉的;assert就相当于调试日志,而且还是只写高危级错误的那种日志。


如果有些公司的测试连这种高危漏洞都不能排除——各位读者,你们觉得在下称它为“走过场”是否夸张?



为何Linux、Windows、oracle、ms sql server以及许许多多的公司敢用assert?
原因很简单——能被assert检查出来的都属于 第一梯队 bug,这类bug测不出来是近乎不可思议的事。

然后,assert查不出来的(如野指针等)才是 第二梯队 bug;这类bug除了良好设计的catch,谁都无能为力。

以上两类都属于 极端严重级别 的bug,它们是单元测试和第一阶段测试的针对目标。

然后,测试第二阶段开始,此阶段测的,才是业务逻辑是否正常、运算结果是否正确等“软”故障。



strcpy空参变arg_error式的行为,说白了就是把第一梯队的严重bug变成第二梯队的偶发故障和第三梯队的“软”故障。

这样一来,测试初期阶段就会形势一片大好,几乎没有几个会crash的bug——但是,一旦crash,就是那句话“有个逻辑错误,偶尔的发生, 影响到了3-5格模块的内容, 其他的逻辑错误都是返回错误。但是没有的异常错误, 最后在strcpy 里面爆发了。你想定位就慢慢花时间吧。”

好不容易把这种漏洞糊上,离deadline已经不远了;于是关于“软”故障的测试匆匆而过——该交货了。

长此以往,他们怎么不可能患上崩溃恐惧症?



——比较一下:
——这是在下曾呆过的一家小公司为某部/局级要害部门做的设备故障检测、处理及验证系统(人命关天的东西:如果我们有计算错误,导致设备状况恶化查不出来,一次死上万人都有可能)
——测试开始还不到一星期,测试组就已经发怒了:怎么到这时候了还有英文(指的是因assert爆出的错误对话框)?
——原因是:不到三天的密集爆发后,这个系统已经再也发现不了assert错了;所以他们已经进入追查“软”故障的流程,对再次遇到assert毫无心理准备!
——那个assert,是他们在持续4、5个月的测试中发现的最后3次“英文”之一。
——请注意,我们是遇到任何含糊之处全部抛异常或assert的。
——当然,我们当时用的不是c/c++,不需要处理指针。
(不过,虽然在下后来做的c/c++项目都没有经过如此严格的测试,但几乎每次都是前2、3次单元测试之后,内部就再也不会有任何种类的崩溃——于是后面的测试,在下就可以把精力集中在参数传递上了)

好吧,即使某些大佬们的系统不需要这样的安全性,得不到长达4、5个月的测试时间——1周不到的测试,仅余2个可能导致崩溃的bug: 诸位凭良心说下,你们做得到吗?

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
82 [报告]
发表于 2008-07-05 12:02 |只看该作者
说白了很简单:

我先前呆过的几家公司都是从一开始就没打算放过任何错误,不管大小。

这种心态下,你可以assert,程序可以崩溃,损失再大也得扛——自然,责任人当然也不可能逍遥法外。

同样,测试部门也必须担责任。


正规公司里,测试可不是伺候程序员大爷的苦工。

本质上说,程序员是公司任务的承包商;测试则是代表公司的采购部验货人。双方几乎是领导与被领导的关系——测试即使不是领导,也绝对不可能是面条公司的苦工


这里面就有个责任界定问题,即: 出了大事故谁来负责?

华为这种公司,一台9系列光交换机崩溃,一个小国的网络就彻底崩溃。
这责任,谁扛得起?


很简单,3级责任:
1、如果一个可以预料的故障,设计师居然预料不到,没有设计异常流程,他的饭碗甚至人身自由恐怕就很成问题了。
   对设计师来说,把不稳定的设备玩稳定是基本功。做不到,请另谋高就。

2、一个本该立刻暴露的故障,程序员稀里糊涂把它“容错”掉了,瞒得过测试,瞒得过数亿用户?
   一旦追究起来,此人饭碗难保;部门经理也要掉一级工资了。

3、作为测试,出现明显的漏测导致线上系统崩溃,不该自己反省下吗?下次卡紧点,不然你们经理又要掉一级工资了。



所以,某些公司里,如果程序员代码太垃圾,测试甚至会刻意保留一些bug不报,仅指出bug数目;要求对方彻底检查,直到保留的bug被自测出来,他们才可以放心。


形成习惯后,由于通过测试的部分可认为绝对可靠,后续开发的效率是极其惊人的。

比如,在下为那个要命系统做的2期改造,40多个修改点一星期搞定,测试找不出任何bug。
之后,客户单位根据自身情况提的任何需求,向来是上午的需求更改提交过来,下午就能出补丁包,半年未出现过bug。
以至于自在下03年底离职至今,竟没有人能接手这个项目——客户不信任,评价永远是“不如老系统”,压力太大。


总结:
    容错必须精确、理性。不然越容错越多。
    调试日志必须是空的。里面出现的任何WARNING及以上级别的信息都意味着逻辑错误,意味着不可挽回的损失。
    任何逻辑错误都不可容忍。它们总有爆的一天——不管你用什么方式美化它、容纳它。
    不要为自己准备太多退路。严格考察起来,这点小技俩瞒不过任何人。

只有你不给自己留退路,你才会真正关心代码质量,才能写出真正无措的代码——同样用着c/c++标准库,Linux、Windows、oracle他们为何就不担心崩溃?

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
83 [报告]
发表于 2008-07-05 12:07 |只看该作者
总之一句话,我再说一遍: 入鲍鱼之肆,久而不知其臭。

激流勇上与苟且偷安,这是两种心态的根本区别。

论坛徽章:
0
84 [报告]
发表于 2008-07-05 15:11 |只看该作者
原帖由 77h2_eleven 于 2008-7-5 10:55 发表

用不着这么麻烦。assert本身在宏定义处就做了你这个工作。
看一下assert.h就知道了。
编译时加-DNDEBUG就会不用断言的。

谢谢指点. 以前确实不知道可以通过这个方法禁止它, 以后可就方便多了,不知道是否所有操作系统和编译器下都知道-DNDEBUG呢?
不过, 大家也就别争了, 从这一点来看, 它出现的原意,是为了调试. 发行版嘛, 还是要追求稳定运行.

论坛徽章:
0
85 [报告]
发表于 2008-07-05 21:46 |只看该作者
原帖由 zszyj 于 2008-7-5 15:11 发表

谢谢指点. 以前确实不知道可以通过这个方法禁止它, 以后可就方便多了,不知道是否所有操作系统和编译器下都知道-DNDEBUG呢?
不过, 大家也就别争了, 从这一点来看, 它出现的原意,是为了调试. 发行版嘛, 还是要 ...


  
#ifdef DEBUG
   assert(....)
#endif

-DNDEBUG
并不矛盾.  比如可以扩展为:
#ifdef DEBUG
   .........//你自己的其它处理
   assert(....)
#endif

论坛徽章:
0
86 [报告]
发表于 2008-07-06 09:46 |只看该作者
一个稳定的系统,肯定是不允许逻辑错误存在的。
测试一定要做到可以保证逻辑错误几乎不发生时才敢往出发代码——否则,谁知道会爆出什么炸弹。

你给我找一个没有逻辑错误的程序出来。  没有逻辑错误那么程序的错误是什么错误?


任何逻辑错误都不可容忍。它们总有爆的一天——不管你用什么方式美化它、容纳它。
    不要为自己准备太多退路。严格考察起来,这点小技俩瞒不过任何人。

只有你不给自己留退路,你才会真正关心代码质量,才能写出真正无措的代码——同样用着c/c++标准库,Linux、Windows、oracle他们为何就不担心崩溃

linux windows oracle 都会崩溃,
如果他们都没有逻辑错误 补丁是哪里来的? 你知道它们内部有多少没有被发现的逻辑错误?  
测试一个函数的逻辑是否正常, 说实话,我还没找到这样的工具。
你如何证明 你本身的整体逻辑设计是没有问题的?

windows 有那么多个bug, 是否每个bug 它都会让我们崩溃一次呢?
linux 也不少, 是否每个bug 它都会让我们崩溃一次呢?

我们是否该不停的看到windows 崩溃,然后停止工作 让m$ 来修改这么代码呢?

所以,某些公司里,如果程序员代码太垃圾,测试甚至会刻意保留一些bug不报,仅指出bug数目;要求对方彻底检查,直到保留的bug被自测出来,他们才可以放心。


形成习惯后,由于通过测试的部分可认为绝对可靠,后续开发的效率是极其惊人的。

测试已经测出所有的bug了?  不会再有bug出现了??


其实 你只说明了一点,加强单元测试, 强壮的模块,便于以后的开发。  但是这和主题无关。

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
87 [报告]
发表于 2008-07-06 16:27 |只看该作者
吃饭肯定是会噎住的。你给我找个吃饭永远噎不住人出来。

如果找不出来,那么大家都应该拒绝吃饭。


走路是会摔倒的。所以古猿本来就不应该站起来。


车祸永远是避免不了的。所以我们要把桥都拆了,路都挖了。


蔬菜洗得再干净,人体内的细菌也还有数公斤之多。所以对楼上来说,洗菜和吃大便没什么两样。


不过,吃大便是您的选择;到处宣传的话,还是很让人反感的。

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
88 [报告]
发表于 2008-07-06 16:31 |只看该作者
是的。逻辑错误难以避免,软件bug层出不穷,没有人能保证它永不出现。

但是,如果有办法可以辅助捕捉到——甚至于,如果有确凿的迹象(比如strcpy得到了空指针)可以证实——逻辑错误的存在,我们是不是应该抓住这个机会把菜洗一洗?

不知阁下是装傻呢,还是吃那个什么已经吃习惯了?

[ 本帖最后由 shan_ghost 于 2008-7-6 16:36 编辑 ]

论坛徽章:
0
89 [报告]
发表于 2008-07-06 21:11 |只看该作者
你脑子里已经被大便都塞满了。 我努力想帮你疏通, 看来是没机会了。

论坛徽章:
0
90 [报告]
发表于 2008-07-06 23:38 |只看该作者

回复 #1 77h2_eleven 的帖子

有点看不懂
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP