免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
0
51 [报告]
发表于 2008-07-03 15:01 |只看该作者
原帖由 @sky 于 2008-7-1 11:20 发表
不用,断言错了程序也挂了,基本不用



基本上和你一样

论坛徽章:
0
52 [报告]
发表于 2008-07-03 15:47 |只看该作者
1.断言一般只存在debug版本中,向客户提交的是release版。
2.断言发生后可以保存内存环境进入调试可以查看各个变量。通过查看栈,查看函数调用过程。最快的发现错误。
断言是一种非常有效的调试手段,咋能不用哪。一万个不理解。

[ 本帖最后由 键盘老农 于 2008-7-3 15:49 编辑 ]

论坛徽章:
0
53 [报告]
发表于 2008-07-03 16:23 |只看该作者
你们弄撮了吧

现在争论的焦点 在于

assert(dest != NULL); /* 使用断言 */
assert(source != NULL);
     

还是
     if (dest != NULL && source != NULL) {

}


     if (dest != NULL && source != NULL) {

}
上面也可以加上断言。 加上了 在debug 环境下便于调试, 不加不影响运行过程
但是只用断言, 在客户环境是会发生崩溃。

我们现在讨论是的是 相信断言, 在客户段 直接来个崩溃,然后开发工程师迅速的定位模块好
还是将隐藏,将错误信息返回出去,让上层代码处理好。 后果是如果上层不处理,忽视错误,错误会不断扩大,流向所有模块。

论坛徽章:
0
54 [报告]
发表于 2008-07-03 17:32 |只看该作者
原帖由 键盘老农 于 2008-7-3 15:47 发表
1.断言一般只存在debug版本中,向客户提交的是release版。
2.断言发生后可以保存内存环境进入调试可以查看各个变量。通过查看栈,查看函数调用过程。最快的发现错误。
断言是一种非常有效的调试手段,咋能不用 ...


同意。

论坛徽章:
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
55 [报告]
发表于 2008-07-03 18:06 |只看该作者
原帖由 键盘老农 于 2008-7-3 15:47 发表
1.断言一般只存在debug版本中,向客户提交的是release版。
2.断言发生后可以保存内存环境进入调试可以查看各个变量。通过查看栈,查看函数调用过程。最快的发现错误。
断言是一种非常有效的调试手段,咋能不用 ...


因为工作环境不同。


一般来说,为国企(如电信、移动等巨头们)工作的都这样——我称之为“日志依赖症”和“崩溃恐惧症”。

进去做过就知道,他们是不会关心诸如“用户体验”之类垃圾的;关键是保证程序不能爆。

那么遇到意想不到的情况怎么办呢?
写条日志,返回个错误,继续。

如果程序在你这里爆了,那么黑锅就是你的。如果你敢说不是,那么既然爆在你手里,该由谁负责找责任人呢?不会是你们经理吧。

然后,顶着巨大的压力,在泥潭中挣扎N天,看着1分钟几兆的垃圾日志,挑一个人狠狠得罪一次——当然,大部分情况下,这个黑锅最终还是要你来背,因为根本就不可能找出bug源头在哪里。


在下就曾在这种地方做过快一年。幸亏鄙人手头还算硬,代码没出过bug;但正因如此,把别人的bug揭出不少,得罪了不少人。

后来就学乖了。
什么狗屁总体设计,什么叫逻辑,这些“高端”问题不是需要动手编码的“软件蓝领”应该知道的。他们返回错误,你开个分支也传回去就是;怕业务走不通,就把错误设成err_success——有错,但基本可以继续。

重中之重是:所有经手的一切都要留日志。这是推卸责任的法宝。

不管你怎么糊弄,只要能让业务流程走通就算本事。别自找不痛快。
正应了那句话: 不干不净,吃了没病。


甭担心所谓的代码质量。不core dump就是完成任务;也甭担心这种垃圾没法做单元测试——没人要你自讨苦吃。

