要理解好的代码,你需要多多编写“不好”的代码

  要理解好的代码,你需要多多编写“不好”的代码

  网络上有许多 “切记不要…”的文章:不要使用继承(inheritance),千万别用单例模式(singleton),scrum将被淘汰。这些真的都不能用吗?如果语句真的很差劲,我们又该如何甄别哪些建议可取呢?

  没有完美的编程语言,也没有最好的编码方式,有的只是指南(也就是已知的缺陷)。很多编程建议十分夸张,每个人都告诉你不要再做这做那。照这样发展,每个指令都是故障之源,我们很快就没有指令可用了。就如同人们并不指望开卡车过木桥能到达对岸,但这不意味着木桥没有承载力,也不是说人们不该开卡车。

  编程语言只是工具。使用的时机、原因以及方法取决于我们自己。不能因噎废食,我们该改进的是使用方式。

  怎样辨别糟糕的建议?

  好的建议有三个组成部分。首先,信息本身;第二,何时使用;第三,何时不用。糟糕的建议通常缺少第二和第三部分——通常呈现出永久适用的特征。

  一个常见的话题是:“不惜一切代价避免使用继承机制”。如果没有适用和不适用条件,你可能会盲从建议而舍弃面向对象系统(OO系统)最关键的工具。如果该建议变成:“继承机制是非常好的工具,但深层次机构(deephierarchies)通常有害。”这次问题很显然出在“深度”上,这个解释精准且洞悉了问题——浅层次机构是好的。

  另一个要注意的就是语言。很多作者往往“肆意下笔,从不更正”,这样的基调在充斥着互联网。为了撰写“肆意”而“肆意”撰写是极有害的,作者不会说明他的建议并非普遍适用。为了避免语气折损,他们往往不点明不适用条件。好的建议应是友好的,而不是强硬的。每个真诚帮助过你的人都不会是怒气冲冲的。

  经验之谈

  涉及到编码,有两条经验尤其适用:

  创造和维护语言非常昂贵。如果新语言中不断加入某种机制,那说明该机制十分重要。这就是全局作用域、继承机制和如果语句仍然存在的原因。任何一篇声称该摒弃它们的文章都忽视了这些机制的重要性。

  举一个很好的例子:类型系统。Python和JavaScript因为不需要分类而吸引了许多开发者,之后就会后悔用无结构语言写了上千行代码。“落伍的”Java和C#就不存在这个问题(也不是说它们就没缺点)。

  这就难怪TypeScript会出现。类型系统会返回弱类型语言——你输入一部分,编译器会补足剩下的。这一想法非常成功,分别通过 var 和 auto关键词打入了C#和C++的世界,甚至Python现在也引入了类型系统。

  · 与之相反,第二条经验是:现代语言从设计上淘汰了混乱的部分。

  这就是宏、goto语句和显式内存管理消失了的原因。过去,Java的垃圾回收机制(GC)饱受抨击,但几乎所有现代语言的GC都不再需要Java虚拟机(JVM)了。

  最近移除的是空指针异常。像Kotlin和Swift这样的现代语言用设计执行null检查,C#8也是同样的,Raw threading和async callbacks也存在自己的问题。现在,我们编写异步程序时就可以使用便捷的async/await语法。

  而这一切都说明:想做一个更好的程序员,需要了解编程语言的历史。

  大多语言由富有工具意识的人创造,由社群指引着发展。每次加入新要素,整个群体都会专注地探讨元素的相关性和对群体的价值,也包括如何完善元素设计。改变和移除元素时也是如此,Python 3做了许多引人瞩目的突破性改变,都卓有成效。

  多编写不好的代码

  我们使用的是数十年以来的创新成果和失败设计。

  只有潜心于“劣质的”C/C++代码,你才能真正地领略到垃圾堆叠的语言之美。这之前你只是想象过去编码有多痛苦,那些写过单例模式并深受其扰(有很多问题,比如编写测试)的人才能真正理解那种痛恨。

  教科书上的示例与实际操作千差万别。前者不过是个提示,后者才会真正改变你的编码方式。

  大多人开始的时候都不会使用Git或Unit Tests来编码。这些项目往往漏洞很多,也经常不能运行。没有Git,你无法得知是否不小心更改了什么。没有测试,你的代码会在某次故障后直接不再运行。诸如此类的体验是促使我们每天使用这些工具的原因。

  要真正理解如何写好代码,首先要会写不好的代码。有几种能促使自己编写糟糕代码的方式(或者找到现有片段的缺点),其实归根结底一件事:试着用另一种方法编码,从而得知你的方案有多好或者过去有多糟。

  下面是你闲暇时间可以做的事:

  学习一门父系语言: 举例来说, Kotlin的父系语言是Scala,Swift等语言的诞生是为了解决Objective-C存在的问题,C#取代了Java。学习父系语言能为你展示过去没有但“今天拥有的”,也使人们更加珍惜今天人们唾弃的很多工具。

  学习一门“承继”语言: C++开发者应该尝试Rust,Java开发者试试Go,Python对应Julia或Nim,JavaScript对应TypeScript或Dart。与学习父系语言不同,学习承继语言将揭露现有缺陷及怎样解决。

  学习LISP:很多人觉得这个语言很怪。LISP没有变量,它是纯函数式编程语言(比Haskell简单)。你不需要精通这门语言,只需尝试写一些算法,比如斐波那契(Fibonacci)、快速排序算法( quick-sort)或者哈夫曼编码(Huffman coding)。如果沉下心慢慢做,你会发现变量在很多情况下并不重要。

  用纯C语言写一个文本处理器: 为文本文件设置一个路径,打开它并删除所有换行符,在每个句号后(.)加入新换行符,然后重组每个单词,保持第一个和最后一个不变。如果处理后每一行都保持平行就值得表扬。它能快速反映出字符串处理的巨变。

  找出设计模式: 准备一个设计模式的清单,并打开你正在做的或做过的项目。花些时间阅读每种模式,并找到某种模式适用的地方。想象每个模式运用在这个项目中将会多简洁,这是将设计模式整合到项目中的最佳方法。

  这些技巧要么改变你的编码方式,要么帮助你审视已完成的代码。无论哪种都会让你意识到一切都不是想象得那样光鲜亮丽。

  我并不是在讲对与错,也不是讲怎样编码,而是在邀请各位多多编码。代码是一种新的语言,尝试用两种方式完成同一件事情,多写代码才是码农的终极进阶之道。

原文地址:https://www.cnblogs.com/yyuyu/p/13705980.html