编程的工作既是技术活,也是体力活,而编写优秀的软件,更是一件比较难的事情。
初级程序员只希望代码不出错,顶级程序员却把写代码当成艺术,当年雷军以过人的能力成为求伯君的左膀右臂,其早年的代码被说成“像诗一样优美”。
很多大牛,在着手写代码时并不是直接上手编写,而是根据需求进行设计,不但将代码中 Bug 出现的机率降到最低,还让代码具有高可读性,高安全性等等。
那大牛们都遵循怎样的原则呢,我们能不能学习一下?
将大牛们的经验总结到一起,可以得到以下「7 大程序设计原则」 。这些设计原理源于对实际软件开发现场的分析,是提高代码质量的经验结晶。
让我们一起一探究竟吧!
01 简单性原则
Simplicity Principle
What:追求简单
简单性原则就是追求简单。
说得极端一点,就是自始至终都以最简单的逻辑编写代码,让编程初学者一眼就能看懂。
因此,在编程时我们要重视的是局部的完整性,而不是复杂的整体关联性。
Why:Bug 喜欢出现在复杂的地方
软件故障常集中在某一个区域,而这些区域都有一个共同的特点,那就是复杂。编写代码时如果追求简单易懂,代码就很难出现问题。
不过,简单易懂的代码往往给人一种不够专业的感觉。这也是经验老到的程序员喜欢写老练高深的代码的原因。所以我们要有足够的定力来抵挡这种诱惑。
Do:编写自然的代码
努力写出自然的代码。放下高超的技巧,坚持用简单的逻辑编写代码。
既然故障集中在代码复杂的区域,那我们只要让代码简单到让故障无处可藏即可。不要盲目地让代码复杂化、臃肿化,要保证代码简洁。
02 同构原则
Isomorphism Principle
What:力求规范
同构原则就是力求规范。
同等对待相同的东西,坚持不搞特殊。同等对待,举例来说就 是同一个模块管理的数值全部采用同一单位、公有函数的参数个数统一等。
Why:不同的东西会更显眼
相同的东西用相同的形式表现能够使不同的东西更加突出。不同的 东西往往容易产生 bug。遵循同构原则能让我们更容易嗅出代码的异样, 从而找出问题所在。
图表和工业制品在设计上追求平衡之美,在这一点上,同构原则也 有着相似之处。统一的代码颇具美感,而美的东西一般更容易让人接 受,因此统一的代码有较高的可读性。
Do:编写符合规范的代码
我们要让代码符合一定的规范。不过,这会与程序员的自我表现欲相冲突。
为了展现自己的实力,有些程序员会无视编程规范,编写独特的代码。可靠与简单是代码不可或缺的性质,但这些程序员常常在无意间让代码变得复杂。
这就把智慧与个性用错了地方。小小的自我满足远不及代码质量重要。所以在编写代码时,务必克制住自己的表现欲,以规范为先。
03 对称原则
Symmetry Principle
What:讲究形式上的对称
讲究形式上的对称。
对称原则就是讲究形式上的对称,比如有上就有下,有左就有右, 有主动就有被动。
也就是说,我们在思考一个处理时,也要想到与之成对的处理。比 如有给标志位置 1 的处理,就要有给标志位置 0 的处理。
Why:帮助读代码的人推测后面的代码
具有对称性的代码能够帮助读代码的人推测后面的代码,提高其理解代码的速度。同时,对称性会给代码带来美感,这同样有助于他人理解代码。
此外,设计代码时将对称性纳入考虑的范围能防止我们在思考问题时出现遗漏。如果说代码的条件分支是故障的温床,那么对称性就是思考的框架,能有效阻止条件遗漏。
Do:编写有对称性的代码
在出现“条件”的时候,我们要注意它的“反条件”。每个控制条件都存在与之成对的反条件(与指示条件相反的条件)。要注意条件与反条件的统一,保证控制条件具有统一性。
我们还要考虑到例外情况并极力避免其发生。例外情况的特殊性会破坏对称性,成为故障的温床。特殊情况过多意味着需求没有得到整理。此时应重新审视需求,尽量从代码中剔除例外情况。
命名也要讲究对称性。命名时建议使用 set/get、start/stop、begin/ end 和 push/pop 等成对的词语。
04 层次原则
Hierarchy Principle
What:讲究层次
注意事物的主从关系、前后关系和本末关系等层次关系,整理事物的关联性。
不同层次各司其职,同种处理不跨越多个层次,这一点非常重要。比如执行了获取资源的处理,那么释放资源的处理就要在相同的层次进行。又比如互斥控制的标志位置 1 和置 0 的处理要在同一层次进行。
Why:层次结构有助于提高代码的可读性
有明确层次结构的代码能帮助读代码的人抽象理解代码的整体结构。读代码的人可以根据自身需要阅读下一层次的代码,掌握更加详细的信息。
这样一来就可以提高代码的可读性,帮助程序员表达编码意图,降低 bug 发生的概率。
Do:编写有抽象层次结构的代码
在编写代码时设计各部分的抽象程度,构建层次结构。保证同一个层次中的所有代码抽象程度相同。另外,高层次的代码要通过外部视角描述低层次的代码。这样做能让调用低层次代码的高层次代码更加简单易懂。
05 线性原则
Linearity Principle
What:处理流程尽量走直线
线性原则就是让处理流程尽量走直线。
一个功能如果可以通过多个功能的线性结合来实现,那它的结构就会非常简单。
反过来,用条件分支控制代码、毫无章法地增加状态数等行为会让代码变得难以理解。我们要避免做出这些行为,提高代码的可读性。
Why:直线处理可提高代码的可读性
复杂的处理流程是故障的温床。
故障多出现在复杂的条件语句和循环语句中。另外,goto 等让流程出现跳跃的语句也是故障的多发地。
如果能让处理由高层次流向低层次,一气呵成,代码的可读性就会大幅提高。与此同时,可维护性也将提高,添加功能等改良工作将变得更加容易。
一般来说,自上而下的处理流程简单明快,易于理解。我们应避开复杂反复的处理流程。
Do:尽量不在代码中使用条件分支
尽量减少条件分支的数量,编写能让代码阅读者线性地看完整个处理流程的代码。
为此,我们需要把一些特殊的处理拿到主处理之外。保证处理的统一性,注意处理的流程。记得时不时俯瞰代码整体,检查代码是否存在过于复杂的部分。
另外,对于经过长期维护而变得过于复杂的部分,我们可以考虑对其进行重构。明确且可靠的设计不仅对我们自身有益,还可以给负责维护的人带来方便。
06 清晰原则
Clarity Principle
What:注意逻辑的清晰性
清晰原则就是注意逻辑的清晰性。
逻辑具有清晰性就代表逻辑能清楚证明自身的正确性。也就是说,我们编写的代码要让人一眼就能判断出没有问题。任何不明确的部分都 要附有说明。
保证逻辑的清晰性要“不择手段”。在无法用代码证明逻辑正确性的情况下,我们也可以通过写注释、附文档或画图等方法来证明。不过,证明逻辑的正确性是一件麻烦的事,时间一长,人们就会懒得用辅助手段去证明,转而编写逻辑清晰的代码了。
Why:消除不确定性
代码免不了被人一遍又一遍地阅读,所以代码必须保持较高的可读性。编写代码时如果追求高可读性,我们就不会采用取巧的方式编写代码,编写出的代码会非常自然。
采用取巧的方式编写的代码除了能让计算机运行以外没有任何意义。代码是给人看的,也是由人来修改的,所以我们必须以人为对象来编写代码。
消除代码的不确定性是对自己的作品负责,这么做也可以为后续负责维护的人提供方便。
Do:编写逻辑清晰的代码
我们要编写逻辑清晰的代码。
为此,我们应选用直观易懂的逻辑。会给读代码的人带来疑问的部分要么消除,要么加以注释。
另外,我们应使用任何人都能立刻理解且不存在歧义的术语。要特别注意变量名等一定不能没有意义。
07 安全原则
Safty Principle
What:注意安全性
安全原则就是注意安全性,采用相对安全的方法来对具有不确定性的、模糊的部分进行设计和编程。
说得具体一点,就是在编写代码时刻意将不可能的条件考虑进去。比如即便某个 i f 语句一定成立,我们也要考虑 else 语句的情况;即便某个 case 语句一定成立,我们也要考虑 default 语句的情况;即便某个变量不可能为空,我们也要检查该变量是否为 NULL。
Why:防止故障发展成重大事故
硬件提供的服务必须保证安全,软件也一样。
硬件方面,比如取暖器,为防止倾倒起火,取暖器一般会配有倾倒自动断电装置。同样,设计软件时也需要考虑各种情况,保证软件在各种情况下都能安全地运行。这一做法在持续运营服务和防止数据损坏等方面有着积极的意义。
Do:编写安全的代码
选择相对安全的方法对具有不确定性的部分进行设计。列出所有可能的运行情况,确保软件在每种情况下都能安全运行。理解需求和功能,将各种情况正确分解到代码中,这样能有效提高软件安全运行的概率。
为此,我们也要将不可能的条件视为考察对象,对其进行设计和编程。不过,为了统一标准,我们在编写代码前最好规定哪些条件需要写,哪些条件不需要写。
摘自:《编程的原则:程序员改善代码质量的 101 个方法》
作者:[日]上田勋