你说怎么测试?
测试有苦工干。
他们是比写代码的蓝领更低一阶级的生物。
你写代码,他们熬夜证实你的代码可以完成功能,不会core dump。
测试通过的标志,就是整个流程可以走通。

你说什么?等价类?边界值?代码覆盖?
切,没人发神经测这个——也没有哪个神仙可以为根本没有定义的东西做这些测试。


就这样做了大概7、8个月,实在受不了了。
这些大佬有法律保障的垄断地位,怎么搞都不怕没饭吃;俺一介平民,俺怕下半辈子没饭吃。
不管合同了,也不要扣的一个月工资了,撤。


——————
其实,进去不到一个月就发现问题了。
俺还搞过几个文档,论述用日志调试的利弊——其中一条是:Windows/Linux/oracle够不够复杂?谁见过它们整天没事哗哗写调试日志?看看现在这个系统每时每刻都在流动的日志,你们能找到什么?

也给同事推过不少好东西。比如把他们原本不可测试的框架(尤其是日志服务;当然,没有任何实质内容)模拟出来,使得新编代码可以在vc下跑;然后强调至少要把每行代码都单步执行到,观察监控窗口的显示是否正确。
仅此一项改进,我们组的代码质量大幅度上升;大家也都清闲了好多(代码质量高了,基本不存在返工,自然就不用像别的组那样拼命加班了)。
给我们组做测试的“苦工”也很高兴,因为他们不用像以前一样,天天跑来求程序员大爷修改bug,流程就轻松走过去了。





只是,入鲍鱼之肆,久而不知其臭。
在下虽然不才,但之前做的都还是正经项目,是要拿到市场上和人竞争的。思路自然和这些人不一样。

结果就是感觉完全没法沟通。
比如,我写了个xml和c结构体间自动转换的东西(只要用一组宏声明对应关系,剩下的工作我全包),解决了程序内部表示和网络间传递的封包的转换问题——过去,这种代码是每个模块、每个功能都要重新写一遍的。
为了保证代码质量,我非常小心的处理了内部使用的众多指针,做了非常多的检查;知道assert会被他们的编译设置直接忽略,我为所有不合逻辑的地方安排了 x/0 语句(制造除0错;x标记了具体位置,对照源文件就能找到详细解释);这样一旦代码跑飞,就一定会导致core dump;然后根据core文件记录的栈结构就可以准确定位错误。

单元测试里,这些特意设置的炸弹炸了几个,帮我纠正了几个bug;然后,即使我刻意给它扔各种各样的垃圾——刻意写错格式的xml;拿普通文本冒充xml;读某个程序内部的二进制代码冒充xml;传入错误的、刻意把一些字段填写越界的结构体;甚至打开日志,随机读一段信息当参数往里乱扔,它都能准确报出错误而不崩溃。
之后,这个东西在很多地方重用,持续运行了半年,没有任何bug。

结果,某次走读代码,讲解这些设计时,可把俺的同事们给吓坏了:他们的头脑永远无法理解这些一碰就爆的炸弹怎么可能提高软件质量;尤其是俺们头,脸都吓白了。

俺就告诉他们:
第一,正是因为这些炸弹,我才能够确信这些代码已经没有任何bug了;
第二,请看vss记录,在不能确信代码无bug前,我在主入口捕获了所有异常的——当然,因为工程没有上线,这段代码是被屏蔽的。如果工程要上线,只要一个宏定义就可以捕获异常,绝对不会core dump。
第三,为何现在又把那些预防代码删掉了?原因很简单,我确信这段代码没有任何bug。除非你给我传野指针或者故意把一个类型不同的结构体强制类型转换后扔过来。

可想而知,这对那些人的观念是多大的一个挑战。最后,不得已,我恢复了总入口的try-catch对,捕获到任何异常都返回错误码才算完事。

