[读书笔记] 代码整洁之道(三)

来源:互联网 发布:和知乎同类型app 编辑:程序博客网 时间:2024/05/16 01:29

继续本书读书笔记的整理。

第五章 格式

本章主要讲了代码排版方面的一些建议,当然这些只是建议,毕竟代码格式方面的东西每个公司甚至各个团队之间都可能不一样。
代码的格式说白了就是代码的风格,它跟代码的清晰度密切相关,代码可读性如何,很大程度上取决于代码的格式是否清晰。
可以从代码的横向和纵向连两个方向来观察代码的格式。

横向格式

最明显的就是代码的缩进,缩进可以从视觉上把代码分层,例如:

if(A){    ...    if(B)    {        ...        ...    }    ...}else{    ...    ...}

可以很明显的看出不同层次的条件语句块,这需要注意tab键的使用,你的代码如果可能运行于多平台之上,那么要特别注意,tab键在不同平台上代码的实际距离可能不一样,所以,一种比较通用的做法就是把tab键映射为特定的空格数量(通常为4个空格),而空格是各个平台通用的,大部分的IDE中都会提供这种映射功能。
另一个就是空格的使用,例如赋值语句的的等号前后要有空格,参数与参数之间的空格等等,这些规范性质的东西在具体的项目的编码规范中往往都有参考。

纵向格式

纵向格式是指代码自上而下的分布样式,可以认为是代码整体流动的方向,所以,函数于被调用函数之间最好是,自伤而下的关系,例如:

void FuncA(){    FuncB();}void FuncB(){    FuncC();}void FuncC(){    FuncD();}....

这就是一段吻合代码流动,或者说代码阅读顺序的格式,当其他人员阅读你的代码时,自上而下依次就可以把整个代码阅读完毕,相反如果代码是如下这个样子的:

void FuncC(){    FuncD();}void FuncB(){    FuncC();}void FuncA(){    FuncB();}....

很容易比较出其中的差别。
代码纵向格式反映了代码在垂直方向上的亲密关系,所以,变量的声明应该靠近其使用的地方,有调用关系的函数应该靠在一起,概念相关的代码也要放在一起,这些都有利于提高代码的可读性。

最后,遵守团队规则

以上只是一些范向的参考守则,最后落实到具体的项目中时,首要参考的当然是书团队的规则,如果法相不妥的或者可以改进的规则,那么团队成员可以一起协商,为整个团队编写出高可读性的代码而努力。

第六章 对象和数据结构

本章探讨了面向过程(比如C)中的纯数据结构(比如struct)和面向对象(比如C++)中的类(class)之间的差别,指导二者应该在什么情况下使用。
过程式的代码便于在不改动既有数据结构的前提下添加新函数,面向对象的代码便于在不改动既有函数的前提下添加新类。反过来讲,面向过程的代码难以添加新的数据结构,因为必须修改所有函数,面向对象式代码难以添加新函数,因为必须修改所有类。
总之,对象暴露行为,隐藏数据,便于添加新对象类型,而无须修改既有行为,当然也难以在既有对象中添加新行为。数据结构暴露数据,没有明显的行为,便于向既有的数据结构中添加新行为,同时难以向既有函数添加新数据结构。
当系统需要灵活的添加新数据类型时,这部分适合使用对象,当希望灵活的添加新行为,这部分适合使用数据类型和过程。

第七章 错误处理

错误处理是代码中不可避免,同时可以极大的增加代码可调式型的东西,本章给出了几条参考准则,以便在程序出错时更好的提供错误本身以及错误上下文信息。
1. 使用异常而非错误码。当然这个依赖于语言本身对于异常的支持情况,否则可能需要开发者自己去造轮子了。错误码之所以不够好,是因为它搞乱了调用者代码,调用者必须在调用之后立即检查所有可能的错误码,例如:

Handle handle = handler.GetHandle();if(INVALID == handle){    ...//what to do when invalid handle}else if(BIG_HANDLE == handle){    ...}

相反直接抛出异常的方式就要智能的多,代码足够简洁,逻辑性也足够好.
2. 先写try-catch语句。这样的好处就犹如先进行代码架构设计一样,优先把代码运行可能出现的正常-错误结构搭建出来,同时也便于一步一步的单体测试。
3. 使用不可控异常,这个在C++中就是不要指定具体的可能抛出的异常类型(exception specification),因为如果后期添加的新的的异常类型,由内而外所有的catch语句都需要修改,一旦有遗漏,相应的异常很可能无法被上层捕获(目前编译器似乎会有这样的检查)。
4. 给出异常发生的环境说明。比较常见的就是call stack信息,以方便定位异常发生时代码的上下文运行情况。
5. 定义常规流程,这个是说不要让异常代码打断业务逻辑,例如:

try{    MealExpense expenses = expenseProxy.GetMeals(employee.GetId())    m_total += expenses.GetTotal();}catch (ExceptionNotFound){    m_total += getCommonMealExpense();}

异常成为了实际业务逻辑的一部分,这是不合理的,更好一些的做法是,创建一个类,用来处理这种特例(spacial case pattern)。
6. 不要返回null值,因为返回null值意味着所有的代码在调用可能返回null值的代码之后,都需要检查null值,否则就可能发生错误,而不自知。取而代之用一个特里对象代码这些null的情况。
7. 禁止传入null值,因为意料之外的null很难处理,除非API有明确的说明,可能传入null值,例如windows平台本身提供的好多函数都会以null参数值组为默认值。
本章的主要理念就是,要不错误处理隔离看待,独立于主要的业务逻辑之外,这样它就可以被单独处理,大大的提高代码的可维护性。

0 0
原创粉丝点击