写代码容易,写好代码不易。
作为一名开发人员,我们所要做的不仅仅是会用一种编程语言和实现一款软件或项目。
作为开发人员,要站在更高的视角去看待一个项目,通过一些优秀的开发习惯,可以让写的代码更加容易理解、更加容易扩展,也可以具有更强的通用性。
虽然养成这些好的习惯在前期需要一些学习和理解成本,但是一旦应用于实际的项目开发中,在后续的功能迭代、场景新增过程中,就会减少重构、重复造轮子的痛苦。
那么什么才是优秀的代码?
我认为优秀的代码具有如下特征:
- 可读性
- 结构设计优雅
- 容易理解,遵循单一责任原则(SRP)
- 容易扩展和修改
- 经历全面的验证和测试用例
为了写好代码,满足这些要求,我这些年一直坚持一些习惯,今天,就分享给大家。
1. 使用有意义的名称
命名是开发过程中非常基础、非常普遍的一项任务,也是决定代码简洁性、可读性的核心所在。
在编程开发过程中,变量、函数、类、参数、模块、包、目录等,很多地方都会涉及到命名问题。
所以,就如同给人起名一样,在开发过程中的命名也至关重要,能够在最短的时间内让我们自己或者其他阅读者能够获取到有价值的信息。
我在命名过程中一直坚持3个原则:它是做什么?它为什么存在?以及它是如何使用的?
比如下面这个例子:
int b; // 用户数量.
在上面的例子中,你需要在声明变量名称的同时给出一个注释,这不是一个好代码的特征。
我之前看到过一篇文章:注释越多就越好吗?
我认为答案是否定的,清晰的代码结构和有意义的命名,让阅读者一眼看上去就能够理解它的功能、作用,这样再加注释就是多余没有意义的。
但是,在上面这个示例代码中,我们很难从它的命名中看出它到底要干嘛,因此,就不得不加上注释说明。
按照前面提到的3个原则,我们可以在变量命名中说明它的作用和目的:
int number_of_users
这样再看上去,代码就会简洁很多,而且对于自己和其他阅读者也更加容易阅读。
需要补充一点,虽然要求有意义的命名,但是也没有必要把要表达的含义逐字的翻译成英文,这样就会更加繁琐,尽量将名字限制在三到四个字即可。
2. 单一责任原则(SRP)
在任何编程语言中,类、函数或方法都是组织代码的好方法,所以当在写代码时,就特别需要注意如何写一个能传达其意图的函数。
大多数初学者都会犯这样的错误,他们写的函数几乎可以处理和完成所有的事情(执行多项任务)。
这使得代码对开发者来说更加混乱,并在他们需要修复一些bug或寻找一些代码的时候造成更多麻烦。
因此,在写函数、类的过程中,我一直坚持2个原则:
- 尽量简洁
- 只做一件事,而且要做得好
以上两点明确提到,函数应该遵循单一责任原则。这意味着它不应该有嵌套结构,也不应该有超过两个缩进层次。遵循这种技术可以使代码更具有可读性。
另外,要确保函数不应该超过三个参数。传递三个以上的参数会使代码变得混乱,如果有任何问题,也很难调试。
此外,如同前面所说,要注意函数名称。为你的函数使用一个描述性的名字,它应该清楚地说明函数的作用:
function subtract(x, y) {
return x - y;
}
在上面的例子中,函数名称清楚地表明它的目的是为两个数字做减法,而且它只有两个参数。
3. 避免写不必要的注释
这个在前面提到过,注释越多就越好吗?
有很多博主会反反复复强调注释的重要性,无论如何都要尽量写注释。
的确,必要的注释对解释代码很有帮助,但它也需要对代码进行更多的维护,而且随着代码的变动,注释也需要相应的改动,否则会引入更多歧义。
此外,如果命名能够清晰的解释一个参数、一个函数的作用,那么再多加一些注释也没有意义。
4. 为人们写可读的代码
很多人,尤其是初学者,在写代码时都会犯这样的错误:他们把所有的东西都写在一行里,而不在代码中留出适当的空白、缩进或换行。
这使得他们的代码很混乱,难以维护。
尤其,当其他开发者试图阅读和理解混乱的代码时,这就浪费了他们的时间。
所以要时刻注意你的代码的格式,写代码不仅仅是为了让它不报错的跑出结果,还需要让人能够更好的理解它。
而且,当你在几天后回到自己的代码中做一些修改时,你也会节省你的时间和精力。
所以要确保你的代码应该有适当的缩进、空间和换行,以使它对其他人来说可读:
// 不好的代码
class CarouselRightArrow extends Component{render(){return ( <a href="#" className="carousel__arrow carousel__arrow--left" onClick={this.props.onClick}> <span className="fa fa-2x fa-angle-left"/> </a> );}};
// 好的代码
class CarouselRightArrow extends Component {
render() {
return (
<a
href="#"
className="carousel__arrow carousel__arrow--left"
onClick={this.props.onClick}
>
<span className="fa fa-2x fa-angle-left" />
</a>
);
}
};
5. 编写单元测试
编写单元测试在开发中是非常重要的,它使你的代码变得干净、灵活和可维护,对代码进行修改和减少错误变得更加容易。
在软件开发中,有一个过程被称为测试驱动开发(TDD),在这个过程中,需求被转化为一些特定的测试案例,然后软件需要不断改进以通过新的测试。
这样 ,我们的代码才能够拥有更强的稳定性和健壮性。
6. 谨慎对待依赖关系
在软件开发中,需要谨慎对待你的依赖关系。
如果可能的话,依赖关系应该始终是一个单一的方向。
举一个单向依赖的例子。
假设我们有一个厨房类,它依赖于洗碗机类。只要洗碗机不依赖于厨房类,这就是一个单方向的依赖关系。厨房类只是在使用洗碗机,但洗碗机并不关心在什么场景下使用。
然而,不可能总是有单向依赖,但我们应该尽量多的有单向依赖。当依赖关系向多个方向发展时,事情会变得更加复杂。在双向依赖中,两个实体都互相依赖,所以它们必须一起存在,尽管它们是分开的。当一些系统的依赖关系没有形成一个单一的方向时,就很难更新,很难解耦。
因此,要始终小心管理你的依赖关系。
7. 让项目井然有序
这是软件开发中一个很常见的问题,我们在项目中添加和删除了很多文件或目录,有时会变得很复杂,让其他开发者无法理解项目并为此工作。
当然,我们不可能在第一天就设计出一个完美的文件夹或文件组织,但以后,当你的项目变得更大时,就需要注意文件夹、文件和目录的组织结构。
一个结构良好的文件夹和文件使一切都变得清晰,理解一个完整的项目,搜索一些特定的文件夹并在其中进行修改变得更加容易。
8. 避免不必要的嵌套
在代码中嵌套是我们经常做的事情,虽然嵌套本身并没有什么问题,但有时会使代码更难读。
一种帮助避免这种情况的方法是使用 "Return Early "设计模式。
它允许我们将if
语句作为一个保护子句,在执行下一步的代码之前检查错误并返回。
它有助于避免使用if/else和不必要的嵌套,举个例子:
修改前
function deleteItem(item) {
if (item != null) {
console.log("Deleting item");
item.delete();
}
}
修改后
function deleteItem(item) {
if (item == null) return;
console.log("Deleting item");
item.delete();
}
这是我在写代码过程中坚持了很久的8个习惯,总结了很久,希望对大家有所帮助!
如果觉得不错的话,就点个赞支持一下吧!