在下当时就反问过他们: 我这个模块,大家都用过,刚才也看到了,逻辑非常清晰、简单,恐怕只有遇上野指针或强制类型转换的错误结构体指针才可能崩溃。一旦发现这类问题,我的代码可以在造成任何破坏前停下来,并且准确识别错误;现在加上这个try,代码是不会爆了;但返回的东西肯定说不清楚发生了什么。后面接手的模块很可能继续使用这些有问题的缓冲区。那么,数据写越界就不会导致程序崩溃吗?不在发现的第一现场处理,到后面垃圾越灌越多,错误如何定位?这时候再崩溃,该由谁负责?

本来,俺们头非常义正辞严地给我们宣传代码质量,讨伐俺的炸弹;听了俺的反问,他乐了:“甭管这个。别爆在咱们手里就行。当然,这个炸弹最后还是没传出去,炸到我们自己也很有可能。不过这个机会很小。我知道你是想保证代码质量,但不能把主动去背黑锅。”
然后,对着全体组员“大家注意了,发现xml解包、打包返回错误,注意检查相关指针!”



看吧,他们就是这样“提高”代码质量的

论坛徽章:
0
56 [报告]
发表于 2008-07-03 18:35 |只看该作者
原帖由 shan_ghost 于 2008-7-3 18:06 发表


因为工作环境不同。


一般来说,为国企(如电信、移动等巨头们)工作的都这样——我称之为“日志依赖症”和“崩溃恐惧症”。

进去做过就知道,他们是不会关心诸如“用户体验”之类垃圾的;关键是保证 ...


原来是有感而发啊,难怪那么长篇大论。

论坛徽章:
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
57 [报告]
发表于 2008-07-03 18:44 |只看该作者
原帖由 swordfish.cn 于 2008-7-3 18:35 发表


原来是有感而发啊,难怪那么长篇大论。


嘿嘿,没有深刻理解和切身体会,借俺个胆子俺也不敢在这么多高手面前瞎说啊~~

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
58 [报告]
发表于 2008-07-03 19:58 |只看该作者
因为怕问题出在自己所负责的模块,因此做一些恶心的设计的,我见的多了。
不过很多时候,也不能怪他们。

人与人之间的关系,决定了模块和模块之间的关系。
人与人之间是敌对的关系,程序和程序之间就是互相不信赖的关系,多做检查是没错的。
但是对于一个整体来说,任何冗余设计都是内耗,都是不必要的。
每个人心目中都有一个整体。有些人就是不想炸弹炸在自己的模块。

举一个前不久发生在我同事身上的例子,
他问我如何保证一个文件不被删掉?
我很奇怪,问他为什么会有这个需求。
原来是他写的日志文件,被别的部门的同事写的传送日志的脚本的 BUG 给 delete 掉了,
导致他们的日志丢失了。

这本来是写那个脚本的人的问题,可是他宁愿用一种恶心的方法去保证日志文件不被删掉。
在我明确表示因为不欣赏这种设计而不愿意帮助他们之后,他们据说采取了一种定期检查并缓冲的方法,
一旦发现日志文件被删(unlink)掉,那么就 fclose 它,然后重新创建一个同名文件,
并重写之前缓冲的所有内容。搞的跟病毒似的。

[ 本帖最后由 flw 于 2008-7-3 19:59 编辑 ]

论坛徽章:
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
59 [报告]
发表于 2008-07-03 20:20 |只看该作者

回复 #58 flw 的帖子

其实说白了就一句话: 心态问题。

错误拎不清,它肯定会爆在某个地方——不管用不用assert都是如此。

所不同者,就是看问题有没有踢皮球的余地,是否实实在在是要做个有用的东西出来。

可以踢皮球,错误就会被踢来踢去;错误可以容忍,崩溃绝不允许;
不能踢皮球,就会恨不得每个错误无论大小都会立刻爆炸,让你能立刻找到并改正它。

前者一个错误挂上十年八年,既然没有确切责任人,那么大家当然都不痛不痒的;后者挂一星期试试,看客户怎么说你,老板怎么问你。

当然,实际情况不会这么绝对;但必须小心不正常的环境对身处其中的我们所逐渐造成的侵蚀。

