假如你刚参与了一个算法项目,当你第一次打开这个项目时,发现里面已经有上万行与算法相关的代码,仔细查看过后,发现如下一些让你抓狂的问题:
1、代码写的非常冗余,维护已经变得越来越困难。
2、几乎没有任何注释。
3、非常错乱的代码风格,让你有一种感觉打开了一个杂乱的网站的html页面。
4、存在那么几个函数,单个函数的源码超过500行。
5、每一次需求的变更,都意味着一次痛苦的代码编写。
这是笔者以前参与一个算法项目时遇到的问题。
在参与这个项目时,大家都在很努力的使项目往期望的方向走,但随着开发进度的往前推进,项目的复杂性正在不断加大,大家都在尽可能使用自己了解的最好的技术将系统打造的更为强壮,但系统但复杂性一点也没有降低。在需求但不断变化中,代码的冗余也越来越明显。程序中到处充斥着废弃的代码,但谁也不敢轻易去删除,谁也不清楚自己的一个不经意操作,是否会导致整个程序的奔溃。
对于代码的开发,里面包含了很多细枝末节的东西,特别对于需要高度配合的项目(如算法人员和工程人员之间),细节的处理是否妥当,将很大程度影响项目是否可以成功交付,跨行之间的配合与细节的处理是大部分开发者所欠缺的,这类人才也是市场上急需的。
python的设计宗旨是简单、优雅、明确。
但很多开发人员通过自己的努力将其做成了复杂、丑陋、晦涩。
结合Python之禅与自己的开发经验,给出如下一些观点与建议,希望可以为你带来一些帮助:
01 优美胜于丑陋
代码除了完成指定功能,同时也是给人看的。优美的代码和优美的风景一样,都能让人感到赏心悦目,优美的代码是一种艺术,相对于丑陋的代码,大家都会倾向于查阅优美的代码。
在工作过程中,尽可能往编写优美代码的方向走。
02 明了胜于晦涩
在代码编写中使用明了的词语来命名方法名、函数名或变量名是非常好的习惯。命名很好的代码,可以省略很多代码注释的工作,优秀的代码会说话。
编写优秀的代码,代码本身就是注释。
最好的代码是不需要注释就可以让大部分人都可以看懂,这需要编写者有很强的编码功底和语言抽象功能,很多时候并不要求所有开发这都有这种能力,但也需要在少量的代码注释情形下可以让代码阅读者可以快速看明白你写的代码。
如果可能,尽量减少晦涩代码的出现,大部分情形下,晦涩代码的出现都是因为开发者对需求了解不清楚或没有用更简单的方式思考,对于代码的负责人,若看到出现类似代码,应当小心谨慎,需要了解对应的需求是否确实会如代码那么晦涩,还是开发人员想复杂了。
03 简单胜于复杂
把简单的事情做复杂并不难,但要把复杂的变得简单,那需要付出巨大的艰辛。
在工程应用中,把简单的需求做得复杂的案例数不胜数;而能通过抽丝剥茧的方式把复杂应用场景拆分的很简单的案例少之又少,当今市场极为缺乏有这种能力的人才。
复杂的来源也是有很多当时以为简单的事情堆积而成的,在多种简单的组合过程中,继续保持整体的简单,是一件值得思考的事情,这要求在对整体了解的情况下对各个细节的把控,编程本来就是一门对细节要求极高的技术,当对细节的掌控了然于胸时,编写出简单的代码就水到渠成了。
04 复杂胜于凌乱
我们排斥复杂,但有时复杂难以避免。可以复杂,但不要凌乱。有迹可循的复杂代码还是具有可读性的,至少可以从代码层面找到处理逻辑。
当代码以凌乱的方式出现时,那是会让人非常崩溃的。犹如你与人交谈时,若与你谈话的人一直东一句,西一句,让你根本不清楚对方在讲什么,估计你与对方聊上几分钟就不想聊了,并期望不想再遇到类似的聊天对象。编程也一样,对于那些凌乱的代码,大家都是避之不恐。
05 扁平胜于嵌套
在编写代码时,每增加一个嵌套,则意味着代码的复杂度增加了一些,代码的执行效率对应的下降了一些。
当出现三层以上的嵌套时,那说明代码编写思路出现了偏差,对于这种代码,应该会非常浪费系统的资源,甚至全部耗尽。实际应用中应当避免,并寻求其它更简单的实现方式。
能用扁平的方式实现时,就不要使用嵌套实现。
06 间隔胜于紧凑
若是面向计算机编程,代码间隔紧凑与否是没有任何关系的。但若需要不断被开发人员查看,适当的间隔那就非常有必要了,组织良好的代码不仅仅是逻辑清晰,在代码结构上也是非常有讲究的,很多时候都会遵循PEP8的规范,那样写出来的代码是让人赏心悦目的。
另一方面,这也能帮助你编写出更加高效的代码,因为通过合理的控制代码结构,当程序发生问题时,组织良好的代码结构可以帮助你更快的找到问题。
07 可读性很重要
很多时候,我们编写的代码除了让计算机执行指定的程序,另一个很重要的点就是给其他人查看。而代码的可读性决定了会有多少人愿意读你的代码。
现在很流行的一个词叫开源代码,对于开源代码,可读性在很大程度上决定了有多人愿意参与到这个开源中。
而对于项目应用中,编写一份可读性非常高的代码是非常必要的,尽管很多时候是以功能优先。提高代码的可读性,不仅仅是一个自我的修炼过程,对于团队、甚至公司,都可以更好的减少开发、维护和学习成本的。
08 特例不足以特殊到违背这些原则
在代码编写过程中,不可避免会需要对某些特例提供支持,甚至有时为了可以支持特例,需要违背一些已有的好的原则。
当有需要类似的操作时,需要做更为全局的平衡,这个特例是否必须,是否有其它可处理方式,怎么最小化特例给其它原则带来的破坏。
09 实用性胜过纯粹
编写代码的首要原则是可用,在可用的基础上才有可能执行其它如性能优化、效率提升等操作。
实用性与纯粹性不同,纯粹性更多体现在实验或验证性操作上,很少参与到真实环境中的应用,而我们需要的是可以在真实环境中可用的代码。
010 永远不要默默地忽视错误
当程序出现错误时,那已经在提示我们程序中的某处代码并没有如我们想象的那么完美,它编写有Bug或是有隐藏Bug,需要我们进行正确的处理,若置之不理,很有可能埋下一颗定时炸弹,在某一刻让你的程序直接崩溃,这种的代价往往都会不小。
在实际的应用中,即时是很小的问题,也不要选择忽视,建立起必要的异常管理,而不要等到问题发生时才进行亡羊补牢的操作,殊不知可能会为时已晚。
011 面对模棱两可,拒绝猜测
计算机的世界是0或1的世界,是即是,非即非,没有不确定性的存在,也没有任何的猜测。
对于编写的任何代码,都应该是清晰的,没有歧义的,若出现有歧义或不清晰的情形,那表明开发者对需要通过代码实现的问题理解不到位,或是有猜测的成分,这种都是需要杜绝的。
012 解决问题最直接的方法应该有一种,最好只有一种
在编程的世界里,任何问题的解决办法都有多种,但更多的时候我们需要的是最直接的方法,并最好只有一种最直接的方法。
如对编程语言的选择,对于科学计算和人工智能相关的事情,最直接的选择就是使用Python,这个对于目前来说是最直接的唯一选择。
013 做也许好过不做,但不想就做,还不如不做
对于编程的过程,是一种知行合一的过程,光靠执行很多时候并不能得到期望的结果,还需要伴随思考的过程。越是大的项目,前期思考的时间占比就越多。在动手之前先做一些计划,对全盘先有一个大致了解,把可能遇到的问题,会存在的瓶颈,会占用时间比较多的步骤,需要协助的资源等先做一个前期的规划,会非常有利于后期的执行的。
若期望一开始就撸起袖子直接干,那不是一个很建议的方法,除非你对需要做的事情已经非常熟悉,否则还是有必要认认真真想一想需要做什么。
014 如果方案难以描述明白,那么一定是个糟糕的方案
对于编程来说,编写的应该是一个确定的事情,并且已经有可以描述明白的方案。
对于不清晰的方案,编程上更不可能清晰。
一个糟糕的方案只会诞生一个糟糕的项目,项目里面则包含各种晦涩的代码。
015 如果实现容易描述,那可能是个好方案
若一个实现可以通过类似伪代码的方式描述出来,这基本上是一个可行的方案,若可以通过伪代码容易的描述,那很有可能是个好方案,真实的应用上还有很多其它的外界因素,只有结合那些因素,才能完全的确定这是否是一个好的方案。
016 命名空间是一种绝妙的理念,多加利用
在编码的过程中,命名的冲突是一个非常需要小心的问题,这种问题一般不容易发现,出现问题时的查找并不容易,所以需要充分借助命名空间的理念,尽量避免如命名冲突的问题。
通过命名空间控制变量的作用域,可以起到很好的变量的相互隔离的效果。
结语:
编码是一件快乐的事情,特别当看到一些貌似不太可行的事情,通过编程的方式变为可行时,会感到一种发自内心深处的快乐。并且当一群人通过群策之力,完成一件艰巨的任务时,创造出一些amazing的事情时,那是一种不可言喻的喜悦。
而编写出如艺术般的代码需要付出很多,也需要经过时间的锤炼,但当它出现在大家眼前时,是需要一种心境的追求才可以企及,任何人都可以往这个方向追求,它没有任何标准,没有任何约束,有的只是你的不断创造,在计算机编程这块沃土上,还有一个超大的空间等待更多的人去开拓。