Camelia, the Perl 6 bug

IRC log for #cqrs-perl6, 2011-04-15

| Channels | #cqrs-perl6 index | Today | | Search | Google Search | Plain-Text | summary

All times shown according to UTC.

Time Nick Message
16:56 masak joined #cqrs-perl6
16:57 masak \o/
16:58 moritz \o/
16:58 masak whoz op? :)
16:58 * masak <---
16:59 tadzik joined #cqrs-perl6
16:59 masak I know jnthn is here only as a lurker. :) he's currently on a train, I think.
16:59 masak or still giving a course of his own AFK.
17:01 moritz masak: do you want p6eval in here?
17:01 masak don't think so.
17:02 masak but thanks for considering it. I hadn't.
17:04 sorear joined #cqrs-perl6
17:04 masak :)
17:05 newguy joined #cqrs-perl6
17:06 masak newguy: you must be the new guy. :) welcome!
17:07 moritz masak: care to set a /topic ?
17:07 newguy yes, very new.. can't even create an output file...
17:07 masak moritz: good idea. hold on.
17:10 Tene joined #cqrs-perl6
17:10 Topic for #cqrs-perl6 is now DDD, CQRS and Event Sourcing: making applications that know what they're up to -- class at 2011-04-15 18:00 UTC
17:31 newguy left #cqrs-perl6
17:37 PerlJam joined #cqrs-perl6
17:37 PerlJam greeble
17:37 masak o/
17:47 SHODAN joined #cqrs-perl6
17:47 masak greetings, SHODAN.
17:48 SHODAN hallo
17:52 mberends joined #cqrs-perl6
17:53 mberends o/ # was not sure I could attend, now I'm glad I can make it :-)
17:53 tadzik o/
17:54 patrickas joined #cqrs-perl6
17:56 masak nice, people keep dropping in :)
17:57 patrickas I just wanted to join perl6 and a mysterious vortex pulled me here ... I have no idea what's happening ;-)
17:57 masak ;)
17:57 masak the reason I chose to pull together this little course is that I feel that the things I learned on Monday-Wednesday deserve a wider audience.
17:58 PerlJam masak++
17:58 masak and you're all intelligent people with some experience in the corporate world, etc. many of you more than me. :)
17:58 masak so I also hope to get some feedback from you on these ideas as we go along.
17:58 * moritz had a bout 2 months of experience in the corporate world... not that much :-)
17:59 masak basically, just feel free to treat the channel as you'd treat #perl6.
17:59 PerlJam hugs all around!
17:59 masak which means that everyone gets to talk at any time, but I'll end up being the one blathering :P
17:59 moritz :-)
18:00 masak here's a loose schedule for the next two hours:
18:00 masak (1) DDD
18:00 masak (2) CQRS
18:00 masak (3) Event Sourcing
18:00 masak (4) Sagas, etc
18:00 masak so, roughly half-hour slots.
18:01 masak I look forward to giving a two-hour course without having to drink massive amounts of water due to talking all the time :P
18:01 moritz it'll just strain your hands :-)
18:01 PerlJam masak: Watch Roger Ebert's TED talk.
18:01 mac joined #cqrs-perl6
18:01 mac hi
18:01 masak PerlJam: noted. will do later :)
18:01 masak mac: hi!
18:02 masak mac: you're just in time. why don't you sit down, and we'll get started. :)
18:02 masak there's a backlog with some introductory comments.
18:02 mac With pleasure, thank you :)
18:02 masak moritz: could you perhaps put the clogs URL in the topic?
18:02 moritz sure
18:02 SHODAN http://distributedpodcast.com/
18:02 * masak bows in thanks
18:02 SHODAN is interesting as well
18:03 masak ok, class.
18:03 masak hi!
18:03 tadzik o/
18:03 Topic for #cqrs-perl6 is now DDD, CQRS and Event Sourcing: making applications that know what they're up to -- class at 2011-04-15 18:00 UTC -- logs at http://irclog.perlgeek.de/cqrs-perl6/2011-04-15
18:03 masak I was on a course in Krakow this week, and I thought it was pretty awesome.
18:03 skyheights joined #cqrs-perl6
18:03 masak skyheights: welcome!
18:03 sorear hi!
18:03 skyheights thx
18:03 masak I thought I'd share some of the concepts with you, and see if you think they're awesome, too. :)
18:04 masak let's start with Domain-Driven Design.
18:05 * PerlJam tries to imagine the antithesis of DDD and fails
18:05 sorear Some of us have no clue what DDD or CQRS is
18:05 masak PerlJam: ever been on a project where the code was less than clear?
18:05 moritz then let's just listen to masak a bit :-)
18:05 sorear Well, except for the Data Display Debugger, which I keep menaing to play with
18:05 masak sorear: will try to rectify that in the next hour or so :)
18:05 PerlJam masak: of course.
18:06 PerlJam masak: so ... that's "random crap design"?
18:06 tadzik neutro? :)
18:06 masak PerlJam: it's nothing new, really. DDD is Separation of Concerns, just like most things.
18:06 masak it gives you a few new boxes to put things in.
18:07 masak some boxes you will recognize, such as "entity object" versus "value object".
18:07 masak we tend to call value objects "immutable objects" in #perl6.
18:08 masak but when you're designing, the objects in your domain will tend to fall into these two categories.
18:08 masak can anyone say when an object falls into the "entity object" bin, and when in the "value object" bin?
18:08 masak what's the distinction?
18:08 masak we'll take a concrete example shortly.
18:08 moritz you haven't given an explanation for "entity object" yet
18:09 moritz so ENOCLUE
18:09 SHODAN entities have an identity?
18:09 sorear I guess ... what SHODAN said
18:09 masak SHODAN: correct.
18:09 PerlJam that's not a distinguishing feature though
18:09 masak that's what defines them.
18:09 PerlJam (or doesn't appear to be)
18:09 masak but... what PerlJam said.
18:09 masak so let's take an example.
18:10 masak an Order in an e-commerce system. entity or value object?
18:10 tadzik entity
18:10 tadzik or, hm
18:10 masak I'd say so.
18:10 masak now, a Seat in an airline.
18:10 masak entity or value object?
18:11 moritz doesn't that depen on what you want to model?
18:11 moritz if you do an inventary, probably an entity object
18:11 masak it could.
18:11 moritz when it's about seat reservations, a value object
18:11 masak oh, I was thinking in the context of booking a flight.
18:11 masak shold've said that.
18:11 sorear a Seat in an airline doesn't seem like something that should be modelled as an explicit object
18:12 moritz what sorear said :-)
18:12 mberends does thinking about lvalue versus rvalue help here, or just confuse matters?
18:12 sorear I think it would make more sense to have reservations with uniqueness on (flight, position)
18:12 masak mberends: it might. basically, value objects are an extension of the built-in "native" types. those that aren't reference types.
18:13 mberends ok :)
18:13 masak hm. the point I wished to make with Seat is that some airlines book you on an individual seat, and then it would make sense to treat a Seat as an entity.
18:14 masak some airlines just book you for the flight, and you get to pick a seat when you board. then it's probably a value object, if it's modeled at all.
18:15 masak there's an emphasis in DDD of going to your customer (or whoever) and actually sitting down and talking about these things.
18:15 masak evolving a common set of terms, and then *using* those terms in your domain model. and in the code, and in the database tables, etc.
18:15 masak it's called a "ubiquitous language".
18:15 PerlJam masak: that's crazy in the real world some times.
18:15 masak tell me about it :)
18:16 masak luckily, we'll learn some things later to make it less crazy. you'll see :)
18:16 masak I do acknowledge that one is often constrained in various ways in practice.
18:16 PerlJam I recall a conversation with a client several years ago where he answered the same question 5 different ways in the course of a phone conversation.
18:16 ashleydev joined #cqrs-perl6
18:16 masak PerlJam: :)
18:16 ashleydev oh hi
18:17 masak ashleydev: \o
18:17 masak PerlJam: that would tend to make it harder to arrive at an analysis of the application.
18:17 masak no-one is pretending that clients always know what they want.
18:17 PerlJam The lesson there is that the client is learning too and their needs (requirements) will change as they learn new implications of past decisions.  It just so happened that I was able to note the implications and get feedback in relative realtime
18:18 masak but the assumption is that having a common language doesn't hurt, at least.
18:18 mberends Will moving the application goalposts then require rigorous refactoring to rename identifiers so that they always describe their purpose?
18:18 masak mberends: basically, yes.
18:18 masak mberends: not renaming becomes a code smell.
18:18 mberends aha
18:19 masak that *includes* renaming things in the data store. we'll come back to that :)
18:19 masak anyway. "ubiquitous language".
18:19 masak this word "ubiquitous", for all the non-native speakers, means "being everywhere".
18:20 masak it's probably not that hard to swallow that having a ubiquitous language would help, and that it's at least a nice-to-have.
18:20 PerlJam It's just hard to get one. :)
18:20 masak yes.
18:20 masak it's also a Red Queen thing. one has to work to remain there.
18:21 PerlJam There's also the problem of people not saying what they mean.
18:21 PerlJam (unintentional information hiding)
18:21 masak well, a common terminology is meant to help hammer out the details.
18:22 masak next concept: a "bounded context".
18:22 masak let's say we start programming at an insurance company.
18:23 mberends http://en.wikipedia.org/wiki/Domain-driven_design has a useful diagram, btw
18:23 masak we realize that everyone keeps talking about Policy, and that this is probably going to be one of our most important entities in the system.
18:23 masak so we go around asking everyone what they want a Policy to be, and what attributes it should have.
18:24 masak the sales manager tells you about all the things he needs to keep track of when selling a policy.
18:25 masak the claims manager tells you about the awesome automated rules they have on the site for directing people to the right kind of policy. it takes care of 90% of the customers automatically.
18:25 masak the actuarials people have a view of the Policy that involves things like risk and profitability.
18:25 masak in the end your note pad is cluttered with small balloons representing all the attributes that all the departments want a Policy to have.
18:26 masak now, there are two possible outcomes.
18:26 masak (1) you go ahead, like most people do, and create a HUGE Policy object that tries to be everything to everybody. also, it sucks. for precisely that reason.
18:27 masak (2) you realize that since we're dealing with three different departments here, each of which are viewing a different aspect of a Policy, you actually don't need to put everything on one single entity.
18:28 * mberends tries to imagine Ford modelling a "car" object ;)
18:28 masak in (2), you go back over your notes and realize that what you're dealing with is three different bounded contexts, one for each department.
18:28 masak mberends: color = Any but "black"
18:28 mberends :)
18:29 masak so, each bounded context has its own set of terms, and the terms only have meaning within the bounded context.
18:29 masak "Policy", above, means three different things in the three contexts.
18:30 masak and it can be modeled separately as three entities.
18:30 PerlJam mberends: That would have been easy because the domain was already well-known.  It was clear what the car could do.   In many projects, you have to define the domain in addition to figure out a way to talk about it .
18:30 masak in essence, a bounded context has its own ubiquitous language. and yes, I know that sounds weird.
18:30 masak but it's like a bounded context is a little universe of its own.
18:31 masak now, the last DDD term, and perhaps the most important one: aggregate.
18:32 masak anyone heard of aggregates outside of DDD?
18:32 moritz sure
18:32 masak moritz: what are they?
18:32 moritz masak: things that are made of other things, simply speaking
18:32 masak :)
18:33 masak right. it's a bit more precisely defined within DDD.
18:33 masak it's about modeling things so that we don't have any references across the model.
18:34 masak so whereas bounded contexts limit our world, aggregates limit the things that need to interact with each other.
18:34 * PerlJam gets that OOPy feeling
18:34 masak the classical example, which you'll find all over the web, is Order and OrderLineItem.
18:34 masak our teacher basically dismissed that example as trivial :)
18:35 masak (the trivial thing being that OrderLineItem doesn't make much sense outside of an Order, so they naturally form an aggregate)
18:35 PerlJam (that's thet main problem with most learning resources ... they only show you the trivial cases  :-)
18:35 sorear masak: small chunks of rock for mixing into concrete
18:35 masak so let's go through the non-trivial case from the course :)
18:36 masak I expect you to protest a bit when doing this example.
18:36 masak sorear: that's a noun phrase, but beyond that I can't map what you said to anything...
18:36 * moritz protests
18:36 masak moritz: hold on until you've seen it :)
18:37 masak ok, have a look at this one: http://masak.org/carl/cqrs-mini-​course/teacher-class-student.png
18:37 masak the domain is a high school or equivalent.
18:37 masak students take zero or more classes. teachers teach zero or more classes.
18:37 * PerlJam hopes masak has the perl-nature when it comes to using DDD and CQRS, etc.
18:38 masak each class has teacher(s) and student(s).
18:38 masak classical double-directed references. this is what we'd usually use an ORM for.
18:38 masak PerlJam: you'll have to explain what you mean by that :)
18:38 PerlJam masak: Just that this stuff are tools in your toolbox, not a panacea
18:39 masak PerlJam: oh, for sure.
18:39 masak there are no silver bullets.
18:39 tadzik :)
18:39 masak but there are more or less interesting ways to approach problems.
18:39 sorear masak: by "class", do you mean "Calculus II" or "Calculus II taught in Room 345 at 2:00 TTh"
18:39 PerlJam sorear++
18:40 masak sorear: something in-between. a given subject on a given semester.
18:40 masak hm, so maybe the latter one.
18:40 masak and yes, the Class will have all those attributes required for that. location. time/day. etc.
18:41 masak now,
18:41 sorear masak: is the constraint actually "no teacher may have more than N stdents *per semester*" then?
18:41 masak sorear: no, per class.
18:42 masak thanks for clearing these things up. :)
18:43 masak the idea being that the number of students in a class is limited by the teachers' capacity in that class.
18:43 masak now. where do we draw our aggregate boundaries?
18:44 masak we'd *like* to draw them as tightly as we can get away with around things, but here we have all these dependencies.
18:44 masak a Student "has" a number of Classes, and vice versa. same for Teacher and Class.
18:45 masak and we can't seem to get rid of the dependencies, because we have invariants to uphold.
18:45 sorear unifying Teacher and Student might help?
18:45 masak perhaps.
18:46 masak still leaves us with dependencies, though.
18:46 PerlJam (it's something I've doen in the past :)
18:46 PerlJam s/doen/done/
18:46 masak and it might actually be valuable to keep those apart :)
18:46 masak let's go ahead and remove remove a dependency.
18:46 masak the easiest one to get rid of is Teacher-Class.
18:46 masak see http://masak.org/carl/cqrs-mini-c​ourse/teacher-class-student-2.png
18:46 masak it's about at this point that I expect some protests ;)
18:47 mberends in relational database terms, teacher and student would be separate entities, and class could be many-student to many-teacher relation (oversimplifying)
18:47 masak mberends: sure, as long as class can also hold its own properties.
18:47 sorear masak: if Prof. X and Prof. Y both teach the same class but have different student limits, how many students can be in the class?
18:48 masak sorear: let's say the sum of them.
18:48 masak sorear: they can each handle up to their limit.
18:48 masak see, we've *dropped* the link between Class and Teacher. they no longer care about each other.
18:49 masak the only thing we need from Teacher in Class, is a .maxStudents value.
18:49 moritz teachers not caring about their classes? nothing new... :-)
18:50 masak :)
18:50 sorear What do we gain by doing this?
18:50 tadzik oh, I know that :)
18:50 masak sorear: we can now make Teacher into its own aggregate root.
18:51 masak before, all we could do was to make the aggregate root World or Universe or College, or something. and that's usually not good enough. the transaction boundary is too large.
18:51 masak but now we go one step further, and remove the Student-Class coupling.
18:52 masak this sounds impossible, because if a Class doesn't "know" about the students that are in the Class, how can it check invariant (B). and how can Student check invariant (A)?
18:53 masak at this point, we took a 5-minute break to all think about it. no-one came up with an answer how to do it.
18:53 masak turns out the solution was a more radical variant of what we already did.
18:54 masak by the way, what we did with copying over info from Teacher to Class is called "denormalization". I bet many of you know that already.
18:54 masak this time, we introduce a new value object to hold the information about a Student's Class.
18:54 masak any ideas for a good name for such an object?
18:55 masak what would represent a student having signed up for a class?
18:55 PerlJam masak: how about the ones used in  teacher-class-student-3.png   ?   :-)
18:55 masak you're too clever for your own good. :P
18:55 masak I should have named it ...-52.png :P
18:55 masak but yeah.
18:56 sorear masak: wait, wait, hold on
18:56 masak yes?
18:56 sorear masak: what's an aggregate root and what do they have to do with transaction boundaries?
18:56 masak good question.
18:57 masak and aggregate root is the "ancestor" in the hierarchy of objects in the aggregate.
18:57 masak transaction boundaries are what aggregates establish.
18:57 masak a transaction always takes place within the aggregate.
18:57 masak no references go in or out except via the aggregate root.
18:57 masak does that answer your question?
18:58 sorear Can transactions reference multiple aggregate roots?
18:58 masak in essence, we're so willing to break these couplings that we even introduce a new value object, Enrollment, that looks great lot like Class.
18:58 masak sorear: yes, but we tend to want to avoid that too.
18:59 masak sorear: if it does, it's still not supposed to channel information between the aggregates.
18:59 masak so the transaction would be purely for the atomicity.
18:59 masak but it's sort of a last-resort thing.
18:59 sorear Any time you add a student to a Class you need to make a big scary transaction in order to enforce the .maxStudents invariant
18:59 masak I'm glad you bring it up.
19:00 masak because essentially, we drop that kind of concern with consistency.
19:00 PerlJam explain.
19:00 masak we care more about the aggregates being independent.
19:00 PerlJam I got that.
19:00 PerlJam :)
19:00 masak let's say the class has a 30-student limit.
19:01 masak two students sign up within 300 milliseconds of each other at a point where there were already 29 students signed up.
19:01 mberends left #cqrs-perl6
19:01 masak this is exactly the situation you'd normally want a transaction for.
19:01 PerlJam It's starting to sound like you're trading direct relationships for no relationship and a protocol.
19:02 sorear masak: what if two students sign up within 300 hours of each other while there were already 29 students?
19:02 masak sorear: then the Class should already have had time to update.
19:02 sorear masak: will you do a (non transactional) relational query?
19:02 masak sorear: (it's implied that Class knows how many students signed up)
19:02 masak instead of a transaction, we... go and talk to our domain experts, the school people.
19:03 masak we tell them "there's this small chance we might get 31 people on a 30-student course. is that a problem?"
19:03 masak "small chance as in one in half a million."
19:03 masak and they go "no, that's not a problem! students tend to drop out of classes anyway!"
19:04 PerlJam perhaps I've got too much of an engineer in my brain, but now it sounds like you're just putting the problem off.
19:04 PerlJam (it's still a problem)
19:04 sorear masak: how does the Class know how many students signed up?
19:04 masak exactly.
19:04 masak PerlJam: we're basically trading away solving this problem up-front for handling it when it occurs.
19:04 PerlJam masak: so rather  than enforce constraints up-front ... blah you type too fast
19:04 sorear that seems like it would require atomically modifying two aggregates
19:05 masak sorear: same way Class updates when a Teacher is added. using in a separate update.
19:05 masak sorear: we don't do it atomically.
19:05 mberends joined #cqrs-perl6
19:05 masak let's leave this for now. I'm not going near as fast as I thought I would :)
19:05 PerlJam masak: so ... that introduces another problem when not enough students drop out
19:05 masak PerlJam: yes, but with ever decreasing probability.
19:05 sorear wait, next you're going to tell me that if the client crashes between changing the schedule and updating .curStudents, the 0.0001% chance of database corruption is acceptable?
19:06 masak PerlJam: and we started out at 1/500_000
19:06 masak sorear: we're going to address that concern too, with event sourcing.
19:06 sorear where "corruption" = "the class has a phantom student, or phantom vacancy"
19:06 sorear ok
19:06 PerlJam okay, lets hear it!  :)
19:06 sorear go on
19:06 masak but first, CQRS.
19:07 masak now, this image I didn't make: http://cqrs.files.wordpress.com/2​010/11/image.png?w=550&amp;h=412
19:07 masak it represents a "classical architecture" for businesses.
19:07 masak you send a request for something and get a DTO back to the client.
19:07 masak (DTO is "Data Transfer Object")
19:08 masak a DTO is basically a C struct with values in it.
19:08 masak you do some client-side editing, and you send the DTO back.
19:09 masak some layer on the server side figures out the delta, what changed in the DTO, and turns that into database commands.
19:09 masak and you get an ACK/NAK response back.
19:09 masak fairly standard setup, no?
19:09 masak lots and lots of architectures look like this.
19:10 masak and... it's not really a good start for doing DDD, because all we're ever dealing with is nouns.
19:11 masak our verbs are limited to the typical four database verbs, Create/Read/Update/Delete.
19:11 masak in the worst case, even our client application is showing us a grid of things that looks suspiciously like a database table or two.
19:12 PerlJam "worst case" is fairly standard.
19:12 masak yes :(
19:12 PerlJam look at melange for example
19:12 masak indeed.
19:12 masak this kind of interface is called a CRUD interface, and as PerlJam says, it's all over the place.
19:13 masak UI people know that humans much prefer doing things "task-based", and that means starting from meaning-rich actions.
19:13 masak it's not "Update the address field", it's either "I moved" or "I want to correct my address".
19:13 sorear masak: uh... I do not have much experience with "conventional web app design"
19:14 masak those two task-based actions mean different things, but in a CRUD application they are molded into the same action.
19:14 sorear you seem to be assuming some kind of ORM
19:14 masak not necessarily, but that's fairly common too, I guess.
19:14 PerlJam no, and ORM is just a means to an end in this case
19:14 PerlJam (if there's an ORM at all)
19:14 masak because an ORM is what you'd need to manage this sad state.
19:14 masak in many cases.
19:15 masak don't you think a company might be interested in the distinction between "I moved" and "I want to correct my address"?
19:15 masak I think so.
19:15 sorear well you're talking about DTOs, and DTOs do not look much like SQL statements
19:15 PerlJam ORMs make it easier, but I've had to maintain too many "applications" that had no ORM but tried to do  the same  things.
19:15 masak in the former case, you might want to send out some advertisements or something. in the latter case, not so much.
19:15 sorear and I'm a wee bit lost, although notsomuch as to be a problem yet
19:16 masak sorear: DTOs are just a way of serializing objects when we send them along the wire.
19:16 masak sorear: and it's not just web apps, it's any app that talks to a server somewhere.
19:17 masak here's another image that shows the workflow in more detail: http://cqrs.files.wordpress.com/2​010/11/image3.png?w=550&amp;h=326
19:17 PerlJam sorear: think of email for an analogy.  If you work remotely and you supervise people, you may often write instructions for your subordinates in an email.  the email is the DTO  :)
19:18 masak the point is that we're actually *losing* information along the way with this poor interface. one talks about an "anemic" model, one that doesn't have lots of semantics in its verbs/actions.
19:18 masak we can do better than just "update, update, update..."
19:18 masak without saying what and why we update.
19:18 sorear masak: that sounds a lot like "separation of concerns gone wrong"
19:18 PerlJam Apple has learned this better than most companies.
19:19 masak yes.
19:19 mberends the distinction between "I moved" and "I want to correct my address" looks like a job for a server centric MVC application. Are you deliberately moving the business logic out to the client?
19:19 sorear masak: everyone knows that dumb byte stores (Unix filesystem) work *much* better than the smart filesystems of the mainframe era
19:19 masak mberends: no, the business logic can sit at the server at this point.
19:20 masak mberends: we might have some simple validation on the client, but no more.
19:20 mberends ok
19:20 PerlJam mberends: that's an interesting way to put it.   I was thinking of it more like moving the "semantics" closer to the server
19:20 masak here's the proposed "semantic" model: http://cqrs.files.wordpress.com/2​010/11/image4.png?w=550&amp;h=326
19:20 masak what's changed is that the client doesn't send DTOs back, but "messages".
19:20 PerlJam i.e., the UI has semantically rich interfaces, so should the API
19:21 masak the rest of CQRS is how to structure those messages.
19:21 masak anyone heard of the "Command Pattern" from Design Patterns?
19:21 sorear no
19:21 mberends no, but I know REST.
19:22 masak so, sometimes we want to "reify" the calling of a method.
19:22 masak to postpone it or send it over the wire.
19:22 masak the Command pattern does this.
19:22 sorear mmm RPC
19:22 masak indeed.
19:22 masak a Command is just a simple object storing the target (aggreagate), the method name (or action), and parameters/data.
19:23 masak think of it as an object that represents an uncalled method.
19:23 PerlJam a thunk
19:24 masak sort of, yes.
19:24 masak so we let every action that we send from the client have its own class that derives from Command, and we send an instance of one of those over the wire when the client wants to change the model.
19:24 PerlJam "change the model"  or "change instances of the model"?
19:25 masak er, change the contents of the data store.
19:25 PerlJam okay
19:25 masak change a row in a table somewhere, say.
19:25 masak on the server side, we have a CommandHandler for each Command.
19:26 masak we tie things up nicely with generics or parametric roles, so that one CommandHandler is typed as handling one Command.
19:27 masak so 'role InvalidateLineItemCommandHandler does HandlingOf[InvalidateLineItemCommand] { ... }'
19:27 masak your naming may be shorter than that.
19:28 sorear If commands are sent to a specific aggregate, how do you create aggregates?
19:28 masak so all the domain logic sits in a layer on the server, as CommandHandlers.
19:29 masak sorear: issue a CreateSomeAggregateCommand with an aggregate_id that doesn't exist yet.
19:29 masak I guess.
19:29 masak either that, or the server assigns the id. that's probably better, come to think of it.
19:30 mberends yes, the CreateNewAggregate would return you the new Id.
19:30 masak I'm a bit doubtful. the server is just supposed to reply ACK/NAK.
19:31 sorear best would probably be X11-style "server gives client a block of 2^32 ids and client allocates from that"
19:31 mberends aww, the similarities to REST were looking good so far :/
19:31 masak I'm sure there are variants involved. :)
19:31 masak CQRS.
19:31 masak I didn't say what it stands for, did I? :)
19:31 masak Command/Query Responsibility Segregation.
19:31 masak Bertrand Meyer writes about CQS, a very related principle.
19:32 masak CQS is sort of on the class/object level, and CQRS is on an architectural level.
19:32 masak CQS (Command/Query Separation) says that methods should ever either return something, or do something. not both.
19:32 masak this becomes important when dealing with DbC and idempotency.
19:33 masak so in CQS you separate things into different methods, either (void) command methods or query methods returning a value.
19:33 masak in CQRS, you go one step further and separate out things in different objects.
19:34 masak we have our Command objects for the write side, and DTOs for the read side.
19:34 masak but so for read side and write side share the same data store.
19:34 masak there's no reason to have it that way.
19:34 masak we keep our database 3NF or BCNF or some other nice NF. why do we do that?
19:35 PerlJam because that's how we're taught in school  ;)
19:35 masak yes... :)
19:36 masak but surely it's not all arbitrary.
19:36 mberends only if we choose to, for reducing the risk of integrity violations.
19:36 SHODAN to try to uphold some sort of referential integrity
19:36 masak indeed.
19:36 masak more exactly,
19:36 masak (and this was a nice insight for me)
19:36 masak 3NF and BCNF are good when we're writing.
19:37 masak because then we don't have to write the same information in many places.
19:37 masak 1NF is wonderful when we're reading.
19:37 masak then we want the information to be sprawled out.
19:37 isBEKaml joined #cqrs-perl6
19:37 masak isBEKaml: welcome to the party :)
19:37 masak the more we can get the read-side tables to look loke our DTOs, the better :)
19:38 isBEKaml masak: am I fashionably late? :O
19:38 masak isBEKaml: see /topic for backlog
19:38 masak isBEKaml: only by about 97 minutes :P
19:38 isBEKaml masak: that's so much in fashion! :P
19:38 masak so we'd actually prefer to split our databases down the middle, having one write database and one read database.
19:39 masak and this is sort of pushing the CQRS further and further up through the architecture.
19:39 masak in fact, there's nothing to stop us from having several read sides. they're like views, we can have one for each particular client/context/concern/whatever.
19:40 masak and the updates that go out from the write side to the read side(s) doesn't have to be atomic or transactional, either.
19:41 masak but having those nice Commands going to the domain, we'd like to be just as meaningful with the data coming out of the domain.
19:42 masak so instead of having the write side emit deltas or something, we have it issue a different type of messages called Events.
19:42 masak now we have Commands, that represent changes issued by the client. and Events that represent changes that occured on the server.
19:43 masak it's important to realize that both of these are really very representation-independent.
19:43 isBEKaml so I have had this thing for quite a while, unable to ask anyone... Is CQRS any different from ESBs or MQs ?
19:44 masak isBEKaml: well, they're related.
19:44 masak isBEKaml: ESBs (enterprise service buses) can definitely be used with event sourcing. but you don't have to.
19:44 masak you'll have to expand the MQ abbreviation for me :)
19:44 isBEKaml hmmm, ESBs and MQs don't share any interaction with outside world. component level interactions alone.
19:44 masak right.
19:44 isBEKaml MQ is a message queue.
19:45 masak ah, 'course :)
19:45 masak both of those can be used profitably with event sourcing.
19:45 masak (which I'm building up to)
19:45 masak but you don't have to use them. they're orthogonal tools.
19:45 masak anyway, we've successfully encapsulated our write side.
19:46 sorear Are you going to explain what event sourcing is?
19:46 masak yes, now.
19:46 masak now it's time to question why we even keep the 3NF write database around.
19:46 masak we're using it to write our changes to the data model. what else?
19:47 mberends I'd be scared to abandon a single authoritative store
19:47 masak you'll still have that.
19:47 masak just not in the form of "latest current state".
19:48 PerlJam mberends: google wasn't scared.  :)
19:48 masak you'll like the new world even better :)
19:48 isBEKaml unique identification?
19:48 masak isBEKaml: how do you mean?
19:48 isBEKaml atomicity and integrity.
19:49 masak well, more exactly, we sometimes need to validate the Commands that come in.
19:49 sorear A single authoritative store is bad, because it wants to impose an order on time
19:49 masak remember, a Command hasn't happened yet. the server can reject it.
19:50 masak and it rejects it based on what's in the write-side model.
19:50 masak now I put forth that we could do just as well with dropping the 3NF database with our current state, and just storing all the Events that are generated by the write side.
19:51 masak in FP terms, "current state is just a left fold over the history of events"
19:51 masak (that's going to mean a lot to FP people, and nothing to everybody else) :)
19:51 PerlJam This seems to go a long way towards proving that most problems can be solved with an extra level of indirection  ;)
19:52 sorear You sound like you just reinvented log-structured databases.
19:52 masak PerlJam: yes, but the cost will turn out do be the same.
19:52 masak sorear: yes!
19:52 masak sorear: as organizations mature, they tend to land on this architecture.
19:52 * moritz has a question
19:52 masak there are so many advantages to having a full history of the world.
19:52 masak moritz: go right ahead.
19:52 moritz if the client issues a command
19:52 moritz how does it know what data to retrieve from the server to update the GUI?
19:53 PerlJam ... and that's why git is better than svn!
19:53 isBEKaml CommandHandler?
19:53 masak moritz: a couple of options. (1) query again from the read side. (2) "fake it" and update locally.
19:53 isBEKaml I mean, CommandHandler should know what each command corresponds to and display the state accordingly on GUI.
19:54 masak (1) is problematic because things are eventually consistent, and the refresh might be too quick.
19:54 masak (2) is problematic if the command fails.
19:54 masak isBEKaml: but the CommandHandler sits on the write side on the server.
19:54 isBEKaml wait, they are separate? (I didn't quite read the backlogs well... )
19:55 masak isBEKaml: we basically have three separate parts somewhere on the 'Net.
19:55 masak isBEKaml: client, write side, read side.
19:55 masak moving right along.
19:55 isBEKaml masak: from what you say, CQRS seems to be for rapid interactions. Was that part of the framework?
19:55 masak no, could be rapid or could be slow. doesn't much matter.
19:55 masak have a look at http://cqrs.files.wordpress.com/20​10/11/image16.png?w=550&amp;h=303
19:56 masak this is a typical state-based model of a purchase order.
19:56 masak in an event store, we'd instead store the purchase order as events on an aggregate. like this: http://cqrs.files.wordpress.com/20​10/11/image18.png?w=550&amp;h=367
19:56 masak so we have this one big table with all our events.
19:57 masak each row of the table says "an event on [this aggregate] with [this data] happened".
19:57 masak so those four events that you see on that second image could have been SELECT-ed out using a very simple query on that table.
19:58 jaffa4 joined #cqrs-perl6
19:58 masak jaffa4: welcome.
19:58 masak and that's how we reconstruct our aggregates whenever we need them on the write side.
19:58 jaffa4 hi
19:58 masak jaffa4: see /topic for backlog.
19:58 isBEKaml that looks a lot like EventQueue.
19:59 masak there's no direct storage of the state of things. we (re-)build our current state from the history of events on a particular aggregate.
19:59 masak isBEKaml: is that a framework?
19:59 masak now, you'll see that this model of things is not only AS powerful as the state model, it actually captures MORE information: http://cqrs.files.wordpress.com/20​10/11/image19.png?w=550&amp;h=359
20:00 masak in that image, we have two additions and one removal. in a state-sourced databse, we wouldn't be seeing the removal represented.
20:00 isBEKaml masak: no. an approach where certain events trigger certain responses. More precisely, I have seen certain datastore reporting tools segregate all responses based on certain key terms like events.
20:01 isBEKaml masak: datastore reporting --> Eg. in point, Siebel.
20:01 masak isBEKaml: could be they're related, I dunno. quite possibly with that name.
20:02 masak (we're now running overtime. people are free to come and go as they please. I expect to have about 30 minutes more material.)
20:02 moritz masak: about my earlier question... are there non-problematic answers too?
20:02 masak moritz: :)
20:03 masak moritz: one tends to go with (1) and tackle the fallout in situation-dependent ways.
20:03 moritz masak: does (1) imply re-querying *all* displayed information from the read side?
20:03 masak moritz: essentially, eventual consistency isn't so bad if you build your client to take it into account, and/or prepare your users for it.
20:04 masak moritz: yes, but the client can be discriminating. a query can look any way you've designed it to look.
20:04 masak moritz: two examples of coping with eventual consistency.
20:04 masak moritz: when you've added a contact in your address book, the client throws up a dialog box asking "add more contacts? yes/no"
20:05 masak moritz: and the second or two it takes you to respond to that dialog box is enough for things to go through to the read side and then update correctly in your client.
20:06 masak moritz: in another case, the users were told that the system sometimes needs some time to "think" about their issued commands. so they should refresh, count to 2, and if they still didn't see anything after refreshing again, they should call tech support. very important.
20:06 masak moritz: so they call, and tech support say "could you hit F5 for me again? it's there? good, thanks, bye."
20:07 moritz masak: I kinda think we're talking past each other
20:07 masak oh :/
20:07 moritz masak: I didn't mean to ask about delays
20:07 masak ...and the users figure out by themselves that they might as well count to 7 and things work. and they educate new users that the system is "thinking".
20:07 masak moritz: ok, could you rephrase your question, then?
20:07 moritz but rather, suppose you display very much information on one screen
20:08 moritz and you issue a command like "add a new address with $data"
20:08 masak moritz: assuming the write side comes back synchronously with an ACK/NAK, there's actually not much of a problem, come to think of it.
20:08 sorear masak: would it be sensible for the client to receive events, so it refreshes itself at the exact moment when it becomes useful?
20:08 masak moritz: the client just needs to be able to roll back to before the command.
20:08 moritz how does the client know which parts of the screen might change, so that it knows what to ask the server for?
20:08 masak sorear: yes. that's an option. clients listening for events.
20:09 moritz does the client have to hardcode "query the address list"?
20:09 masak sorear: there are also other nice tricks, such as clients caching the state as it would look if the command had already gone through.
20:09 isBEKaml masak: Along the analogy of the messages thread, would it be possible for clients to know when to update? "I recieved a new message in this thread now. Update? "
20:09 moritz there might be many more components affected by a  more involved command
20:09 masak moritz: basically, the client can implement as much of the write-side logic as it pleases, making it more "independent".
20:10 masak moritz: but it will also by necessity mean a bit of code duplication between write-side and client.
20:10 masak isBEKaml: sounds like sorear's question about clients receiving events.
20:11 isBEKaml masak: yes, but clients don't know update actions at all.
20:11 isBEKaml masak: that would go into write state (this is a two way transaction)
20:12 masak isBEKaml: ok, let's talk about what the read side looks like, and come back to the client. I think that will clear it up.
20:12 isBEKaml ok
20:12 masak so the read side sends out events everytime a command goes through.
20:12 masak on the read side(s), we essentially have a number of listeners for events.
20:13 masak these are called EventHandlers, and they are structually very similar to CommandHandlers.
20:13 masak the most important difference being that there might be 0..* EventHandlers per event, but there's only ever one CommandHandler per Command.
20:14 masak the EventHandlers are often organized into neat little groups. going back to the Teacher-Student-Class example, there might be one group of EventHandlers that specifically care about the size of a Class.
20:14 masak increasing and decreasing that size as the appropriate events come rolling in.
20:15 sorear masak: getting back to your school example, when a student adds a class both the Class and Student aggregates need to be updated.  Is that one command or two?
20:15 masak there's a name for groups of EventHandlers. they're called Projections.
20:15 masak sorear: one command, but two trips to the data store. with events, probably two events.
20:15 masak sorear: since it affects two aggregates.
20:16 masak now, Projection is exactly the right name here.
20:16 masak we're basically filtering on events coming in, taking the bits and pieces we care about.
20:17 masak and you can imagine that the read model doesn't have to look anything like the write model.
20:18 masak isBEKaml: coming back to your question, there's nothing to prevent a client from having a similar set of Projections for things it care about.
20:18 masak so from a very high-level view, our system looks like this: http://cqrs.files.wordpress.com/20​10/11/image34.png?w=550&amp;h=390
20:19 masak three (high-level) components, each one generating objects that another component consumes.
20:19 sorear It sounds like modifying a CQRS app with data already present could get very messy.
20:20 isBEKaml sorear makes a good point.
20:20 masak sorear: there's an analogy here with accounting.
20:20 masak sorear: accountants who "get creative" and go in and edit the books... go to jail.
20:20 masak sorear: same thing here. the event stream is immutable for all intents and purposes.
20:20 isBEKaml most web/enterprise applications are nothing new. They build on what's already there, but with each new thing, they break apart old ones and bake in new changes.
20:20 masak when we want to "undo" an event, you issue a compensating command.
20:21 masak sorear: but maybe you meant changing the domain model?
20:21 sorear right
20:21 masak I'd argue that that part is now much *easier*.
20:21 isBEKaml this is a rather protracted process everytime. How about changes for a quick turnaround and making those changes highly configurable?
20:21 sorear what if I want to add a new projection, but I already have 100TB of events?
20:21 masak sorear: first off, disk is cheap nowadays.
20:22 masak and those events probably have business value, or will have in the future.
20:22 sorear masak: to build the new projection I need to replay the whole log
20:22 sorear right?
20:22 sorear that takes a lot of time when there are a lot of events
20:22 masak sorear: right.
20:23 masak sorear: my bet is that you can run through the event log in minutes or hours.
20:23 isBEKaml sorear: many wouldn't do that. That's like associating one user's twitter stream to another user. (not possible to change usernames)
20:23 masak sorear: even if you'd happen to actually have 100TB, which sounds like a lot for most systems, that would still take on the order of days.
20:23 rindolf joined #cqrs-perl6
20:24 masak and it's a one-time thing.
20:24 masak among the things you gain:
20:24 birdwindupbird joined #cqrs-perl6
20:25 masak $boss comes to you and says "I need us to start measuring the frequency with which customers delete things from their baskeds before checkout"
20:26 masak with state sourcing, you go "um, ok, I'll bake that in on the next iteration, and you'll start getting statistics sometime after that."
20:26 rindolf left #cqrs-perl6
20:26 masak with event sourcing, "ok, I'll just build a new projection this afternoon, and you'll get all the data you want from the beginning of time."
20:26 masak you see, we can build all the data structures we like *after* we realize that we wanted them.
20:26 masak all this just because we're handling intentions, not just changes in data.
20:27 moritz sounds a lot like why git is great
20:27 masak yes.
20:27 masak there was a whole part in the course on merging :)
20:27 masak (of events)
20:27 masak had very much of a git vibe to it.
20:28 masak I'll do one last thing, and then I'll shut up for today.
20:28 masak sagas.
20:28 isBEKaml case studies?
20:28 masak more like workflows.
20:28 isBEKaml saga sounds so melodramatic. :D
20:29 masak here's an example situation: http://masak.org/carl/cqrs-mini-course/sagas.png
20:29 masak we're an online company selling stuff, and someone orders a snow scooter from us.
20:29 jaffa4 left #cqrs-perl6
20:30 masak the boxes in the image represent our different bounded contexts. they could be servers in varous parts on the globe.
20:31 masak when the sale is made, Sales issues an ArticleSold event, and that event is picked up by Billing which bills the customer, and Inventory which sends the snow scooter with a truck to Shipping.
20:31 masak so one event has a number of effects in other bounded contexts. that's ok.
20:32 masak now let's say that after a while, Billing sends an event BillingFailed for that particular customer.
20:32 masak which bounded context should handle that event? what should it do?
20:33 moritz that depends on whether the item has already been shipped
20:33 masak yes, it does.
20:33 moritz or RussianCollection receives the event
20:33 masak let's say it's still on the truck somewhere en route.
20:33 masak ;)
20:34 masak RussianCollectionAgency is outside of our model in this case. they might become involved in a real-world scenario.
20:34 isBEKaml wait, doesn't shipping occur only after successful billing? or are these effects independent of each other and not sequential?
20:35 masak isBEKaml: it might be an invoice, in which case billing might fail much later.
20:35 masak of course, we could just ship the snow scooter anyway...
20:36 masak ...but that's probably not so good for business in the long run.
20:36 masak ok, so the problem we're facing here is that the BillingFailed event doesn't need to go to one single context, it sort of needs to go to all of them.
20:36 masak Inventory knows how many snow scooters we have in total.
20:37 moritz waitwaitwait
20:37 masak Shipping knows if it can store a snow scooter until the next order arrives.
20:37 masak Sales might know prices and risks and stuff.
20:37 masak moritz: yes?
20:37 moritz doesn't it first of all trigger an AbortShippement, which on success triggers all those other things?
20:38 moritz I mean, it might already be at the customer
20:38 masak moritz: indeed. let's suppose it's still en route to Shipping, and that the action we should take depends on a lot of business-specific things.
20:39 masak this is an example meant to motivate the need for a saga :)
20:39 masak essentially a saga would be created as the ArticleSold event goes out -- or, in general, the "first" event in a series of connected events.
20:40 masak and the saga has a life cycle that ends with one of several predetermined outcomes.
20:40 masak ArticleDelivered or SaleAborted, let's say.
20:41 masak (note, by the way, how all Commands are in the imperative and all Events are in the past tense. that is very much by design.)
20:41 pmurias joined #cqrs-perl6
20:42 masak anyway, a saga is two things. it's a set of EventHandlers (i.e. a Projection), like anything else consuming Events.
20:42 masak it's also a state machine. essentially, what it does is keep track of its state as a single integer during the course of the saga.
20:42 birdwindupbird left #cqrs-perl6
20:43 masak one could write a tool without too much trouble that will *prove* that a given saga will terminate. there's something called Join Calculus that enables us to make such deductions on a state machine.
20:43 masak I find that extremely cool.
20:44 masak and it seems to me that sagas is the kind of abstraction level that we should write our business applications on. there's just so much there that you can do with that that's not even imaginable as something we would automate without event sourcing.
20:45 sorear I've been following you so far, but what's event sourcing?
20:45 masak ...and we're doing all of this without a framework of any sort.
20:45 masak sorear: oh.
20:45 isBEKaml It seems to me that to "get" these sagas, I need to enact role playing games.....
20:45 sorear I take it it's one of the things you just explained
20:46 masak sorear: event sourcing is simply making the event history the primary source of information, as opposed to the 3NF database.
20:46 sorear Ah.
20:46 masak sorear: basically, CQRS and event sourcing are two separate things (which happen to work very well together)
20:46 masak isBEKaml: yes. :)
20:47 masak isBEKaml: one of these graph-proving saga tools would be nice, too.
20:47 isBEKaml masak: dramatic!
20:47 masak ooh, that's an excellent name for it! :)
20:47 masak ok, I'm done.
20:47 masak thank you for your kind attention.
20:47 tadzik masak++
20:47 masak I enjoyed this. hope you got something out of it too :)
20:48 moritz masak++ indeed
20:48 tadzik I feel that I need to re-read that tomorrow
20:48 isBEKaml I enjoyed this too.  However, I need to sleep on it (way too many similarities and a muddled brain at 2am :)
20:48 masak moritz++ for sending in the bot, so that we have logs :)
20:49 isBEKaml masak++
20:49 * moritz buys the event sourcing, but doesn't know if he buys the whole of CQRS yet
20:49 masak that's fine, they're orthogonal.
20:49 masak oh!
20:49 masak one last thing.
20:49 masak would you believe it that I learned something new about TDD?
20:50 moritz yes
20:50 masak :P
20:50 masak I was... well, not blown away, but at least very impressed.
20:50 masak some of you might have heard something about BDD, Behavior-Driven Development.
20:51 masak it's something the Ruby people seem to like, with their Cucumber and their brittle human-readable specifications.
20:51 masak but let's say we have a system with Commands and Events, and we'd like to write tests for it.
20:51 masak do we need to mock anything to interact with the domain model? no!
20:52 masak we just write our tests as Given/When/Then.
20:52 masak Given [some set of prevoid conditions] When [I do something] Then [these various things should hold]
20:52 isBEKaml is GWT part of the framework?
20:52 masak it's part of BDD.
20:52 masak now, we start analyzing what goes into those brackets.
20:53 moritz first bracket: a set of previously issued event
20:53 masak right. a list of them, because order matters.
20:53 masak second one?
20:53 moritz a command
20:53 masak beautiful, isn't it? :)
20:53 masak and the third?
20:54 isBEKaml projections and eventqueues.
20:54 moritz more events being triggered
20:54 masak simpler than that.
20:54 masak moritz: right.
20:54 masak isBEKaml: the projects are just filters to events.
20:54 masak so, we can write all our tests on the interfaces between our high-level components.
20:54 masak we never need to write a test that knows the internals of the domain model.
20:55 masak which makes our tests *very* robust in light of future changes.
20:55 masak it's basically architecture-level encapsulation, again.
20:55 TimToady joined #cqrs-perl6
20:55 masak TimToady: welcome. backlog in /topic
20:55 isBEKaml masak: Like I said, I'm still at the high level and floundering with similarities to what I have seen so far. I might bother  you later over PM or channel for further clarity.
20:56 masak also, you'll note that the Then part not only tests what happened, but also, by extension, what didn't happen.
20:56 isBEKaml s/with/at/
20:56 masak isBEKaml: that's fine. in fact, I look forward to it.
20:56 masak what I need at this point is to be challenged on these new ideas, so that I can process them better, too.
20:57 masak so. I meant to go for two hours, but seems we went for three. :)
20:57 moritz time of a short last question?
20:57 masak absolutely.
20:57 masak and I'll stick around on the channel as well.
20:57 moritz what about runtime efficiency?
20:58 masak very much comparable to state sourcing.
20:58 moritz because of copious caching in the reader?
20:58 masak that's one aspect of it.
20:59 masak also, we might actually win a bit from the way we construct aggregates from a single query on the event history.
20:59 masak the average number of events on a given aggregate might be very low.
20:59 masak let's say it's 10.
20:59 masak that's the number of rows we get back from the event store.
21:00 masak from a single table.
21:00 masak compare that to the number of joins and other stuff we might have had to do on a normalized database.
21:00 moritz got a point there
21:01 masak in case the event history for some aggregates actually gets very long and it becomes a burden, we can start snapshotting in strategic places.
21:01 masak essentially buying back a bit of the 3NF database where it's needed.
21:02 mberends years ago I rejected a design like that for an inventory system: the quantity in stock of any product would have been the sum of hundreds of movements in and out.
21:02 masak a snapshotter is just another projection on the write side.
21:02 masak mberends: as people like to say, disk is cheap.
21:02 isBEKaml that's just what made me think of ESBs. Commit points.
21:03 isBEKaml that results in a better fail-over design. since ESBs are a SPOF. (Single Point of Failure)
21:03 masak keep in mind that snapshots are like optimizations -- they shouldn't be applied prematurely and without measuring first.
21:04 masak isBEKaml: on the course, Greg (the teacher) adviced against service buses partly because they're a single point of failure.
21:04 masak isBEKaml: often, they're also a bulldozer solution to a simple gardening problem.
21:04 masak isBEKaml: there's something called "service brokers" that doesn't create a single central point that can fail.
21:05 isBEKaml masak: your use of ServiceBrokers brings something. I think I'll just shut up now lest I confuse myself even further.
21:05 SHODAN isn't that the other way around?
21:05 masak as I understood it, it's each component holding its own little outgoing event queue.
21:05 masak SHODAN: maybe. I'm still new at this.
21:06 SHODAN i see
21:06 masak I remember being confused at which was which when I took the notes too.
21:06 SHODAN anyhow it's a very interesting field
21:06 masak yes.
21:06 * moritz wonders how well event sourcing stored in an RDBMS copes with referential integrity
21:07 masak moritz: where would the referential integrity come in?
21:07 masak there are basically no references left.
21:07 SHODAN mainly because it brings the business closer to the developers if done correctly. they will be able to speak to each other and understand each other better
21:07 isBEKaml event sourcing need not be stored into an RDBMS... they can even stored into data fields or non structured databases.
21:07 masak SHODAN: yes, that's what I think too.
21:08 masak SHODAN: DDD already does that, but CQRS goes one step further, and Event Sourcing even further.
21:08 moritz masak: in the examples of the shopping cart, each event would need to hold the id of a cart
21:08 masak isBEKaml: or an append file. :)
21:08 SHODAN not only because of the ddd and using the same language, but because the busineess processes are modelled closer to reality
21:08 masak moritz: yes. the cart is the aggregate in this case.
21:08 isBEKaml masak: just a file too. :)
21:08 SHODAN by using the commands and events that the business already understands
21:08 masak moritz: that's the only reference we're holding.
21:09 isBEKaml masak: that's what I was thinking of when I said non structured databases (nosql and sqlite)
21:09 masak SHODAN: it's almost ridiculous how much one starts to model the business. we had examples of sagas that directly modeled passing around a phsyical document within an organization.
21:09 moritz masak: the DB doesn't easily enforce easily that a cart ID makes sense, no?
21:09 masak isBEKaml: ah, ok. but I meant just a flat file without any database.
21:10 masak moritz: sure it does. if your SELECT gives no events back, the cart doesn't exist, and that Command is likely bogus.
21:10 moritz masak: I mean on insertion
21:10 masak so we just fail it.
21:10 SHODAN and the scalability of this type of system is really good
21:11 moritz do you SELECT and check before inserting?
21:11 masak moritz: I guess you could.
21:11 masak moritz: but probably better to choose a unique ID on the write side.
21:11 masak SHODAN: yes, I didn't even get to that. the read sides are embarassingly scalable.
21:12 masak SHODAN: and the write side can be sharded, since the aggregates are like little islands.
21:12 SHODAN yep
21:12 isBEKaml message queues!
21:12 SHODAN yes, what about them?
21:13 masak I meant to have working Perl 6 code ready for tonight, but there just wasn't any time...
21:13 masak I think it's very realistic to make a simple CQRS/Event system in Perl 6, though.
21:14 masak it'd be interesting to see how much of .NET's generics we can do with Perl 6's parametric roles.
21:14 patrickas left #cqrs-perl6
21:15 SHODAN is that the best way in perl 6 you think?
21:15 masak I don't know. but parametric roles seem to be a close enough match here.
21:16 masak what I'm concerned about is not getting enough static type checking on them. but I need to try it out to know whether that is a real worry.
21:17 SHODAN yes, but (and i'm saying this as a perl 6 noob) even if that is how it's usually done in c#, does that mean the perl 6 solution should emulate that behaviour?
21:18 masak no.
21:18 SHODAN but it's a good start?
21:18 SHODAN :)
21:18 masak it... seems a close enough fit.
21:19 masak 'parameterized roles' is basically what we call generics in Perl 6.
21:19 masak TimToady might have more to add on this.
21:19 masak if we don't choose to use parameterized roles... hm...
21:20 masak I guess one could register a given CommandHandler using a global hash.
21:20 isBEKaml left #cqrs-perl6
21:20 masak maybe that will have to be done anyway, even with the parameterized roles.
21:21 masak so it's just a matter of building it up explicitly in code, or implicitly by way of the role parameters.
21:21 masak but I'll need to actually write it out to know for sure :)
21:21 SHODAN that's usually the best way
21:23 masak something tells me we could get this kind of system to be fairly performant, even with Rakudo :)
21:23 moritz especially if it allows you enough decoupling to write many components in faster environments :-)
21:24 SHODAN :)
21:24 masak ...and it does exactly that.
21:25 masak not only could you have all the three major components in different languages, you could even differentiate on different read sides and clients if you want ;)
21:25 skyheights masak: thanks!
21:26 skyheights left #cqrs-perl6
21:28 masak other things I could have mentioned but didn't, which might be good to know about: event versioning. we can basically "upgrade" old versions of events to newer versions with more data fields. (or fewer)
21:28 masak this is the equivalent in doing database upgrades.
21:30 masak either we choose to have event handlers for each version of the event type, or we have older versions of an event be upgraded (also through a method) as they come into a system.
21:30 masak we can version commands as well, with similar results.
21:35 * moritz will be back with more questions tomorrow
21:38 Tene masak: Very interesting.  Lots to read about.  Might influence some design of a platform we're building at work.
21:38 masak \o/
21:38 masak that's just what I wanted to happen.
21:41 Tene It sounds very enterprisey, but not annoying yet.
21:45 Tene masak: any resources for information about using an event log as a canonical data source?
21:46 masak Tene: http://cqrsinfo.com/documen​ts/building-event-storage/
21:46 SHODAN left #cqrs-perl6
21:46 masak Tene: as to "enterprisey", I wish you could have come to that course.
21:47 masak Tene: we did everything while steadfastly avoiding all frameworks. everything was just pure code-from-scratch goodness. it was fantastic.
21:48 Tene masak: I'll have shown up as soon as I build my tardis. :)
21:48 masak :)
21:49 masak if you want to look at some real example code, there's a working example over at https://github.com/gregoryyoung/m-r
21:57 Tene masak: and where did you post the code you wrote?
21:58 masak not sure I posted any code I wrote.
22:06 masak left #cqrs-perl6
23:38 pmurias left #cqrs-perl6

| Channels | #cqrs-perl6 index | Today | | Search | Google Search | Plain-Text | summary