代码的颜值---格式化(clean code阅读笔记之四)

代码的颜值很重要

_注:正文中的引用是直接引用作者Bob大叔的话,两条横线中间的段落的是我自己的观点,其他大约都可以算是笔记了。 _


从这一章的第一段就能看出来,Bob大叔对格式化是非常看重的,他连着使用了几个排比句来说明代码的格式化对于一个工程作为一个整体的重要性。所有的代码---不论是一个人不同时期写的代码,还是一个团队不同的成员写的代码---都应该是一致的、优雅的。

为什么要格式化

代码的格式化直接影响到「使用代码沟通」的问题,而「使用代码沟通」是一个专业的开发者的第一要务,而不是「只要能让代码能运行起来就行」。

你今天写的功能可能不久之后就会需要被更改,但是代码的「可读性」将会对「未来代码的修改或重构」产生深远的影响。

接下来是一些对「使用代码沟通」能力有影响的方面:

垂直方向上的格式化

垂直方向上的格式化简单说就是代码的长度。

我们在开发的过程中应该尽量去追求写出较小的代码源文件,作者给出了一个参考值是:「大多数的文件应该都小于200行,最长的文件最好要小于500行」。但是作者也说这条规则不应该成为一个硬性的标准,而是我们在开发过程中不断追求的境界。毕竟有时我们不可避免地必须写出一些比较长的源文件。

1. 报纸的比喻

一个源文件读起来应该像报纸里的文章一样,名字应该简短但能表达文章的基本意思,源文件刚开始的部分应该能够提供一些高层的抽象和算法,然后具体的实现细节在接下来的章节中依次展开,直到源文件的最后,在那里我们能找到最低等级的函数和最细节的实现。

一张报纸(一个项目)会有很多文章(源文件)组成,大多数都很短,偶尔有一些稍微有些长,极少数的情况也会出现占据整个页面的长度的文章。

2. 不同概念之间的垂直间隔

在源文件中不同的概念(往往指的是函数)之间应该使用空行来隔开,这样在读者阅读这段代码时会非常舒服。

3. 垂直聚集

与上一条中阐述的内容刚刚相反,相似或者相关性较强的概念之间往往不应该有分隔(往往是注释,或者是无意义的空行),而应该聚集在一起。

4. 垂直距离

我们经常会碰到这种情况,我们阅读代码时迷失在了寻找「变量与变量间、函数与函数间、类与类之间的关系」的过程中不能自拔,大量的时间花在了寻找「那段代码在哪里」。

相近的概念应该在垂直距离上尽量接近,相似的概念应该尽量存在于同一个函数(除非你有比较好的原因不去这么做),protected的变量应该被禁止使用(这条可能在某些语言里不存在)。

变量的定义 应该尽量靠近它被使用的地方。

实例变量(instance variable) (类的动态变量)应该被定义在类的起始。

不论是遵循「剪刀原则」,将实例变量定义在类的最低端,还是根据Java的惯例,将实例变量定义在类的最顶端,都是好的。但请不要把实例变量放在除了这两种之外的其他位置。

有依赖关系的函数 应该在垂直的距离上尽量靠近,而且往往调用者应该在被调用者的上边(如果可能的话)。

概念上关系较密切的代码 应该根据他们关系的密切程度来选择他们间的距离

5. 垂直排序

垂直坐标上的元素(可能是代码块,函数,变量等)应该按照自上而下的阅读顺序进行排列,这样更易于阅读。

水平方向上的格式化

作者对于一些典型的应用(Junit, FitNesse, testNG, Time and Money, JDepend, Ant, Tomcat)的行的宽度进行了统计,绝大多数的宽度都在60个字符以下,大于80个字符以上宽度的占比非常小。通常的说,代码的行宽应该小于100或120。

1. 水平的间隔和聚集

作者在这个小节里说了一个比较微妙的事物---空格,因为要使用空格来区别水平方向上的不同概念


//代码4-1
private void measureLine(String line) { 
    lineCount++;
    int lineSize = line.length();
    totalChars += lineSize;             
    lineWidthHistogram.addLine(lineSize, lineCount);        recordWidestLine(lineSize);
}

在水平方向上,作者主张在强相关的元素之间不使用空格,而在弱相关的元素之间添加空格来予以区分,比如代码4-1。

  • 赋值语句的左右是两个区别很大的部分,那么使用空格来突出赋值操作符(就是= )并对赋值语句的左右两部分加以区分。
  • 函数名和左括号之间是十分相关的,所以就不使用空格
  • 参数之间的逗号分隔符之后使用空格,用以突出分隔符并区分两个不同参数。
2. 水平对齐

有些人(包括Bob大叔自己早期)喜欢在有一堆的变量定义或赋值语句时,使用对齐来使代码变得更易读,但这样是没有用的。使用这样的对齐会喧宾夺主,把代码阅读者的阅读重心吸引到了错误的地方。

//代码4-1
public class FitNesseExpediter implements ResponseSender 
{
    private     Socket            socket;
    private     InputStream      input;
    private     OutputStream        output;
    private     Request          request;
    private     Response            response;
    private     FitNesseContext  context; 
    protected   long                requestParsingTimeLimit;
    private     long                requestProgress;
    private  long               requestParsingDeadline;
    private  boolean             hasError;
                     
    public FitNesseExpediter(Socket              s,
                             FitNesseContext    context) throws Exception
    {
        this.context =            context;
        socket =                    s;
        input =                  s.getInputStream();
        output =                   s.getOutputStream();
        requestParsingTimeLimit =   10000;
    
    }

如果你的代码中出现了很长的变量定义或赋值语句列表,长到需要使用左对齐来使它们更易读,那么主要问题应该是你的代码中不应该出现这么长的变量定义或赋值列表,而不是缺少了左对齐

3. 缩进

源文件里的内容与其说是「提纲和内容」的关系,不如说是「层级」关系。

在代码中,要传达的信息之间的从属关系从文件到类、类到方法、方法到代码块、代码块到子代码块,逐级往下,为了区分这种层级,开发者非常喜欢使用代码的缩进来使代码更加易读。


缩进 是代码质量管理里很重要的一环,我个人比较喜欢使用制表符(TAB,往往是4个空格)来标识缩进,然而我有个同学就特别喜欢使用2个空格来表示缩进,这种事情仁者见仁智者见智。


不要破坏缩进(breaking indentation)。谨记一定要使用缩进。
有时候一个if语句或者for循环代码块或者函数非常小,开发者会觉得不需要使用缩进,而把大括号,执行语句等都写在同一行,如代码4-4中所示,这种是必须要避免的。

//代码4-3
public class CommentWidget extends TextWidget {
    public static final String REGEXP = "^#[^\\r\\n]*(?:(?:\\r\\n)|\\n|\\r)?";
    public CommentWidget(ParentWidget parent, String text){super(parent, text);}
    public String render() throws Exception {return ""; } 

}
4. 空语句

我个人非常不喜欢空语句,并且在开发过程中是会尽力避免使用空语句的,如果我不得不使用它,也一定会加上大括号并且使用缩进来让代码更易读。

团队规则(Team Rules)

如果一个项目是一个团队协同开发,那么团队中的每个人都要遵循这个团队定下来的格式化要求,来保证一个项目中的格式是顺滑的、一致的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容