<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_专注于面向对象、领域驱动设计，及软件架构方面的学习</title><subtitle type="text">要学会站在巨人的肩膀上让自己成长。QQ：94388050</subtitle><id>http://feed.cnblogs.com/blog/u/17223/rss</id><updated>2012-06-01T23:50:13Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/17223/rss"/><entry><id>http://www.cnblogs.com/netfocus/archive/2012/02/12/2347938.html</id><title type="text">聚合（根）、实体、值对象精炼思考总结</title><summary type="text">1. 聚合根、实体、值对象的区别？从标识的角度：聚合根具有全局的唯一标识，而实体只有在聚合内部有唯一的本地标识，值对象没有唯一标识，不存在这个值对象或那个值对象的说法；从是否只读的角度：聚合根除了唯一标识外，其他所有状态信息都理论上可变；实体是只读的；值对象也是只读的；实体唯一与值对象有区别的地方是实体有一个聚合内唯一的标识，而值对象没有任何唯一标识；从生命周期的角度：聚合根有独立的生命周期，实体的生命周期从属于其所属的聚合，值对象无生命周期可言，因为只是一个值；2. 聚合根、实体、值对象对象之间如何建立关联？聚合根到聚合根：通过ID关联；聚合根到其内部的实体，直接对象引用；聚合根到值对象，直</summary><published>2012-02-12T06:22:00Z</published><updated>2012-02-12T06:22:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347938.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347938.html"/><content type="html">&lt;p&gt;&lt;strong&gt;&lt;span style="font-size:16.0pt;"&gt;1.&lt;span style="font-family: 'Times New Roman'; font-size: 7pt; font-weight: normal; "&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-size:16.0pt;font-family: 宋体;"&gt;聚合根、实体、值对象的区别？&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;从标识的角度：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;聚合根具有全局的唯一标识，而实体只有在聚合内部有唯一的本地标识，值对象没有唯一标识，不存在这个值对象或那个值对象的说法；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;从是否只读的角度：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;聚合根除了唯一标识外，其他所有状态信息都理论上可变；实体是只读的；值对象也是只读的；实体唯一与值对象有区别的地方是实体有一个聚合内唯一的标识，而值对象没有任何唯一标识；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;从生命周期的角度：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;聚合根有独立的生命周期，实体的生命周期从属于其所属的聚合，值对象无生命周期可言，因为只是一个值；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-size:16.0pt;"&gt;2.&lt;span style="font-family: 'Times New Roman'; font-size: 7pt; font-weight: normal; "&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-size:16.0pt;font-family: 宋体;"&gt;聚合根、实体、值对象对象之间如何建立关联？&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;聚合根到聚合根：通过&lt;/span&gt;ID&lt;span style="font-family:宋体;"&gt;关联；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;聚合根到其内部的实体，直接对象引用；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;聚合根到值对象，直接对象引用；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;实体对其他对象的引用规则：&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;）只能引用其所属聚合内的聚合根、实体、值对象；&lt;/span&gt;2&lt;span style="font-family:宋体;"&gt;）必须确保实体是只读的；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;值对象对其他对象的引用规则：只需确保值对象是只读的即可；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-size:16.0pt;"&gt;3.&lt;span style="font-family: 'Times New Roman'; font-size: 7pt; font-weight: normal; "&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-size:16.0pt;font-family: 宋体;"&gt;如何识别聚合与聚合根？&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;明确含义：首先聚合代表了某个上下文边界，此上下文边界表示某个独立的业务场景，聚合根是聚合边界内的一个根实体；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;识别顺序：先识别有哪些聚合边界，再确定每个聚合边界内的哪个实体是聚合根；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;聚合边界确定法则：根据不变性约束规则（&lt;/span&gt;Invariant&lt;span style="font-family:宋体;"&gt;）。不变性规则有两类：&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;）聚合边界内必须具有哪些信息，如果没有这些信息就不能称为一个有效的聚合；&lt;/span&gt;2&lt;span style="font-family:宋体;"&gt;）聚合内的某些对象的状态必须满足某个业务规则；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;例子分析&lt;/span&gt;1&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;：订单模型&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Order&lt;span style="font-family:宋体;"&gt;（一&lt;/span&gt; &lt;span style="font-family: 宋体;"&gt;个订单）必须有对应的客户信息，否则就不能称为一个有效的&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;；同理，Order对OrderLineItem有不变性约束，&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;也必须至少有一个&lt;/span&gt;OrderLineItem(&lt;span style="font-family:宋体;"&gt;一条订单明细&lt;/span&gt;)&lt;span style="font-family:宋体;"&gt;，否&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;则就不能称为一个有效的&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;；另外，&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;中的任何&lt;/span&gt;OrderLineItem&lt;span style="font-family:宋体;"&gt;的数量都不能为&lt;/span&gt;0&lt;span style="font-family:宋体;"&gt;，否则认为该&lt;/span&gt;OrderLineItem&lt;span style="font-family:宋体;"&gt;是无效&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;的，同时可以推理出&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;也可能是无效的。因为如果允许一个&lt;/span&gt;OrderLineItem&lt;span style="font-family:宋体;"&gt;的数量为&lt;/span&gt;0&lt;span style="font-family:宋体;"&gt;的话，就意味着可能会出现所有&lt;/span&gt; OrderLineItem&lt;span style="font-family:宋体;"&gt;的数量都为&lt;/span&gt;0&lt;span style="font-family:宋体;"&gt;，这就导致整个&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;的总价为&lt;/span&gt;0&lt;span style="font-family:宋体;"&gt;，这是没有任何意义的，是不允许的，从而导致&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;无效；所以，必须要求&lt;/span&gt; Order&lt;span style="font-family:宋体;"&gt;中所有的&lt;/span&gt;OrderLineItem&lt;span style="font-family:宋体;"&gt;的数量都不能为&lt;/span&gt;0&lt;span style="font-family:宋体;"&gt;；那么现在可以确定的是&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;必须包含一些&lt;/span&gt;OrderLineItem&lt;span style="font-family:宋体;"&gt;，那么应该是通&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;过引用的方式还是&lt;/span&gt;ID&lt;span style="font-family:宋体;"&gt;关联的方式来表达这种包含关系呢？这就需要引出另外一个问题，那就是先要分析出是&lt;/span&gt;OrderLineItem&lt;span style="font-family:宋体;"&gt;是否是一个独立的聚合&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;根。回答了这个问题，那么根据上面的规则就知道应该用对象引用还是用&lt;/span&gt;ID&lt;span style="font-family:宋体;"&gt;关联了。那么&lt;/span&gt;OrderLineItem&lt;span style="font-family:宋体;"&gt;是否是一个独立的聚合根呢？因为聚合根意&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;味着是某个聚合的根，而聚合有代表着某个上下文边界，而一个上下文边界又代表着某个独立的业务场景，这个业务场景操作的唯一对象总是该上下文边界内的聚合&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;根。想到这里，我们就可以想想，有没有什么场景是会绕开订单直接对某个订单明细进行操作的。也就是在这种情况下，我们&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;是以&lt;/span&gt;OrderLineItem&lt;span style="font-family:宋体;"&gt;为主体，完全是在面向&lt;/span&gt;OrderLineItem&lt;span style="font-family:宋体;"&gt;在做业务操作。有这种业务场景吗？没有，我们对&lt;/span&gt; OrderLineItem&lt;span style="font-family:宋体;"&gt;的所有的操作都是以&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;为出发点，我们总是会面向整个&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;在做业务操作，比如向&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;中增加明细，修改&lt;/span&gt; Order&lt;span style="font-family:宋体;"&gt;的某个明细对应的商品的购买数量，从&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;中移除某个明细，等等类似操作，我们从来不会从&lt;/span&gt;OrderlineItem&lt;span style="font-family:宋体;"&gt;为出发点去执行一些业&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;务操作；另外，从生命周期的角度去理解，那么&lt;/span&gt;OrderLineItem&lt;span style="font-family:宋体;"&gt;离开&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;没有任何存在的意义，也就是说&lt;/span&gt;OrderLineItem&lt;span style="font-family:宋体;"&gt;的生命周&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;期是从属于&lt;/span&gt;Order&lt;span style="font-family:宋体;"&gt;的。所以，我们可以很确信的回答，&lt;/span&gt;OrderLineItem&lt;span style="font-family:宋体;"&gt;是一个实体。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;例子分析&lt;/span&gt;2&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;：帖子与回复的模型，做个对比，以便更好地理解。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;不&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;变性分析：帖子和回复之间有不变性规则吗？似乎我们只知道一点是肯定的，那就是帖子和回复之间的关系，&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;：&lt;/span&gt;N&lt;span style="font-family:宋体;"&gt;的关系；除了这个之外，我们看不到任何其他的&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;不变性规则。那么这个&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;：&lt;/span&gt;N&lt;span style="font-family:宋体;"&gt;的对象关系是一种不变性规则吗？不是！首先，一个帖子可以没有任何回复，帖子也不对它的回复有任何规则约束，它甚至都不知道自&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;己有多少个回复；再次，发表了一个回复和帖子也没有任何关系；其次，发表回复对帖子没有任何改变；从业务场景的角度去分析，我们有发表帖子的场景，有发表&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;回复的场景。当在发表回复的时候，是以回复为主体的，帖子只是这个回复里所包含的必要信息，用于说明这个回复是对哪个帖子的回复。这些都说明帖子和回复之&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;间找不出任何不变性约束的规则；因为帖子和回复都有各自独立的业务场景的需要，所以可以很容易理解它们都是独立的聚合根；那也很容易知道该如何建立他们之&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;间的关联了，但是我们要尽量减少关联，所以只保留回复对帖子的关联即可；帖子没有任何必要去保存一个回复的&lt;/span&gt;ID&lt;span style="font-family:宋体;"&gt;的列表；那么你可能会说，当我删除一个帖子&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;后，回复应该是没有存在的意义的呀？不对，不是没有存在的意义，而是删除了帖子后导致了回复对帖子的关联信息的缺失，导致数据不一致。这是因为帖子和回复&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;之间有一种必然的联系（&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;：&lt;/span&gt;N&lt;span style="font-family:宋体;"&gt;），回复一定会有一个对应的帖子；但是回复有其自己的生命周期，不应该随着帖子的删除而级联删除。这种情况下，如果你删除了&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;帖子，就导致回复也成为了一条无效的数据；所以，我们绝对不允许删除任何聚合根，因为一旦你删除了聚合根，那就意味着与该聚合根相关的其他任何聚合根都会&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;有外键引用缺失的问题，会导致整个领域模型数据的不一致；所以，永远都不要删除聚合根；&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2347938.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347938.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2012/02/12/2347923.html</id><title type="text">项目管理总结图</title><summary type="text"/><published>2012-02-12T06:08:00Z</published><updated>2012-02-12T06:08:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347923.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347923.html"/><content type="html">&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/13665/2012021214071475.png" alt="" /&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2347923.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347923.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2012/02/12/2347921.html</id><title type="text">STATE BEHAVIOR CAP</title><summary type="text"/><published>2012-02-12T06:06:00Z</published><updated>2012-02-12T06:06:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347921.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347921.html"/><content type="html">&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/13665/2012021214050440.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/13665/2012021214051983.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/13665/2012021214053456.jpg" alt="" /&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2347921.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347921.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2012/02/12/2347919.html</id><title type="text">LMAX架构</title><summary type="text">Reference URL:http://martinfowler.com/articles/lmax.html该架构主要基于：Disruptor + In Memory DDD + Event Sourcing通过高并发框架（Disruptor）实现用户事件的输入和Domain Event的输出；一个常驻内存的Business Logic Processor（DDD领域模型），它负责在纯内存中处理业务逻辑；关键点：首先确保用户输入事件被持久化到数据库，并定时创建快照，然后在内存中响应事件更改业务对象的状态；因为一切都是在内存中处理，所以没有IO，也不需要数据库事务，非常快；机器down了怎么</summary><published>2012-02-12T06:04:00Z</published><updated>2012-02-12T06:04:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347919.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347919.html"/><content type="html">&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/13665/2012021214023190.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/13665/2012021214025031.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/13665/2012021214031164.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div&gt;&lt;div style="font-size: 19px;"&gt;&lt;span style="border-collapse: separate; color: #000000; font-family: Arial; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"&gt;&lt;strong&gt;Reference URL:&lt;/strong&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="border-collapse: separate; color: #000000; font-family: Arial; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"&gt;&lt;span style="font-size: 15px;"&gt;http://martinfowler.com/articles/lmax.html&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;strong&gt;&lt;span style="border-collapse: separate; color: #000000; font-family: Arial; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"&gt;&lt;span style="font-size: 15px;"&gt;该架构主要基于：Disruptor + In Memory DDD + Event Sourcing&lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-size: 15px;"&gt;通过高并发框架（Disruptor）实现用户事件的输入和Domain Event的输出；&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 15px;"&gt;一个常驻内存的Business Logic Processor（DDD领域模型），它负责在纯内存中处理业务逻辑；关键点：首先确保用户输入事件被持久化到数据库，并定时创建快照，然后在内存中响应事件更改业务对象的状态；因为一切都是在内存中处理，所以没有IO，也不需要数据库事务，非常快；&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 15px;"&gt;机器down了怎么办？因为我们首先确保了业务对象的任何状态改变之前先持久化用户输入事件，所以在down机的时候通过事件回溯重新得到最新的业务对象。因为有了快照的保存，所以重建对象也非常快；&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div style="font-size: 15px;"&gt;&amp;nbsp;&lt;/div&gt;&lt;div style="font-size: 15px;"&gt;该架构的主要观点：&lt;/div&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-size: 15px;"&gt;肯定了In-Memory内存模式 + 异步输入与输出事件（Disruptor） + Event Sourcing 架构，LMAX实践也验证了这个架构。这个架构降低复杂性。&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 15px;"&gt;LMAX的核心是新型并发框架Disruptor，其核心是根据现代CPU硬件缓存特点发明不同于通用LinkedList或Queue的新型数据结构RingBuffer。&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 15px;"&gt;号称并发未来的Actor模型被LMAX团队验证是有瓶颈的。&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 15px;"&gt;提出新的并发模型，每个CPU一个线程，多个CPU多个线程并发模式，摒弃了锁模式。&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 15px;"&gt;ORM等Hibernate没有完全解决OO的目标，关系数据库的事务也不是最后救命的稻草。LMAX用自己的事件记录的方式实现事务，这也不同于所谓内存事务STM。&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 15px;"&gt;架构师要分离关注，一是通过DDD降低业务的复杂性；二是通过技术探索创新，降低技术平台的复杂性，让程序员更多精力投入业务问题解决上。&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2347919.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347919.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2012/02/12/2347911.html</id><title type="text">事件溯源（Event Sourcing）</title><summary type="text">我认为，我们可以从事实观的角度去理解事件溯源。一个对象从创建开始到消亡会经历很多领域事件，以前我们是在每次对象参与完一个业务动作后把对象的最新状态持久化保存到数据库中，也就是说我们的数据库中的数据是反映了对象的当前最新的状态。而事件溯源则相反，不是保存对象的最新状态，而是保存这个对象所经历的每个事件，所有的由对象产生的事件会按照时间先后顺序有序的存放在数据库中。可以看出，事件溯源的这种做法是更符合事实观的，因为它完整的描述了对象的整个生命周期过程中所经历的所有事件。那么，领域事件到底如何影响一个领域对象的状态的呢？很简单，当我们在触发某个领域对象的某个行为时，该领域对象会先产生一个领域事件，然</summary><published>2012-02-12T05:51:00Z</published><updated>2012-02-12T05:51:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347911.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347911.html"/><content type="html">&lt;div&gt;&lt;div&gt;&lt;span&gt;我认为，我们可以从事实观的角度去理解事件溯源。一个对象从创建开始到消亡会经历很多领域事件，以前我们是在每次对象参与完一个业务动作后把对象的最新状态持久化保存到数据库中，也就是说我们的数据库中的数据是反映了对象的当前最新的状态。而事件溯源则相反，不是保存对象的最新状态，而是保存这个对象所经历的每个事件，所有的由对象产生的事件会按照时间先后顺序有序的存放在数据库中。可以看出，事件溯源的这种做法是更符合事实观的，因为它完整的描述了对象的整个生命周期过程中所经历的所有事件。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;那么，领域事件到底如何影响一个领域对象的状态的呢？很简单，当我们在触发某个领域对象的某个行为时，该领域对象会先产生一个领域事件，然后该对象自己响应该事件并更新其自己的状态，同时我们还会持久化在该对象上所发生的每一个领域事件；这样当我们要重新得到该对象的最新状态时，只要先创建一个空的对象，然后将和该对象相关的所有领域事件按照事件发生先后顺序从先到后再全部应用一遍即可还原得到该对象的最新状态，这个过程就是所谓的事件溯源；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;另一方面，因为是用事件来表示对象的状态，而事件是只会增加不会修改。这就能让数据库里的表示对象的数据非常稳定，不可能存在DELETE或UPDATE等操作。因为一个事件就是表示一个事实，事实是不能被磨灭或修改的。这种特性可以让领域模型非常稳定，在数据库级别不会产生并发更新同一条数据的问题；其实CAP定理之所以做不到，根本原因也是由于数据可以被修改；现在通过事件溯源，我们实现CAP或许就成为了可能；&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;我们可以看到，基于这样的设计，领域对象的状态完全是由事件驱动的。不仅如此，事件还可以被事件总线分发出去，通知领域模型外的一切事件响应者发生了什么，基于这种Publish-Subscribe的通信模式，我们可以最大限度的实现系统的松耦合。&lt;/div&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2347911.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347911.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2012/02/12/2347910.html</id><title type="text">CQRS Architecture Overview</title><summary type="text">CQRS on itself is a very simple pattern. It only describes that the component of an application that processes commands should be separated from the component that processes queries. Although this separation is very simple on itself, it provides a number of very powerful features when combined with </summary><published>2012-02-12T05:49:00Z</published><updated>2012-02-12T05:49:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347910.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347910.html"/><content type="html">&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span style="font-size: 12pt; "&gt;CQRS on itself is a very simple pattern. It only describes that the component of an application that processes commands should be separated from the component that processes queries. Although this separation is very simple on itself, it provides a number of very powerful features when combined with other patterns.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;The diagrams below show an example of an extended layout of a CQRS-based event driven architecture. The UI component, displayed on the left, interacts with the rest of the application in two ways: it sends commands to the application (shown in the top section), and it queries the application for information (shown in the bottom section).&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/13665/2012021213473430.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/13665/2012021213475584.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/13665/2012021213481031.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/13665/2012021213482553.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/13665/2012021213483756.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div&gt;&lt;p&gt;&lt;strong&gt;&lt;span&gt;&lt;span&gt;Command handling&lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;The user interface sends commands to make changes to the system. Commands are simple object that contain all the data needed to perform the underlying action. An example of the command could be&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;MoveUserToNewAddress&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;. The command should hold the new address for the user and the user id that indicates which user has moved.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;Commands also tent to express intent by there name. For example, although the command&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;MoveUserToNewAddress&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;and&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;CorrectAddressForUser&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;both contain the same data &amp;#8211; the address and the user id &amp;#8211; the intent is definitely different.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;All commands are send to a Command Service. This service receives the commands and routes them to the corresponding command handlers.&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;Command handlers should not contain any business logic. The only thing they do is making changes to aggregate roots from the domain and makes changes to them.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span&gt;The domain&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;The command handler retrieves domain objects (Aggregates) from a repository and executes methods on them to change their state.&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;&amp;nbsp;All business logic is captured within these objects and is not used for querying. This allows us to optimize this model for behavior.&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;span style="font-size: 12pt; "&gt;Aggregate roots contain the actual business logic and are&amp;nbsp; responsible for guarding their own invariants. State changes on aggregate roots cause domain events to occur. This sequence of domain events represents all the changes that has been made. This pattern is called&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://martinfowler.com/eaaDev/EventSourcing.html"&gt;&lt;span style="font-size: 12pt; "&gt;event sourcing&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 12pt; "&gt;.&amp;nbsp;Both the Domain Events and the Aggregates form the domain model.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;&lt;span&gt;The domain events&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;All state changes in the domain are represented by domain events. They are simple object that contain all data related to the change. We gave two examples of command names. The events that are related to the state change of these commands will be&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;UserMovedToNewAddress&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;and AddressCorrectedForUser. Notice that the names are in the past tense.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span&gt;The Repository&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;div&gt;&lt;span style="font-size: 12pt; "&gt;The repository act as a in-memory aggregate collection. The repository allow us to get a single aggregate by the aggregate id or save a single aggregate root into it.&amp;nbsp;Getting an aggregate root is done by getting all its related events and replaying them to build up the aggregate root into the latest state.&amp;nbsp;Saving an aggregate root will result in persisting all its uncommitted events that occurred while making change to it.&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;The events are stored in the event store and when an aggregate root is saved, all the events will also be published to the event listeners.&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;&lt;span&gt;The event store&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;All events that have occurred end up in the event store. It contains all the event that represents the state changes in the system. These can be used to build up the current state by replaying them all. This store can also be used to fill up new or repair existing read model.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span&gt;The event bus&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;When an aggregate root is saved via the repository all the uncommitted events that represent the state changes that has been made are persisted into the event store. Beside that, the repository also publish these events via the event bus. This bus publishes it to event listener that has registered itself as one being interested in the events. An important choice to make is whether the bus publishes the events to the subscribers in a synchronous or asynchronous way.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;Synchronous means that the event handling that is done by the subscribers blocks the current execution and that this waits for all subscribers to complete before returning to the user. This model is simple and is a sensible default.&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;span style="font-size: 12pt; "&gt;Asynchronous would not wait for all subscribers to complete before returning to the user. It will drop the event on the bus and return to the user. This will keep the execution of command fast, but introduces&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Eventual_consistency"&gt;&lt;span style="font-size: 12pt; "&gt;eventual consistency&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 12pt; "&gt;. The read models will be consistent at some point of time.&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;&lt;span&gt;The event handlers&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;There are different event handlers subscribed to the events bus. The most common one are denormalizers. These event handlers take events and makes changes to the read model based on them. For example, a denormalizer could update the users address in the user table based on the data in the&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;UserMovedToNewAddress&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 12pt; "&gt;event. But it could also update the total number of users in city X based on that the same event.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;Event handlers are not only interesting to keep the read model up to date. But they could also be written to make changes to an external system or send warning email to the business when certain event occur. It could also be that an event handler issues a new command . Event handlers are great components to extent the system with new functionality without making changes in it.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span&gt;Read models&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;An important part of every application is data. Most of the screen in an user interface request it. But every screen just tents to have a different view on the data. For example, one wants all the products with there name, price and category, while another wants the products with there name and top 3 latest product review score and name of the reviewer.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; "&gt;Read models are models that can be optimized for data querying. And what is a optimal query? That is a query that just queries the data from one source. In other words:&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;em style="font-size: 12pt; "&gt;select * from x where y&lt;/em&gt;. No joining, just give me the data. We can accomplish this by creating one table per view. So that every view can just request data by a simple query.&lt;/p&gt;&lt;div&gt;&lt;span style="font-size: 12pt; "&gt;Your read model doesn&amp;#8217;t even have to be a relational database, it could be a document based database that contains a collection for every view.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2347910.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347910.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2012/02/12/2347900.html</id><title type="text">数据、事实、实体、值对象、事务、不变性</title><summary type="text">数据有两个重要属性：首先数据是基于时间的，数据是表达一段时间内一个逻辑为真的事实。另外一个属性是数据本质上是不可变的，因为和时间有关，我们是不能回到过去改变数据的真实性。这两个属性就意味着：对数据你其实只有两个主要的操作：读取现有数据，并(随着时间)添加更多新的数据，CRUD(增删改查)称为CR(增读)。这样，CRUD其实没有U修改，因为修改对不可变数据是不其作用的(非常类似DDD中值对象不可变，不能修改，只能更换)。CRUD中也没有删除Delete，其实大部分删除其实是一种创建新数据，如果Bob停止跟随Mary，但是他们不能改变他曾经跟随过他的事实，删除那个他不跟随她的数据，你会增加一个数据</summary><published>2012-02-12T05:43:00Z</published><updated>2012-02-12T05:43:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347900.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347900.html"/><content type="html">&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;数据有两个重要属性：首先数据是基于时间的，数据是表达一段时间内一个逻辑为真的事实。另外一个属性是数据本质上是不可变的，因为和时间有关，我们是不能回到过去改变数据的真实性。这两个属性就意味着：对数据你其实只有两个主要的操作：读取现有数据，并(随着时间)添加更多新的数据，CRUD(增删改查)称为CR(增读)。这样，CRUD其实没有U修改，因为修改对不可变数据是不其作用的(非常类似DDD中值对象不可变，不能修改，只能更换)。CRUD中也没有删除Delete，其实大部分删除其实是一种创建新数据，如果Bob停止跟随Mary，但是他们不能改变他曾经跟随过他的事实，删除那个他不跟随她的数据，你会增加一个数据记录，说他在某个时刻不再跟随她了。&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;其实状态变化有两种思维：一种是过程形式，一种是逻辑形式。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;过去我们的实体都是列出对其认识的内在属性，当事件发生致使实体发生变化时，往往就是加锁后逐一改变，或者事务方式（类似副本方式）。&amp;ldquo;逐一改变&amp;rdquo;就是过程式，具体详细地描述变化过程，于是在并行的时候缺失原子性，为了实现避免脏读等问题，加锁成了一种手段。当然，事务方式也解决了这样的问题，这与非副本的不变值对象方式，是达到同样目的的不同方式，同时这两者都属于逻辑表达。以前我作过比较，在领域当中谈论逻辑变化，我认为后者较好。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;值对象是实体状态的一种落实，我过去提出过的观点，这是源自于状态变化的逻辑形式思维。谈论逻辑时，状态迁移必须具有原子性，所以我在某个帖子说值对象不变性，可以达到去锁的目的。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;注意：值对象不变性源自值，并非因为实体状态，是因为值对象具有值的不变性，所以才能成为实体状态的落实。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;一些更深入的认识：&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;存在状态变化即存在副作用（side effect），所以实体是副作用存在的因。很多人认为副作用是坏的，应该去掉，但这只限于逻辑运算时。只要人们想获得信息，副作用就根本不能避免，最容易理解就是print。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;可变的实体与不可变的状态，正好就是副作用存在的分界线。实体之所以会存在，其实是因为人们想获取信息，于是值对象（值）载体便出现了&amp;mdash;&amp;mdash;引用对象（即实体对象）。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;状态迁移，就是实体发生变化，它说明实体从一个状态迁移到另一个状态。这里面最小单元是状态，也就是说我们考虑的不是状态的构成及其内在变化（逐一改变），而是计算出新状态，然后以&amp;ldquo;替换&amp;rdquo;的手段来实现实体变化。这与我们所说到的值对象不变性和事实是最小单元如出一辙。（所以&amp;ldquo;状态迁移&amp;rdquo;是一种事实观）&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;状态是表达一段时间内一个逻辑为真的事实，这句话很好说明了事实观与实体观的联系。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;过去我思考&amp;ldquo;什么是实体&amp;rdquo;，其实实体很简单，就是一个KEY，是为了区别与其他存在的存在。而我们写类的时候，其中的id并非实体KEY，而&amp;ldquo;类名+类id&amp;rdquo;才是实体KEY。所以关系数据库中表方式与类方式类似，并不完全满足事实观，而key-value数据库能更好展现逻辑。关系数据库的数据平铺方式，使得查询速度极快，同时实现了逻辑查询，但这并非从实现&amp;ldquo;产生事实的逻辑&amp;rdquo;角度出发的&amp;mdash;&amp;mdash;事件的角度。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;immutable is eveything,不可变是一切。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;状态变化是由事件引起的，从事件来划分。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;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.....&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;一、&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;其实这就是一种&amp;ldquo;连续&amp;rdquo;和&amp;ldquo;离散&amp;rdquo;思维的区别，尽管世界在我们感官中是连续的，但连续过程和中间的&amp;ldquo;切面状态&amp;rdquo;不是我们关注的，业务说的是规则，是逻辑的，正如我们经常说的&amp;ldquo;业务逻辑&amp;rdquo;。在规则或者逻辑中，不存在所谓的切面状态。例如&amp;ldquo;借书&amp;rdquo;这一个原子动作，有人会&amp;ldquo;借一半&amp;rdquo;，或者说&amp;ldquo;借一半&amp;rdquo;是我们所关注的状态？&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;二、&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;若果我们一个个地改属性，当改了第一个属性值，没改第二个属性值时，这就存在了所谓的切面状态。单线程时，因为顺序执行，不会读出切面状态，变相成为原子操作，但多线程并发时，读出无效的切面状态是可能的。解决的方式：&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;1）改的时候不能读，就是我们以前用得最多的锁；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;2）随时可读，改的时候必须&amp;ldquo;同一时间&amp;rdquo;完全改完，而这就是不变性的整体替换；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;3）当然后来又想到一种，读与改不会同时进行，暂时感觉比较复杂，没有深入，浅思考了下，感觉实时相对较弱。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;三、&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;还有一点，事务性和不变性，个人认为两者很像，但又有点不同：&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;事务讲究复制隔离，达到不相互影响，而且最后也需要替换。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;不变性无需复制，因为其一开始就要求在逻辑运算期间是&amp;ldquo;不能改&amp;rdquo;。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;两者相似点：&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;1）并行时都是相互不影响；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;2）更新时都是替换手段。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;不同点：&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;1）事务的参与逻辑是在逻辑执行前就复制好，得到隔离性；事务包装整个过程，实现原子性。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;2）不变性方式的&amp;ldquo;结果对象&amp;rdquo;是在逻辑执行完后，根据各种条件创建的，其原子性体现在替换，并不是包装过程。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;总的来说就是一前一后，事务有点像&amp;ldquo;平行世界&amp;rdquo;的概念。还有有趣的一点是，不变性前后两个状态不要求是同构的。不变性还有很多有趣的地方，这里就不一一列举了。而不变性也有缺点的，如要多对象同时改变时，需要机制来处理。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;为什么有这样大统一美妙大道至简的现象呢？因为计算机软件系统是本身是符号逻辑或者形式逻辑或分析逻辑的一种体现，而不变性是逻辑上的一个基础概念(蒯因与引用透明)，如果你学习了分析逻辑的这个基础，你就找对了方向，但是如果你学习几十年数据结构和算法基础，你不一定能悟出其背后的逻辑真义。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;VO相对的是RO（ReferenceObject），独立于&amp;ldquo;状态、实体&amp;rdquo;概念的，或者说是不同层次的。只是VO和RO出现相对较早，而且比较吻合&amp;ldquo;状态、实体&amp;rdquo;概念。所以，值对象只是状态的落实，或者说实现。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&amp;ldquo;实体状态在某个时间点上状态是静止的&amp;rdquo;，瞬时的实体状态映射到计算机就是不变的数据，在对象思维中就是值对象。而实体则是RO，不过注意的是这个引用概念有点变化，并不是引用地址，而是变成实体KEY。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;值对象的不变性是源自于值概念的，试想为啥非要叫做&amp;ldquo;值对象&amp;rdquo;，而不叫&amp;ldquo;不变对象&amp;rdquo;。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2347900.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347900.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2012/02/12/2347901.html</id><title type="text">关于领域模型与技术架构的关系的思考</title><summary type="text">人类社会的一切事物都是来源于对造物主智慧的学习，人类本身是不会创造任何东西的。外国新技术并不能作为软件架构的终极准则，因为老外也是人。我认为客观世界的架构应该是软件架构的唯一准则，换而言之，上帝也是一个架构师，而这个客观世界就是他的作品。有这么完美的学习对象，为什么要舍本逐末呢？就拿领域对象的设计来说，在客观世界中，人如果要做某件事情，比如扫地这个动作，扫地难道是人自己完成的吗？其实扫地是人借助扫帚这个工具完成的。换而言之，领域对象的一些动作，也根本不属于他自己，如果你把这些动作硬要强加在领域对象身上，就肯定会出现类似领域对象中调用技术层这种别扭的问题。比如，经常有什么贫血对象，和充血对象之类</summary><published>2012-02-12T05:43:00Z</published><updated>2012-02-12T05:43:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347901.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347901.html"/><content type="html">&lt;div&gt;&lt;div&gt;&lt;span&gt;人类社会的一切事物都是来源于对造物主智慧的学习，人类本身是不会创造任何东西的。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;外国新技术并不能作为软件架构的终极准则，因为老外也是人。我认为客观世界的架构应该是软件架构的唯一准则，换而言之，上帝也是一个架构师，而这个客观世界就是他的作品。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;有这么完美的学习对象，为什么要舍本逐末呢？&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;就拿领域对象的设计来说，在客观世界中，人如果要做某件事情，比如扫地这个动作，扫地难道是人自己完成的吗？其实扫地是人借助扫帚这个工具完成的。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;换而言之，领域对象的一些动作，也根本不属于他自己，如果你把这些动作硬要强加在领域对象身上，就肯定会出现类似领域对象中调用技术层这种别扭的问题。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;比如，经常有什么贫血对象，和充血对象之类的讨论，这其实很可笑，保存、删除、这些概念，本身是在计算机领域才存在的概念，现在大家都想把他强加在领域对象上，领域对象本身是对业务的模拟，怎么可能有这些动作？大家也觉的不妥，于是就绕弯弯，想发明一种说法和思想，自己说服自己，让这件事情变的合理。但是这在本质上就是错误的，这种追求也是徒劳的。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;DOMAIN就应该只关注于领域对象之间的关系和行为就足够了，涉及到技术的，都交给其他层完成，而不是非要在DOMAIN中加上技术性的操作，你觉得别扭，这是必然的，因为在原本的业务概念中，根本不存在这中技术性的概念！领域对象，应该仅仅关注自身状态和行为，以及和其他领域对象之间关系的建立，至于一切计算机领域的概念（比如保存、删除这些概念），都不应该出现在领域对象中，因为这是违背自然规律的组合，或者说是违背业务概念的。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;领域模型中的对象之间既然有关系，就肯定需要相互协作共同完成某个更大的业务逻辑；那么如何协作呢？目前最优雅并能确保领域对象处于核心主动地位的方式是通过Domain Event；在C#，Java这样的语言中，对象天生并不具备发送消息和接收消息的能力，需要依赖于外部框架；而像Scala的Akka那种Actor Model，一个领域对象就是一个Actor，Actor能够通过发送异步消息和其他Actor通讯联系，这种消息发送是异步的，属于&amp;ldquo;fire-and-forget&amp;rdquo;方式。那么在C#这样的语言下，我们可以通过Domain Event也可以达到类似Actor一样的效果；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Domain Event是EDA（Event Driven Architecture）思想的一种体现，EDA原本是用于SOA（Service Oriented Architecture）中，服务与服务之间的通信；Domain Event则是将EDA用于领域对象之间的通信；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;引入Domain Event主要目的是为解决如何将领域模型和技术架构进行解耦，让领域模型不依赖于特定的技术架构实现，从而可以让领域模型真正反映纯粹的业务模型。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2347901.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347901.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2012/02/12/2347895.html</id><title type="text">关于对象之间通信的一点思考</title><summary type="text">1. 经典的DDD的告诉我们如果一个领域概念是一个跨多个聚合的动作，比如转帐，那么就应该用领域服务来实现这样的业务概念。领域服务的输入和输出参数都是聚合根，领域服务内部按照业务逻辑规定的执行顺序，按照面向过程的方式，逐个调用相关聚合根的相关方法完成整个业务操作。这种方式的优点是：1）清晰的表达和封装了业务逻辑；2）代码清晰，容易理解，代码可读性强；缺点：1）基本的OO思想告诉我们，对象与对象之间应该是通过发送消息和接收消息的方式来通信的。但是通过前面这种方式，对象之间不再像我们想的那样会通过发送消息和接收消息来相互协作了，而都是被动的被一个第三方协调者服务对象来统一协调，这其实是一种面向过程的</summary><published>2012-02-12T05:42:00Z</published><updated>2012-02-12T05:42:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347895.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347895.html"/><content type="html">&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;1. 经典的DDD的告诉我们如果一个领域概念是一个跨多个聚合的动作，比如转帐，那么就应该用领域服务来实现这样的业务概念。领域服务的输入和输出参数都是聚合根，领域服务内部按照业务逻辑规定的执行顺序，按照面向过程的方式，逐个调用相关聚合根的相关方法完成整个业务操作。这种方式的优点是：1）清晰的表达和封装了业务逻辑；2）代码清晰，容易理解，代码可读性强；缺点：1）基本的OO思想告诉我们，对象与对象之间应该是通过发送消息和接收消息的方式来通信的。但是通过前面这种方式，对象之间不再像我们想的那样会通过发送消息和接收消息来相互协作了，而都是被动的被一个第三方协调者服务对象来统一协调，这其实是一种面向过程的思维，而非基于消息通信的面向对象思维；2）这种通过领域服务的方式只强调了对象的个体行为（即对象只有改变自己状态的行为），而没有注重对象之间的交互行为，对象应该还有能力发送消息给其他对象或者响应其他对象发送的消息；&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;那么为了能让对象之间有交互行为，能相互发送消息和接受消息，该如何做呢？一般来说有两种方法：1）方法调用，A对象调用B对象的方法，这种方法最常用最直接，但是缺点是会导致A依赖于B。这个问题我们往往会通过面向接口编程在一定程度上消除这种依赖关系；2）事件消息模式，生产者-消费者模式，即采用触发事件响应事件的模式；通过这种方式，A对象就不是直接调用B对象的方法了，而是触发一个事件，然后B对象去响应这个事件，或者如果采用消息总线的方式的话，就是A对象通知消息总线发布某个事件，然后消息总线发布这个事件，然后B对象响应这个事件。通过这样的通信方式，巧妙的将A，B两个对象的关系进行了解耦，本来A直接依赖B（A-&amp;gt;B）的情况变成了A与B相互独立，变成了这种方式：A-&amp;gt;消息&amp;lt;-B。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;2. CQRS Event Source采用的通信方式。首先，在这种方式下，聚合与聚合之间的关系通过ID表示，而不是通过对象引用的方式来表达对象关联。这就让我们不能直接通过简单方便的对象导航的方式定位到关联对象并调用其方法了。那么这种方式下，对象之间如何通信呢？就是采用上面提到的基于事件消息的通信模式。CQRS架构中Command端的大致执行流程是：UI发送Command到CommandService，CommandService根据传入的Command调用相关的Command Handler，Command Handler获取相关的聚合执行相关方法，聚合执行方法后触发事件，消息总线发布该事件到外部，事件响应者（Event Handler）响应事件。关于最后一步的实现还有一些目前不确定的方案，目前采用一般两种方式：1）Event Handler生成一个新的Command然后发送给Command Service；2）Event Handler直接取出目标聚合根，然后调用其方法；另外，一般两个聚合之间采用异步的方式通信，所以我们会集成NServiceBus等异步消息通信框架实现消息的传递；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;关于对象之间通过直接方法调用来交互，和通过发送消息来交互的一点思考：&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;1）对象A直接调用对象B的某个方法，实现交互；直接方法调用本质上也是属于一种特殊的发送与接受消息，它把发送消息和接收消息合并为一个动作完成；方法调用方和被调用方被紧密耦合在一起；因为发送消息和接收消息是在一个动作内完成，所以无法做到消息的异步发送和接收；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;2）对象A生成消息-&amp;gt;将消息通知给一个消息处理器（如NServiceBus,EventBus之类）-&amp;gt;消息处理器通过同步或异步的方式将消息传递给接收者；这种方式是通过将消息发送和消息接收拆分为两个过程，通过一个中间者来控制消息是同步还是异步发送；在消息通信的灵活性方面比较有优势，但是也带来了一定的复杂度。但是复杂度一般可以由框架封装，消息的发送方和接收方仍然可以做到比较简单；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;最后，在记录一点关于事件与消息的关系的论述：&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;事件和消息可以说是从不同方面描述的同一个东西，消息是事件发生后产物，消息发送必须有发送事件发生才能实现。每次事件只发送一次消息，事件和消息是一对一的。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2347895.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347895.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2012/02/12/2347893.html</id><title type="text">WHY CQRS and EVENT SOURCING</title><summary type="text">Business value of the events, the value of having a log, the fact that the Event Store is additive only.The biggest advantage of this architecture is that it allows you to design your model to meet specific requirements. Typically, the requirements for changing data are significantly different than </summary><published>2012-02-12T05:40:00Z</published><updated>2012-02-12T05:40:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347893.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347893.html"/><content type="html">&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;Business value of the events, the value of having a log, the fact that the Event Store is additive only.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;The biggest advantage of this architecture is that it allows you to design your model to meet specific requirements. Typically, the requirements for changing data are significantly different than those for querying data.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;Another advantage is application extensibility. In the more traditional layered architecture, services often need each other to do their job. Especially in long-running projects, the result is a big tangled mess that only the developers know how to maintain. CQRS enforces loose coupling between components through events.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;There are a few types of applications that would benefit from this architecture. However, some of the principles and ideas of CQRS would benefit any medium to large application in the end.An application that offers views on the same data is one such group. CQRS uses events to update query data. It doesn't matter if there is one table showing this data, or hundreds, each event listener component will keep its own data source up-to-date. Examples of views on information are over view pages, search engine indexes, reporting information, "what happened last month" emails, ad-hoc email notifications, etc, etc. LinkedIn is an example of such an application.Another example is applications that are likely to be extended in the future. Since events are ubiquitous in any CQRS application, it is very easy to create add-ons that act upon these events. Changes are typically a lot less intrusive than with the more traditional approach. Some web shop implementations, for example, need to start small due to budget restrictions. However, after some time, they might require an inventory feature that is updated automatically when an order is made. Perhaps some time later, a shipping department needs to be kept up-to-date about orders ready for shipping.The last type of application is the one that needs to scale. The traditional layered architecture is not one that supports scalability very well. Transaction management is a very heavy process in a scaled environment. XA transactions ask for a big price to pay on each transaction, while only one-in-many transactions actually go wrong. CQRS uses asynchronous updates through events. If any conflicting event is found (e.g. an item was bought, but the item is not in stock), we need to fix that in a compensating transaction. It is effectively the ACID vs. BASE discussion. It really is something that we (as developers) have to get used to. We have to educate ourselves, and our customers that things just go wrong from time to time. Instead of presenting the error to the user (with the default "please try again later" screen), we try to solve it in the background.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;An additional feature of CQRS that I personally like a lot is "event sourcing". In a more traditional layered architecture, audit trails are typically implemented as a side effect of the actual changes they describe. This makes an audit trail very error prone and thus unreliable. Event sourcing uses a different approach: let your event be the origin of all changes. In other words, changes will occur as a result of an event.&amp;nbsp;In practice, this means that the methods on an aggregate (the term as defined by Domain Driven Design, Eric Evans) will not change its state directly. Instead, they will generate en event that is then applied on the aggregate. When the aggregate is stored in the repository, the generated events are dispatched to the rest of the application. In such case, the repository will not store the aggregate itself, but just the latest (uncommitted) events. The event stream that results is the overview of all changes that ever occurred on the aggregate. If a repository needs to rebuild an aggregate from storage, it will replay all past events. The opportunities that event sourcing provides are not limited to audit trails. You could also use these events to set the application to a certain state in time and replay events back on components for debugging purposes. Axon contains building blocks that make it easier to use event sourcing. There is an abstract implementation of an aggregate that you can extend with the case-specific business logic and a basic implementation of a repository that stores events in the file system.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;A complex domain may be easier to tackle by using CQRS.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;The other main benefit is in handling high performance applications. CQRS allows you to separate the load from reads and writes allowing you to scale each independently. If your application sees a big disparity between reads and writes this is very handy. Even without that, you can apply different optimization strategies to the two sides. An example of this is using different database access techniques for read and update.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;Firstly when one uses Event Sourcing with CQRS one can avoid the need for 2pc between the data store and the message queue that you are publishing messages to. This is because the Event Store can be used as both an event store and a queue. Conceptually the Event Store is an infinitely appending file. One can just have a read location that gets updated (chasing the end of the file) and presto you have a queue as well. A side benefit from this is that you also end up with only one disk write for both your storage and your durable queue, this may not initially seem like a big win but when you are trying to build performant systems this can help a lot!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;The second and I believe most important area where Event Sourcing really aids CQRS is in the only having a single model. If we were to say use a relational database, object database, or anything else that only keeps current state we would have a slight issue. The issue is that we have two different models that we cannot keep in sync with each other. Consider that we are publishing events to the read model/other integration points, we are also saving our current state with a tool like nhibernate. How can we rationalize that what nhibernate saved to the database is actually the same meaning as the events we published, what if they are not? When we use Event Sourcing we only use our events, they are the only model there is nothing to keep in sync. If there is a problem with the Event Stream that people use to integrate with us, like that we had a bug and never sent an event OUR state will be wrong as well.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;The largest single benefit about CQRS is when you start running into problems with the CAP theorem.&amp;nbsp;You can use CQRS to get around problems you run into with CAP. The trick is that CQRS breaks up the system into multiple pieces that you can then adjust them separately. You are not avoiding CAP, you still have CAP limitations but you now have them in multiple places and you can make different choices in different places.&amp;nbsp;Let&amp;#8217;s go through such a scenario. the customer needs all three; consistency, availability, and partitionability. Doing this in a single system according to CAP is impossible. But let&amp;#8217;s get more into the problem and apply CQRS. We now have two distinct units, the first is the write side and the second is the read side. Where is consistency needed, is it everywhere or just for certain operations? How does our application scale? What is our ratio of reads to writes?&amp;nbsp;We can make different decisions on the read side and the write side. We can be ACID on the write side and BASE on the read side.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;One obvious form of return is that it's easy to serialize the events to make an Audit Log.&amp;nbsp;Another use for this kind of complete Audit Log is to help with debugging. Of course, it's old hat to use log files for debugging production problems. But Event Sourcing can go further, allowing you to create a test environment and replay the events into the test environment to see exactly what happend, with the ability to stop, rewind, and replay just like you can when executing tests in a debugger. This can be particularly valuable to do parallel testing before putting an upgrade into production. You can replay the actual events in your test system and test that you get the answers you expect.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;Event Sourcing is the foundation for Parallel Models or Retroactive Events. If you want to use either of those patterns you will need to use Event Sourcing first. Indeed this goes to the extent that it's very hard to retrofit these patterns onto a system that wasn't built with Event Sourcing. Thus if you think there's a reasonable chance that the system will need these patterns later it's wise to build Event Sourcing now. This does seem to be one of those cases where it isn't wise to leave this decision to later refactoring.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;Event Sourcing also raises some possibilities for your overall architecture, particularly if you are looking for something that is very scalable. There is a fair amount of interest in 'event-driven architecture' these days. This term covers a fair range of ideas, but most of centers around systems communicating through event messages. Such systems can operate in a very loosely coupled parallel style which provides excellent horizontal scalability and resilience to systems failure.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;Event sourcing is an approach to thinking about persistent data where the primary record is a log of all events that make updates. A traditional representation of database state can be entirely recreated by reprocessing this event log. Event sourcing&amp;#8217;s benefits include strong auditing, creation of historic state, and replaying of events for debugging and analysis. Event sourcing has been around for a while, but we think it is used much less than it should be.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;Almost-infinitely scalable;&amp;nbsp;Focused on the business rather than the technology;&amp;nbsp;Can grow to handle complex problems without growing development costs;&amp;nbsp;Adapt to changing business requirements;&amp;nbsp;Efficiently integrate with other software and systems&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;Command-Query Responsibility Segregation is not a silver bullet, but rather an approach that has proven itself to be efficient in solving some of the frustrating problems of delivering enterprise software:Performance bottlenecks and scalability;Concurrency conflicts, their resolution and prevention;Data staleness;Complexity of the design, development and maintenance&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 12pt; "&gt;A Comprehensive Solution:&amp;nbsp;When looking at how code outside the domain model interacts with it, look for the agile "simplest thing that could possibly work"&amp;#8212;a single method call on a single object from the domain, even in the case when you're working on multiple objects. Domain events can help round out your solution for handling more complex interactions and technological integrations, without introducing any complications.&amp;nbsp;When starting down this path, it took me some time to adjust my thinking, but the benefits of each pattern were quickly felt. When I began employing all of these patterns together, I found they provided a comprehensive solution to even the most demanding business domains, while keeping all the code in each part of the system small, focused, and testable&amp;#8212;everything a developer could want.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2347893.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2012/02/12/2347893.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
