|
|
51CTO旗下网站
|
|
移步端
创造专栏

如何写好代码?

为赶项目进度欠下一堆技术债怎么办?工作逻辑复杂,如何处理比较好?相似之效应要不要copy修改一下复用?怎么写代码注释?好代码无论对个人还是组织都至关重要,然而要写好代码却是一件非常不容易的作业,要求长期的阅历积累和学习。关于写好代码,本文作者分享了6个入门的比较重要的线,瞩望对同学们有所启发。

笔者: 阿里技术| 2020-07-31 08:12

阿里妹导读:为赶项目进度欠下一堆技术债怎么办?工作逻辑复杂,如何处理比较好?相似之效应要不要copy修改一下复用?怎么写代码注释?好代码无论对个人还是组织都至关重要,然而要写好代码却是一件非常不容易的作业,要求长期的阅历积累和学习。关于写好代码,本文作者分享了6个入门的比较重要的线,瞩望对同学们有所启发。

写了多年之编码,前后认为如何写出干净优雅的编码并不是一件容易的作业。按10000小时刻意训练的定律,假设每天8小时,一度月20远处,一年12个月,简言之也要求5年控制之年华成为大师。其实我们每天的上班中真实用于写代码的年华不可能有8个小时,并且很多时候是在成功任务,在工作压力很大的时节,可能想要达到的对象是如何尽快的行之有效功能work开头,代码是否干净优雅非常可能没有能放在重中之重优先级上,而是怎么快怎么来。

在这样的情况下是异样容易欠下技术债的,时光长了,这样的编码基本上无法保障,只能推倒重来,其一资本是异样高的。欠债要还,是不是迟早的题材,并且等到要还的时节还要赔上额外的难得的利息。还贷的有可能是团结,也有可能是新兴的后代,但都是组织在还债。故此从组织的力度来看,写好代码是一件非常有必不可少的作业。如何写出干净优雅的编码是个很艰难之议题,我没有找到万能的solution,更多的是部分trade off,可以稍微讨论一下。

代码是写给人看的还是写给机器看的?

在多数之情况下我会认为代码是写给人看的。虽然代码最后的执行者是机械,但是实际上代码更多的时节是送人看的。咱们来看望一段代码的生命周期:付出 --> 单元测试 --> Code Review --> 功能测试 --> 性能测试 --> 上点 --> 运维、Bug修复 --> 高考上点 --> 离休下线。付出到上点的年华也许是几周或者几个月,但是线上运维、bug修复的潜伏期可以是几年。

在这几年之年华里面,几乎不可能还是土生土长的作者在保障了。后者如何能了解之前的编码逻辑是极其重大的,如果不能保护,只能自己重新做一套。故此在档次中我们经常能看到的状况就是,观看了前人的编码,都认为这是什么垃圾,写的混乱,还是我自己重写一遍吧。就算是在开发的经过中,要求别人来Code Review,如果他们都看不懂这个代码,怎么来做Review呢。还有你也不指望在暑期的时节,因为其他人看不懂你的编码,只好打电话求助你。其一我印象极其深刻,记得我在办事不久之时节,一次回到了老家休假中,突然同事打电话来了,出现了一番问题,问我该如何解决,那时电话还要收卫生费的,异常贵,但是我还不得不支持直到耗光我之通话费。

故此代码主要还是写给人看的,是咱们的交流的路子。该署非常好的开源的品种虽然有文档,但是更多的我们其实还是看它的源码,如果开源项目里面的编码写的很难读,其一项目也基本上不会火。因为代码是咱们开发人员交流的中心路线,甚至可能口头讨论不知晓的作业,咱们可以通过代码来说清楚。代码的读报我以为是着重位的。各国公司估计都有协调之编码规范,恪守相关的标准保持代码风格的联合是着重地(引进谷歌代码规范[1]和微软代码规范[2])。专业里一般都包括了如何开展含量、类、函数的命名,函数要尽量短并且保持原子性,无需做多件事情,类的中心设计的规则等等。此外一个建议是可以多参考学习一下开源项目中的代码。

KISS (Keep it simple and stupid)

普通大脑工作记忆之增量就是5-9个,如果工作过多或者过于复杂,对于大一部分人来说是心有余而力不足直接了解和处理的。普通我们需要一些扶持手段来处理复杂的题材,比如做笔记、图,有点类似于在内存不够用之情况下我们借用了外存。

学CS的同窗都晓得,外存的走访速度肯定不如内存访问速度。此外一般来说在逻辑复杂的情况下出错的可能性要远大于在简练的情况下,在复杂的情况下,代码的分支可能有很多,咱们是否能够对每个情况都考虑到位,该署都有窘迫。为了使得代码更加可靠,并且容易理解,最好的措施还是保持代码的简短,在拍卖一个问题的时节尽量使用简单的逻辑,无需有过多之总分。

但是现实的题材并不会总是那么简单,这就是说如何来处理复杂的题材呢?与其借用外存,我更加倾向于对复杂的题材展开分层抽象。网络的通信是一番奇异复杂的作业,中间使用的装备可以有成百上千种(手机,各族IOT装备,台式机,laptop,玉器,成像机...), OSI协和对各层做了抽象,每一层需要处理的状况就都大大地简化了。穿过对复杂问题的说明、空泛,这就是说我们在每个层次上要消灭处理的题材就简化了。其实也类似于算法中的divide-and-conquer, 复杂的题材,要先拆解掉变成小的题材,故而来简化解决之主意。

