代码整洁之道读书笔记(Ch4-Ch7)
这几章从注释、程序格式、对象与数据结构的规范以及错误处理四个方面介绍了如何使代码变得简洁易懂。不同于上次摘抄的方法,这一次我会结合第一次个人作业的代码进行分析。
第四章 注释
这一章告诉我们,好的注释要满足以下三点要求:
- 尽量避免用注释解释程序意图
- 注释要精练简洁
- 注释要明确,不能给人误导
好的程序往往通过代码就能告诉程序员这段代码要做什么,注释只能出现在可能出现歧义的地方以及需要特别注意的地方。当你想通过添加注释来解释意图的时候,不妨先想一想将功能分块、修改函数名、封装类等方法能不能帮助你更好地表达。万不得已必须要加注释的话,那你一定要注意注释的简洁性与明确性。下面我分析一下第一次个人作业中Linux平台下遍历文件夹的程序注释部分。
void traverseFileandCount(char* path, struct alphaArray* dictionary)
{
DIR *pDir; //定义一个DIR类的指针
struct dirent *ent=NULL; //定义一个结构体 dirent的指针,dirent结构体见上
int i = ;
char childpath[]; //定义一个字符数组,用来存放读取的路径
pDir = opendir(path); // opendir方法打开path目录,并将地址付给pDir指针
memset(childpath, , sizeof(childpath)); //将字符数组childpath的数组元素全部置零
while ((ent = readdir(pDir)) != NULL)
//读取pDir打开的目录,并赋值给ent, 同时判断是否目录为空,不为空则执行循环体
{
if (ent->d_type&DT_DIR)
/*读取 打开目录的文件类型 并与 DT_DIR进行位与运算操作,即如果读取的d_type类型为DT_DIR
(=4 表示读取的为目录)*/
{
if (strcmp(ent->d_name, ".") == || strcmp(ent->d_name, "..") == )
//如果读取的d_name为 . 或者.. 表示读取的是当前目录符和上一目录符,
//则用contiue跳过,不进行下面的输出
continue;
sprintf(childpath, "%s/%s", path, ent->d_name);
//如果非. ..则将 路径 和 文件名d_name 付给childpath, 并在下一行prinf输出
//printf("path:%s\n",childpath);原文链接这里是要打印出文件夹的地址
traverseFileandCount(childpath, dictionary);
//递归读取下层的字目录内容, 因为是递归,所以从外往里逐次输出所有目录(路径+目录名),
//然后才在else中由内往外逐次输出所有文件名
}
else
//如果读取的d_type类型不是 DT_DIR, 即读取的不是目录,而是文件,
//则直接输出 d_name, 即输出文件名
{
//cout<<ent->d_name<<endl; 输出文件名
//cout<<childpath<<"/"<<ent->d_name<<endl; 输出带有目录的文件名
sprintf(childpath, "%s/%s", path, ent->d_name);
//你可以唯一注意的地方是下一行
//目前childpath就是你要读入的文件的path了,可以作为你的读入文件的函数的参数
count(childpath, dictionary);//这里就是你的处理文件的接口!,
}
}
}
先声明一点:这位同学加这么多注释并不是他的编程习惯,只是为了其他使用这段程序的同学更好懂。
我们来看一看这些注释,很明显,介绍这段程序功能的是注释而非代码!而且,每一句都有注释,降低了程序的可读性和简洁性。如果这段程序出现在我的代码当中,估计助教会疯掉。下面我稍微修改一下这个程序。
#define childPathLength 512 //tranverse file recursively
void traverseFileandCount(char* path, struct alphaArray* dictionary)
{
DIR *filePoint;
struct dirent *fileInfo = BULL;
char childPath[childPathLength]; filePoint = opendir(path);
memset(childPath,,childPathLength);//init the childPath array with 0 while((fileInfo=readdir(filePoint)) != NULL)
{
if(isDirectory(fileInfo))
{
if(isPresentOrPriorDirectory(fileInfo))
continue;
sprintf(childpath, "%s/%s", path, ent->d_name);//create new path
traverseFileandCount(childpath, dictionary);
}
else
{
sprintf(childpath, "%s/%s", path, ent->d_name);//create new path
count(childpath, dictionary);
}
}
} bool isDirectory(struct dirent *fileInfo)
{
return fileInfo->d_type&DT_DIR;
} bool isPresentOrPriorDirectory(struct dirent *fileInfo)
{
return strcmp(ent->d_name, ".") == || strcmp(ent->d_name, "..") == ;
}
首先,变量命名上我使用filePoint来表示指向文件的指针,使用fileInfo表示读取的文件信息。这样即使读者不知道DIR和dirent究竟是什么,也可以通过变量的名字猜出来变量的作用。如果此处使用注释,那么当读者看到下面的程序的时候(比如ent->d_type),可能会疑惑这个ent是什么,为了弄明白这个变量的意思,读者不得不返回定义的地方去看。相比之下,filePoint和fileInfo则清楚许多。
接着,我将ent->d_type&DT_DIR和strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0两句比较难懂的话包装成了两个函数,通过函数名来解释它们的作用。当读者读到isDirectory(fileInfo),更容易想到这个函数是用来判断这个文件路径是否是目录的,读到isPresentOrPriorDirectory(fileInfo)的时候,也会大致知道这个函数是判断这个文件路径是否是当前目录或者上一级目录。这样的做法虽然多出了两个小函数,但是省掉了文字注释,提高了程序的可读性,我觉得更好一点。
其他地方,我保留了初始化子路径数组的注释和创建新路径的注释,因为memset和sprintf这两个函数可能有些人不知道。我也试图将其包装成一个函数,但是由于要传输3个参数,这样很大的降低了可读性,所以没有这么做。
第五章 格式
这一章从垂直格式和水平格式两方面告诉读者如何构建一个良好的程序格式。
- 垂直方向,采取从上到下的编程模式。被调用函数紧跟在被调用函数后面。
- 水平方向,注意缩进要清晰,变量定义无需对齐,一行代码不要过长。
下面看一下第一次个人作业我的主函数。
int main()
{
char filePath[filePathLength];
struct alphaArray dictionary[alphabet];
struct wordStatisticsResult topFrequencyWord[topFrequencyWordNum];
struct phaseStatisticsResult topFrequencyPhase[topFrequencyPhaseNum];
dictionaryInit(dictionary);
getFilePath(filePath);
traverseFileandCount(filePath, dictionary);
outputResult(dictionary);
topFrequencyWordStatistics(dictionary, topFrequencyWord);
topFrequencyPhaseStatistics(dictionary, topFrequencyPhase);
outputToFile(filePath,topFrequencyWord, topFrequencyPhase);
dictionaryDestroy(dictionary);
return ;
}
我现在很喜欢这种编程方法:在主函数里面将不同的功能分块,然后逐个实现,实现过程中不断细分功能模块。这样从上到下的编程很高效,很清楚,而且程序阅读起来也有条理。垂直格式上我自认为做得不错,可是水平格式上就丑了许多。
(page->wordArray + hash)->wordStr = (char*)realloc((page->wordArray + hash)->wordStr, sizeof(char)*((page->wordArray + hash)->strlength) * );
很丑是吧。(page->wordArray + hash)->wordStr实在是太长了,为什么不用tempWordStr代替呢?第一次作业时间有点紧张所以没有优化,下次我会注意的。
良好的垂直和水平格式会使你的代码更清晰美观。试想一下有良好格式的代码是一位三围比例合适的美女,你忍心自己写出的代码是一位身体比例不协调的丑女吗?所以,一定要在这方面下功夫,你的程序会因此赏心悦目。
第六章 对象和数据结构
由于Java还不怎么会用,所以这一部分也是囫囵吞枣的读了一遍。大致意思就是,尽量抽象类的接口,将类内部的情况隐藏起来,问了同学,说这样做可以减少耦合。
第七章 错误处理
同样,在c里面没用过try/catch进行错误处理,所以这一部分也不是很明白。只记得里面说先写try/catch语句定义好范围,然后编写细节部分。
注:以上代码以及修改只是我现在能做到的水平,如有不足欢迎指点!
代码整洁之道读书笔记(Ch4-Ch7)的更多相关文章
- 我读<代码整洁之道>--读书笔记整理
第一章 整洁代码 "我可以列出我留意到的整洁代码的所有特点,但其中有一条是根本性的,整洁的代码总是看起来像是某位特别在意他的人写的.几乎没有改进的余地,代码作者设么都想到了,如果你企图改进它 ...
- 《代码整洁之道》ch1~ch4读书笔记 PB16110698 (~3.8 第一周)
<代码整洁之道>ch1~ch4读书笔记 <clean code>正如其书名所言,是一本关于整洁代码规范的“教科书”.作者在书中通过实例阐述了整洁代码带来的种种利处以及混乱代码 ...
- 《代码整洁之道》ch5~ch9读书笔记 PB16110698(~3.15) 第二周
<代码整洁之道>ch5~ch9读书笔记 本周我阅读了本书的第5~9章节,进一步了解整洁代码需要注意的几个方面:格式.对象与数据结构.错误处理.边界测试.单元测试和类的规范.以下我将分别记录 ...
- <读书笔记> 代码整洁之道
概述 1.本文档的内容主要来源于书籍<代码整洁之道>作者Robert C.Martin,属于读书笔记. 2.软件质量,不仅依赖于架构和项目管理,而且与代码质量紧密相关,本书提出一 ...
- <代码整洁之道>、<java与模式>、<head first设计模式>读书笔记集合
一.前言 几个月前的看书笔记 ...
- 《代码整洁之道》(Clean Code)- 读书笔记
一.关于Bob大叔的Clean Code <代码整洁之道>主要讲述了一系列行之有效的整洁代码操作实践.软件质量,不但依赖于架构及项目管理,而且与代码质量紧密相关.这一点,无论是敏捷开发流派 ...
- 如何写出如散文般的代码――《代码整洁之道》读书笔记(Ch1-Ch3)
不知道有多少人像我一样,程序出现问题时添加函数添加变量解决,变量名用a,b,c等"简单"的字母来表示.不知道有多少人像我一样,看完自己的代码,心里暗骂"什么玩意儿!&qu ...
- Programming好文解读系列(—)——代码整洁之道
注:初入职场,作为一个程序员,要融入项目组的编程风格,渐渐地觉得系统地研究下如何写出整洁而高效的代码还是很有必要的.与在学校时写代码的情况不同,实现某个功能是不难的,需要下功夫的地方在于如何做一些防御 ...
- 《代码整洁之道》&《程序员的职业素养》
这是why技术的第32篇原创文章 春节期间读了两本技术相关的书籍:编程大师Bob大叔的<代码整洁之道>和<代码整洁之道:程序员的职业素养>. <代码整洁之道>出版于 ...
随机推荐
- Secondary NameNode究竟是做什么的
Secondary NameNode:它究竟有什么作用? 在hadoop中,有一些命名不好的模块,Secondary NameNode是其中之一.从它的名字上看,它给人的感觉就像是NameNode的备 ...
- 第3章—高级装配—条件化的Bean
条件化的Bean 通过活动的profile,我们可以获得不同的Bean.Spring 4提供了一个更通用的基于条件的Bean的创建方式,即使用@Conditional注解. @Conditional根 ...
- ele
vue饿了么app项目实战视频 5-1 1.项目代码规范修改.
- nginx安装及其配置详细教程
1 nginx 介绍 1 什么是nginx Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器. 由俄罗斯的程序设计师Igor Sysoev所开发,官方 ...
- JavaScript数据结构-2.排序算法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Struts2 ongl内存结构
valuestack是OgnlValueStack的实现,而OgnlValueStack是基于ValueStack的实现 valuestack的内存结构为: 里面主要的为:context和root r ...
- 什么是 JWT -- JSON WEB TOKEN
看链接:http://www.jianshu.com/p/576dbf44b2ae 来个工具类: import java.io.Serializable; import java.util.Date; ...
- 前端工程师的mysql笔记
背景 最近常参与后台php项目,虽说刚毕业时自学过一阵子php和mysql,不过长时间没用也忘差不多了,于是把mysql再温习一遍,前端同学也可以一起学习下! mysql安装以及操作 安装 brew ...
- SSIS教程:创建简单的ETL包 -- 4. 增加错误处理流程(Adding Error Flow Redirection)
为了处理在转换过程中可能发生的错误,MicrosoftIntegration Services 允许根据每个组件和每个列来决定如何处理无法转换的数据. 可以选择忽略某些列中的失败.重定向整个失败的行或 ...
- php常用的时间函数
测试环境:php5.3.29 unix时间戳(从Unix 纪元(January 1 1970 00:00:00 GMT)到给定时间的秒数.).以下简称时间戳. 设置默认时区 date_default_ ...