【转】代码里的命名规则:错误的和正确的对比

原文出处: goyello   译文出处: 外刊IT评论

 

编程初学者总是把大量的时间用在学习编程语言,语法,技巧和编程工具的使用上。他们认为,如果掌握了这些技术技巧,他们就能成为不错的程序员。然而,计算机编程的目的并不是关于精通这些技术、工具的,它是关于针对特定领域里的特定问题创造出相应的解决方案,程序员通过相互合作来实现这些。所以,很重要的一点,你需要能精确的用代码表达出你的思想,让其他人通过代码能明白你的意图。

代码里的命名规则:错误的和正确的对比

让我们先看看编程大师Robert C. Martin的杰作《Clean Code | 代码整洁之道》里的一句话:

“注释的目的是为了弥补代码自身在表达上的不足。”

这句话可以简单的理解为如果你的代码需要注释,最有可能是你的代码写的很烂。同样,如果在没有注释的情况下你无法用代码完整的表达你对一个问题或一个算法的思路,那这就是一个失败的信号。最终,这意味着你需要用注释来阐明一部分的思想,而这部分在代码里是看不出来的。好的代码能够让任何人在不需要任何注释的情况下看懂。好的编码风格能将所有有助于理解这个问题的所有信息都蕴含在代码里。

在编程理论中,有一个概念叫做“自我描述的源代码”。对于一段代码,一种常见的自我描述机制是遵循某种非严格定义的变量、方法、对象命名规则。这样做的主要作用就是使源代码更易读易懂。所以,也就更容易维护和扩展。

这篇文章里,我将举出一些例子,说明什么是“不好的代码”,什么是“清楚的代码”

命名要能揭示意图

如何命名,在编程中这永远都是个老大难问题。有些程序员喜欢简化、缩短或加密名称,使得只有他们自己能懂。下面让我们看一些例子:

不好的代码:

1
2
3
4
5
int d;
// 天数
int ds;
int dsm;
int faid;

“d”可以表示任何东西。作者使用注释来表明他的意图,却没有选择用代码来表示。而“faid”很容易导致误解为ID。

清楚的代码:

1
2
3
4
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;

命名时避免含义引起误解的信息

错误的信息比没有信息更糟糕。有些程序员喜欢“隐藏”一些重要信息,有时候他们也会写出一些让人误解的代码。

不好的代码:

1
2
Customer[] customerList;
Table theTable;

变量“customerList”其实不是个list。它是一个普通的array(或客户集合)。除此之外,“theTable”是一个Table类型的对象(你可以用IDE容易的发现它的类型),“the”这个词是个不必要的干扰。

清楚的代码:

1
2
Customer[] customers;
Table customers;

命名要有合适的长度

在高级编程语言中,变量名的长度通常不太限制。变量名几乎可以任何长度。虽然如此,这也可能使代码变得闹心。

不好的代码:

1
2
var theCustomersListWithAllCustomersIncludedWithoutFilter;
var list;

好的名称应该只含有必要的词汇来表达一个概念。任何不必要的字词都会使名称变长、难于理解。名称越短越好,前提是能在上下文中表达完整的意思(下订单这个场景中,“customersInOrder” 要比 “list” 好)。

清楚的代码:

1
2
var allCustomers;
var customersInOrder;

命名时编码规范保持一致,让规范帮助理解代码

所有的编程技术(语言)都有自己的“风格”,叫做编码规范。程序员应该在写代码时遵循这些习惯,因为其他的程序员也知道这些,并按这种风格编写。下面我们看一个没有明显规范的不好的代码例子。下面的这段代码没有遵循很好的已知的“编码规范”(比如PascalCase, camelCase, Hungarian规范)。更糟糕的是,这有一个毫无意义的bool变量“change”。这是个动词(用来描述动作),但这里的bool值是来描述一个状态,所以,这里应该用一个形容词更合适。

不好的代码:

1
2
3
4
5
6
const int maxcount = 1
bool change = true
public interface Repository
private string NAME
public class personaddress
void getallorders()

一段代码,只看它的一部分,你就应该直接明白它是什么类型,只需要看它的命名方法。

例如:你看到了“_name”,你就能知道它是个私有变量。你应该在任何地方都利用这种表示方法,没有例外情况。

清楚的代码:

1
2
3
4
5
6
const int MAXCOUNT = 1
bool isChanged = true
public interface IRepository
private string _name
public class PersonAddress
void GetAllOrders()

命名时相同的概念用相同的词表达

定义概念很难。在软件开发过程中,很多时间都花在分析业务场景、思考正确的定义里面所有的元素。这些概念永远都是让程序员头痛的事。

不好的代码:

1
2
3
4
5
6
7
//1.
void LoadSingleData()
void FetchDataFiltered()
Void GetAllData()
//2.
void SetDataToView();
void SetObjectValue(int value)

首先:

