【数据的创建与更新】
数据有两个重要属性:
1.首先数据是基于时间的,数据是表达一段时间内一个逻辑为真的事实。
2.另外一个属性是数据本质上是不可变的,因为和时间有关,我们是不能回到过去改变数据的真实性。
这两个属性就意味着:对数据你其实只有两个主要的操作:1) 读取现有数据 2) (随着时间)添加更多新的数据
也就是从传统的 CRUD(增查改删-通常称为增删改查) 变更为 CR(增Create,读-Read)。
其实U(修改)和R(删除)是没必要的,因为修改对不可变数据是不起作用的(非常类似DDD中值对象不可变,不能修改,只能更换),而大部分删除实质是创建新数据。比如:(Bob停止跟随Mary,但是他们不能改变他曾经跟随过他的事实。因此删除个他不跟随她的数据,实际上是应该增加一个数据记录,说他在某个时刻不再跟随她了。)
【状态的变化 的原子性】
其实状态变化有两种思维:一种是过程形式,一种是逻辑形式。
过去我们的实体都是列出对其认识的内在属性,当事件发生致使实体发生变化时,往往就是加锁后逐一改变,或者事务方式(类似副本方式)。“逐一改变”就是过程式,具体详细地描述变化过程,于是在并行的时候缺失原子性,为了实现避免脏读等问题,加锁成了一种手段。当然,事务方式也解决了这样的问题,这与非副本的不变值对象方式,是达到同样目的的不同方式,同时这两者都属于逻辑表达。以前我作过比较,在领域当中谈论逻辑变化,我认为后者较好。
值对象是实体状态的一种落实,我过去提出过的观点,这是源自于状态变化的逻辑形式思维。谈论逻辑时,状态迁移必须具有原子性,所以我在某个帖子说值对象不变性,可以达到去锁的目的。
注意:值对象不变性源自值,并非因为实体状态,是因为值对象具有值的不变性,所以才能成为实体状态的落实。
一些更深入的认识:
存在状态变化即存在副作用(side effect),所以实体是副作用存在的因。很多人认为副作用是坏的,应该去掉,但这只限于逻辑运算时。只要人们想获得信息,副作用就根本不能避免,最容易理解就是print。
可变的实体与不可变的状态,正好就是副作用存在的分界线。实体之所以会存在,其实是因为人们想获取信息,于是值对象(值)载体便出现了——引用对象(即实体对象)。
状态迁移,就是实体发生变化,它说明实体从一个状态迁移到另一个状态。这里面最小单元是状态,也就是说我们考虑的不是状态的构成及其内在变化(逐一改变),而是计算出新状态,然后以“替换”的手段来实现实体变化。这与我们所说到的值对象不变性和事实是最小单元如出一辙。(所以“状态迁移”是一种事实观)
状态是表达一段时间内一个逻辑为真的事实,这句话很好说明了事实观与实体观的联系。
过去我思考“什么是实体”,其实实体很简单,就是一个KEY,是为了区别与其他存在的存在。而我们写类的时候,其中的id并非实体KEY,而“类名+类id”才是实体KEY。所以关系数据库中表方式与类方式类似,并不完全满足事实观,而key-value数据库能更好展现逻辑。关系数据库的数据平铺方式,使得查询速度极快,同时实现了逻辑查询,但这并非从实现“产生事实的逻辑”角度出发的——事件的角度。
immutable is eveything,不可变是一切。
状态变化是由事件引起的,从事件来划分。
The immutability exists not for the sake of itself. Immutability is abstraction. It does not "exist" in nature. World is mutable, world is permanently changing.....
一、
其实这就是一种“连续”和“离散”思维的区别,尽管世界在我们感官中是连续的,但连续过程和中间的“切面状态”不是我们关注的,业务说的是规则,是逻辑的,正如我们经常说的“业务逻辑”。在规则或者逻辑中,不存在所谓的切面状态。例如“借书”这一个原子动作,有人会“借一半”,或者说“借一半”是我们所关注的状态?
二、
若果我们一个个地改属性,当改了第一个属性值,没改第二个属性值时,这就存在了所谓的切面状态。单线程时,因为顺序执行,不会读出切面状态,变相成为原子操作,但多线程并发时,读出无效的切面状态是可能的。解决的方式:
1)改的时候不能读,就是我们以前用得最多的锁;
2)随时可读,改的时候必须“同一时间”完全改完,而这就是不变性的整体替换;
3)当然后来又想到一种,读与改不会同时进行,暂时感觉比较复杂,没有深入,浅思考了下,感觉实时相对较弱。
三、
还有一点,事务性和不变性,个人认为两者很像,但又有点不同:
1.事务讲究复制隔离,达到不相互影响,而且最后也需要替换。
2.不变性无需复制,因为其一开始就要求在逻辑运算期间是“不能改”。
两者相似点:
1)并行时都是相互不影响;
2)更新时都是替换手段。
不同点:
1)事务的参与逻辑是在逻辑执行前就复制好,得到隔离性;事务包装整个过程,实现原子性。
2)不变性方式的“结果对象”是在逻辑执行完后,根据各种条件创建的,其原子性体现在替换,并不是包装过程。
总的来说就是一前一后,事务有点像“平行世界”的概念。还有有趣的一点是,不变性前后两个状态不要求是同构的。不变性还有很多有趣的地方,这里就不一一列举了。而不变性也有缺点的,如要多对象同时改变时,需要机制来处理。
为什么有这样大统一美妙大道至简的现象呢?因为计算机软件系统是本身是符号逻辑或者形式逻辑或分析逻辑的一种体现,而不变性是逻辑上的一个基础概念(蒯因与引用透明),如果你学习了分析逻辑的这个基础,你就找对了方向,但是如果你学习几十年数据结构和算法基础,你不一定能悟出其背后的逻辑真义。
VO相对的是RO(ReferenceObject),独立于“状态、实体”概念的,或者说是不同层次的。只是VO和RO出现相对较早,而且比较吻合“状态、实体”概念。所以,值对象只是状态的落实,或者说实现。
“实体状态在某个时间点上状态是静止的”,瞬时的实体状态映射到计算机就是不变的数据,在对象思维中就是值对象。而实体则是RO,不过注意的是这个引用概念有点变化,并不是引用地址,而是变成实体KEY。
值对象的不变性是源自于值概念的,试想为啥非要叫做“值对象”,而不叫“不变对象”。