编程的本质(极客时间 | 陈皓《左耳听风:编程范式游记》系列的其中一篇)
Program = Logic + Control + Data Structure
两篇论文
1976年,瑞士计算机科学家,Algol W,Modula,Oberon 和 Pascal 语言的设计师 Niklaus Emil Wirth写了“Algorithms + Data Structures = Programs” ,即“算法 + 数据结构 = 程序”。
1979 年,英国逻辑学家和计算机科学家 Robert Kowalski 发表论文 “Algorithm = Logic + Control”,论文里提到:
任何算法都会有两个部分, 一个是 Logic 部分,这是用来解决实际问题的。另一个是 Control 部分,这是用来决定用什么策略来解决问题。Logic 部分是真正意义上的解决问题的算法,而 Control 部分只是影响解决这个问题的效率。程序运行的效率问题和程序的逻辑其实是没有关系的。我们认为,如果将 Logic 和 Control 部分有效地分开,那么代码就会变得更容易改进和维护。
编程的本质
- Programs = Algorithms + Data Structures
- Algorithm = Logic + Control
第二个表达式想表达的是,数据结构不复杂,复杂的是算法。算法由两个逻辑组成,一个是真正的业务逻辑,另外一种是控制逻辑。业务逻辑是复杂的。
算法的效率往往可以通过提高控制部分的效率来实现,而无须改变逻辑部分(也就是算法的意义)。
举个阶乘的例子, X(n)!= X(n) * X(n-1) * X(n-2) * X(n-3)* … * 3 * 2 * 1
。
逻辑——定义阶乘:
1) 1 是 0 的阶乘;
2)如果 v 是 x 的阶乘,且 u=v*(x+1),那么 u 是 x+1 的阶乘。
控制——实现上面的逻辑:
用这个定义,既可以从上往下地将 x+1 的阶乘缩小为先计算 x 的阶乘,再将结果乘以 1(recursive,递归),也可以由下而上逐个计算一系列阶乘的结果(iteration,遍历)。
各种编程范式或程序设计的方法,比如:
- 函数式编程中的 Map/Reduce/Filter,它们都是一种控制。而传给这些控制模块的那个 Lambda 表达式才是我们要解决的问题的逻辑。它们共同组成了一个算法。
- 就像 Go 语言委托模式的那个 Undo。Undo 是我们要解决的问题,是 Logic,但是 Undo 的流程是控制。
- 就像我们面向对象中依赖于接口,而不是依赖于实现。接口是对逻辑的抽象,真正的逻辑放在不同的具象类中,通过多态或是依赖注入这样的控制来完成对数据在不同情况下的不同处理。
所有的语言或编程范式都在解决以下 3 个问题(它们体现了编程范式的本质):
- Control 是可以标准化的。比如:遍历数据、查找数据、多线程、并发、异步等,都是可以标准化的。
- 因为 Control 需要处理数据,所以标准化 Control,需要标准化 Data Structure。我们可以通过泛型编程来解决这个事。
- 因为 Control 需要处理用户的业务逻辑,即 Logic。所以,我们通过标准化接口 / 协议来实现,我们的 Control 模式可以适配于任何的 Logic。
把逻辑和控制分离
有效地分离 Logic、Control 和 Data 是写出好程序的关键所在!
业务逻辑决定了程序的复杂度,业务逻辑本身就复杂。把控制逻辑和业务逻辑放在一块,代码就不可能写得简单。
Logic 是程序复杂度的下限。Logic + Control 的互相交织成为了最终的程序复杂度。
- Logic 是你的业务逻辑:逻辑过程的抽象 + 一个由术语表示的数据结构的定义。业务逻辑跟控制逻辑是没关系的。
- Control 即程序执行的方式:一个程序流转的方式(自顶向下、自底向上) + 执行过程的策略(并行或串行,同步或异步) + 调度不同的执行路径或模块 + 数据之间的存储关系。这些和业务逻辑没有关系。
以文本解析为例
无双BaOY_WHA:前不久,我自己写了一个“服装制板语言”的解释器,代码里把 Logic 和 Control 都混在了一起,全部在一个解析函数里,这个函数十分冗长。
学习完“编译原理之美”后,我发现写“文本解析”有通用的套路:
- 词法分析。用一个有限自动机来匹配特定的 Token;
- 语法分析。用“递归向下”、“上下文无关”等方法构建一个“抽象语法树”。
- 语义分析。……
这个通用的套路就属于 Control。有篇关于正则表达式的高效算法的论文,叫“Regular Expression Matching Can Be Simple And Fast”。
以表单检查为例
常见的检查用户表单信息的代码:
function check_form_x() {var name = $('#name').val();if (null == name || name.length <= 3) {return { status : 1, message: 'Invalid name' };}var password = $('#password').val();if (null == password || password.length <= 8) {return { status : 2, message: 'Invalid password' };}var repeat_password = $('#repeat_password').val();if (repeat_password != password.length) {return { status : 3, message: 'Password and repeat password mismatch' };}var email = $('#email').val();if (check_email_format(email)) {return { status : 4, message: 'Invalid email' };}//...return { status : 0, message: 'OK' };}
其实,我们可以做一个 DSL + 一个 DSL 的解析器,比如:
var meta_create_user = {form_id : 'create_user',fields : [{ id : 'name', type : 'text', min_length : 3 },{ id : 'password', type : 'password', min_length : 8 },{ id : 'repeat-password', type : 'password', min_length : 8 },{ id : 'email', type : 'email' }]
};var r = check_form(meta_create_user);
这样,DSL 描述是“Logic”,而 check_form
则成了“Control”,代码就非常好看了。
小结
代码复杂度的原因:
- 业务逻辑的复杂度决定了代码的复杂度;
- 控制逻辑的复杂度 + 业务逻辑的复杂度 => 程序代码的混乱不堪;
绝大多数程序复杂混乱的根本原因:业务逻辑与控制逻辑的耦合。
- Logic 部分才是真正有意义的(What)
- Control 部分只是影响 Logic 部分的效率(How)
如何分离 Control 和 Logic 呢?我们可以使用下面的这些技术来解耦。
1.状态机 - State Machine
- 状态定义
- 状态变迁条件
- 状态的 action
2.DSL - Domain Specific Language
- HTML,SQL,Unix Shell Script,AWK,正则表达式……
3.编程范式
- 面向对象:委托、策略、桥接、修饰、IoC/DIP、MVC……
- 函数式编程:修饰、管道、拼装
- 逻辑推导式编程:Prolog
编程的本质(极客时间 | 陈皓《左耳听风:编程范式游记》系列的其中一篇)相关推荐
- 极客时间学习笔记-左耳听风
本文笔记全部来自<极客时间-左耳听风> 2018-09-21 弹力设计篇之"幂等性设计" Twitter 的 Snowflake 就是一个比较好用的全局 ID实现. P ...
- 左耳听风-开篇词 :洞悉技术的本质,享受科技的乐趣
左耳听风-开篇词 :洞悉技术的本质,享受科技的乐趣 01 | 导读 1)作者的职业背景是金融和电商行业,主要研究方向是大规模分布式系统的基础架构. 2)作者为多个企业做过内部培训和分享,培训内容包括: ...
- 【极客时间】《Java并发编程实战》学习笔记
目录: 开篇词 | 你为什么需要学习并发编程? 内容来源:开篇词 | 你为什么需要学习并发编程?-极客时间 例如,Java 里 synchronized.wait()/notify() 相关的知识很琐 ...
- 本人亲自整理的极客时间设计模式之美的硬核笔记
由于笔记内容过多,我把它放到语雀上了. 点击我 以下内容是为了让搜索引擎,检测到这篇文章.要阅读体验,请点击上面的连接"点击我",去我的语雀看.对了,我看到语雀那里有投诉的功能,请 ...
- 【极客时间-网络编程实战】
极客时间-网络编程 盛延敏 文件 实战思维导图 开篇词│学好网络编程,需要掌握哪些核心问题? 学习高性能网络编程,掌握两个核心要点就可以了:第一就是理解网络协议,并在这个基础上和操作系统内核配合,感知 ...
- 极客时间《Java并发编程》学习笔记
该领域是跟着"极客时间"平台的课程<Java并发编程>入门的,讲师是王宝令.说实话,这个领域如果抱着大部头的书就啃的话,由于缺少实践很难会建立一个体系,即不知道为什 ...
- 极客时间App安卓版上线,让知识获取更加简单
在12月8日于京举办的 ArchSummit 全球架构师峰会上,极客邦科技正式宣布旗下 IT 知识服务产品-极客时间 App 继 iOS 版本发布后,蓄势一个月,安卓强势上线,已全面登陆各大应用市场. ...
- 极客时间算法练习题总结
文章出处:极客时间<数据结构和算法之美>-作者:王争.该系列文章是本人的学习笔记. 在极客时间<数据结构和算法之美>最后,王争老师加餐了7天训练内容,对每一部分需要掌握的数据结 ...
- 【极客时间】左耳听风
极客时间-左耳朵耗子 01程序员如何用技术变现 上 02 程序员如何用技术变现下(2022/9/25) 10 渴望.热情和选择(2022/10月5日) 02 程序员如何用技术变现下 如何让自己的技能变 ...
最新文章
- 新手求助,关于添加隐式intent程序崩溃问题
- stm32实际运用中遇到的问题
- 从nginx日志原始二进制数据还原文件
- .net core项目启动时报_未处理Socket异常(以一种访问权限不允许的方式做了一个访问套接字的尝试。)...
- 我们的2008。。。。。。
- 【算法基础】十大经典排序算法(动图)
- 在kubernetes集群中运行nginx
- 用JavaScript往DIV动态添加内容
- python 第3天
- python数据分析工具_python数据分析工具 | pandas
- 【免公众号】新版盲盒交友程序源码盲盒交友系统一元交友
- MFC 程序设计读书体会
- 计算机组成原理学习笔记——数据通路
- vue引入jsmind(右键菜单)
- hdu 3932 Groundhog Build Home
- Mybatis-Plus 传入时间查询的方式
- 8分频verilog线_任意分数分频Verilog实现
- 【关于NI CAN USB-8473在实际应用中的案例分析】
- java读取word中的表格并存入到mysql数据库中实例
- php 实现ppt转动态swf,如何将ppt转换成swf,ppt转swf的软件,ppt转换flash
热门文章
- 嘉立创SMT贴片打板流程
- SHELL脚本之编写脚本实现调整屏幕亮度的脚本
- 项目经理:你来设计一下Redis 故障转移、高可用的方案
- 【视觉-摄像机1】opencv 调用工业摄像机(USB接口和GigE接口)
- PHP中实现常用邮箱的判断
- java程序发布与部署_java程序UAT的部署
- 五邑大学和广东药学院计算机,请问韶关学院,五邑大学,仲恺农业技术学院这三间学校哪间好一点?...
- 采集数据零点漂移问题解析
- Linux7怎么禁用IPv6使用IPv4,centos7关闭ipv6仅使用ipv4的操作过程
- no SQ lines present in the header解决方案