本文转载自公众号“读芯术”(ID:AI_Discovery)。
即使是在软件开发领域,我们也一直想象着,会否有一本“武林秘籍”能让人很快打通任督二脉,进入软件开发能力和效率的全新境界。
“软件开发没有捷径可走!每个人都需要练习才能变得更好!”这样的话我们听了很多次了,但是那些拥有10倍效率的软件生产力实践专家是怎么做到的?有没有什么要领可以让人突飞猛进?有的!
但是,即使我把它分享给你,详细地讲给你听,你可能也需要花费10年的时间才能掌握它,充分体会到它的简单性。我就是这样的。我的高中编程老师用通俗易懂的语言阐明了这一点,然后我通过一些示例代码,逐步了解了应用它的流程。但直到10年后,它才真正深入我心。
这个秘密就是平均效率和10倍效率之间的关键区别。掌握它,你能拥有全新的效率,当出现新的需求以及代码环境发生变化时,你可以编写出重用性更高、损坏性更低的代码。
这个秘诀就是掌握抽象化。很多开发人员讨厌“抽象化”这个词,你会听到这样的建议,比如“不要过早抽象化”,或是《Python之禅》中著名的“显式比隐式好”,暗示具体化比抽象化好。
这些建议本身是没有问题的,但一切都取决于具体内容。现代应用程序使用了大量的代码。如果你把现代十大应用的源代码打印出来,纸张高度能与摩天大楼一较高下,而软件的维护成本也很高。你创建的代码越多,成本就越高,而抽象化是简单代码的关键。
约翰·前田在《简单法则》中写道:“简单就是减去明显的东西,加上有意义的东西。”正确的抽象化可以通过隐藏对当前上下文不重要的细节,减少执行相同工作所需的代码量(通常是几个数量级),从而使代码更具可读性、适应性和可维护性。
图源:unsplash
抽象不是一个单向的概念。它实际上是由两个互补的概念构成的:
- 泛化--删除重复的(显而易见的)的部分,并将其隐藏在抽象之后。
- 特殊化--将抽象应用于特定用例,仅添加需要不同的部分(有意义的)。
请看以下代码:
- constdoubleList= list => {
- const newList = [];
- for (var i =0; i < list.length; i++) {
- newList[i] = list[i] * 2;
- }
- return newList;
- };
这段代码本身没有什么问题,但其中包含了很多细节,对该特定的应用而言可能并不重要:
- 包含一个显式赋值,而不是以声明方式描述要执行的操作,这太冗长了。
- 包括正在使用的容器/传输数据结构(数组)的详细信息,这意味着它仅适用于数组,它包含状态形状依赖性。
- 包括迭代逻辑,这意味着如果你需要其他操作,这些操作也需要访问数据结构中的每个元素,那么你也需要在该代码中重复非常相似的迭代逻辑。它强制重复,这违反DRY原则(请勿重复自己)。
这些都是没有必要的部分,可以将其隐藏在“抽象”之后。如此一来,这种通用性很强的方法就能改变现代应用程序的构建方式,减少我们需要编写的显式for循环的数量。
使用map操作,可以将代码简化为单行本,即通过删除明显的部分(我们很可能在类似代码中重复的部分),专注于有意义的部分(只是对于我们的用例来说需要不同的东西):
- constdoubleList= list => list.map(x => x * 2);
初级开发人员认为他们必须编写大量代码才能产生很多价值,而高级开发人员理解无需编任何写代码的价值。
想象一下,作为一名编码员,你在像JavaScript这样的编程语言中广泛使用了map操作。Map可以把详细信息抽象化,例如你要映射的数据类型,包含该数据的数据结构的类型以及枚举数据结构中每个数据节点所需的迭代逻辑。正是这样,十年来,它提高了我开发每个应用程序的效率。
图源:unsplash
杰里米·阿什肯纳斯使此类操作在JavaScript中变得很流行,并通过开拓在CoffeeScript中的使用,为我们在JavaScript中理所当然的许多重要语法快捷方式铺平了道路。
他制作了Underscore和Backbone,Backscore产生了Lodash(JavaScript中最受欢迎的功能编程实用程序带),Backbone则使JavaScript中的MVC架构得以普及,并为Angular和React奠定了基础。
约翰·雷西格制作了非常流行和有影响力的jQuery,它形成了可重用的、封装的JavaScript模块(jQuery插件)的最大集合,直到几年后出现了标准的Node模块和ES6模块。
jQuery的选择器API如此有影响,它构成了当今DOM选择API的基础。当要对React组件进行单元测试时,我仍然能从jQuery的选择API中受益。
给我一个足够长的杠杆和支点,我就能翘起地球。正确的抽象就是可以极大地影响生产力的强大杠杆。抽象并不是一个令人讨厌的字眼,模块、函数、变量、类,所有这些都是抽象的形式,它们存在的全部原因是为了简化抽象和抽象的构成。
没有抽象就不能构建复杂的软件。即使是汇编语言也会使用抽象——指令名称、内存地址变量、子例程(如函数调用)跳转到的代码点等。现代软件是由抽象构成的分层蛋糕,每一层都给你一个撬动不可能的支点。
图源:unsplash
我们所追求的高效率关键在于简单性,即如何减少正在生成的代码数量,如何用更少的资源完成更多的工作,掌握抽象化,你就掌握了秘诀。