代码的作者试图表达“get the data”的概念,他使用了多个词“load”,“getch”,“get”。一个概念只用一个词表达就行了(在同一个场景中)。

第二:

“set”这个词用在了2个概念里:第一是“data loading to view”,第二个是“setting a value of object”。这是两个不同的概念,你应该使用不同的词。

清楚的代码:

1
2
3
4
5
6
7
//1.
void GetSingleData()
void GetDataFiltered()
Void GetAllData()
//2.
void LoadDataToView();
void SetObjectValue(int value)

命名时使用跟业务领域相关的词

程序员写的所有代码都是跟业务领域场景逻辑相连的。为了让所有关系到这个问题的人都能更好的理解,程序中应该使用在领域环境中有意义的名称。

不好的代码:

1
2
3
4
5
public class EntitiesRelation
{
Entity o1;
Entity o2;
}

当在编写针对某个领域的代码时,你应该始终考虑使用领域有联系的名称。在将来,当另外一个人(不仅是程序员,也许是测试人员)接触你的代码时,他能轻松的理解这个业务领域里你的代码是什么意思(不需要业务逻辑知识)。你首先考虑的应该是业务问题,之后才是如何解决。

清楚的代码:

1
2
3
4
5
public class ProductWithCategory
{
Entity product;
Entity category;
}

命名时使用在特定环境里有意义的词

代码里名称都有自己的上下文。上下文对于理解一个名称非常重要,因为它能提供额外的信息。让我们来看看一个典型的“地址”上下文:

不好的代码:

1
2
3
string addressCity;
string addressHomeNumber;
string addressPostCode;

在大多数情况中,“Post Code”通常是地址的一部分,很显然,邮政编码不能单独使用(除非你是在开发一个专门处理邮编的应用)。所以,没有必要在“PostCode”的前面加上“address”。更重要的,所以的这些信息都有一个上下文容环境,一个命名空间,一个类。

在面向对象编程中,这里应该用一个“Address”类来表达这个地址信息。

清楚的代码:

1
2
3
4
5
6
class Address
{
string city;
string homeNumber;
string postCode;
}

命名方法总结

概述起来,做为一个程序员,你应该:

    • 命名是来表达概念的
    • 注意名称长度,名称里只该含有必要的词语
    • 编码规范有助于理解代码,你应该使用它
    • 名称不要混用
    • 名称在业务领域里要有意义,在上下文里有意义

转载于:https://www.cnblogs.com/daocaowu/archive/2013/06/07/3125452.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360667.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

您的Apache Camel应用程序现在包括现成的文档

几个月前,我在博客中发布了有关即将发布的2.15版本的信息,该功能包括获取有关在端点上配置的每个属性的详细信息的功能-Apache Camel,请向我解释这些端点选项的含义 。 我们沿着这条道路继续前进,今天,我们将其从端点…

具有Spring Boot和数据功能的Java头优先弹性搜索

在本文中,我将为您提供有关如何在Java项目中使用Elastic Search的简单介绍。 由于Spring Boot是开始我们项目的最简单,最快的方法,因此我选择使用它。 此外,我们将大量使用心爱的Spring Data的Repository Goods。 首先&#xff0…

python 表单中值为空的还需要传入么_牛掰!100行Python,自动动手打造一款多国语言翻译软件...

大家在平时的学习或者工作中,往往少不了要阅读外文的文献,或者将外文的文献翻译成中文。这时候就需要打开网页,然后进行搜索,非常的麻烦。既然是玩Python,小编就带领大家来打造一款多种语言翻译的软件,无需…

使用Visual Studio 2010 一步一步创建Powershell Module 和 Cmdlet

之前写了一个C# 调用PowerShell方法, 那么怎么反过来操作呢,也就是怎么样用C#写一个powershell命令呢? 现在就用C#写一个超级简单的Module和Cmdlet 1. 在VS中创建一个Library的项目 文件->新建->项目->C#->Class Library 在这里给…

休眠锁定模式– PESSIMISTIC_FORCE_INCREMENT锁定模式如何工作

介绍 在我以前的文章中 ,我介绍了OPTIMISTIC_FORCE_INCREMENT锁定模式,并将其应用于将子实体版本更改传播到锁定的父实体。 在本文中,我将介绍PESSIMISTIC_FORCE_INCREMENT锁定模式,并将其与乐观的锁定模式进行比较。 相像多于不…

实用程序类与函数式编程无关

最近,我被指控反对函数式编程,因为我将实用程序类称为反模式 。 绝对是错的! 好吧,我确实认为它们是一种糟糕的反模式,但是它们与函数式编程无关。 我相信有两个基本原因。 首先,函数式编程是声明性的&…

freeredius3.0 mysql_EDIUS视频采集卡 STROM 3G HD/HD SDI

