摘要: 编程初学者总是把大量的时间用在学习编程语言,语法,技巧和编程工具的使用上。他们认为,如果掌握了这些技术技巧,他们就能成为不错的程序员。然而,计算机编程的目的并不是关于精通这些技术、工具的,它是 ... ...
编程初学者总是把大量的时间用在学习编程语言,语法,技巧和编程工具的使用上。他们认为,如果掌握了这些技术技巧,他们就能成为不错的程序员。然而,计 算机编程的目的并不是关于精通这些技术、工具的,它是关于针对特定领域里的特定问题创造出相应的解决方案,程序员通过相互合作来实现这些。所以,很重要的 一点,你需要能精确的用代码表达出你的思想,让其他人通过代码能明白你的意图。
让我们先看看编程大师 Robert C. Martin 的杰作《Clean Code》里的一句话:
注释的目的是为了弥补代码自身在表达上的不足。
这句话可以简单的理解为如果你的代码需要注释,最有可能是你的代码写的很烂。同样,如果在没有注释的情况下你无法用代码完整的表达你对一个问题或一个算 法的思路,那这就是一个失败的信号。最终,这意味着你需要用注释来阐明一部分的思想,而这部分在代码里是看不出来的。好的代码能够让任何人在不需要任何注 释的情况下看懂。好的编码风格能将所有有助于理解这个问题的所有信息都蕴含在代码里。
在编程理论中,有一个概念叫做“自我描述的源代码”。对于一段代码,一种常见的自我描述机制是遵循某种非严格定义的变量、方法、对象命名规则。这样做的主要作用就是使源代码更易读易懂。所以,也就更容易维护和扩展。
这篇文章里,我将举出一些例子,说明什么是“不好的代码”,什么是“清楚的代码”
命名要能揭示意图
如何命名,在编程中这永远都是个老大难问题。有些程序员喜欢简化、缩短或加密名称,使得只有他们自己能懂。下面让我们看一些例子:
不好的代码:
int d;
// 天数 int ds;
int dsm;
int faid;
d”可以表示任何东西。作者使用注释来表明他的意图,却没有选择用代码来表示。而“faid”很容易导致误解为 ID。
清楚的代码:
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;
命名时避免含义引起误解的信息
错误的信息比没有信息更糟糕。有些程序员喜欢“隐藏”一些重要信息,有时候他们也会写出一些让人误解的代码。
不好的代码:
Customer[] customerList;
Table theTable;
变量“customerList”其实不是个 list。它是一个普通的 array (或客户集合)。除此之外,“theTable”是一个 Table 类型的对象(你可以用 IDE 容易的发现它的类型),“the”这个词是个不必要的干扰。
清楚的代码:
Customer[] customers;
Table customers;
命名要有合适的长度
在高级编程语言中,变量名的长度通常不太限制。变量名几乎可以任何长度。虽然如此,这也可能使代码变得闹心。
不好的代码:
var theCustomersListWithAllCustomersIncludedWithoutFilter;
var list;
好的名称应该只含有必要的词汇来表达一个概念。任何不必要的字词都会使名称变长、难于理解。名称越短越好,前提是能在上下文中表达完整的意思(下订单这个场景中,“customersInOrder” 要比 “list” 好)。
清楚的代码:
var allCustomers;
var customersInOrder;
命名时编码规范保持一致,让规范帮助理解代码
所有的编程技术(语言)都有自己的“风格”,叫做编码规范。程序员应该在写代码时遵循这些习惯,因为其他的程序员也知道这些,并按这种风格编写。下面我 们看一个没有明显规范的不好的代码例子。下面的这段代码没有遵循很好的已知的“编码规范”(比如 PascalCase, camelCase, Hungarian 规范)。更糟糕的是,这有一个毫无意义的 bool 变量“change”。这是个动词(用来描述动作),但这里的 bool 值是来描述一个状态,所以,这里应该用一个形容词更合适。
不好的代码:
const int maxcount = 1
bool change = true
public interface Repository
private string NAME
public class personaddress
void getallorders ()
一段代码,只看它的一部分,你就应该直接明白它是什么类型,只需要看它的命名方法。
例如:你看到了“_name”,你就能知道它是个私有变量。你应该在任何地方都利用这种表示方法,没有例外情况。
清楚的代码:
const int MAXCOUNT = 1
bool isChanged = true
public interface IRepository
private string _name
public class PersonAddress
void GetAllOrders ()
命名时相同的概念用相同的词表达
定义概念很难。在软件开发过程中,很多时间都花在分析业务场景、思考正确的定义里面所有的元素。这些概念永远都是让程序员头痛的事。
不好的代码:
//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. void GetSingleData ()
void GetDataFiltered ()
Void GetAllData ()
//2. void LoadDataToView ();
void SetObjectValue (int value)
命名时使用跟业务领域相关的词
程序员写的所有代码都是跟业务领域场景逻辑相连的。为了让所有关系到这个问题的人都能更好的理解,程序中应该使用在领域环境中有意义的名称。
不好的代码:
public class EntitiesRelation
{
Entity o1;
Entity o2;
}
当在编写针对某个领域的代码时,你应该始终考虑使用领域有联系的名称。在将来,当另外一个人(不仅是程序员,也许是测试人员)接触你的代码时,他能轻松的理解这个业务领域里你的代码是什么意思(不需要业务逻辑知识)。你首先考虑的应该是业务问题,之后才是如何解决。
清楚的代码:
public class ProductWithCategory
{
Entity product;
Entity category;
}
命名时使用在特定环境里有意义的词
代码里名称都有自己的上下文。上下文对于理解一个名称非常重要,因为它能提供额外的信息。让我们来看看一个典型的“地址”上下文:
不好的代码:
string addressCity;
string addressHomeNumber;
string addressPostCode;
在大多数情况中,“Post Code”通常是地址的一部分,很显然,邮政编码不能单独使用(除非你是在开发一个专门处理邮编的应用)。所以,没有必要在“PostCode”的前面加 上“address”。更重要的,所以的这些信息都有一个上下文容环境,一个命名空间,一个类。
在面向对象编程中,这里应该用一个“Address”类来表达这个地址信息。
清楚的代码:
class Address
{
string city;
string homeNumber;
string postCode;
}
命名方法总结
概述起来,做为一个程序员,你应该:
命名是来表达概念的
注意名称长度,名称里只该含有必要的词语
编码规范有助于理解代码,你应该使用它
名称不要混用
名称在业务领域里要有意义,在上下文里有意义
请随便发表你的意见。如果你知道在命名或代码表达方面的其它问题,请写在下面的评论里。
相关推荐
代码里的命名规则:错误的和正确的对比编程初学者总是把大量的时间用在学习编程语言,语法,技巧和编程工具的使用上。所以,很重要的一点,你需要能精确的用代码表达出你的
1. 命名规范:命名规则是编程规范中的基础,它对于代码的可读性和团队协作至关重要。开发手册要求避免使用下划线或美元符号作为变量名的开头和结尾,同时禁止使用拼音与英文混合或直接使用中文的方式进行命名。正确...
它通过对比字节码与预设的缺陷模式,能够在不运行程序的情况下发现可能存在的问题,极大地提高了代码审查的效率和准确性。 #### 功能概览 FindBugs支持多项高级检查,包括但不限于: - 检测`hashCode`和`equals`...
7.3 指针与数组的对比:探讨了指针和数组在内存管理上的差异。 7.4 指针参数是如何传递内存的?:解析了通过指针参数传递内存的工作原理。 7.5 FREE和DELETE把指针怎么啦?:解释了释放内存后指针的处理。 7.6 动态...
- 错误处理:如何正确地处理异常和错误,包括使用异常机制、返回错误码等。 - 性能优化:在保证代码可读性的前提下,提出性能改进的建议,如减少不必要的计算、合理使用数据结构等。 - 安全性:强调安全编码的...
1.2 每行代码不超过80字符,便于阅读和多窗口对比。 1.3 注释应简洁明了,用中文注释描述功能和目的,避免英文缩写不易理解。 1.4 使用4个空格作为缩进,不用制表符,保持一致性。 二、变量命名 2.1 变量名应具有...
书中不仅涉及了程序的版式、命名规则、表达式和基本语句、常量、函数设计、内存管理、C++函数的高级特性、类的构造函数、析构函数与赋值函数、类的继承与组合等编程基础知识,还包括了对编程误区的批评和针对上述...
- 指针与数组对比:对比指针和数组的特点。 - 指针参数传递内存:讲解指针作为函数参数时的数据传递机制。 - FREE和DELETE处理指针:分析这两个操作符对指针的影响。 - 动态内存释放:探讨动态分配内存的释放...
这份指南不仅涵盖了代码的格式和风格,还深入探讨了命名规则、表达式、基本语句、内存管理、函数设计等关键编程概念,以及C++特有的高级特性如函数重载、运算符重载和类的构造函数等。下面,我们将根据文档的标题、...
- 指针与数组的对比:分析指针和数组的异同点。 - 指针参数是如何传递内存的:解释指针作为参数时的数据传递机制。 - FREE和DELETE把指针怎么啦:解析FREE和DELETE操作对指针的影响。 - 动态内存会被自动释放吗...
3. **命名规则**:涵盖通用规则以及特定于Windows和Unix平台的应用程序命名规则。 4. **表达式和基本语句**:探讨运算符优先级、复合表达式、条件语句(IF)、循环语句、switch语句及goto语句的使用。 5. **常量**:...
这份规范涵盖了从注释、命名规则到编码风格等多个方面,适用于所有基于.NET平台的软件开发工作。 1. **注释规范**: - 注释语言要求使用中文,以便团队成员理解。 - 注释应简洁明了,描述对象的基本功能,避免...
类型命名应遵循大写约定,结构类型如记录、数组等的定义应清晰,以便于后续代码中正确地引用和操作。类型定义应尽可能具体,避免过度泛化,以提高代码的执行效率和可读性。 ##### 3.6 语句:控制流程的清晰表述 ...
通常,这样的文件会包含每个参赛团队的独立代码文件,可能有不同的命名规则,比如“TeamA_EProblem.cpp”、“TeamB_ESolution.java”等,也可能包括解释性文档、测试数据和运行结果。 从这个压缩包中,我们可以学习...
**重要性:** 规范化的命名规则可以减少混淆,提高代码的可读性。 - **共性规则:** 采用统一的命名约定,如使用下划线分隔单词(snake_case)或者驼峰式命名法(CamelCase)。 - **简单应用程序命名规则:** 针对...
- **操作系统相关的命名规则**:针对不同的操作系统,如Windows和UNIX,可能有不同的命名约定。 4. **表达式和基本语句** - **运算符优先级**:了解并正确使用运算符优先级可以避免混淆和错误。 - **复合表达式*...