bug数少,性能良好,易于修改。高质量代码影响深远,也是一个人被认为是高效开发者的背后主要原因。然后,虽然这一点很重要,但是新手却很难做到。关于该主题的文章通常会整理出许多零散的技巧,但一个新的开发者怎么可能记住所有的这些条例。光《代码大全》,该领域最经典的书籍,就长达960页。
我相信有可能构建一个简单的心理框架,它可以用于任何语言或库,并可以自然的产生高质量的代码。本文我将讨论五个主要概念。记住它们,你就能轻松的写出高质量的代码。
1、放弃你的个人癖好
当你在读文章看到新技能时,你会非常兴奋。现在你将写出非常聪明的代码,你所有的同行都会觉得眼前一亮。
问题是,对于那些只想解决他们的bug,然后去忙其他事情的人,你那些聪明的技巧只会让他们分心,而没其他作用。正如我在“在软件开发应用神经科学”一文中所说,当别人必须要去理解你的代码时,他们的“心理堆栈”就会被填满,因此很难取得进展。
不要以需要解释的方式来个性化你的工作
不要用”你的方式“来编码。按照标准来编码就行。这些东西已经有标准存在,用一种大家所期望的方式来编码,以便让你代码易于理解和可预测。
2、分而治之
复杂的代码通过可以通过模块化来使其更清晰,除了创建多个函数以外,还有许多其他方式也可以实现模块化。将长条件的结果存储到一两个变量中就是一种很好的模块化方式,这种方式还有一个好处就是不需要函数调用的开销。这种方式可以将其组合成一个更大的条件,或者在其他地方重用。
解决问题的方法应该是使每个部分尽可能的集中,影响只限于局部状态,不要将不相关的问题混淆在一起,可能的话,尽量不要产生副作用。程序语言和库往往有其自身的问题,将其抽象出来有利于你的代码专注于自身的业务。单一职责原则(Single Responsibility Principle)是另一个专注和局部化代码的良好设计的例子。
我喜欢利用变量来划分业务逻辑
测试驱动开发(TDD),除了成功实行带来的好处之外,还可以强迫开发人员遵循之前一些不受欢迎的原则。无状态的程序代码被认为是缓慢而又没有必要的(参考:大部分老的C/C++代码),而现在几乎每个人都在讨论纯粹的函数式编程。即使你不做测试驱动开发,你也应该了解这种方式背后的原则。在新的范式下工作能让你成为一名坚韧的开发人员。
3、分离并让其可行
你的计算机和工具处理你代码的难度跟你编程的难度是一致的,预处理器的数量以及你使用的变体与代码的复杂程度存在某种正相关性。
我们暂且搁置这些额外的构建工具给我们带来的好处。它们很有可能需要你使用特定的领域语言,例如自定义模板,或者复杂的、动态的数据结构(如散列表)。你的IDE通常不善于处理这些东西,因此要定位相关的代码片段就变得更加困难。
避免使用与IDE不兼容的语言扩展和库。它们对你的工作效率的影响将远远超过它们带来的那些微不足道的好处(如,配置更简单,更简洁的语法等)。
使用ServiceLocator是与大部分IDE集成不当的一个典型示例
另一种与IDE“集成”的方式是避免使用魔术代码。大部分语言提供更多使用动态代码的方式。滥用这些功能,如魔术字符串、魔术数组索引和自定义模板语言等功能,将导致更难连接的代码库。通常来说,任何只有人类才能理解的特性都会导致你走入这条路,并且很难从这条路回来,因为如果你的IDE不能理解你的代码,那么在你想要将代码迁移到一个更静态的架构上时,任何重构的功能都将是没有用的。
4、良好的可读性
努力创建一个可预测的架构。你的团队成员将能共容易的定位问题,这将大大减少他们处理某个问题的时间。一旦你确定了项目的整体结构,就要尽量让主要元素在明显的位置。例如使用MVC,就要把模型、视图和控制器放在各自的文件夹内,不要放在路劲很深的三个文件夹内,也不要分散在各个地方。
我之前讨论过模块化。但也存在过度模块化的问题,这会导致代码更难定位。IDE可能会有一点帮助,但是往往由于存在太多不相干的代码,你不得不让IDE忽略供应商/库的文件夹,或者编入指引,手动处理这些问题。这是一种双输的局面。因此要试着选择那些能尽可能多的覆盖需求的库,从而减少使用库的数量。
库和工具还可能成为新开发者的障碍。我最近使用EcmaScript 7 (babel)创建了一个项目,后来我才发现,我们很多新的开发者都卡在那里,都在试图理解它的意思。因而大大的降低了团队的开发效率。我低估了新手对这些问题的压力。不要使用太难且不容易掌握的工具。这需要等待更好的时机。
这是我写的一份makefile的真实代码,新开发者无法过多处理新技能
5、易于理解
如果你读到了这部分,那恭喜你:这可能是最重要的一部分。选择好的名字是软件开发中最大的问题之一。构建工具不太可能改善这一点,因为计算机不可能知道某一解决方案背后的真正原因。你必须自己记录原因。为变量和函数创建一个相关的、符合上下文环境的名称是一种非常不错的方式。名称可以传达意图,甚至可以减少必要的文档。
在名称中使用前缀是为名称添加意义的一种好方式。这在以前是一个非常流行的惯例,我认为这一惯例没有被保持的原因是容易误用。例如匈牙利命名法最初是为了增加意义,但是后来却成了一种减少上下文的方式,例如只添加类型信息。
流式的接口(Fluent interfaces)最近经常被滥用
最后,也是最常讨论的,就是降低循环复杂性。这就意味着要尽可能降低条件分支的数量。每个额外的分支不仅要增加缩进,降低可读性,更重要的是它增加了你追踪问题的路劲。
结论和推荐阅读
以上5点就是简单而又涵盖各方各面的概念,我这里的目标是给你一个框架,可以让你更加简单的组织你的代码。
在编程的时候专注这些方面的练习,已对其进行巩固。如果你还没有这么做,强力推荐你看看《代码大全》。该书中有大量的例子,基本上可以解析你可能遇到的绝大部分情况。