架构师进阶之《Your Mouse is a Database》
Design = Computation + Semantics
我们在讲设计的时候很少去讲设计模式,设计原则这些东西,并不是说没有用。为什么没有重点去讲设计模式和原则呢?
2000 年左右
自己的一些经历:
那时候还没有敏捷的概念。
其实在软件工程比较发达的地区,已经有一些负面的声音,因为商业性太强了。
2000 年的时候,敏捷的概念还没有出来,那个时候有个统一的称呼,是叫轻量级方法。XP 是一个比较先锋的方法,是以技术实践为核心的。主要是围绕编程这件事情。对于小团队来说开发效率提高很多。
XP
2000 左右的时候,XP 和自己想的很一致,感觉就是为程序员量身定制的一样,但那个时候还是个异类。
XP 非常推崇代码质量,kent beck 是 smalltalk 的创始人,面向对象的推崇者。
XP 就把设计模式的潮流推了起来。
个人当时用 C++编程,各种设计模式。当时也是非常痴迷,各种设计模式的书籍。每次会议都提交上百个模式。感觉就不太对,发现永远都学不完。
总结
2003 年的时候,打算把之前学过的东西都用一下。做完之后,把做的东西总结,写了一个书。
《嵌入式电信软件开发》
1.面临挑战,电信领域开发,平台多变,硬件多变,可靠性,升级平滑,快速演进。。。。
2.瀑布式缺点。
3.把结构化方法批评一下。基本都是套话,是不是造成问题的原因,也说不清楚。
4.面向对象。世界观讲起,依赖管理。
要想开发好软件,一定要用敏捷,一定要用面向对象
5.TDD,CI,重构
6.如何向组织引入敏捷开发
7.领域驱动设计
8.各种模式
9.Conduits+框架
10.Active Object 模式
11.主备同步
12.AOP 和横切关系处理
反思
这些东西是不是真的好。假设把电信两个字去掉,却可以应用到其他任何领域。那么既然是这个设计应用于电信领域,为什么可以通用到各个领域。
电信软件到底有哪些特点?
很多根本的问题没有解决,比如说不停机?比如说如何容错?
主备倒换可以做到一些,但是主备倒换是粒度很粗的。
这些核心问题都没有很好的解决方案。
设计模式这个层次上没有办法解决这些问题。
如果说反过来看,哪些是起关键作用的。发现两点起了关键作用:
1.问题定义
2.主备保护
Two Papers
<Concurrent functional programming for telecommunications>
<Making reliable distributed systems in the presence of software errors>
看了这两篇论文之后,一切都清楚了。
告诉了你怎么评价一个好的设计。
Pearls of software Engineering
各种方法论:瀑布,XP,敏捷,看板,lean 等
编程语言:上万种语言
设计原则,设计模式:数不胜数
整个软件工程发展至今,反思一下,哪些是真正的精华(珍珠)。
只有编程语言是不可或缺的。其他大部分都是昙花一现。这个东西是确确实实的。是根本性的东西。可以从根本上改变设计的东西。
What does really mean?
我们用 XXX 语言编程是什么意思?
Computation Model + Semantics
用汇编语言,用 C 语言真正的区别是什么?真正的感受是什么?
jmp 和 while 循环是什么区别?汇编语言是在操作物理机器,C 语言看到的虽然也是一个机器,但是层次不一样了。
汇编语言只有全局的,C 语言有局部变量。
本质上就是计算模型和语义不同了。这是决定性的。
这些东西决定了我的开发生产力。
我们面对的问题语义层次更高了。
Rethinking
Semantics
其实程序语言和程序是一回事
假设你用汇编语言编了一段时间,有没有想到发明一个更高层次的语言?
计算的描述和执行分离
x=y+1
这个表达式是个计算的描述,但是在 C 语言里写完之后,我就再也控制不了它了。
计算的描述和执行分离是一个非常强大的解耦技术。
C 语言其实也是个计算的描述。
面向对象变成了世界观,对于世界上所有东西进行建模。这也就是为什么面向对象有那么多新东西出来,其实就是不停的打补丁。
例子:
SQL,makefile
计算模型的区别是根本性的区别。
例子:
界面布局,计量系统,状态迁移表。。。
计量系统
计量系统是啥?如果不能回答的话,只是回答了很多设计模式,设计原则,相当于白做了。只能用对象模型上面去解释。
面向对象只是更好的汇编语言
计量系统的本质就是个向量计算。
状态迁移表是一个模型。是一个状态机的抽象。然后有个解释器解释这个表。
线性代数
向量和矩阵只是语法,背后是计算模型。线性代数也是个 DSL。
总结
面向对象是很好的实现工具,但不是唯一的建模工具。
Design
核心步骤
Problem Domain -> Requirements -> Computation Model + Semantics
-> Languages(API/Data representation) -> Interpreter/Compiler
这条路可以走很远,可以一直走下去。
设计模式。面向对象只是一种特定的计算模型。设计模式大部分情况下都是补丁。
DDD。像 DDD 的思想很早之前就已经很流行了,《DDD》这本书就很难懂,依附于面向对象,把问题搞复杂了。核心就是划分不同的子领域,应用不同的计算模型。
DCI。是 06 年提出来了,职责分派。系统的整体的行为看不见,DCI 就是解决这个问题的,就是解决面向对象的缺陷。核心思想把对象的角色(行为)和数据进行分离,Context 就是场景,纯的函数就是描述我的计算。这样我就能看到一个核心的视图了。数据的继承和方法的继承性质完全不一样,如果放在一起就会出问题。
字符串解析领域用 C 语言也可以写,但是抽象出来正则表达式就不一样了。
如果是特定领域,只要把核心的东西拿出来,定义好数据表达,就已经很好了。
总结
什么是编程:
不过是在某种计算模型的基础上表达计算。
什么是程序:
程序是一个特定的机器,这个机器可以用通用机器来模拟。
CASE: POTS loop
电话系统。
现在比较流行的是 Reactive Programming。有个 Reactive 联盟。今年 armstrong:Reactive 系统其实早就有了,就是交换机。Reactive 里面所有的概念都是通信领域的一些概念。
Distrubute Networks Server
我们希望事件是有序的,但是实际上来的时候是无序的。
Semantics Gap:
Order vs unorder
Determinism vs Non-Determinism
Thread(顺序型的 sequential) Vs Event(Callback)
方式 1:Block 串行调用
可以,但是不可用的。吞吐量太差。
每个用户一个线程,太消耗资源。
方式 2:Non-Block
状态机变复杂了。
电信领域
电信领域 10 大问题
需要的语义
封装语义
并发
错误检测
位置透明
动态代码升级
基于这样的语义解决
编程问题 Count Down
思路
给我一个问题,我先把这个问题说清楚。
先不考虑性能,一定对的方法,把问题描述清楚。
总结:先形式化一个答案。
问题:什么才是一个正确的解?
先解决你给我一个解我告诉你是否是正确的解。
这个做完之后可以进行程序证明。
Your Mouse is a Database
基础是并发。
是面向并发编程的一个概念在里面。
ACM 的一篇论文,是一个库的核心思想的展现。
UI 的编程模型虽然经过几代的变换:
1.loop 循环,加 listener
2.事件回调,OnMouseDown, OnMouseUp
所以鼠标也是产生数据的东西,和数据库没什么区别,鼠标也是产生数据的源。
鼠标一点数据就出来了,在数据层面上没有区别,在 DB 可以用 SQL 来写。那 OnMouseDrag 怎么写呢?在原子操作里是没有 OnMouseDrag 的原子的。
状态机模式
通用方法:
OnMouseDown 之后,置一个标志,OnMouseMove 就开始是 OnMouseDrag 了,OnMouseUp 之后再把标志回位。
其实就是个状态机
select 模式
select * from xxx
不然整个逻辑都散落在钩子函数里面去。
我们能不能像 SQL 语句那样对鼠标进行编程。
典型应用
流式
无限
实时
异步实时消息推送的场景
比如,订阅一个话题,有消息推送给我。
如何对这样的场景进行编程呢?如果用回调的方式编程,业务的复杂性非常高的。
实例:单次补齐
场景:用户输入太快,大于 200ms 才有效。否则会有重复。
数据正方体。
解决低延时的数据流。
Callback Model
return in one shot
回调都是返回 void,回调函数是无法通信的,只能通过全局变量
Non-first class value
1.先解决 void 的问题:
现有个返回值出来,以前是 void,现在需要一个返回结果,后面可以操控的东西。
Result
close
get data
这个叫做 Future,并发编程里都有这个概念。
2.如何把 Future 变成非 Block
Block 和 pull 是一个事情,主要是数据来的时候我不知道。
解决方法,挂接回调函数。
异步消息特点:
不定期,可能是源源不断的。这样推演下来我们把整个异步流当成一件事情
stream behaviour
tuple module 语法
Code Now
模式小总结
这种方式用面向对象的方法来解决永远解决不了的。这是计算模型的胜利。
从语义出发。
iterater 和 oberserver
在数学上是对偶的。iterator 也是个流。一个是 pull,一个是 push。
《Gof》那本书可以扔掉?
解决 mouse up 的问题
刚才只实现了一半。现在要解决 up 的问题。
结束条件
mouse drag 是有条件的 mouse move 流,从语义的角度来看。我们还需要什么语义?
mouse drag = mouse move between (mouse down, mouse up)
所以我们需要实现一个 between(s1,s2) ->form s1 ...until s2
组合
组合是一个非常重要的性质,大的程序可以通过小的程序组合而来。until 应该是比 between 更基础的原子。
code
有什么问题?
没有 unsubscribe,在哪个时机 unsubscribe?
编译不过。
自己引用自己没有办法,就要寻求外面的力量,可以改一下 stream 的实现
扩展 stream 协议
应用 erlang 的 behaviour
并发
电信领域,并发是最本质的特性。
评论