EDIUS STROM 3G HD/HD SDI高清非编系统视音频采集卡STORM 3G? 适用于视频专业人士,满足基于SDI编辑和无带化工作流程,同时可以在低成本的HDMI监/视器上预监。基于PCIe插口类型的STORM 3G解决方案包括EDIUS?非线性编辑软件,3G HD…

以编程方式确定Java类的JDK编译版本

当需要确定使用哪个JDK版本来编译特定的Java .class文件时, 通常使用的方法是使用javap并在javap输出中查找列出的“主要版本”。 我在博客文章Autoboxing,Unboxing和NoSuchMethodError中引用了这种方法,但是在继续以编程方式实现此方法之前&…

如何使用Spring Security和Basic身份验证保护Jersey REST服务

在我之前的博客文章“ 检查REST API是否有效的快速方法–从清单文件中获取GET详细信息”中 ,我展示了如何开发REST资源以轻松检查开发的REST API是否可用。 在本文中,我将介绍如何使用Spring Security和基本身份验证来保护此资源的安全性– “在HTTP事务…

python提取数据段_python提取数据段 python数据分析

如何在python中用slice分段取数据?执行以下操作:&gt&gt arange(6)&gt&gt a[0,1,2,3,4,5]&gt&gt a[0:3],a[5][[2,3,4,4&a…

一个JAXB Nuance:字符串与枚举(受限制的XSD字符串)

尽管用于XML绑定的Java体系结构 ( JAXB )在名义情况下(尤其是自Java SE 6以来) 相当容易使用,但它也存在许多细微差别。 一些常见的细微差别是由于无法将 XML模式定义 (XSD)类型与Java 类型精确…

休眠锁定模式– OPTIMISTIC_FORCE_INCREMENT锁定模式如何工作

介绍 在我以前的文章中 ,我解释了OPTIMISTIC锁定模式是如何工作的,以及它如何帮助我们同步外部实体状态更改。 在本文中,我们将介绍OPTIMISTIC_FORCE_INCREMENT锁定模式的使用模式。 使用LockModeType.OPTIMISTIC ,将在当前正在运…

设置本地Nexus存储库并从Maven部署WAR文件

Maven Central充当中央存储库管理器,其中二进制工件由不同的团队/公司/个人上载并与世界其他地方共享。 就像github和其他对源代码控制非常有效的源代码存储库一样,这些存储库管理器还充当您自己生成的二进制工件的部署目标。 设置本地存储库管理器具有…

mac solr mysql 配置文件_Solr配置文件浅析

接上一篇Linux下安装solr7.4,来谈谈solr的配置文件schema.xml和db-data-config.xml首先看schema.xml:idfield标签用来定义solr core中的字段。这里列出的三个字段如果没有特殊原因尽量保留。字段id被声明为uniqueKey,是让id来唯一标明一个solrdocument。…

JSF:在正确的阶段进行验证(了解生命周期)

嗨,大家好! 尽管标题强调验证一词,但本文实际上是关于JSF生命周期的。 那是因为我相信,真正了解生命周期的最简单方法之一就是通过做出我们一直在做的事情:验证用户输入。 总的来说,理解所谓的JSF生命周期…

OpenShift v3:使用WildFly和MySQL的Java EE 7入门

OpenShift是Red Hat的开源PaaS平台。 OpenShift v3 (将于今年发布)将提供使用Docker和Kubernetes运行微服务的整体体验。 以经典的Red Hat方式,所有工作都在OpenShift Origin的开源中完成。 这也将推动OpenShift Online和OpenShift Enterpris…

mySQL日期函数并运行_mysql日期相关的函数

1、获取当前时间:/**获得当前日期时间(date time)函数:now(), 常用**/select now() fromdual;/**获取当前时间戳,current_timestamp或者current_timestamp()**/select current_timestamp, current_timestamp() fromdual;/**获得当前日期时间…

序列化对象C++对象的JSON序列化与反序列化探索

新手发帖,很多方面都是刚入门,有错误的地方请大家见谅,欢迎批评指正 一:背景 作为一名C开发人员,我始终很期待能够像C#与JAVA那样,可以省力的进行对象的序列化与反序列化,但到现在为止&#xff…

python socket udp并发_Python进阶----UDP协议使用socket通信,socketserver模块实现并发

Python进阶----UDP协议使用socket通信,socketserver模块实现并发一丶基于UDP协议的socket实现UDP协议传输数据代码如下:👇### 客户端# -*-coding:utf-8-*-# Author:Dsimport socket# 实例化UDP协议的socket对象 ,配置参数, socket.SOCK_DGRAM(数据报)udp_clisocket.…

Java IO基准测试:Quasar与异步ForkJoinPool与ManagedBlock

“ Arien看到了我们运行的parallelStreams和ForkJoin基准测试的结果后,在Twitter上与我们联系。 这激起了他的兴趣,因此他进行了一些自己的测试,将Quasar纤维加入了混合物。 这是他的结果和结论。” –塔基皮(Takipi)A…