date: 2017-12-26 22:52:46
title: 「编程风格: 好代码的逻辑」 读书笔记
编程风格 - 图灵社区: http://www.ituring.com.cn/book/1724
编程风格 - 百度脑图: http://naotu.baidu.com/file/3c02e1c237197b958ce2068fb8c297bf?token=9cc47ce46f4699e1
这引用图灵社区的听到的一个段子:
编程活久见, 你总有遇到的一天
看完这本书, 以后就不容易发出 还有这种操作 的感慨了.
悠久的历史
往日的美好
就让这 往日的美好 时刻警醒我们, 宽裕的内存与合适的名字 是多么的美好
Forth 风格
有一个 数据栈 有一个 数据堆, 开发者以 过程 的形式抽象(一组指令)
基本风格
单片风格
- 没有命名的抽象对象
- 没有或几乎不使用库
一长串的代码, 而且从头至尾没有提出任何新的抽象概念, 也没有使用许多库里已有的抽象概念.
食谱风格
- 没有长跳转
- 过程函数
- 全局变量共享状态
一般认为, 过程函数对这一变量具有副作用
流水线风格
- 函数间无状态共享
- 复合函数
高尔夫风格
- 尽可能简化代码
函数组合
无限镜像风格
- 使用归纳法, 对问题或其核心部分进行建模
骨牌风格 Kick Forward
- 每个函数都有一个额外的参数, 通常是最后一个, 该参数是另一个函数
- 在函数的末尾, 函数参数会被调用
单子风格
- 封装数据, 使之抽象化
- 将若干函数逐个绑定在抽象上, 建立函数调用顺序
- 打开封装, 查看数据最终结果
对象与对象交互
对象风格
- 较大问题被分解为问题域相关的对象
- 每一个对象都是一个数据封装, 过程暴露在外面
- 数据只能通过这些过程访问, 不可直接访问
- 每个对象可以重新定义在其他对象中已经定义好的过程
消息风格
- 较大问题被分解为问题域相关的对象
- 每个对象是仅公开一个过程的数据封装, 只能接收和发送消息
- 消息分发机制能将消息发送至另一个封装
闭域风格
- 较大问题被分解为问题域相关的对象
- 每个对象是一个键值映射, 其中某些值是 过程/函数
- 对象的方法引用对象自身的键, 使得映射是闭的
抽象对象风格
- 较大问题被分解为问题域相关的对象
- 抽象对象的定义是对对象抽象的行为
- 具体对象以某种方式与抽象对象绑定, 绑定机制不定
- 应用程序的其他部分并不依赖对象的内容, 而依赖对象的行为
好莱坞风格
- 利用不同形式的抽象(对象/模块等), 将较大问题分解成若干个实体
- 这些实体不能被直接调用
- 这些实体为其他实体提供接口, 使其他函数能注册回调
- 在计算的特定情景中,这些实体调用其它已注册过回调的实体
公告板风格
- 发布事件订阅事件
- 公告板执行所有事件管理和分配工作
反射与元编程
内省风格
- 利用不同形式的抽象(对象/模块等)分解较大问题
- 抽象可以获得自身以及其他抽象的信息, 但不能改变这些信息
反射风格
- 内省
- 程序在运行时, 可以通过增加对象/变量等方法进行自我修改
切面风格
- 问题的切面
- 一个外部绑定机制将抽象和切面绑定在一起
插件风格
- 主程序与每个包单独被编译
- 有一个外部说明来定义哪些包需要被加载, 通常形式为 配置文件/路径约定/用户输入/其他用于运行时加载外部代码的机制
异常处理
构建风格
- 每一个函数检查自身参数的和合理性, 当参数不合理时, 返回合理的结果/给参数制定合理值
- 所有的代码块检测可能存在的错误, 当发生错误时, 跳过代码块, 设置合理的状态,并继续执行函数的其他部分
Tantrum 风格
- 每一个函数检查自身参数的和合理性, 当参数不合理时, 程序停止运行
- 所有的代码块检测可能存在的错误, 当发生错误时, 可能将上下文相关的信息写入日志, 同时将错误传递回函数调用链
消极攻击风格
我现在是没有抗议的, 但这是不对的, 我迟早会抗议的
- 每个过程和函数分别检查参数的合理性, 当参数不合理时, 停止运行并跳出
- 在调用其他函数时, 程序仅检测能够提供有意义反馈的错误
- 异常处理在函数调用链中位于叫上层合适的位置, 仅在程序的最外层进行异常处理, 无视异常实际发生的位置
声明意图风格
- 类型申明
隔离风格
- 核心程序没有任何副作用, 包括 IO
以数据为中心
持久表风格
- use db: 持久数据/查询数据
试算表风格
- excel: 试算表 -> 数据流编程
漂流风格
- 数据可用形式为数据流, 而不是一个整体
- 函数是数据流的 过滤器/变换器
- 根据下游的需求对上游的数据进行处理
并发
参与的风格
- 与消息风格类似, 但其中每个对象在独立线程中运行
数据空间风格
- 并发单元只能通过数据空间进行数据交换
Map Reduce 风格
数据分块 -> 并行 Map -> Reduce 重组成输出
双重 Map Reduce 风格
第二个 Map 使用 Reduce 作为参数, 达到 Map/Reduce 都并行执行
交互
三层架构风格
- MVC
- 所有实体均与这三者之一相关, 每部分职责不同
Restful 风格
- 资源的 CRUD
词汇表(知识点)
列表: list, 对应其他语言中 数组(array)
元组: tuple, 不可变列表, 其他语言中通常使用 常量(const)
列表下标: 数组下标, 著名的从 0 开始计数
上下界: 著名的 数值溢出/数组越界 问题
字典: dict, 对应其他语言的 hash/map
self: 对应其他语言的 this
构造函数: __init__
, 对应其他语言的 __construct()
OOP: object-oriented programming
类 对象 属性 方法 扩展/继承/覆盖 实例 单例
基类 = 超类 vs 继承类 = 子类
抽象类: 不能直接实例化的类, 只能被其它类继承
代理: 某个对象使用其他对象的方法执行过程的能力
消息分发: 接受消息/解释消息标签并确定执行步骤的过程. 该过程可能是 方法执行/错误返回/向其他对象转发消息
原型: 无类面向对象语言中的对象. 原型带有自己的数据和函数, 可以自由的改变而不影响其他对象. 新原型可以通过复制已存在的原型获得
抽象数据类型: 通过自身操作抽象定义的实体
装饰器: 其设计目的在于允许行为被增加在个别对象上, 能够在不改变源代码的情况下改变函数和方法
控制反转: 任何支持独立开发的代码, 被通用库和组件调用的技术
事件 - 发布 - 订阅
内省: 程序获取自身信息的能力
反射: 程序获取自身信息并自我修改的能力
什么时候需要反射: 在设计过程中, 当无法预期代码被修改的方式时, 会使用反射
eval
切面: 受限制的反射; 关注于分析已有问题分解的实现是否违背使用非反射分解方式集中代码程序; 关于高熵源代码的话题
AOP: aspect-oriented programming, 面向切面编程
依赖注入: 支持动态加载函数和对象具体实现的技术
插件: plugin/addon
错误代码: errorno, 特定组件指示错误信息
异常: 程序运行中超出正常预期的情景; 一种 有结构的/良性的/受限制 的 GOTO 语言替代方案
动态类型检查 vs 静态类型检查
显示类型 vs 隐式类型
强制类型转换 vs 类型推理 vs 类型安全
ACID: atomicity consistency isolation durability -> 保证一致性
Tantrum-ish: 保守方式
RDB
NoSql: 对象关系型
公式: 函数 -> 根据其他值, 在数据空间上, 更新某个值
协同程序: 支持推迟和恢复执行的多个入口和出口的程序
生成器: (即半协同程序)一种特殊的协同程序, 用于控制值的迭代. 生成器通将控制返回至调用方, 而不是程序任意一处
迭代器: 用于遍历值的对象
参与者: 拥有独立线程的对象/网络中每某个处理节点. 参与者拥有一个接收消息的队列, 参与者之间通过发送消息交互
异步请求: 在异步请求中, 请求者不等待回复, 回复在请求结束后返回
消息: 发送者与接收者之间信息的数据结构, 该过程可能通过网络实现
基底(substrate) 元组 数据 空间: 类型数据对象
数据操作三个原语: in / out / read; put / get / sense
主动 MVC vs 被动 MVC
主存: RAM, 内存, 能够被 CPU 直接访问
辅存: 借助内存才能被 CPU 访问(硬盘等)
栈: 数据结构; 支持内存执行的活动区域; 过程/函数调用的数据
堆: 数据结构; 动态内存的分配和释放
栈机器: 使用栈而不是寄存器来支持程序表达式的计算
栈溢出: 程序耗尽栈内存的情况
尾递归: 在函数尾部发生的递归调用
尾递归优化
控制流: 程序指令的执行顺序和表达式的评估顺序, 包括 条件/迭代/函数调用/返回等
副作用: 副作用是指一个程序中能观察到的变化部分. 副作用包括 向文件/屏幕写 / 读取输入 / 改变可观测变量的值 / 引起异常等. 程序通过副作用与外部相互作用
幂等性: 若一个函数和过程是幂等的, 对其进行多次调用将观察到同样的结果, 与一次调用的效果毫无二致
不可变变量 vs 可变变量
过程函数
高级函数: 把函数作为输入或者输出的函数
柯里化: 一种将多参数函数转化成一系列高阶函数的组合技术, 其中每个高阶函数只带有一个参数
函数: 在数学中, 函数是一种输入映射到输出的关系; 在编程中, 函数是接收输入并产生输出的过程
纯函数 vs 非纯函数: 是否受外界因素影响
惰性计算: 一种程序执行策略, 直到需要计算结果时才执行计算
后续: 后续是一个表示 程序剩余部分 的函数. 该概念服务于不同目的, 优化编译器/提供指称语义/异步处理. 又因为能够为函数的非本地返回, 提供一般化的机制, 后续也作为 goto 语句/异常 等语言结构的替代方案
回调地狱: 一种面条是代码的形式, 因嵌套了过多重匿名函数作为参数而形成
单子: 一种将已定义的计算步骤封装的结构. 一个单子包含两个主要操作: 构造函数创建单子的同时封装数据; 绑定操作以函数作为参数以某种方式将函数绑定在单子上, 并返回单子(可能是单子本身). 除此之外的第三种操作用于 打开封装/输出/计算 此单子
回调函数
框架: 一类特殊库/可重用组件, 提供一个能被进一步开发的通用应用程序功能
圈复杂度: 一个用来衡量代码复杂度的标准 CC = E - N + 2P
LOC: line of code; SLOC, source line of code