《架构整洁之道》学习笔记之编程范式

引言

近来开始阅读 Robert C. Martin 的新著《架构整洁之道》(Clean Architecture)。没有人愿意看到团队内的项目逐渐发展成一团乱麻,相互纠缠。那如何从根本上减少这种问题的发生呢?这就需要我们掌握一些宏观层面的设计思想,从给项目打基础时就应该考虑好各个模块、类、函数等如何设计成高内聚、低耦合的结构。整洁的项目架构是利于长远发展的,这篇笔记将会记录一些从书中学习到的重要知识点,便于后期复习和参考。

当然,作者还有一本大名鼎鼎的著作《代码整洁之道》也非常值得阅读,关于这本书也做了点笔记,参见《代码整洁之道》读书笔记~

要点记录

三大编程范式是根基,每种范式其实都给我们带走了一些东西:goto 语句、函数指针、赋值。三种编程范式的总结:

  1. 结构化编程Discovered by Edsger Wybe Dijkstra in 1968. Structured programming imposes discipline on direct transfer of control.
  2. 面向对象编程Discovered by Ole Johan and Kristen Nygaard in 1966. Object-oriented programming imposes discipline on indirect transfer of control.
  3. 函数式编程Invented by Alonzo Church in 1936. Functional programming imposes discipline upon assignment.

以上三种编程范式会影响到架构的方方面面:我们使用多态机制跨越架构边界;使用函数式编程影响数据位置和访问;使用结构化编程构建基础算法模块(基石)。可以对照软件架构三大概念:功能、组件隔离和数据管理

结构化编程

  1. 任何程序都可以由三种结构组成:

    1. Sequence
    2. Selection
    3. Iteration
  2. 结构化编程允许模块可以被递归地分割成很多小的可被证明的单元,这也就意味着模块可以按照功能解耦

  3. 科学并非依靠证明某些声明正确而存在,而是证明它们是错误的(Science does not work by proving statements true, but rather by proving statements false)。并非所有的事情都可以被证实的~
  4. Mathmematics is the discipline of proving provable statements true. Science, in contrast, is the discipline of proving provable statements false
  5. Dijkstra 曾经说过 Testing shows the presence, not the absence, of bugs。测试并不能保证你的程序一定正确,但是可以通过测试证明你的程序存在错误,并通过充分测试,让你的程序更加正确,直到满足我们的预期

面向对象编程

  1. 设计良好的架构需要我们理解并应用 OO 的一些原则
  2. 什么是面向对象:

    • 数据 + 行为的组合
    • 为真实世界建模
    • 封装(Encapsulation)、继承(Inheritance)和多态(Polymorphism)
  3. UNIX 系统要求每个 IO 设备驱动都需要提供五个标准函数:open, close, read, writeseek

  4. 多态实际上就是函数指针的应用,自从冯诺依曼架构诞生以来,程序员们就一直在使用这种技术了。但是显式地使用函数指针是很危险的,并且使用时需要遵循一些原则,比较麻烦。OO 则将你从中解放出来,让你更加轻松地实现多态。
  5. OO 允许在任何地方,为任何情形使用插件式架构(主要是多态的威力,其实在其它语言中,如 Rust/Go,使用接口机制也能达到类似的目的)
  6. 使用 OO 语言可以完全控制系统中源码的依赖方向。多态机制可以让任何源码依赖都可以被倒置,无论它们在哪儿
  7. OO 带来的好处,用几个关键字概括:

    • 依赖倒置(Dependency inversion)
    • 可独立部署性(Independent deployability)
    • 可独立开发性(Independent developability)
  8. 从软件架构的角度看,面向对象可以通过使用强大的多态机制,来控制系统源码依赖。这样可以创建出插件式架构,可以将更高层的抽象策略和底层的实现隔离开。底层的实现细节交给各个插件去完成,并且它们可以被独立开发和部署,而不会和更高层的模块耦合。

函数式编程

  1. 所有的竞争条件、死锁条件和并发更新的问题都是由可变变量导致的。函数式编程则限制了变量修改
  2. 将可变和不可变的组件隔离开来:不可变组件使用函数式执行任务(不使用任何可变量);不可变组件通过和可变组件通信的方式来做状态变更
  3. Event Sourcing: 核心策略是不存储状态,而是存储事务。当需要获取状态时,只需要从最开始回放事务,最终得到想要的状态。这样的系统就只有 CR(创建、读取) 了,而不会存在状态更新和删除。因此,很多并发引来的更新问题都不会发生(其实可以对比下基于日志式 LSM 的存储引擎)。

总结

结构化编程、函数式编程以及面向对象编程都分别给我们带来了不同的限制(To tell us what not to do),而非带来新的功能。
软件并非快速发展的高科技,因此很多原则至今依然适用。不管机器怎么变化、工具如何变得更好,但软件的本质还是一样。
所谓的软件程序不过就是由顺序、选择、循环结构(间接)组成,不多不少。

0%