第三、四部分——变量、语句

“在声明变量时初始化”——减少未赋值的风险。

“尽可能减少变量的存活时间”——感觉如果按照推荐,一般子程序都写的很短,那么这个也就不重要了吧。

“一个好记的名字反应的通常是问题,而不是解决方案,是what而不是how”

“避免使用相似含义的名字,如果你能让2个变量交换名字还不妨碍理解的话,就说明都要重新改名了。”——越功能简单越名字容易相似,哪那么好改啊。

“避免使用数字,什么file1,file2”——有时候就是图省事,哈

“阅读代码的次数远远多于编码,所以命名变量应该是阅读方便而不是编写方便”——不过现在公司都是一人维护一个模块,基本很少有别人来读代码。

“编码使用神秘数值,要么枚举要么常量”

“有除法预防除0错误”——经常犯

“检查中间结果溢出”——这个很重要,考虑最后结果是不是会溢出,有时候中间变量的溢出更会导致问题。

“避免数量级相差巨大的数之间的加减”——浮点型很难保证精度。

 

枚举的好处:

1、可读性好。

2、返回值用枚举替代bool,可以返回更多的结果,比如有2种失败等。

——2种模式下用一个方法返回是哪种模式,千万别有bool而要用枚举,否则新增需求是非常麻烦的。

3、枚举对第一项和最后一项再给一个特殊的名字,便于循环

enum{

color_first=0,color_red=color_first,color_green,color_blue,……color_black,color_end=color_black,

};

——循环时的确方便

 

使用typedef来自定义数据类型,方便修改,同时方便移植。

——方便移植倒是很理解,不过方便修改这点倒是很少遇到。

 

把相关元素组织到结构体里面,然后对结构体操作。好处在于交换2组数据时非常方便。

用结构体传递参数给方法。好处是再增加一个参数时,不用那么麻烦的再改好几个地方了,而且函数声明定义也不会那么长一串。

 

把指针操作限制在子程序里面或者类里面操作。——比如链表里面的指针操作。

delete指针时销毁内存——这点挺好的,delete前bzero一把,就不会导致使用已经delete的数据,有时候崩溃有时候没问题的情况了。但是有个问题,如果是标准数据类型还好,或者结构体也还好,有长度,对于有string的类,怎么bzero啊,根本就没有具体长度。???

 

方法传递变量,建议用const引用来传递,减少一次复制。

 

把if-else里面正常处理和处理常见情况放在最前面处理。

default只用来处理输入错误。

注意空循环里有没有sleep,可能导致cpu占满。

循环条件要尽可能短,嵌套循环不要超过3层。把长寻访放到子程序里面。

 

goto在分配资源,使用资源后再释放资源的子程序里面比较有用,尤其是出错要退出的时候,大量的释放资源的代码很重复。

——用宏定义把所有的释放都变成一条语句也可以,不过似乎很难看的样子。

 

第十八章《表驱动法》

凡是能用逻辑语句来选择的事物,都可以通过查表法来选择。

使用逻辑虽然直白,但是逻辑太多,查表法反而更好。

——比如以前设计一个程序,查找某ip段属于某个域,用x[256][256]-list,查找速度和理解性上都比用数字段好多了。

把结果提前计算出来,放在表中直接查阅,比现计算要快。

或者把计算出来的结果存在表中,避免下次计算。

“最好是找一种好的方案同时避免引发灾难,而不要试图去寻找最佳答案。”

 

第五部分:代码改善

20软件质量概述:

外在特征:(给用户用)

正确性(错误的稀少)、可用性(用户学习和使用一个系统的容易程度)

效率(占用系统资源多少,执行速度)、可靠性(很长的雾故障时间)

完整性integrity【应该叫完善性】(如拒绝访问未授权数据、确保日期字段是有效数据等)

适应性(如果即可以在xp小跑,也能在w7下跑)、精确性(在正确性的基础之上判定完成工作的优劣程度)

健壮性(接受无效输入的容错处理,和压力承受能力。)

内在特征:(给其他程序员用)

可维护性(是否容易修改、容易增加功能、提供性能、修正缺陷)

灵活性(用于其他用途时,修改的难度)【感觉没啥意义,其他用途还不如重写呢。写代码的时候就考虑灵活性,会导致限制很大】

可移植性(编译移植到其他平台)【与其为了可移植性导致效率下降,真不如重写一个算了。比如libevent为了夸平台,win上用的竟然是select。ACE在win上的完成端口还可以,但是在linux的epoll不是很好】

可重用性(某些功能用到其他程度里面的难易程度)

可读性(代码好读否)、可测试性

可理解性(可读性的加强版,更容易了解整体设计)

 

检查通读代码容易发现接口错误。

功能测试容易发现控制缺陷。

非正式测试一遍只能有50-60%的测试覆盖率。

编写无缺陷程序可能会让我们花费更少的时间。

 

21 协同构建:

相互协作的好处:开发人员都有盲点,但是其他人不一定有相同的盲点,所以让其他人检查自己的代码是有好处的。

结对编程:一个敲代码,一个在一边看。好处是人在有压力之下效率更高缩短时间表,能改善代码的质量和可读性,传播公司文化,执导培养新人等。【感觉好可怕,被一个人盯着去编码,难受】

 

正式检查、评审:

参加人员:

主持人(负责分配人员,分配任务,检查汇报结果,跟踪指派的结果。不能是作者)

作者(直接写文档、代码的人)

评审专家(在开会前找出缺陷,提交给作者和主持人)

记录员(评审专家一员,记录问题的确认,和新问题的记录)

步骤:

计划(作者提交主持人,主持人选定专家,开会时间)

概述(可选,加入专家不熟悉具体情况,作者做介绍)

准备(每个专家独立检查,有问题提交主持人和作者)

开会(主题是确认是不是问题,到确认就可以了,不应该去讨论解决方案。有新问题记录。不应该超过2个小时,很难保持精力,同时时间太长,专家在之前就不会认真找问题而在希望在会议中去找了。)

返工(确认记录,修复之)

跟进(主持人督查返工情况)

第三小时会议(有关人员讨论解决方案)

注意事项:

“很多公司发现,去掉或者合并某些步骤往往增加而不是降低了成本”

对事不对人,目的是找出缺陷,而不是探索替代方案,也不是批评作者水平低。

“90%的错误是在准备时发现的,10%是在会议上发现的。”

 

22开发者测试:

单元测试(单个子程序,单个类,或者单个小程序)

组件测试(个人理解是某个独立模块或子系统,涉及到多个程序员)

集成测试(多个子系统,多个开发团队)

回归测试(修改bug后的再次测试,防止这次修改导致其他错误)

系统测试(某些性能,安全,资源消耗等问题只能在这个层面测试)

测试是为了找出问题,测试永远不能证明程序中没有错误,测试本身并不能改善代码质量。

【建议先写测试用例再编码——本书提到很多次了,估计作者应该有切身体会。】

先写测试用例,会让你在开始写代码之前思考一下需求和设计,而这会催生出更高质量的代码。

使用容易手工检查的值作为测试输入。

“绝大多数错误都是在少数类中。”

“19%的错误都是对设计或需求的错误理解或误解导致的。”

测试数据本身出错的密度比测试代码还要高,可能导致程序员消耗几个小时的时间,发现原来是数据错了。

保留测试记录【公司一般都有bug记录和关系,感觉可以增加的就是“查找错误消耗的时间,修正错消耗的时间”】

 

23调试:

调试不是改进代码的方法,而是诊断代码缺陷的方法。

科学调试方法:

1、把错误状态稳定下来(找出必先的大致条件)

2、确定错误来源(收集错误相关数据,分析,构造一个假说,正式或者证伪这个假说)

3、修补缺陷

4、测试

5、查找还有类似错误否

如果没有重复性,就要考虑是不是初始化文件,或者是与时间有关,或者是野指针。

 

蛮力调试:对代码全部检查,从头开始设计和编码等等。

“对蛮力测试,你反应是做不了。但是往往花了2个小时去调试本来30分钟就能写完的代码。”

“动手之前要先了解问题。匆忙动手解决问题是你所能做的最低效的事情之一。”

“理解程序本身,而不仅仅是问题。”

“保存最初的源代码”【比如上传cvs,这点很重要,深有体会】

“修改代码一定要有适当的理由,而不是改动这里试试能不能解决问题。”

“一次只做一个改动。,改动越多越容易出错。”

“修改后检查自己的改动。”【修改后对比原先的代码很重要】

“把编译器设定为最严格,修改所有的报警的地方”【有必要吗,比如vc里面给一个枚举赋整型值也告警,这也都得修改吗?】

 

24重构

重构的理由:

具体见P565

比如:

代码重复(同样的一段代码,到处都是,每次一个修改得改好几个地方)

太多参数的子程序

……

超前设计(将来才会用到的功能)【感觉和前面的可维护性矛盾啊,不考虑超前,怎么适应未来的扩展功能?】

 

重构不等于重写。

 

----------------------------

【留个问题,上班的时候问问,g++在调试的时候能改内存的值吗?】

答:可以  gdb里面,输入“p   变量=新值”就可以了,另外类的符号重载在这里是无效的,比如string abc;那么不能p abc=“123” 而yoga用p abc.assign("123")

另外顺便发现了string的几个特点

 char ch1[20] = {0};
 ch1[0] = 'a';
 ch1[10] = 'b';
 string abc(ch1,20);
 cout <<abc.length()<<";"<<abc.size()<<";"<<abc<<";"<<abc.c_str()<<";"<<endl;

打印结果应该是:20;20;ab;a;