tag:blogger.com,1999:blog-22587889.post1458756076482053633..comments2024-02-11T13:21:47.930+05:30Comments on Ruminations of a Programmer: CQRS with Akka actors and functional domain modelsAnonymoushttp://www.blogger.com/profile/01613713587074301135noreply@blogger.comBlogger19125tag:blogger.com,1999:blog-22587889.post-35878533376849394082013-11-24T19:12:59.017+05:302013-11-24T19:12:59.017+05:30That's true .. Not all use cases need to have ...That's true .. Not all use cases need to have the latest update fed into the query subsystem instantaneously. e.g. My bank account does not always have the latest debit or credit reflected in the query screen the moment they happen. And you can always control the frequency at which the query subsystem gets refreshed from the updates. Anonymoushttps://www.blogger.com/profile/01613713587074301135noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-87460251278058307892013-11-24T18:56:45.265+05:302013-11-24T18:56:45.265+05:30What about consistency? If I understand it correct...What about consistency? If I understand it correctly, the query store is fed with updates asynchronously. So,the query store may not always have the latest state.Otavio Macedohttps://www.blogger.com/profile/11608506807263634034noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-37103657232695420902012-07-17T15:16:23.614+05:302012-07-17T15:16:23.614+05:30This is still a great post. Getting some inspirati...This is still a great post. Getting some inspiration from it for my current project. Regarding the FP/DDD discussion ... this presentation gives a nice intro why those concepts fit together (http://skillsmatter.com/podcast/design-architecture/ddd-functional-programming).Tobihttps://www.blogger.com/profile/08106015733347258133noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-6880052238258812282012-04-09T13:40:47.658+05:302012-04-09T13:40:47.658+05:30Well, I'm on the wrong side of the altlantic ;...Well, I'm on the wrong side of the altlantic ;)<br /><br />Yes, when I wrote my app (classic OO oriented), I was not aware of the advantages of the functionnal approach.<br />Event Sourcing + immutable structures seems to match very well.<br />But maybe it would require a bit more memory for the "current" data model in the heap than the mutable OO approach (?). Maybe that's the price to pay for more simplicity and robustness.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-22587889.post-51186508921445938332012-04-08T18:44:05.589+05:302012-04-08T18:44:05.589+05:30I am also seriously exploring Event Sourcing as an...I am also seriously exploring Event Sourcing as an option in practical real world applications. Event Sourcing, asynchronous messaging and functional programming goes very well together. I will be speaking on this same topic in PhillyETE next week. Please do drop by if you are around :-)Anonymoushttps://www.blogger.com/profile/01613713587074301135noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-64561641327052662012-04-08T16:20:21.551+05:302012-04-08T16:20:21.551+05:30I have an Event Sourcing app in production for 9 y...I have an Event Sourcing app in production for 9 years. (Full audit trail is a strong requirement in our domain.)<br />It works very well (impossible to override data by error), it is fast (because current state is in-memory) and very flexible (no schema update needed, POJO-based queries).<br /><br />But my boss still doesn't understand why I don't use a plain SQL database. :((Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-22587889.post-38113775058372353762012-01-03T18:38:44.252+05:302012-01-03T18:38:44.252+05:30@Banq
Not sure why you feel FP is not suitable fo...@Banq<br /><br />Not sure why you feel FP is not suitable for DDD. The advantage that a functional domain model gives you is immutability. We don't mutate shared state. Hence you can safely share your domain model components with other application components. In the example, note how all updates are done functionally using lenses.When you are doing DDD you can do similar stuff with aggregates.Anonymoushttps://www.blogger.com/profile/01613713587074301135noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-34139641300476845512011-12-30T06:52:13.586+05:302011-12-30T06:52:13.586+05:30here is a java CQRS sample with jdon framework lik...here is a java CQRS sample with jdon framework like AKKa actors:http://jivejdon.blogspot.com/2011/09/ddd-dci-and-domain-events-example.html<br /><br />can you tell me what difference with them? or why use FP? FP is not fit for DDD that is a static entity model class .Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-22587889.post-1543966102487966262011-07-19T01:26:10.231+05:302011-07-19T01:26:10.231+05:30After reading this post I keep thinking of more pl...After reading this post I keep thinking of more places it can be applied, and the advantages of doing so (cheap undo, free audit trail etc)<br /><br />Do you have any thoughts on the best way to persist the commands? It would be a shame to only be able to use the technique for short-lived purposes.wibblehttps://www.blogger.com/profile/05037877011433943038noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-42932652919071106342011-05-17T16:16:26.045+05:302011-05-17T16:16:26.045+05:30Hi oxbow -
The collapsing takes place when the Co...Hi oxbow -<br /><br />The collapsing takes place when the CommandStore receives a Snapshot message. All accumulated closures on a specific trade are executed in sequence to result in the latest updated snapshot of the trade. Have a look at the sample code in the post how I do that using a fold.<br /><br />Thanks.Anonymoushttps://www.blogger.com/profile/01613713587074301135noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-79398854000794207042011-05-16T14:51:16.858+05:302011-05-16T14:51:16.858+05:30Thanks - I understand lenses a little better now. ...Thanks - I understand lenses a little better now. I'm interested in what looks like the apparent non-scalability of using this in a real system, however. Could you perhaps elucidate what a "collapseHistory" method might look like in your CommandQueryStore? That is, how can I collapse a sequence of (Trade => Trade) updates into a single (Trade => Trade) update? Otherwise the CommandQueryStore is one big memory leak.oxbowhttps://www.blogger.com/profile/09110490196361200081noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-59504380258464305342011-02-16T16:05:54.977+05:302011-02-16T16:05:54.977+05:30Lenses are usually used for functionally updating ...Lenses are usually used for functionally updating nested structures. They are somewhat like zippers. The main advantage of using lenses is that they are composable, though we don;t use any composability in this example. Not sure why you feel using lenses make the code look obscure.Anonymoushttps://www.blogger.com/profile/01613713587074301135noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-35123992890709574682011-02-16T00:41:44.598+05:302011-02-16T00:41:44.598+05:30I saw the comment about lens and your response. Wh...I saw the comment about lens and your response. While I understand in general that lens are useful and not sure what value they provide in this particular example. <br />For example, as far as I can tell the only usage are the calls to set() in the closures enrichTrade and addValueDate and seem to obscure rather than clarify the intent of the code. Am I missing something?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-22587889.post-26006008292115415782011-02-14T15:16:35.996+05:302011-02-14T15:16:35.996+05:30I think the reason you feel that I don't make ...I think the reason you feel that I don't make this difference is the naming of CommandStore. It should be renamed to EventStore, because that's what it stores. In the implementation doEnrichTrade, doAddValueDate are the commands which result in events like TradeEnriched and ValueDateAdded, which are then stored.<br /><br />Lenses offer a way to update aggregates "functionally*. You can find more information on lenses in the presentation by Benjamin Pierce, which I linked in the main article.Anonymoushttps://www.blogger.com/profile/01613713587074301135noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-33087414787439561412011-02-14T12:07:56.068+05:302011-02-14T12:07:56.068+05:30Axon, a CQRS framework, makes a distinction betwee...Axon, a CQRS framework, makes a distinction between commands and events. The first 'notify' the system that the external world has changed 'MovedAddressCommand'. This is then translated to one or more events 'ChangedAddressEvent' that are stored in the event strore for later replay. Only events are received by the query components. In addition, events can be captured by other aggregates and can in turn lead to more events.<br />Commands are not stored unless for additional auditing.<br /><br />You do not seem to make this distinction. Is this on purpose?<br /><br />Could you explain why lenses are important? As I understand lenses, they are about having an external view to the actual aggregate. Isn't this already filled in by the query components.Erik van Oostenhttps://www.blogger.com/profile/15976519439979651010noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-57099805436653544232011-02-14T00:55:08.202+05:302011-02-14T00:55:08.202+05:30Thanks for the answer. After reading your comment ...Thanks for the answer. After reading your comment and playing with the scala repl it looks rather obvious. Must be the years of imperative programming. ;-)<br /><br />Regards, Janjfrhttps://www.blogger.com/profile/15073523818126201196noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-400119647793442502011-02-13T18:59:02.272+05:302011-02-13T18:59:02.272+05:30The for comprehension yields a composition of taxF...The for comprehension yields a composition of taxFeeIds and taxFeeValues, which is a function that takes a trade as input. Have a look at the very next line where I invoke taxes(trade) which then supplies the necessary trade argument to forTrade. This is a technique of implementing the Reader monad in scala. You can get a better understanding of the concept by looking at an earlier blog that I wrote on this subject (http://debasishg.blogspot.com/2010/12/case-study-of-cleaner-composition-of.html).Anonymoushttps://www.blogger.com/profile/01613713587074301135noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-38109606631087323112011-02-12T19:45:46.336+05:302011-02-12T19:45:46.336+05:30Could You explain how the closure "enrichTrad...Could You explain how the closure "enrichTrade" works. It uses the function forTrade (in the for expression) but I just don't know how the trade is passed to "forTrade"<br /><br />Regards, Janjfrhttps://www.blogger.com/profile/15073523818126201196noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-13520671474204462112011-02-01T01:24:07.107+05:302011-02-01T01:24:07.107+05:30Great post! Inspirational!Great post! Inspirational!hedefalkhttps://www.blogger.com/profile/10283382670696431077noreply@blogger.com