也许,一个在不踢皮球的环境中生活的人看来绝对不可容忍的问题,在来回踢皮球的环境里的人看来就是天经地义的。


但另一方面,环境虽然如此,但个人追求决定你的做法,也决定着你的理解。

就如同楼上用的“恶心”一词、以及同样环境下不同的人所采取不同措施一样。


在下反复提到这样一句话: 入鲍鱼之肆,久而不知其臭,用意就在提醒各位朋友:你的工作环境可能是污秽的,但你的心灵应该是干净的。

只是,很多朋友可能一出校门,投入的环境就很不正常,闻不出怪味道也就理所当然了。

[ 本帖最后由 shan_ghost 于 2008-7-3 20:40 编辑 ]

论坛徽章:
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
60 [报告]
发表于 2008-07-03 20:27 |只看该作者
贴几个小故事,摘自《write clear code》一书。
(此书中文名 编写无错代码,是微软一位高人所写,前些年非常流行)

不要让这种事情发生在你的身上
在1988年晚些时候,Microsoft公司的摇钱树DOS版Word被推迟了三个月,明显地影响了公司的销售。这件事情的重要原因,是整整六个月来开发小组成员一直认为他们随时都可以交出Word。
问题出在Word小组要用到的一个关键部分是由公司中另一个小组负责开发的。这个小组一直告诉Word小组他们的代码马上就可以完成,而且该小组的成员对此确信不疑。但他们没有意识到的是在他们的代码中充斥了错误。
这个小组的代码与Word代码之间一个明显的区别是Word代码从过去到现在一直都使用断言和调试代码,而他们的代码却几乎没有使用断言。因此,其程序员没有什么好的办法可以确定其代码中的实际错误情况,错误只能慢慢地暴露出来。如果他们在代码中使用了断言,这些错误本该在几个月之前就被检查出来。



不是用来检查错误的
当程序员刚开始使用断言时,有时会错误地利用断言去检查真正地错误,而不去检查非法的况。看看在下面的函数strdup中的两个断言:
char* strdup(char* str)
{
        char* strNew;
        ASSERT(str != NULL);
        strNew = (char*)malloc(strlen(str)+1);
        ASSERT(strNew != NULL);
        strcpy(strNew, str);
        return(strNew);
}
第一个断言的用法是正确的,因为它被用来检查在该程序正常工作时绝不应该发生的非法情况。第二个断言的用法相当不同,它所测试的是错误情况,是在其最终产品中肯定会出现并且必须对其进行处理的错误情况。




消除所做的隐式假定,或者利用断言检查其正确性
光承认编译程序还不够
最近,Microsoft的一些小组渐渐发现他们不得不对其代码进行重新的考察和整理,因为相当多的代码中充满了“+2”而不是“+sizeof(int)”、与0xFFFF而不是UINT_MAX进行无符号数的比较、在数据结构中使用的是int而不是真正想用的16位数据类型这一类问题。
你也许会认为这是因为这些程序员太懒散,但他们却不会同意这一看法。事实上,他们认为有很好的理由说明他们可以安全地使用“+2”这种形式,即相应的C编译程序是由Microsoft自己编写的。这一点给程序员造成了安全的假象,正如几年前一位程序员所说:“编译程序组从来没有做使我们所有程序垮掉的改变”。
但这位程序员错了。
为了在Intel 80386和更新的处理器上生成更快更小的程序,编译程序组改变了int的大小(以及其他一些方面)。虽然编译程序组并不想使公司内部的代码垮掉,但是保持在市场上的竞争地位显然更重要。毕竟,这是那些自己做了错误假定的Microsoft程序员的过错。




