`
yeminping
  • 浏览: 180040 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

【转载】优秀程序员的45个习惯之25--代码要清晰地表达意图

阅读更多

代码要清晰地表达意图

—— 高效程序员的 45 个习惯之一

 

“可以工作而且易于理解的代码挺好,但是让人觉得聪明更加重要。别人给你钱是因为你脑子好使,让我们看看你到底有多聪明。”
 

Hoare 谈软件设计

C.A.R. Hoare

设计软件有两种方式。一种是设计得尽量简单,并且明显没有缺陷。另一种方式是设计得尽量复杂,并且没有明显的缺陷。

 

我们大概都见过不少难以理解和维护的代码,而且(最坏的是)还有错误。当开发人员们像一群旁观者见到 UFO 一样围在代码四周,同样也感到恐惧、困惑与无助时,这个代码的质量就可想而知了。如果没有人理解一段代码的工作方式,那这段代码还有什么用呢?

 

开发代码时,应该更注重可读性,而不是只图自己方便。代码被阅读的次数要远远超过被编写的次数,所以在编写的时候值得花点功夫让它读起来更加简单。实际上,从衡量标准上来看,代码清晰程度的优先级应该排在执行效率之前。

 

例如,如果默认参数或可选参数会影响代码可读性,使其更难以理解和调试,那最好明确地指明参数,而不是在以后让人觉得迷惑。

 

在改动代码以修复 bug 或者添加新功能时,应该有条不紊地进行。首先,应该理解代码做了什么,它是如何做的。接下来,搞清楚将要改变哪些部分,然后着手修改并进行测试。作为第 1 步的理解代码,往往是最难的。如果别人给你的代码很容易理解,接下来的工作就省心多了。要敬重这个黄金法则,你欠他们一份情,因此也要让你自己的代码简单、便于阅读。

 

明白地告诉阅读程序的人,代码都做了什么,这是让其便于理解的一种方式。让我们看一些例子。

 

coffeeShop.PlaceOrder(2);

 

通过阅读上面的代码,可以大致明白这是要在咖啡店中下一个订单。但是, 2 到底是什么意思?是意味着要两杯咖啡?要再加两次?还是杯子的大小?要想搞清楚,唯一的方式就是去看方法定义或者文档,因为这段代码没有做到清晰易懂。

 

所以我们不妨添加一些注释。

 

coffeeShop.PlaceOrder(2 /* large cup */);

 

现在看起来好一点了,但是注释有时候是用来对写得很差的代码进行补偿的(见第 105 页中习惯 26 用代码沟通

 

Java 5 .NET 中有枚举值的概念,我们不妨使用一下。使用 C# ,我们可以定义一个名为 CoffeeCupSize 的枚举,如下所示。

 

public enum CoffeeCupSize

{

  Small,

  Medium,

  Large

              }

 

接下来就可以用它来下单要咖啡了。

 

        coffeeShop.PlaceOrder(CoffeeCupSize.Largxe);

 

这段代码就很明白了,我们是要一个大杯 [① ] 的咖啡。


 

作为一个开发者,应该时常提醒自己是否有办法让写出的代码更容易理解。下面是另一个例子。

 

Line 1   public int compute(int val)

     -  {

     -     int result = val << 1;

     -    //... more code ...

     5     return result;

     -  }

3 行中的位移操作符是用来干什么的?如果善于进行位运算,或者熟悉逻辑设计或汇编编程,就会明白我们所做的只是把 val 的值乘以 2

 

      PIE 原则

      所写的代码必须明确表达你的意图,而且必须富有表现力。这样可以让代码更易于被别人阅读和理解。代码不让人迷惑,也就减少了发生潜在错误的可能。代码要清晰地表达意图。

 

但对没有类似背景的人们来说,又会如何 —— 他们能明白吗?也许团队中有一些刚刚转行做开发、没有太多经验的成员。他们会挠头不已,直到把头发抓下来 ] 。代码执行效率也许很高,但是缺少明确的意图和表现力。

 

用位移做乘法,是在对代码进行不必要且危险的性能优化。 result=val*2 看起来更加清晰,也可以达到目的, 而且对于某种给定的编译器 来说 ,可能效率更高(积习难改,见第 34 页的习惯 7 )。不要表现得好像很聪明似的,要遵循 PIE 原则:代码要清晰地表达意图。

 

要是违反了 PIE 原则,造成的问题可就不只是代码可读性那么简单了 —— 它会影响到代码的正确性。下列代码是一个 C# 方法,试图同步对 CoffeeMaker MakeCoffee() 方法进行调用。

 

Public void MakeCoffee()

{

    lock(this)

    {

      // ... operation

    }

}

 

这个方法的作者想设置一个临界区( critical section —— 任何时候最多只能有一个线程来执行 operation 中的代码。要达到这个目的,作者在 CoffeeMaker 实例中声明了一个锁。一个线程只有获得这个锁,才能执行这个方法。(在 Java 中,会使用 synchronized 而不是 lock ,不过想法是一样的。)

 

对于 Java .NET 程序员来说,这样写顺理成章,但是其中有两个小问题。首先,锁的使用影响范围过大;其次,对一个全局可见的对象使用了锁。我们进一步来看看这两个问题。

 

假设 Coffeemaker 同时可以提供热水,因为有些人希望早上能够享用一点伯爵红茶。我想同步 GetWater() 方法,因此调用其中的 lock(this) 。这会同步任何在 CoffeeMaker 上使用 lock 的代码,也就意味着不能同时制作咖啡以及获取热水。这是开发者原本的意图吗?还是锁的影响范围太大了?通过阅读代码并不能明白这一点,使用代码的人也就迷惑不已了。

 

同时, MakeCoffee() 方法的实现在 CoffeeMaker 对象上声明了一个锁,而应用的其他部分都可以访问 CoffeeMaker 对象。如果在一个线程中锁定了 CoffeeMaker 对象实例,然后在另外一个线程中调用那个实例之上的 MakeCoffee() 方法呢?最好的状况也会执行效率很差,最坏的状况会带来死锁。

 

让我们在这段代码上应用 PIE 原则,通过修改让它变得更加明确吧。我们不希望同时有两个或更多的线程来执行 MakeCoffee() 方法。那为什么不能为这个目的创建一个对象并锁定它呢?

 

Private object makeCoffeeLock = new Object();

 

Public void MakeCoffee()

{

    lock (makeCoffeeLock)

    {

      // ... operation

    }

}

 

这段代码解决了上面的两个问题 —— 我们通过指定一个外部对象来进行同步操作,而且更加明确地表达了意图。

 

在编写代码时,应该使用语言特性来提升表现力。使用方法名来传达意向,对方法参数的命名要帮助读者理解背后的想法。异常传达的信息是哪些可能会出问题,以及如何进行防御式编程,要正确地使用和命名异常。好的编码规范可以让代码变得易于理解,同时减少不必要的注释和文档。

 

要编写清晰的而不是讨巧的代码
向代码阅读者明确表明你的意图。可读性差的代码一点都不聪明。
 
切身感受

应该让自己或团队的其他任何人,可以读懂自己一年前写的代码,而且只读一遍就知道它的运行机制。

平衡的艺术

  • 现在对你显而易见的事情,对别人可能并不显然,对于一年以后的你来说,也不一定显然。不妨将代码视作不知道会在未来何时打开的一个时间胶囊。
  • 不要明日复明日。如果现在不做的话,以后你也不会做的。
  • 有意图的编程并不是意味着创建更多的类或者类型。这不是进行过分抽象的理由。
  • 使用符合当时情形的耦合。例如,通过散列表进行松耦合,这种方式适用于在实际状况中就是松耦合的组件。不要使用散列表存储紧密耦合的组件,因为这样没有明确表示出你的意图。

摘自:http://turingbooks.iteye.com/blog/548698

分享到:
评论

相关推荐

    优秀程序员45个习惯

    【优秀程序员45个习惯】是一本旨在提升程序员专业素养的书籍,由敏捷开发领域的权威Venkat Subramaniam和Andy Hunt共同撰写。这45个习惯覆盖了态度、学习、开发流程、用户、编程以及团队协作等多个方面,旨在帮助...

    程序员必备技能----断点调试(IDEA版)---- 代码

    程序员必备技能----断点调试(IDEA版)---- 代码

    【高清完整pdf】高效程序员的45个习惯 敏捷开发修炼之道

    在编码方面,书中提出了清晰表达意图、动态评估取舍、增量式编程、保持简单、编写内聚代码等核心习惯。此外,书中还提到了关于告知而非询问、根据契约进行替换等沟通与协作方面的建议。 调试是软件开发过程中不可或...

    优秀程序员的十个习惯

    【优秀程序员的十个习惯】 1. 持续学习与跟进新技术:作为优秀程序员,保持对新知识的渴望至关重要。不断学习新的编程语言、框架和工具,关注行业动态,参与专业社区讨论,如CSDN、ITPUB、CHINAUNIX、digg.com等,...

    程序员简历模板10份-蓝色主题

    程序员简历模板10份--蓝色主题 各不相同 程序员简历模板10份--蓝色主题 各不相同 程序员简历模板10份--蓝色主题 各不相同 程序员简历模板10份--蓝色主题 各不相同 程序员简历模板10份--蓝色主题 各不相同 程序员简历...

    WINDOWS程序员使用指南(三)----OLE_DDE

    WINDOWS程序员使用指南(三)----OLE_DDEWINDOWS程序员使用指南(三)----OLE_DDE

    WINDOWS程序员使用指南(五)----OBJECT WINDOWS库

    WINDOWS程序员使用指南(五)----OBJECT WINDOWS库WINDOWS程序员使用指南(五)----OBJECT WINDOWS库

    程序员简历模板10份-蓝色主题 各不相同

    程序员简历模板10份--蓝色主题 各不相同 程序员简历模板10份--蓝色主题 各不相同 程序员简历模板10份--蓝色主题 各不相同 程序员简历模板10份--蓝色主题 各不相同 程序员简历模板10份--蓝色主题 各不相同 程序员简历...

    《Visual C++程序员成长攻略》-戴博-源代码-4566-NEW

    《Visual C++程序员成长攻略》-戴博-源代码-4566-NEW

    一个优秀的程序员的十个习惯

    7. **注重文档编写**:编写清晰的代码注释和文档是优秀程序员的重要习惯。文档不仅是自我记录,也是团队间的知识传递,有助于提高团队效率和项目的可维护性。 除此之外,还有其他几个关键习惯: 8. **测试驱动开发...

    简历模板-程序员-通用-精选

    简历模板-程序员-通用-精选简历模板-程序员-通用-精选简历模板-程序员-通用-精选简历模板-程序员-通用-精选简历模板-程序员-通用-精选简历模板-程序员-通用-精选简历模板-程序员-通用-精选简历模板-程序员-通用-精选...

    程序员表白神器 love-master

    程序员表白神器你值得拥有-程序员表白神器你值得拥有 程序员表白神器你值得拥有-程序员表白神器你值得拥有 程序员表白神器你值得拥有-程序员表白神器你值得拥有 程序员表白神器你值得拥有-程序员表白神器你值得拥有 ...

    软件工程课程设计-学生管理系统-程序员SUMER

    软件工程课程设计---学生管理系统--程序员SUMER 软件工程课程设计---学生管理系统--程序员SUMER 软件工程课程设计---学生管理系统--程序员SUMER 软件工程课程设计---学生管理系统--程序员SUMER 软件工程课程设计---...

    2019大数据揭秘京沪程序员的爱情代码-WIFIPIX-201902.pdf

    ### 2019年大数据揭秘京沪程序员的爱情代码研究报告 #### 序言与背景介绍 随着信息技术的发展,大数据分析已成为研究社会行为的一种重要手段。本报告基于2019年情人节期间的数据,通过分析北京(帝都)与上海(魔都...

    优秀程序员的45个习惯.rar

    优秀程序员的45个习惯.rar ok good

    WINDOWS程序员使用指南(二)----MICROSOFT基本类库

    WINDOWS程序员使用指南(二)----MICROSOFT基本类库WINDOWS程序员使用指南(二)----MICROSOFT基本类库

    程序员的情书-----看专业程序员对程序的评价

    文中提到“我能抽象出整个世界”,表达了作者作为程序员具备很强的抽象思维能力,能够将复杂的世界用简洁、清晰的模型来表示。 ### 2. 重载与覆盖(Overloading and Overriding) “我可以重载甚至覆盖这个世界里...

    优秀程序员的45个习惯

    优秀程序员的45个好习惯,看看总有好处的

Global site tag (gtag.js) - Google Analytics