《程序员修炼之道 - 从小工到专家》读后感(四)
在生活中检查每一个可能的问题似乎是一种病态,然而编码时对输入数据、接口的误用以及自己的可能问题保持警惕十分必要。
这一章介绍了许多工具,用来对代码进行约束、检查,以免出现问题而带来更大的问题。
按合约设计:Designed by Contract,俗称DBC。
合约:合约约定了进入一个函数/方法/模块的前条件,即进入模块必须满足的条件,常常指满足模块运行的情景或变量取值范围等等;后条件,即模块需要达成的结果,模块运行之后所能达到的状态;不变量,是对于模块的约束,在调用模块前后始终为真的一些描述。
合约可以是动态的,由“合约代理”在不同模块之间协商出一套合约,但我不知道相应技术。
这是一个很好的想法,其优点在于让代码早崩溃,此时问题更小更单纯。但是在常用的c、cpp中这个想法并没有那么可行。可以通过断言实现一部分功能。
不过通过良好的文档,可以对前条件、后条件、不变量进行描述,从而达到合约的想法,一定程度上获得其优点。
死程序不说谎:一个出现问题的程序可能会因为异常操作造成很大的破坏,所以运行出现问题时,崩溃好于破坏。要利用异常机制。
断言式编程:对于“不可能发生”的情况进行断言,以保证系统的健壮与安全,以免因错误数据或恶意攻击出问题。
然而断言时要避免加入执行代码及其他有副作用的代码,避免“海森堡bug”:不当调试改变了被调试系统的行为。
异常:检查每一个可能的错误,尤其是意料之中的错误是有必要的。
要将异常用于真正异常情况的处理而非模块逻辑的一部分。检查这一点的方式是去掉异常,观察模块能否正常运作。
怎样配平资源:谁申请的资源谁解除该资源,降低代码耦合度。
对于嵌套分配,以与资源分配相反的顺序解除资源分配以免资源的遗弃,在代码不同地方申请资源时以相同顺序申请以免死锁。
在异常处理机制中,一个模块可以通过捕捉异常再抛出从而退出和正常退出两条退出途径。为了遵守对资源利用有始有终并减少重复的原则,有以下思路:对于c++,使用类封装而非指针以保证析构函数会解除相应的资源;对于java,可以使用finally语句解除资源。在更多复杂的情况下,比如树状结构中一个资源指向更多资源,可以用类封装等方式减少出错率。
练习中指出了两个小技巧:c/c++中为了避免释放后的指针被错误地引用,修改不该修改的内存,可以将指针值改为null;java为惰性内存管理,所以使用完某个变量后可以将变量值改为null,从而解除引用,使变量更快被回收。