安静地处理
假如你受雇为核反应堆编写软件,就必须对堆芯过热这一情况进行处理。
某些程序员解决这个问题的方法可以是自动地向堆芯灌水、插入冷却棒或者是能使反应堆冷却下来的一些其他什么方法。而且,只要程序已经控制了势态就不必向有关人员发出警报。
另一些程序员可能会选择另一种方法,即只要堆芯过热就向反应堆工作人员发出警报。虽然相应的处理仍由计算机自动进行,不同的是操作员总是知道这件事。
如果由你来实现这一程序,你会选择哪一种方法?
我想关于这一点,大家基本上不会有太多的异议,即总是应该向操作人员发出警报,这与计算机能够恢复反应堆的正常操作是两回事。堆芯不会无缘无故地出现过热现象,一定是发生了某种不同寻常的事情,才会引起这一故障。因此在计算机进行相应处理的同时,最好使操作人员搞清楚发生了什么事情以避免事故的再次发生。
令人惊奇的是,程序员,尤其是有经验的程序员编的程序通常都是这样:当某些意料不到的事情发生时,程序只进行无声无息的安静处理,甚至有些程序员会有意识地使程序这样做。也许你自己用的是另一种方法。
当然,我现在谈的是所谓的防错性程序设计。





要利用不同的算法对程序的结果进行确认
还是让我们看看Microsoft Excel重新计算工具的做法吧。由于速度是电子表格软件成功的关键,所以为了保证绝不对其它无关单元中的公式重新计算,Excel使用了一个相当复杂的算法。这样做的唯一问题是因为该算法过于复杂,所以对其进行修改难免会引进新的错误。Excel的程序员当然不希望这种事情发生,所以他们又编写了一个只用在Excel调试版本的重新计算工具。当原来的重新计算工具完成了重新计算工作之后,再用这个重新计算工具对含有公式的所有单元进行一遍虽然缓慢但很彻底的重新计算。如果两次计算的结果不同,就会触发某个断言。
Microsoft Word也遇到过类似的问题。由于字处理程序在进行页面布局时速度也很关键,所以Word的程序员用汇编语言编写了这部分程序,以便能够对其进行人工优化。这样一来,虽然速度上去了,但在防止程序有错方面却变得很糟。而且同不常发生变化的Excel重计算工具不同,Word的页面布局程序需要随着Word新功能的增加而定期改变。因此为了能够自动地查出页面布局程序中的错误,Word程序员为每个可进行人工优化的汇编语言程序都相应地写了一个C程序,如果两个版本产生的结果不一致,就触发某个断言。



一个告诫
一旦开始使用断言,也许就会发现程序中的错误会显著增加。人们对此如果没有心理准备就会感到惊惶失措。
我曾经重写了一个由几个Microsoft小组共享的代码,它有许多的错误,因为在编写原来的代码库时没有使用断言,但我在新版库中加上了断言。使我吃惊的是,当我把新版代码交给这些小组使用之后,一个程序员竟很生气地要求我把原来的代码库还给他。
我问他为什么?
他说:“安装这个库后出现了许多错误。”
“你是说新库引起了错误?”,我感到震惊。
“好象是这样,我们遇到了许多过去没有的断言。”
“你们检查过这些断言吗?”,我问道。
“检查过,它们在我们的程序中是错误的。这么多的断言不可能全没错误,而且我们也没有时间去跟踪这些根本不属于我们的问题。我想要回原来的库。”
我当然不认为他们没有问题。所以我请求他继续使用新库,直到发现某个断言有错为止。他虽然心里不高兴,但还是答应了我的请求。结果,他发现所有的错误都出在他们自己的项目,而不是我的新库中。
正因为我事前没有告诉他们新库中已加上断言,所以这个程序员才会感到惊慌,因为没有人想出错。但如果我告诉大家出现了断言失败是件好事,也许这个程序员就不会那么惊慌了。然而,对错误感到惊慌的并不止程序员。因为公司是通过项目尚未完成功能的数目和项目中出现的明显错误数目来进行项目评估的,所以每当这些数字显著增加时,项目组中的每个人都会变得精神紧张。因此,要让别人知道你增加断言的打算。否则,就得为他们准备一些EXCEDRIN。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP