一周技术思考(第22期)-编程的基本礼节

大家好,这里记录,我每周读到的技术书籍、专栏、文章以及遇到的工作上的技术经历的思考,不见得都对,但开始思考总是好的。

 

编程礼节

 

 

这个词,我武断地下个结论,估计你很少听到。

 

在上周的技术思考那篇文章中,我们提到程序员之间最经常使用的沟通媒介是代码,程序员之间的互相尊重也体现在代码里面。

 

代码也是一种给人看的文档,而文档的本质在于交流。

 

在编程中,良好的交流意味着读代码的人能够理解、修改和使用代码。

 

另外,我们也提到,Bob大叔在《代码整洁之道》这本书中,曾说过,“人们说脏话的频率是衡量代码质量的唯一标准”。

 

那么肯定没有比吐脏字,表现的更不尊重了吧。

 

到底发生了什么,能让你到了[骂人]的地步了呢。

 

我们一起想想看,是不是,无论什么形式的沟通,最基本和最初级的尊重表现形式,肯定莫过于礼节了,对吧,如果你的代码呈现出的“编程礼节”总是带有“微笑”的表情,是不是就能起到程序员之间交流时候的润滑剂效果呢。

 

那怎么样才能让我们的代码看上去是“笑脸相迎”呢,我们说的编程里面的这种“礼节”,具体的表现形式又是怎样的呢。

 

 

礼节一:编写“养眼”的代码

 

我说,最“表面层次”的礼节,就是,把我们的代码“打扮”的干净、利索、整洁

 

图1

 

让我们一起来看看下面三段代码。

 

这三段代码的内容都是一样的,这里的“一样”,是说,我们的PerFormanceTester这个类需要3个不同的TcpConnectionSimulator实例,而这三段代码都完成了这个任务。

 

这三段代码又是不一样的,这里的“不一样”,是说,你所看见的,如它们的换行、排版、注释多少都是不一样的。

 

代码段1

 

 

代码段2

 

代码段3

 

好了,当读到这里,你应该把上面三段代码都看完了,你觉得哪段代码更让人悦目呢。

 

你肯定不会选择代码段1的,那个排版首先就让人不舒服,你可能会说,代码段2看上去已经很可以了,格式整齐,是的,在整洁性上,它比代码段1肯定强了不少,你再看看代码段3呢,它又把代码段2中的重复性注释,都规整到一行里面了,这样是不是“看上去更养眼”很多呢。

 

要想让源代码“看上去养眼”,这里有三条技巧性原则送给大家。

 

使用一致性的布局,让读你代码的程序员很快就习惯这种风格。

让相似的代码看上去相似。

把相关代码行分组,形成代码块。

 

一段具有良好可读性的代码,它的首要条件,也是要具备整洁性第一,或者索性我们就管它叫做“整洁性第一”原则。我个人觉得这个叫法,也未尝不可的。

 

如果,你遵循上面我们说的那三个“养眼”原则。你选择好的变量命名,写好的注释,把代码整洁地写成更好的格式。这样,当别人读你代码的时候,会感到很轻松,也能很快速地理解你所写代码的含义,而且,这个“别人”也很有可能是几个月之后的你

 

礼节二:编写“浅栈”的代码

 

这里的“栈”,指的是“思维栈”,“浅栈”也就是不需要怎么思考,就能很轻易地理解。反应到一段代码上面,也就是可读性强。

 

一团乱糟糟的代码,肯定会阻碍你进行阅读,就像上面那副漫画所展现的那样,你去哪里找你想要的档案呢。更不用提,读完代码,还需要继续在原来代码的基础上做修改和添加新的功能了。找代码都找不到的情况下,又如何添加新功能,你想想,是不是。

 

可读性基本原则:

 

代码的写法应当使别人理解它所需要的时间最小化。

 

让我们来看两段代码,你认为哪种方式更容易阅读和理解呢?

 

if(length >= 10)

还是

 

if(10 <= length)

 

这一段又是哪种写法更容易阅读呢?

 

while (bytes_recevied < bytes_expected)

还是

 

while(bytes_expected > bytes_expected)

 

都是第一种方式,对么,为什么都是一种方式那样的写法?

 

在《编写可读代码的艺术》一书中的第七章有一条指导性的原则:

 

 

你或许觉得这样有点牵强,可根据我们看到的这个原则,它也是符合一定心理学基础原理的,不是么。

 

那好,我们看下面这段代码,估计你的感觉就会更近些了。

 

