前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >读《代码整洁之道》

读《代码整洁之道》

作者头像
oec2003
发布2019-07-19 17:43:31
8490
发布2019-07-19 17:43:31
举报
文章被收录于专栏:不止dotNET不止dotNET不止dotNET

什么是整洁代码

代码的质量非常重要,糟糕的代码有可能会毁了一个公司。对于一个很注重代码质量的人来说呆在一个只关注交付而不关注代码质量的公司是很痛苦的。

什么是整洁的代码,不同的人又不同的定义。我认为整洁的代码应该是符合所使用语言代码规范的;可复用的;便于维护的;简洁的。

糟糕的代码想做太多的事情,意图混乱;整洁的代码的每个函数、类和模块都全神贯注一件事,不受周围的干扰,也就是设计原则中的单一原则。

命名的艺术

命名随处可见,变量、函数、类、模块、命名空间等都需要有好的命名。一个名称如果能让阅读者一看就知道要表达的意思,就可以认为是一个好的名称。

不要使用单个字母来做变量名,时间一长,自己都不清楚自己当初的命名是什么意思。小方法体,如循环中的计数器除外。

不要使用有误导性的字母作为变量名,比如小写字母l和大写字母O,因为他们和数字的一和零很像,有的字体还比较好区分,但大多数字体很难分辨。

「匈牙利命名法(HN)」:该命名法是一位叫 Charles Simonyi 的匈牙利程序员发明的,后来他在微软呆了几年,于是这种命名法就通过微软的各种产品和文档资料向世界传播开了。在当时那个时代编译器并不做类型检查,程序员需要使用HN来帮助自己记住类型。现在的高级静态编程语言具有更丰富的类型系统,编译器可以很好的做类型检查,所以使用NH纯属多余。使用NH的几个弊端:

  • 增加了名称的长度
  • 使名称变得不可读
  • 增加了修改名称的难度,修改了变量的类型,变量名就要随着修改,否则会造成误导。

书中讲到对接口的命名不要使用“I”作为前缀,这点我持保留意见,可能因为我一直是从事的.NET上的开发,.NET的类库中的接口基本都是使用“I”作为前缀的,而且在《NET 设计规范》一书中也强调接口要使用“I”作为前缀。

对于方法名做到每个概念一个词,应该保持一致,比如对于绑定数据的方法,不要有的地方用BindData,而另一些地方使用DataBind,总之做到在整个代码中保持风格一致。

最后想说的是命名除了一些通用的法则外,对于一些规范性的问题还是要遵循所使用语言或平台规定或是约定俗成的惯例。比如方法名C#中推荐使用Passcal风格,而在Java中则是使用Camel风格。

函数

函数一直都被要求要短小,有不少书中都以行数来作为标准,比如一个行数在20行以内被称为小函数,或是要在5行以内才是小函数。以行数来要求似乎有些苛刻,有一些极端的情况,比如初始化一个Model,里面有几十个字段,这时这个初始化函数中就有几十行代码,而且是无法拆分的,所以我认为,函数只要是在做一件事情就可以了。通常来说如果函数只做一件事,自然就不会很长。我对函数长度的极限是横竖都不要超过一屏。

函数应该只做一件事,判断函数时候只做一件事,看函数中是否很能够拆分,如果可以,就果断进行重构。

当函数中有Swicth语句的时候,就不可避免的要做多件事情了,而且函数会随着Switch条件的增加会越来越长。因为函数中做了多件事情,违反了SRP原则,因为随着增加条件我们要去修改这个函数,违反了OCP原则。这个问题可以通过工厂模式来解决。

函数的名称要使用描述性的名称,让人一看名称就知道该函数是做什么的。当函数只做一件事情的时候,取名就容易多了。还有比较重要的一点,风格要保持一致。

在一个函数中不要去调用职责之外的另外的函数,尤其是底层的函数,否则给高层调用带来风险。举个简单的例子:比如在用户登录的时候我们可能会有一个CheckPassword的方法来验证登录的用户名和密码,如果在CheckPassword函数中在验证成功后调用Session.Init()来对Session进行初始化,就会存在隐患。根据名称来看只是检查密码用,如果有人在非登录的情况下调用了该方法,会更改当前会话。

使用异常代替错误返回码,如果使用错误返回码会要求立即处理错误,当在高层调用很多底层方法时,每个方法都要去根据错误返回码进行处理,会造成函数逻辑混乱,如果使用异常处理则只需要在catch中处理即可。

远离重复,拒绝重复,方法有很多,抽象到基类或放到底层公共类库中。

没有人能一次性就将函数写的很完美,好的函数是通过重构得到的。

注释

注释是一把双刃剑,好的注释能够给我们好的指导,不好的注释只会将我们误导。注释是弥补代码中表述不足的一种手段,就像设计模式是用来弥补语言不足一样。

代码是我们获取信息的准确来源,注释随着项目人员的更替 反复的修改最终可能词不达意了,因为很多开发人员在整合代码,修改方法的时候常常不会修改注释。

有时候看到一个函数的代码写的很糟糕,逻辑很混乱,有开发人员可能想,给这个函数加上几行注释,这样有可能起到适得其反的作用,这时要做的是将函数整理干净。

代码即注释,很多书和大师都这么讲,意思是我们要用代码本身来解释我们的意图,那就要求我们要控制好函数只做一件事,函数名和变量名要规范和可读。

当然也不是所有的注释都没有用,像下面几种类型的注释是有必要的:

  • 具有警示性的注释
  • 描述一些负责业务场景
  • 有些函数现在还是一个空壳,但在将来可能有用,有必要写

当我们不得不写一些注释的时候,要确保言简意赅,能够很好的表达意思,不要造成误解,也不要写多余的废话。

还有一种日志被称为日志式注释,一般出现在一个类的开始部分,记录每次修改时的时间、人员名称和修改内容。随着时间的推移这类注释会变得非常冗长。这类注释在一些项目中很普遍,而且有时会被严格要求写,但书中强调现在的源代码都会有源代码工具来进行管理,修改记录在源代码工具中有保存,这种日志式的注释应该全部删除。

有的开发人员喜欢在注释中签上自己的名字,这种做法也没没有必要,因为我们有源码管理工具。

项目代码中经常会出现被注释掉的代码,这对后面的维护人员会造成困扰,也会使代码变得混乱,这种代码同样可以删掉,因为我们有源码管理工具。

错误处理

错误处理简单来说就是当软件出现错误时还能正常工作。错误处理很重要,但不能打乱的原本的代码逻辑。

使用异常处理而非返回码,底层往上抛,最上层集中处理。这点在函数相关章节中也提到过,之所以看到有的地方是使用错误返回码,是因为早期的一些语言没有异常处理机制,现在的语言基本都有异常处理机制。

异常的信息应该足够充分(包含出错的位置以及原因)。

不要在catch块中去实现业务逻辑,就是说当出现异常的时候一定要抛出,而不要改变状态或是做其他一些操作,这样会留下很多陷进。

底层的方法不要返回Null值,否则在调用时会添加很多的判断,可以抛出异常或返回特例对象,特例对象是指返回一个函数返回值类型的空对象。

在最上层捕获了异常后,记录日志,给出相应的友好结果反馈,千万切记不要再往上抛了,例如:一个控制台程序,如果在Main函数中捕获到异常再往上抛出,控制台程序就崩溃了。

单元测试

我工作以来所经历的公司中都很少使用单元测试,以致于我现在对单元测试这方面还不是特别熟悉,只是在自己的个人项目中写过一些单元测试的代码。在.NET平台下可以使用VS自带的单元测试功能或是NUnit。

有一种编程的方法叫TDD(测试驱动开发),意思是先写单元测试,然后写对应的代码,通过修改调试让写的代码通过单元测试。使用TDD,会使测试覆盖所有的代码,测试代码和生产代码的比例有可能会达到1:1 ,所以也会带来成本的问题。TDD三定律:

  • 在编写不能通过的单元测试前,不可以编写生产代码
  • 只有编写刚好无法通过的单元测试,不能编译也算不通过
  • 只可编写刚好足以通过当前失败测试的生产代码

测试代码和生产代码一样的重要,也需要保持整洁。测试代码要随着生产代码的修改而修改,否则只会产生大量无用的测试代码,而且也会给生产代码的修改带来风险。

单元测试的好处:

  • 有了测试不用担心对代码的修改
  • 有了测试可以毫无顾虑的去改进架构和设计

如果您是做项目,快速满足客户需求就可以了,没有必要在项目中添加单元测试,如果是开发产品,单元测试还是非常重要的,因为产品的快速迭代就像在给高速飞行中的飞机加油一样,不能停还要保证稳定性,不能出任何问题,而单元测试是一个很好的保障。

类通常由变量、属性和方法组成。按照书中所讲的Java的约定,类应该由一组变量开始,如果有静态公共常量,应该放在前面,然后是私有静态变量和私有实体变量。公共函数跟在变量之后,一些供公共函数调用的私有工具函数在公共函数之后。

和函数一样,类也应该要尽可能的短小。但和函数不同不是以代码行数来权衡,而是以职责。如果无法准确的为某个类命名,则有可能是该类的职责过多。

单一职责原则(SRP):类或模块应该有且只有一条加以修改的理由。

在实际的工作中很多开发人员往往不会思考这么多,他们只想着让代码可以工作就可以了,所以经常出现几千行的大类。系统应该是有许多短小的类而不是少量巨大的类组成。每个小类有单一的职责,只有一个修改的原因,所有这些小类在一起协同工作完成系统的功能。

高内聚:如果一个类中每个变量都被每个方法所使用,则该类有最大的内聚性,保持内聚性得到许多短小的类,内聚性高说明变量和方法相互关联形成一个逻辑整体。

对于类要要良好的嗅觉,一个类在开始创建的时候,职责还是很单一的,但随着功能越来越复杂,参与开发的人越来越多,就可能慢慢变得臃肿,需要我们能时刻保持警惕,嗅出坏味道,并做重构。

总结

很多年前看的此书,现在翻翻还是很有帮助,好书就应该时常翻阅下,不同时期会有不同的理解。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 不止dotNET 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是整洁代码
  • 命名的艺术
  • 函数
  • 注释
  • 错误处理
  • 单元测试
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档