我该怎么搞他?虽然只有3行代码
和大家讨论一个函数设计的问题,在这方面我是一个门外汉,还希望大家多帮助
我解释一下,这里的代码我用的是java的,但应该对于各位不会存在任何问题的,都是相通的,我也是出于项目的要求才写java的,关键是思路,和具体的语言应该没什么关系.
有必要解释一下的是:
对于c++来说通过debug和release来决定是否启用assert
对于java来说则是通过参数-ea,-da来决定是否启用,其实原理是一样的,可能我下面的说法有些混.
函数很简单,其实就3行代码,但却让我想了一天的时间来考虑该怎么搞他
public void joinGroup(Group group) {
if(group == null)
return;
groups.add(group);
}
这里的group势必不能为null,其实这是一种约定,因为传入null没有任何意义啊
所以传入null应该属于错误,这种类型的错误应该在开发阶段予以发现,其实这里
改为assert的作用在于帮助这个方法的client发现错误并修复.
=>
public void joinGroup(Group group) {
assert group != null;
group.add(group);
}
但同时需要考虑的是一旦release后,则这个方法处于无保护的状态下,如果遇到
null的话,这里会将null add至groups,但一定会在后面的某个地方产生NullPointer
的异常.所以仅仅是assert还是不够的,因为assert只是在debug阶段帮助你一下,
但绝对不可能就能保证在release以后就不会再发生传入null的可能性,这取决于
测试的完整性.这种完整性只是理论上的,相对的.
那我们又该如何处理最终产品中的这个问题呢?
有几种可选的方法,一种就是if null then return,另一种则是exception
把持不包庇错误的原则,我们应该还是首选exception
=>
public void joinGroup(Group group) {
assert group != null;
if (group == null)
throw new NullPointerException();
group.add(group);
}
这样一来,assert还有什么意义呢?
而且也违反了exception的初衷
开始郁闷
于是google =>
任何一个失败了的Assertion都应该当作Bug来处理。
需要注意的是,不要将Assert和Exception的处理(Try…Catch…Finally)混淆,
Assert处理的是一些不应该发生的错误情况,而Exception处理的是由于各种原因
(如网络环境,服务器Down机,数据库Crash等等)产生的异常。
:http://www.microsoft.com/china/community/program/originalarticles/techdoc/debuggingInNET.mspx
Good!
这样的说法故然没错,可是...
一定能确保在release之前debug出所有的bug
mission impossible,一来是时间问题,二来就是测试成本的问题,三还有环境的问题
我们是不可能对所有用户的环境进行测试的,不是吗?
那么万一没有在debug阶段把这个bug消灭之前就release(这也是常有的事了),然后呢?
又该怎么办?
没办法吧,google again...吃饭先
BTW:其实到了这里问题也变得明晰多了,
首先就是要清楚这里是错误还是异常
错误一般来说意味着BUG和shutdown
而异常只是超出一般正常的情况,相当于需要安排另一条路,可以看成是一个else
这里处理异常的话首先排除return,然后就是要遵守不能包庇错误的原则.
剩下的就应该是确定异常和assert的时机问题了.
慢慢来
事情总是会有办法的,虽然我现在还是不知道该怎么办,但我现在至少知道了
assert+exception一定是不对的.为什么呢?
从蔡学墉的Shit? Happens中看到assert会别编译器当成以下代码来编译:
if (ea) {
if( statement ) {
throw new AssertionError();
}
}
换句话说如果我同时写
assert group != null;
if(group == null)
throw NullPointerException();
其实是自欺欺人,多此一举
变成在打开assert的时候,即debug的时候连写了丢两次异常的代码,
而release的时候只不过变成了一次异常而已,如果是这样的话,release
的时候把assert开着不就ok了,或者说就直接写throw,那基本上assert
就废掉了.总之同时使用两者肯定是不对的啦
过去我对assert的阴影在于报错,如果给用户一个程序用了一会就突然
assert Failure那会有多黑暗啊,所以赶紧编一个release,至少就不会弹出
框来,显然我很肤浅...别砸我..
后来才懂原来是因为效率的原因.
因为你知道能release的程序一定是assert怎么都不会错的,如果assert还会
时不时的弹一下说明程序还有bug,不是通过release就万事大吉了.
换言之,如果说我根本不考虑效率的问题,那么assert放在release中也不会
产生除任何效率以外其他副作用.
那么我是否能考虑给客户的就是打开assert的版本,因为我不在乎速度
assert group != 0;
groups.add(group);
这样就ok了,在目前的情况达到我所有的目的,因为我现在对速度没有任何要求.
别砸我,是的,当时就是这样
不过我内心深处知道他依然不完美,怎么可以这样呢?
事实上,一定很多人这样写
if(group != null)
groups.add(group);
我过去就是这样的,不过这种是最没有效率,最自欺欺人,最要被批的写法
可能很多人认为if对效率来说可以说是微乎其微,可是却包庇了错误,
我们的目的在于写出没有bug的代码,但一定会有一个过程,从开发阶段到用户使用
的阶段,我们都在为这个目标所努力,有些东西想躲是躲不过去的,
难道有人认为写一句if就万事大吉了吗?我想一定会出问题的,只是时间的问题而已.
而且严重增加了后期排查错误的难度.
开发阶段我们应该倚仗assert来帮助我们debug,而交付以后,可能更加需要考虑由
用户来帮助你来发现问题,解决问题,怎么在这之间建立桥梁,可能光靠assert是不
够的,这样的体验直接导致下次不会再找你替他开发软件,不行不行.
该怎么办呢?
大家能帮忙说说你的思路吗?
问题点数:200、回复次数:62Top
1 楼xing_xing_xing(哈哈)回复于 2006-01-22 21:47:00 得分 5
http://www.refactoring.com/catalog/introduceNullObject.html 这个也许对你有帮助,
如果要完美的话。Top
2 楼wd_6532(用frontpage写asp,jsp,php,ace)回复于 2006-01-22 21:47:50 得分 0
markTop
3 楼ONLY_CHYGO(柴狗)回复于 2006-01-22 21:52:20 得分 0
这个问题我也想问的,顶楼主Top
4 楼Mackz(在相互)回复于 2006-01-22 22:05:27 得分 20
想得过于复杂了吧,最多加一个DUMP便于查找错误发生的原因就是了,对于用户,给个提示也没有关系。Top
5 楼wangk(倒之)回复于 2006-01-23 09:07:05 得分 35
用容错+Assert。Top
6 楼wangk(倒之)回复于 2006-01-23 09:09:05 得分 0
if(group != null)
groups.add(group);
else
assert group != 0;Top
7 楼ydfivy(我就是一送外卖的)回复于 2006-01-23 09:19:42 得分 0
不能加一个类似C中宏的那种东西.
DEBUG时ASSERT.
RELEASE 判断为NULL.
瞎说的.
Top
8 楼rageliu(天气好了就去长白山看水怪去了,嘿嘿...)回复于 2006-01-23 09:26:37 得分 0
回复人: wangk(倒之) ( ) 信誉:102 2006-01-23 09:09:00 得分: 0
if(group != null)
groups.add(group);
else
assert group != 0;
这个好象不错,可以判断是否为null又能区别出debug和releaseTop
9 楼Featured(我握着爱情的门票静静排队……)回复于 2006-01-23 09:38:43 得分 0
verify之Top
10 楼noneone(noneone)回复于 2006-01-23 09:48:41 得分 0
纯粹个人观点,除非是要追求完美,把程序当成一种艺术来看待,否则有这份时间还不如去搞一些更有意义的事
程序的设计取决于目的,如果你的程序是做为一个模块给别人用的,譬如你在做系统API、内核或者某种库,你不应该设计一个返回值为void的函数,对非法的参数应该直接告诉调用者,“这是非法参数”
如果你完全是自产自销,那就可以随便折腾了Top
11 楼jihailong(谁给我分我和谁急)回复于 2006-01-23 10:10:23 得分 0
过度追求完美,呵呵Top
12 楼nonocast(如果没有如果)回复于 2006-01-23 10:49:50 得分 0
To xing_xing_xing(ζ未名ζ)
NullObject这里不会是一个很好的解决方法,
其实你知道,NullObject只是为了省略一个if null的条件,
但我一直强调的一点就是如果if了,不管是直接写if group == null或是使用NullObject
其实无疑是把问题吃掉了,就像明明有一个地方错了,但你还要包庇他
如果汽车你还能启动至少应该表明他没问题,不能开到一半就炸了,不是吗?
我不同意写if的
同样的wangk(倒之)
if(group != null)
groups.add(group);
else
assert group != 0;
这个和
assert group != null;
if(group != null)
groups.add(group);
有什么区别呢?
还多一个else
Top
13 楼nonocast(如果没有如果)回复于 2006-01-23 10:53:11 得分 0
To Mackz(在相互)
其实如果在这里dump的话,那么系统中dump就会every where
是不是dump有什么模式或是规则可以谈谈?
我理解dump就是和log有些类似,
也是有很多种方法,log现场还是log流程
面对一堆log够喝一壶的了,呵呵Top
14 楼wangk(倒之)回复于 2006-01-23 11:06:34 得分 0
我觉得你想让客户像公司内部测试一样为你提供准确的调试信息是不现实的,因为客户可能什么都不懂,你应该把重点放在写出稳定的代码上。至于出错分析,你不妨像MS一样提供一个drwtsn类似的工具,把出错信息反馈回来再分析。
而且容错是有限度的,不是所有的错误都可以容的,像关键路径就不可以,但这些是程序设计决定的。Top
15 楼nonocast(如果没有如果)回复于 2006-01-23 11:19:24 得分 0
我个人感觉我在这方面的能力非常有限,因为都是自学的,很少能系统理论的学习这方面的知识体系.所以我在写一个函数的时候我很难判断出这个错误是不是可以容,换句话说如何把握这个尺度.因为我这里容的错误我无法知道他会影响到什么地方,我的关注点应该放在这个类,不是吗?
我也是希望客户一定要给我多详细的反馈,但我觉得应该是有方法的,其实Joel也说到应该有一个
bug trace的东西,但具体实现我可能觉得就有些力不从心.当然其中也会有成本的问题.
对于你说要写出稳定的代码,这个我也是认同的,其实无论是write clear code抑或在code complete中都强调过防御性编程,可能程序在一个不会报错的情况下运行看起来是一件不错的事情,但同时也是有另外一面的就是他本身回避了错误,如果这样的错误存在,试问这样的稳定又有什么意义?
可能我的工作环境,境遇会和大家有所不同,我必须要拿出勇气面对每一行代码,必须确认每一行代码,否则我就没饭吃,我不是理想主义者,我只是觉得这是很基本的层面,我不会,所以我要请教诸位,要学习,就这么简单
对于noneone, jihailong,我不敢苟同.
Top
16 楼mscf(扎西特勒)回复于 2006-01-23 11:25:19 得分 2
等待新的开发语言Top
17 楼lw549(那个孩子他爹)回复于 2006-01-23 11:27:01 得分 0
msdn里对每个api都有准确的说明,或许值得借鉴
明确说明下面的内容
1.对参数的要求
2.如果参数错误,会引起Exception还是容错处理,怎么处理
3.如果做了容错处理,要在返回值或返回参数中做怎样的处理Top
18 楼mscf(扎西特勒)回复于 2006-01-23 11:27:25 得分 0
BUG是软件的属性,追求太完美是不切实际的做法哦。Top
19 楼nonocast(如果没有如果)回复于 2006-01-23 11:27:33 得分 0
在很早的Dr.Dobb's中就有这样一段
从更广的尺度看,我们的整个行业还远未达到成熟,还面临着软件质量和易用性方面的严峻挑战。还记得当年盖茨和通用汽车之间的经典对话吗?
"如果通用汽车像微软那样进行技术开发的话,我们的汽车将每天无缘无故地故障两次.....,每款新车上市的时候,司机都必须重新学习,因为操作方式改变很大......"
当软件在我们的社会种承担的责任越来越多,越来越重要的时候,通用汽车当年冷冷的反驳,应该成为时刻提醒我们的警钟。
这段话给我留下了很深的印象Top
20 楼Raptor(猛禽)回复于 2006-01-23 11:30:33 得分 0
首先要确定你这个函数是作为给第三方使用的API还是自己的程序内部使用的?
如果是给第三方使用,则必须加上Exception或类似的保护。
如果是自己的程序内部使用,就用Assert,因为如果出错,问题不在这个函数,而是在调用它的地方。Top
21 楼lw549(那个孩子他爹)回复于 2006-01-23 11:30:38 得分 0
至于究竟是容还是不容要看具体情况而定
1.如果容错很难实现,建议不要容错
原因:不是推卸责任,也不是偷懒,因为越复杂的代码维护成本越高
2.如果容错后,逻辑变得很难理解,建议不要容错
原因:不要为了容错而容错Top
22 楼ly_liuyang(Liu Yang LYSoft http://lysoft.7u7.net)回复于 2006-01-23 11:31:05 得分 0
汗~~Top
23 楼Raptor(猛禽)回复于 2006-01-23 11:32:48 得分 30
首先要确定这个函数是内部使用还是提供给第三方的API。
如果是给第三方的API,则必须提供Exception之类的保护。
如果是内部使用,就用Assert,只在调试时使用,因为就算发生null错误,问题也不在这里,而是在调用的地方。Top
24 楼nonocast(如果没有如果)回复于 2006-01-23 11:36:25 得分 0
问题就在你能确定release以后就一定没错了吗?
bug一定会在release后的一段时期内长期存在的
在开发阶段我们可以利用assert,可是在release以后呢?
如果错误危及到数据完整性的话...Top
25 楼Raptor(猛禽)回复于 2006-01-23 11:45:58 得分 0
但至少这个函数没错,错误显然发生在调用处,所以要检查也应该是在调用处检查。Top
26 楼Raptor(猛禽)回复于 2006-01-23 11:46:55 得分 0
一个错误只应该在一个地方检查,而不是在调用路径的每一处。Top
27 楼wangk(倒之)回复于 2006-01-23 11:56:41 得分 0
我记得好像有个原则,就是参数得正确性尽可能由调用者来检验。
我认为你要把本该由调用者责任接过来得话,实在是效率太低了。至于判断出这个错误是不是可以容,只要立足于你写的类即可,考虑太多是没有意义的。Top
28 楼yingpf(阿飛)回复于 2006-01-23 14:30:26 得分 0
前几天我也在思考这个问题,想了很久,想不太明白,后来想想如果所有的问题都由函数来处理的话,会很麻烦,而且不一定能做的很好,所以我也觉得类似的问题,应该由调用者来保证指针的有效性。Top
29 楼nonocast(如果没有如果)回复于 2006-01-23 14:39:33 得分 0
可事实上joinGroup作为一个wrapper
他即使调用者有是被调用者
这里他需要调用groups.add(group);
那他怎么保证group呢?Top
30 楼pomelowu(羽战士)回复于 2006-01-23 14:44:22 得分 3
关注一下,比较模糊的概念。Top
31 楼lzzqqq(Jonersen)回复于 2006-01-23 14:57:24 得分 0
不知所云Top
32 楼nonocast(如果没有如果)回复于 2006-01-23 16:06:03 得分 0
其实就是交流一下大家平时在写函数时所思考的东西
一种习惯吧Top
33 楼kikikind(可乐)回复于 2006-01-23 17:40:23 得分 0
关注~~~
别:好多星星呀哈`~~什么时候我也升星星呀~~~:)Top
34 楼nonocast(如果没有如果)回复于 2006-01-23 19:00:55 得分 0
星星多没用,呵呵
厉害的角色都是潜水的Top
35 楼colcn88((散花)只想让家里人过得更好)回复于 2006-01-23 20:07:50 得分 0
学习Top
36 楼Kid4you(Kid4you)回复于 2006-01-23 20:40:45 得分 0
只有学习了Top
37 楼Raptor(猛禽)回复于 2006-01-24 11:12:39 得分 0
>可事实上joinGroup作为一个wrapper
>他即使调用者有是被调用者
>这里他需要调用groups.add(group);
>那他怎么保证group呢?
这不废话么,只要保证调用joinGroup的调用者可以保证group不为null,那么groups.add自然有保证。除非对joinGroup的调用者你不能保证(比如我前面举例说过的,用于给第三方使用的API),那就必须在这里加入Exception或类似的保护机制。
只要在设计中确定group为null时就是一种错误情况,那么对错误的检查越早越好,因为这样更能准确地确定错误发生的地方。既然joinGroup的参数不能为null,那么说明错误出现在调用之前,最好还是在调用之前检查,为什么那里会产生null值。这跟joinGroups是不是wrapper一点关系也没有。
关键在于始终坚持一个固定的约定:比如参数有效性始终由调用者保证,或始终由被调用者保证。如果二种情况混用则自然是要糊涂的。
比如joinGroup是groups.add的调用者,你如果要求它保证调用groups.add时参数是有效的,则同样的道理,它也可以要求调用它的地方要保证参数有效,那么如果它的调用者能保证,这里的检查就是不必要的。就是这么回事。而沿着这条线索,总能找到第一个可能出错的地方,在那里检查即可。
Top
38 楼nkwesley(江南丝竹)回复于 2006-01-24 11:24:18 得分 0
稳定压倒一切
可读性次之
效率再次Top
39 楼nonocast(如果没有如果)回复于 2006-01-24 12:58:26 得分 0
Raptor(猛禽)不错不错,写的很好,只是通常大家都是怎么做的,怎么来写出高质量的代码的?
有没有什么best practice之类的,:)
To nkwesley
你的顺序我非常赞同,很多人在连稳定都没有的基础上大谈效率,这不是糟蹋人嘛
不过你怎么定义稳定呢?具体的操作有是怎么样的呢?
说说这个吧,大家会更感兴趣^_^
Top
40 楼ggw007(呢喃)回复于 2006-01-24 13:14:39 得分 5
public LONG joinGroup(Group group)
{
LONG lResult;
try
{
lResult = 0;
if(group == NULL)
{
lResult = 0xFFFFFFFF;
return lResult;
}
try
{
group.add(group);
}
catch(...)
{
lResult = 0xFFFFFFFE;
}
}
catch(...)
{
lResult = 0xFFFFFFFD;
}
return lResult;
}
==========================================================================
我觉得这样子比较好,比较稳驮,这是C语言的代码,不知道JAVA能不能写成这样子
Top
41 楼ggw007(呢喃)回复于 2006-01-24 13:18:38 得分 0
这样子所有的异常,都会在你的控制之内,可group 等于NULL,不是异常,正常情况Top
42 楼ggw007(呢喃)回复于 2006-01-24 13:23:25 得分 0
在调用 之个函数之前你就要保证 group不为NULL,且有效,
看你怎么约定了,是在函数内检测呢?还是在调用这个函数之前检测了
不能用assert 或 exception 这是模块设计出的问题,不可能在代码中解决的Top
43 楼nonocast(如果没有如果)回复于 2006-01-24 13:33:54 得分 0
JAVA,c# both OK
但问题是这样写的话是不是有些扭曲
可读性就很低了,不但是函数内代码从实际的一行变为10行
而且client方也需要处理N个返回值
对于约定不为NULL的情况,你在函数采用的是防御性代码if,这样的意义在什么地方呢?Top
44 楼loki2k(loki)回复于 2006-01-24 13:48:50 得分 0
难道你在debug时出现assert了不管的?
出现这种情况说明你程序没写好!
肯定需要改的啊!Top
45 楼SeekTruth(鹤舞白沙)回复于 2006-01-24 13:57:59 得分 0
谈谈我的看法:
1. 楼主的代码:
if(group == null)
return;
groups.add(group);
这咱代码风格如果我没记错的话,称为防御式编程,虽然可以保证程序不出现异常,但是隐藏了程序的错误
2. assert(断言)的使用
断言用于诊断程序"不应该"出错的情况,如参数 group 不能为Null,如果group为Null,
说明程序逻辑出现了问题,joinGroup的调用者没能保证参数的正确性.
3. 为了保证运行时候的健壮性和正确性,楼主应该使用异常机制.
-------------------------------------------------------------------
最后,祝楼主和CSDN上的朋友们新春愉快,工作顺利,万事如意!Top
46 楼icecools(浮生若梦)回复于 2006-01-24 14:30:17 得分 0
<write solid code>里面有专门讲这个的吧Top
47 楼nonocast(如果没有如果)回复于 2006-01-24 15:06:27 得分 0
我只是看过write clear code
你说的write solid code是ms的吧?好像里面多是防crack的吧
而且印象中针对代码的比较少Top
48 楼nonocast(如果没有如果)回复于 2006-01-24 15:11:07 得分 0
其实在write clear code中,作者一再强调DEBUG和RELEASE的区别
我倒是觉得针对debug,release应该区别对待,有不同的机制来处理Top
49 楼lemon_wei(研究BT,做好P2P)回复于 2006-01-24 15:24:43 得分 0
函数的返回值不使用void类型,发生不同的错误返回不同的值,函数说明中告诉调用者,返回值的含义。Top
50 楼nonocast(如果没有如果)回复于 2006-01-24 15:34:03 得分 0
在不考虑性能的情况下,返回值我倒是觉得没有异常来的好
不管是从client的角度,还是代码可读性的角度
因为很多时候我们都忽略了返回值,而且返回值只能返回上一层,而异常可以跨N层Top
51 楼bluebohe(薄荷)回复于 2006-01-24 15:51:35 得分 100
我的建议:错就错了!!
public void joinGroup(Group group)
{
groups.add(group);
}
我们公司都是这样做的!一般情况下,尽量避免if(!group)return;的语句
!group是一个不应该发生的事情,如果加入if(!group)return;这样的语句,当真的!group时,程序仍然运行,运行到了一个其他难以调试的角落才会死掉,或者根本不死,但出现了某些难以判断的错误,你想,在成千上万行代码中找一个这种不死机的错误是非常需要技术的。这样的话,得不偿失。
对于开发者而言,可怕的不是死机,而是不死机的错误,或者是难以重现的错误。楼主的做法抑制了死机,但是带来相当大的隐患。这种隐患,对用户来说可能是小问题,但对于你来说,就成了大问题
Top
52 楼BeYourself(http://www.sunsides.com)回复于 2006-01-24 16:06:32 得分 0
csdn第一强帖,学习
http://groups.google.com/group/coder-referenceTop
53 楼nonocast(如果没有如果)回复于 2006-01-24 16:06:52 得分 0
哈哈,谢谢老大的答复
的确是不能加if的,那个if只是我的一个引子啦
老大太忙可能没有看完我的长篇唠叨
我的意思是对于debug版本一定是不能加入if的,不能包庇错误
问题是我的测试成本有限,
我担心的是release依然有bug,会影响数据,所以我的目前的做法是
加入
Assertion.assertNotNull(group);
Assertion是我自己实现的一个类assert类,在里面抛出异常
然后在application层[最高层]截获(对于asp.net在web.config可以配置,j2ee可以在web.xml中配置),引导到错误报告界面,给用户填写错误原因,
最后将用户填写的错误过程以及stack传回来保存起来以便查找bug
等一段时间系统稳定后再将Assertion这个类换掉或是关闭.提高性能.
可能很多人都是debug管debug,release管release
而我因为测试成本的原因可能要兼顾debug和release
在客户用的时候边用边改
请问您的意见是?Top
54 楼bluebohe(薄荷)回复于 2006-01-24 16:29:01 得分 0
我们是做嵌入式软件的,需要我们的代码能够在PC和所有嵌入式机器上面能够很好的work。
因此我们的代码加入了大量的打印语句,根据需要,打印可以输出到文件或者VC debug窗口,或者其他的调试工具窗口,
添加了大量的打印代码后,一个运行过程的log文件就足够看出问题所在了。不论你怎么写代码,不管是release还是debug,都应该有充足的log来发现问题
public void joinGroup(Group group)
{
groups.add(group);
}
---->
public void joinGroup(Group group)
{
dprintf("group=%X\n",group);
groups.add(group);
}
这就足够了,不需要那么麻烦
int dprintf(const char *fmt, ...)
{
int ret=0;
static char msg[102400], *ptr;
va_list args;
va_start(args, fmt);
#if defined(WOBUXIANGYAODPRINTF)||defined(HAVE_DPRINTF8)
return 0;
#endif
ptr = msg;
// sprintf(ptr, "[time: %d] ", GetTickCount()); ptr+=strlen(ptr);
ret = vsprintf(ptr, fmt, args);
#ifdef USE_LOGFILE
if (log_file==NULL) {
log_file = fopen("logfile.log", "wb");
srand( (unsigned)time_ms());
}
ret = fputs(msg, log_file);
// fprintf(log_file, "%d %s", GetTickCount(), msg);
// 这句话是必要的,否则如果写快了,文件内容不全
fflush(log_file);
#endif
va_end(args);
if (strlen(msg)>=800) {
OutputDebugString("[DPRINTF] Buffer OverFlow\n");
DebugBreak();
}
OutputDebugString(msg);
return ret;
}
Top
55 楼bluebohe(薄荷)回复于 2006-01-24 16:35:57 得分 0
debug和release的区别应该仅仅在调试输出语句方面,不应该在功能上,或者版本不同走不同的流程,否则debug就失去了它的意义。
即使是release版本,也是一样,死就死吧,给我log就行了:)Top
56 楼nonocast(如果没有如果)回复于 2006-01-24 16:52:32 得分 0
呵呵,非常感谢!Top
57 楼bluebohe(薄荷)回复于 2006-01-24 17:13:34 得分 0
看完了你的长篇大论,你的最终问题就是这个:
开发阶段我们应该倚仗assert来帮助我们debug,而交付以后,可能更加需要考虑由
用户来帮助你来发现问题,解决问题,怎么在这之间建立桥梁,可能光靠assert是不
够的,这样的体验直接导致下次不会再找你替他开发软件,不行不行.
该怎么办呢?
大家能帮忙说说你的思路吗?
____________________________________________________________
一个不影响用户使用的log就是解决方案Top
58 楼nonocast(如果没有如果)回复于 2006-01-25 11:00:30 得分 0
被bs了,什么长篇大论,是罗里罗嗦
因为这篇开始只是我的一个private weblog
但后来发觉问题比我想象的要复杂,或者说我还没到能彻底理顺这个问题的level
所以才发上来,有时候问问题也是一门学问,只说一两句,大家也不知道你要什么,病急乱投医
说复杂了就罗索
但我想还是罗罗嗦嗦好些,能把大家带入到问题里来
其实我发现通过这个问题一方面说明我还很不成熟,
其实像bluebohu这种大牛一看就知道你要说什么,你想知道什么
这个就是差距,学习中...很佩服这样的人,其实像bluebohe,包括很多MVP也好该多谈谈自己的经验介绍介绍自己认同的best practice,呵呵Top
59 楼bluebohe(薄荷)回复于 2006-01-25 11:52:06 得分 0
迷魂汤被你灌了那么多,其实我不过是一个小程序员而已,随便发一个我们调试的log
“EisTV4_DVB.exe”: 已加载“F:\cvs\cvs_develop2\proj-tv3[ipaneldtv call]: ipaneldtv_create(25165824)
[ipanel] ### (tm=10) -- create STB iPanel MiddleWare -- begin.
[porting call]: ipanel_porting_get_max_sockets()==6
[porting call]: ipanel_porting_network_init()
[STBBrowser_new] (tm=30) starting iPanel .............................
#define PORT_SC2000 (at iPanelTV)
#define (at iPanelTV)
f:\cvs\cvs_develop2\proj02\lib_web\web_runtime.c version : Jan 25 2006 10:34:42
#define PORT_SC2000 (at core )
#define (at core)
iPanelRuntime_create ctxA->heapsize = 25165824(0x1800000)
iPanelRuntime_create ctxA->f_malloc = 0x580520
iPanelRuntime_create ctxA->f_free = 0x5805c0
iPanelRuntime_create ctxA->rdfs_sys_buffer = 0x0
iPanelRuntime_create ctxA->rdfs_ui_buffer = 0x0
xmem started: 0x2f60040~0x3060040 segsize=1048576(0x100000) blocksize=0x10
[XMEM] too many blocks count(92400) got! blocksize is 256
xmem started: 0x3070040~0x4770040 segsize=24117248(0x1700000) blocksize=0x200
[SDK] init done... Total used memory=8912, available memory=24673712
Hi,installl rdfs device now....
DEBUG_DEVICE: device registered: 'rdfs'
[sc2000 Debug] dev=graphics *dev size=20 (*dev).open=0060A850
DEBUG_DEVICE: device registered: 'graphics'
DEBUG_DEVICE: device registered: 'nvram'
[EIS-NET] Network starting
DEBUG_DEVICE: device registered: 'socket'
iPanelRuntime_create params->device_rdfs = 0x6084b0
iPanelRuntime_create params->device_graphics = 0x60a770
iPanelRuntime_create params->device_nvram = 0x60e4d0
iPanelRuntime_create params->device_socket = 0x582c40
[SC2000 Debug]file f:\cvs\cvs_develop2\proj02\lib_web\web_runtime.c Line 173 msg device End gfx_init Start
[FlashDevice_read] NVRAM_STATUS_INFO addr=0xd7b768 size=0x100000
[FFS] flag_ram=0 size=0x100000(16 sections,2048 blocks)
allocate buffer: 0x30abba8
allocate buffer: 0x30bbba8
allocate buffer: 0x30cbba8
[FFS] blocks: used=1 total=2048
[xmem_malloc] malloc large chunk 2097152
[FlashDevice_read] NVRAM_STATUS_INFO0 addr=0x30dbfa8 size=0x200000
[FFS] flag_ram=1 size=0x200000(32 sections,4096 blocks)
[FFS] blocks: used=1 total=4096
[FFS] started... Total used memory=2312416, available=22370208
[GRAPHICS] set format 'RGB1555'
[xmem_malloc] malloc large chunk 665600
EIS fonts Initialize...
XFont is from xfont-sino-gbk.h
[RDFS] FONT Buffer=0x00808628 Size=968408
[WARN: USES HAVE_EXACT_FONT_SIZE, this could causes memory fragmentation
[InitHeader] OffsetBig5Tab=0(0x0)
[RDFS] UI Buffer=0x008f4d00 Size=1110788
[SC2000 Debug]file f:\cvs\cvs_develop2\proj02\lib_web\web_runtime.c Line 198 msg gfx_init End
[SC2000 Debug]file f:\cvs\cvs_develop2\proj02\lib_web\web_runtime.c Line 231 msg ffs End
[HttpThread_new] max sockets=5
[HTML] starting... Total used memory=3019424, available memory=21663200
[HTML] started... Total used memory=3084000, available=21598624
[porting call]: ipanel_porting_get_DNSserver1()
[DEBUG_IPANEL] the DNS server name is '192.168.10.248'
JMemHeap_new 0x40000
[xmem_malloc] malloc large chunk 344208
[JMemHeap_initialize] totalsize=262144, 16384 blocks, blocksize=16
Hash Remap result 3 977
[COMPRESS_TEST] now test the compress and uncompress function!
[COMPRESS_TEST] init completed
[COMPRESS_TEST] compress OK len=106
[COMPRESS_TEST] decompress OK len=512
[COMPRESS_TEST] compress and uncompress function ok!
Hash Remap result 5 1493
f:\cvs\cvs_develop2\dvb\proj-dvb\lib_dvbsi\dvb_si.c(219): ### tm=590 starting DvbSiManager with EPGEvent size=88...
version : Jan 25 2006 10:33:54 -- used/free memory=3462256/21220368
[DvbPmtManager_new] tm=600 me=0x2fa58d8(0xffff/0xffff/0xffff) PID=0x1fff PAT=0x0 SDT=0x0
f:\cvs\cvs_develop2\ipaneltv\lib_app\app_dvbdata.c(1121) : Breakpoint
[DVB] failed to open network information file: 'wmcNetwork'
f:\cvs\cvs_develop2\ipaneltv\lib_app\app_dvbdata.c(1135) : Breakpoint
[DVB] failed to get off channel handle for channel ID=-1
[eis_read_network] starting channel parameters: frequency=0, symbol rate=0, modulation=0 ===========
[eis_read_network] version=255, initial frequency=0, name=''
[eis_read_deliveries] total 0 deliveries got...
[NIT] created for talble_id=0x40, me->filter_status=4, flag_ready=0
[BAT] created: me->filter_status=4, flag_ready=0 ===================================================
[DvbSiManager_new] ### time=640 DvbsiManager started: used/free meory=3466880/21215744 *******************
[NetworkTransportFilelist] number of ts files 1
[DEMUX] WARNING!!! requested option 'network_id' not set in eis.ini !!!
[DSMCCManager_setCallback] set me->numFilterMax=16
[DvbSiManager_proc] (tm=671) have not got DVB_MESSAGE_TS_SWITCHED!!! please check if it lasts long term...
[iPanelRuntime_create] me->socket_timestep=4
[iPanelRuntime_create] finished! Total used memory=3466880, available=21215744
DEBUG_DEVICE: device registered: 'LocalFile'
DEBUG_DEVICE: device registered: 'network'
DEBUG_DEVICE: device registered: 'customize'
DEBUG_DEVICE: device registered: 'PSI'
screen size 640 520
screen size 640 520
f:\cvs\cvs_develop2\ipaneltv\lib_ipanel\src\stb_browser.c(405): me->hBrowser = 49962520
[App] test channel up/down, app_dvb.c, enter 'App_resetOpenService'.
[porting call]: ipanel_porting_get_volume()
[AppSoftKeyboard_new] begin run ......
[porting call]: ipanel_porting_get_startpage()
[porting call]: ipanel_porting_get_homepage()
[openUrlEx] ### (tm=741) opening 'http://127.0.0.1/page/file/ini.htm'
[HTML_DOWNLOADING_START] ### (tm=741,memory=21179600) 'http://127.0.0.1/page/file/ini.htm'
open a ui/skin/http page,stop current service and clear current service struct!
[App] test channel up/down, app_dvb.c, enter 'App_resetOpenService'.
[App] ? no 'eventpage.htm', need one.
[porting call]: ipanel_porting_sound_init()
f:\cvs\cvs_develop2\ipaneltv\lib_ipanel\src\stb_browser.c version : Jan 25 2006 10:33:42
[STBBrowser_new] (tm=771) finished! Total used memory=3503072, available=21179552
Top
60 楼bluebohe(薄荷)回复于 2006-01-25 11:54:00 得分 0
这只是一小部分,一个正常运行一个小时的log怎么也有四五千行吧,这些log就是我们板子调试的基础Top
61 楼nonocast(如果没有如果)回复于 2006-01-25 12:13:55 得分 0
赞!Top
62 楼manplus(魅力加加)回复于 2006-01-30 06:25:53 得分 0
markTop