if(a == b){     //Case one ...} else{   //Case two ...}

还是

 

if(a != b){     //Case tow ...} else{   //Case one ...}

 

更容易阅读和理解呢。

 

还是第一种方式,对不对,这又是什么原理呢,还真有个原理:

 

首先处理正逻辑而不是负逻辑的情况。

 

我们上面所举的代码的例子虽然都很简单,但它足以说明问题,你会发现第一种方式都比第二种方式更简单,这也是阅读起来更容易理解的保证。不要把代码写复杂,有时候一些年老的,或者号称经验丰富的程序员,故意把代码写的相对“复杂”,不然似乎体现不出他的专业性。

 

比如,拿我们常用的三目运算符来举例。

 

if(hour >= 12){     time_str += "pm";} else{   time_str += "am";}

这样是不是很好理解,可是“专业”程序员,会这样写。

 

time_str += (hour >= 12) ?"pm" :"am";
 

你说,也容易阅读呀,那如果碰到下面这样的呢。

我们首要目的,是要把代码写的简单。

 

相对于追求最小化代码行数,一个更好的度量方法是最小化人们理解它所需的时间。

 

Bug喜欢出现在复杂的地方。

 

如果软件代码出现线上问题,经验告诉我们这些问题常常会集中在某一个区域,这些区域都有一个共同的特点,那就是复杂。

 

编写代码时如果追求简单易懂,代码就很难出现问题。

 

到这里相信你已经对什么是可读性的代码有来自己一定的理解。

 

接下来,为了让大家的可读性理解印象更深刻,我们再”加点料“,我为大家准备来下面这两段关于if嵌套代码例子。

 

代码段4

 

代码段5

 

关于可读性这块,最后问你,代码段4和代码段5,哪个更容易阅读理解呢。

 

答案当然是代码段5,当你读代码段4的时候,很是考验你的“心智消化系统”,每个嵌套层次都会在你的“思维栈”上又增加一个条件

 

通过提早返回,来减少嵌套。

 

礼节三:编写“有型”的代码

 

优质代码都有型,开发优质的软件需要基本技法作为支撑。

 

我一周去健身房的次数基本在4次以上,起初我锻炼的目的是为了让自己看上去不是那么瘦弱,强壮些更好。但随着我对健身的深入理解,后来我的目标就变成了,让自己的体态看上去匀称,也就是有点“型”,那如果让自己的体态变好,我一般就是练三个部位,胸、背和腿,这些是撑起一个人良好体态的基础“模块”

 

为了练好身体的这些模块,我会选择比如使用杠铃卧推、坐姿推胸、器械飞鸟等动作练胸,使用高位下拉、坐姿划船、俯身划船等动作练背,使用杠铃深蹲、箭步走、杠铃硬拉等动作练腿。

 

那代码如果要有”型“应该锻炼哪些“意识部位”呢,我个人认为在面向对象编程领域里,有基本的三个“部位”是一定要锻炼的,那就是封装、继承和多态。

 

为了练好面向对象编程的这些模块,我们有什么动作呢。根据《编程的原则》一书中给出的建议,我们有以下10个动作。

 

抽象

封装

信息隐藏

打包

关注点分离

充足性、完整性、原始性

策略和实现的分离

接口与实现的分离

单一引用点

分治

 

正如我健身的时候,为了有效锻炼,我肯定要选择更有效的动作,来达到体型的锻炼,面向对象编程我们也会有被人们使广泛的动作,我从中选择来抽象、封装、关注点分离来跟大家做一个沟通。

 

因为大家已经有相当多的面向对象编程的实践经历了,我这次并不打算在这篇文章中像上面那样列举一些代码段,我计划也“抽象”一次,给你一次“三行而后思”的机会。

 

抽象

抽象的反面是具体,我们日常中接触到的事物基本都是具体的,如果面向具体编程,把一个一个的具体事物通过编程的方式实现出来,这样将会耗费我们无穷的精力和时间。为了提高我们解决问题的思考效率,就需要我们在各个具体的事物之间进行不断总结,从具体的对象中抽出共同的性质,再将其固定为更加通用的概念,设计模式也是这么来的

 

抽象是人们在处理复杂事物时使用的基本手段,在思考效率上,抽象远胜于具体。

 

封装

程序的组成包括数据和逻辑,我们把相互关联的数据和逻辑分到一组,再定义为一个模块,这就是封装。这样一来,一个一个的模块都是独立的“零件”,我们就有机会去重复使用它们。同时呢,当我们将来有需求过来,要涉及到修改这些模块中的代码的时候,这些修改带来的影响也都会被限制在这些模块内部。

 

有了关联性很强的数据组成的数据结构,以及关联性很强的逻辑组成的函数群之后,我们便能获得更简洁且高质量的模块了。

 

分离

这里说的分离就是关注点分离。所谓关注点,也就是我们程序要实现的功能和目的。我们把各个关注点相关联的代码集中在一起放入独立的模块,这种方式就是我们践行关注点分离的动作。

 

那这里的模块,不就是上面所说的封装的产物么,其实,大家只要意识到这一点也就说明对封装有了更进一步深刻的理解。只谈封装,其实只是做到了模块化的第一步,当谈到关注点分离的时候,就是我们模块化的第二步。

 

关注点分离中最具代表性的模式,莫过于是“模型视图控制器”(ModelViewController,MVC)。以关注点为单位创建的模块,会要求我们把不同的和不相关的代码以及功能分开,比如这个MVC的模式。

 

如果一个模块在不同前提下有不同的功能,我们就需要分割模块,让各个模块处于独立的状态。

 

 

恭喜你,又完成一次思考。

 

 

参考资料:

1、图1、代码段1、代码段2、代码段3、代码段4和代码段5引自《编写可读代码的艺术》;

2、漫画人像图来自网络;

忆往期:

架构六大思维养成记

你好,我是前台,再给你引荐下XY台

工作十几年,开了上千个会,该说说了

一个年老代程序员午后谈谈架构和架构师

如何让软件姓“软”

一文一点 | 给你一份实现业务复用的指南

这个假期我通过【得到】得到了什么

一文一点 | 什么才是复用的最高等级

一文一点 | 系统从高可用到高不可用都经历了什么

4000字8分钟带你理解Serverless架构

考虑系统扩展性时仅仅理解AKF立方体是不够的

全面详解互联网企业开放API的 “守护神”

从HTTP/1.1到HTTP/2,让WEB性能更上一层楼

我的第6个京东618

上班十年后我发现可以这样边工作边学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值