KISS还有另外一层意思,“如无必要,勿增实体” (奥卡姆剃刀原理)。CS官方有一句 "All problems in computer science can be solved by another level of indirection", 为了系统之扩展性,支持将来的组成部分可能生存的转移,咱们经常会引入一层间接层,或者增加中间的interface。在做这些决定的时节,咱们要多考虑一下是否真的有必不可少。增长额外的一层给咱们的功利就是不难扩展,但是同时也增加了复杂度,有效系统变得更加不可理解。对于代码来说,很可能是我这里调用了一番API,不知晓实际的接触在哪儿,对于了解和调剂都可能增加困难。

KISS自己就是一番trade off,要把复杂的题材通过架空和分拆来简单化,但是是否需要为了保留变化做更多的indirection的泛,该署都是要求精心考虑的。

DRY (Don't repeat yourself)

为了迅速地贯彻一个功能,了解之前有类似之,把代码copy来到修改一下就用,可能是最快的主意。但是copy代码经常是许多问题和bug的滥觞。有一类问题就是copy来到的编码包含了部分其他的逻辑,可能并不是这部分需要的,故此可能有冗余甚至有的额外的风险。

此外一类问题就是在保障的时节,咱们其实不知晓修复了一番地方后,还有好多其他的中央还要求修复。在我过去的品种中就出现过这样的题材,有个问题明明之前做了修复,过几角另外一个用户又提了类似之题材出现的另外的门路上。相同的逻辑要尽量只出现在一番地方,这样有问题的时节也就足以一次性地修复。这也是一种浮泛,对于相同的逻辑,空泛到一个类或者一个函数中扮,这样也有利于代码的读报。

只是要写注释

个体的意见是多数之编码尽量不要注释。代码本身就是一种交流语言,并且一般来说编程语言比我们常见使用的口语更加的准确。在保持代码逻辑简单的情况下,采用良好的命名规范,代码本身就很清楚并且可能读起来就已经是一篇良好的篇章。特别是OO的语言的话,自己object(名词)加operation(普通用动词)就已经足以说明是在做什么了。重温一下把这个操作的名词放入注释并不会增加代码的读报。并且在此起彼伏的保障中,会出现修改了代码,却并不修改注释的状况出现。在我做的很多Code Review官方我都看到过这样的状况。尽量把代码写的可以了解,而不是通过注释来理解。

当然我并不是反对任何的诠释,在光天化日的API上是要求注释的,有道是列出API的明天置和今后置条件,诠释该如何使用这个API,这样也得以用于自动产品API的文档。在部分奇异优化逻辑和负责算法的中央加上这些逻辑和算法的诠释还是异样有必不可少的。

一次做对,无需相信下会Refactoring

普通来说在代码中写上TODO,等着后再来refactoring或者改进,基本上就不会再有以后了。咱们可以去我们的编码库里面搜索一下TODO,探望有好多,并且有好多是多少年前的,我深信不疑这个结果会让你很奇怪(迎接大家留言分享你查找之后的结果)。

尽量一次就做对,无需相信下还会返回把代码refactoring好。人口都是有冷水性的,一旦形成了现阶段的作业,move on后再回去处理这些概率就特别小了,除非下次真的要求修改这些代码。如果说不会再回去,这就是说这个TODO也没有什么意义。如果真的要求,就不要留下这个题目。我见过有的人留下了一番TODO,throw了一番not implemented的exception,下一场几角后其他同学把这个代码带上点了,直接挂掉的状况。尽量不要TODO, 一次做好。

只是要写单元测试?

个体的意见是必须,除非你是否做prototype或者快速迭代扔掉的编码。

Unit tests are typically automated tests written and run by software developers to ensure that a section of an application (known as the "unit") meets its design and behaves as intended. In procedural programming, a unit could be an entire module, but it is more commonly an individual function or procedure. In object-oriented programming, a unit is often an entire interface, such as a class, but could be an individual method.

From Wikipedia

单元测试是为了保证我们写出的编码确实是咱们想要发挥的逻辑。顶我们的编码被合并到大类型中的时候,后的三合一测试、功能测试甚至e2e的统考,都不可能覆盖到每一行的编码了。如果单元测试做的缺乏,其实就是在代码里面留下一些温馨都不知晓的土窑洞,哪天调用方改了部分东西,走到了一番不适用的分支可能就挂掉了。我之前带的品种中就出现过类似之状况,代码已经上点几年了,有一次稍微改了一下调用方的底数,认为是个小改动,但是上点就挂了,就是因为遇到了之前根本没有人测试过的分支。单元测试就是要保证我们团结写的编码是按照我们盼望之逻辑实现的,要求尽量的完成比较高的覆盖,确保我们团结之编码里面没有留下什么黑洞。关于测试,我想单独开一篇讨论,故此就先简单聊到此处。

要写好代码确实是已经非常不容易的作业,要求考虑正确性、读报、鲁棒性、可测试性、可以扩展性、可以移植性、性能。眼前讨论的只是个人以为比较重要的入门的组成部分线,想要写好代码需要经过刻意地考虑和练习才能真正达到目标!

相关链接

[1]https://google.github.io/styleguide/[2]https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/

【编纂推荐】

  1. 你只修改了2列代码,为什么需要两角时间?
  2. 谷歌再推 Kotlin:代码量比 Java 调减 80%
  3. 采用Cython加快你的Python代码
  4. 只有完美代码不够的,如何做一个完美的Pull Request?
  5. Github 名将你的编码打包送到了北极封存千年,戏友:这副糗大了,还有 bug 呢!!
【义务编辑: 武晓燕 TEL:(010)68476606】

点赞 0
  • 代码  机械  装备
  • 分享:
    大家都在看
    猜你喜欢
  • <strong id="2b3cbd66"></strong>

  • <samp id="314567f2"></samp>
  •