引用一下维基百科的定义:
1.声明式编程 Declarative Programing
In computer science, declarative programming is a programming paradigm — a style of building the structure and elements of computer programs—that expresses the logic of a computation without describing its control flow.
This is in contrast with imperative programming, which implements algorithms in explicit steps.
2.命令式编程 Imperative Programming
In computer science, imperative programming is a programming paradigm that uses statements that change a program's state. In much the same way that the imperative mood in natural languages expresses commands, an imperative program consists of commands for the computer to perform. Imperative programming focuses on describing how a program operates.
The term is often used in contrast to declarative programming, which focuses on what the program should accomplish without specifying how the program should achieve the result.
这一大堆英文怎么理解呢?
想象一下,在家的时候,你对妈妈说,‘妈,我要吃糖醋排骨!’。显而易见,你只是想要吃糖醋排骨,至于糖醋排骨是你妈妈忙活一番做出来的,还是你妈妈点了外卖,外卖小哥冒着风雪送来的,只要糖醋排骨能让你满意,其它的你也许都不关心。
同样的,公司领导对你说,你这个月的业绩要上千。至于你是加班加点累死累活,还是轻松悠哉看看剧就能做出这个业绩,说实在的,领导并不关心。
又或者,操作html的DOM结构时,你想获取class包含beautiful的所有DOM元素,你只需要声明一下document.querySelectorAll('.beautiful'),而不用关心js引擎怎么去把DOM tree翻得底朝天,将这些元素都给找出来返回给你。
以上,结论是:
在家时,你关注的是糖醋排骨,妈妈操心怎么给你弄来糖醋排骨,你是在做声明式编程,而你妈妈是在做命令式编程。
在公司时,领导关注的是业绩,你操心的是怎么把业绩做到上千,领导是在做声明式编程,而你是在做命令式编程。
操作DOM时,你关注的是结果,而js操心的是怎么把你要的结果都找到和拿回来,你是在做声明式编程,而js引擎是在做命令式编程。
声明式编程,关注的是what to do,即做什么。
命令式编程,关注的是how to do,即怎么做。
这两种编程范式,都能在生活和代码里随处可见。
每天上课或上班之前,给自己写的便签,上面罗列了一堆要做的事。是声明式编程。
礼拜天想炖个汤,给自己补补身子,按食谱上的一步步说明来做。是命令式编程。
.....
太多例子,就不逐一说明了。
现在,我们大概是理解声明式编程与命令式编程的含义与区别了。
不过,光理解,是远远不够的,编程编程,既然是编程,那就是要编写程序用起来的。在我们编写程序的时候,怎么运用它们呢?它们能给我们带来什么样的启发和思考呢?
上述例子里,想必是做妈妈的比较烦心,做员工的你比较烦心,js引擎也比较烦心,因为大家都要干很多脏活累活,方方面面都思考和准备了许多,怕不是头发都要掉光了。相反,声明式编程的人们就快活多了,只需要说一两句话,表明一下自己的想法,就能实现愿望。
于是,我们会期望,“伟大的阿拉丁神灯啊,能帮我把代码都写了么?”,阿拉丁神灯就说:“孩子啊,代码就不用写了,帝都二环的十套别墅已经给你准备好,请安心享受人生吧!”
开个玩笑,能声明式地写代码,那当然会很舒心,可声明式编程显然是建立在命令式编程的基础上的,脏活累活没人干的话,一堆堆声明就只是摆设,没啥用。
编程早期,sql这东西还没出现,大家都是自己干苦力活,要查什么数据都是撸一遍又一遍的循环,还要操心各种锁啊,事务啊等等乱七八糟的问题,简直天天怀疑人生。后来sql出现了,想要啥数据,只需要对数据库说 SELECT XX FROM XXX,多简单,多惬意。
不过,随着时代的发展,网页内容越来越丰富,从数据库里查数据虽然简单,但将数据以特定的结构组装起来,通过接口返回给浏览器展示可是很烦人的事情,接口少还能忍受,可接口一多,大概也还能忍?然而要改变一堆堆接口的数据结构呢?大概是想掀桌子打人老子不干爱谁谁干的感觉?
究其原因,是因为写接口(给前端调用的接口)这件事,是脏活累活,是命令式的编程。那么,能不能把它变成声明式的编程?
老祖宗教导过我们,在计算机的世界里,没有什么问题是添加一个中间层解决不了的事情,不信看看OSI标准模型,或者TCP/IP协议栈?当然,真要解决不了,那就再加一层呗。
于是,几十年过去,终于有人想起要把写接口的大部分脏活累活都承包了下来,封装成一层,叫
GraphQL。
从此,写接口只需要声明自己要什么样的数据,而不用操心那些改来改去的烦心事了。(现在的GraphQL还有诸多缺陷,比如N+1、权限控制等问题,不过这些都会逐渐改进的)
当然,不止写接口这件事,在我们日常的工作中,也存在许许多多类似的情况。例如,初始化一个工程或项目,如果没有相应的脚手架工具,要自己一遍遍按部就班地搭基础设施得多累?有了脚手架,声明一个项目,就能给你把demo搭出来。可以说是半自动化了。自动化是为了什么?还不是为了解放生产力?此外,也是为了更好地降低出错概率,以减少因为出错导致的成本。毕竟相对于人来说,机器出错的概率实在是低得多了。
又比如,我们是不是时不时会被一些项目困扰?那些烦人的糟糕的架构设计,代码里层出不穷的BUG,产品经理不断带来的改来改去的需求,所有这些,都可以归根为命令式编程带来的问题:繁琐、脆弱、多变。
有没有那么一些解决方案,能把这些命令式编程的脏活累活都干了,抽象出对人类友好的声明式接口。就像令无数人头疼的正则表达式一样,存不存这么一种声明式的正则引擎,例如,声明 [提取出所有十二位数的手机号码],正则引擎就像数据库一样给出我们想要的结果?
看起来像人工智能?大概就是这样了。
从命令式编程到声明式编程的过渡, 是技术不断发展进化的过程。
----------------
后记:命令式编程与声明式编程并无优劣之分,使用对象是我们人类的时候,声明式编程的风格自然是更好的,这是人的惰性决定的。但对机器而言,命令式编程显然更好理解,更准确来说,一大串010111的机器码是更方便理解的。另外,从代码调试的角度来看,声明式编程不好调试,甚至无从调试,比如js引擎,当querySelectorAll接口出错的时候,你还能直接断进去调试?所以这要求我们在做命令式的脏活的时候,要提供稳定、靠谱的服务。