 Hello, everyone. My name is Honor. So it's a four letter somewhat difficult to pronounce sometimes, but anyway, currently I'm located in Norway Oslo. As I said, it's like 222 a.m. right now. And it's a little bit dark, unfortunately. And Norwegians happen to like dim lights in everywhere. So I try to adjust my zoom and camera as much as possible. Currently I work at Microsoft as a front end developer. Though, throughout my most of my career, I was a back end developer. I work on the platform for, I think, for 20 years, use, use it since one zero beta. My contents with function program is actually started with another language called me merly. Maybe heard it. It was actually a fantastic language developed as a thesis master thesis in in in a Polish university. Though there was some activity and I also contributed language and I learned things like what's an option option type there. And from there I diverged to using F sharp, which actually, especially with the with the with the fable, it somehow translated allowed me to translate myself to be a front end developer, ironically. So, earlier, I tried to learn react several times and I was jump jump back. But thanks to F sharp and fable, I was able to also learn to how to do how to program and react and become a front end developer at Microsoft today. So, at work, I don't use F sharp at this job. But in my previous job in Norway, I was, I was a full time front end developer and using F sharp for content for a year. I also have some site projects. So effectively doing full stack F sharp, being the front end and the back end and the database persistence, etc. And also I occasionally organize workshops for curious people. So, one of the reasons why I came up with this talk is that once you once you step in the functional functional programming realm. A lot of things you learn in the OP world starts not to apply you just, I mean, for example, let's say you want to do a standard credit application with with F sharp, then you immediately find yourself just surrounded with all these tools that is designed for C sharp, then you start to use again entity framework and, for example, or ends or whatever database mapping tool you use, and then you just realize it's it becomes this little pointless to you to use a function program in the first place if you're going to use the tools that is designed for non function programming languages. So, in that sense, which today's talk is about CQRS command query responsible segregation. It's actually a match made in heaven for functional programming languages because the CQRS pattern is more like a message oriented and event oriented architecture, unlike the regular conventional architectural design patterns. In that sense, it makes it makes it a very good match, but also, it's a little bit challenging how to how to how to build up all of things and integrate all of things how would you do a real life application. I feel there's some sort of courage amount of information. So this is what I'm trying to address. And say, so this talk is about a CQRS via app.net, which is a very, very opinionated way of doing things, but I believe if you're curious people, it might give some ideas, maybe they can just take the idea and apply it in a different form or I don't know. So that's that will be all up to you. So I'll share my screen, there will be some slides. During the talk, you can just stop me, interrupt me for anything you're curious. You want me to dig further. That's all fine by me. I assume you can see my slide. So, when we talk about CQRS, it stands for command query responsible segregation, and it actually has several flavors. So, I think it's awesome that it's almost like a sort of the company that develops aka.net is actually here in Houston. So it's actually kind of a kind of a nice kind of, you know, it's like it's crossed the world and come back. Yeah, that's true. I actually met the guy here, but when he came to Oslo, NDC, I had some good time with them. Yeah, so I know about them. Yeah, and I'm pretty much in connection with them. He's doing great stuff. I really appreciate his effort doing this. Although he's trying to use a commercial business, so super valuable effort. So, as I said, command query responsible segregation comes in several flavors. At first, it's, it's there's a very lightweight form which you can just apply that if you don't want to go full blown CQRS, which is called command query segregation, CQRS, and then we'll talk about the differences, then the little bit more medium form. So you can do CQRS with or without event sourcing event sourcing is another methodology where your, your, you construct your process, your data is sort of list of events, instead of regular tables or regular persistence, whatever you're using. And then what you do is you just go to these events and maybe able to replay them and then create some sort of projection which we talk about it. And this is the, this is the flavor we'll cover and probably vast measures of time you would want to go with CQRS with event sourcing because this just it just really completes the pattern as well as it's somewhat very functional friendly, I would say. So, the talk about is just what is CQRS, why do we need it, and how do we use it, it's just you can, we can try to summarize in three steps. And then we can just talk about what is what was it before a little bit diving into into CQRS, let's just talk about the, the concepts. So, as I said, it's a, I talked about the command and query. Actually, so what we tell why what what what we try to explain my command, it's something like some sort of message that's intention to alter the state. Okay, let's say you want to order a pizza and you just say place order so it presents some sort of demand. And typically, in your in your security applications from the command you don't you don't return the state it's not it's not the, it's not the ideal way to to to fetch the state. But as a query side, it just returns the data. And you just don't touch that site and don't try to use the query side for altering the state it's just it's it's all existence is just to reading it and there's also due to a synchronicity. And it also the query side usually returns some sort of stale data, but you have to live with it, which we'll talk about that as well. So this is some sort of important chart, you can see. This represents a flow, the flow of one of the one of the ways it presents a flow of secure is where we have a command handler and demand handler. So command handler is like something that accepts a command. And it also, it's also except the state it's also somewhat gather the state, such as let's say you are you're ordering something, then the command would be a place order. The state will be, for example, could be something like a stock amount right. Then the command handler can just decide what would be the outcome, for example, if there's enough stock. For the, for the item, then you can just generate an event, such as order is placed, or we can just reject the reject the reject the command such as the order is rejected because there's not, there's not enough stock for that item. The decision maker. But eventually what it does is it just to generates the event and then that event is just going goes to the event handler. And with the current state, it just generates a new state, such as if you have ordered something then the stock amount will be reduced. It will be your newer state. And if you run this cycle if you place orders for a particular item, eventually we'll consume all the all all all your stock, and then you will be you will start to emit rejection events in a typical cycle. So this is a bit more, more broader picture of the architecture. So on the right hand side, you can see just as a UI, and you I can talk to your, your, your backhand via regular service interfaces. And you can see actually we tried to split the model into the command model and the query model. It's a very, very big distinction. I'll talk about the reason why we do that but just to understand why we do that. And this is actually the, it's just a CTS version of it. So there's just a single common database there, and the command model and the query model share a single data model. And once you separate the model, then you end up with the CTS part. And here's another representation of the same pattern. On the left hand side, you can see the typical crowd application, you, people develop, there's a presentation layer up section layer and domain layer. And in the in the secret side, it's actually considered dashed line. On the left part, you can see, well, the application and domain it's somewhat separated from the query side again. And here's another representation and this is, this is more. This presents this actually the CQS with event sourcing. Again, on the left hand side, you can see the presentation application layer. You, you just request for action. And then what happens is, instead of your the classical tables you would just use in a crowd application. Well, there are some sort of, I don't know, orders table. You just instead of love the events what happened in the system. Okay. It's like a bank transaction book or ledger book kind of thing. So you just record what happened in the system. And there's another mechanism that runs in the back end of Scott which I tend to call a projection engine. And it just scans these events constantly, and then fulfills the data, whatever they whatever you want, it could be multiple projection engines which can then construct the redata store from that. This thing continuously runs as, as the data is feed it to the log of events. So there is, you can you can think about, well, I talk is nice but have you ever used this thing in any real project. So I work in Dubai for some time, like a three years. And the interesting bit about Dubai is that it, it's actually has the words busy airport in terms of international passenger traffic. Except like around 100 million passengers per year. And they have some sort of rules such as all government officers must be from from from the citizens which only constitutes the 20% of population. So you, as an expert you can't have such a job or just you can't attend attain citizenship or just they come they can have this kind of rules. And for that, they have a tendency to automate everything as as much as possible. So one of the projects I work on is just interested called a smart tunnel, where people just walk through a tunnel. And then while we're walking it scans your eyes, and it finds out who you are and completes your immigration process you don't show any documents for don't even stop. So, I can just briefly show the video, although it's a little bit, not technically related. Just, just, just to show how it works. Um, just, let's just just talk about the, the tunnel parts. I just want to show the video here maybe there's something, it's due to my headphone I suppose. I don't know why I can't play this. So you can see the tunnel here in the back end. And then people just walk through. So it's strange. Whatever. Okay, let's just skip this part. So it's it's some sort of tunnel and this is something I used for this pattern is something something I use in a real project. Next slide. So, one of the things. Can I ask a question. So, when you say that you use that in this tunnel. Exactly. You know, was it like moving the conveyor belt or was it the camera. Yeah. Well, it's the system so there's one one system that feeds the incoming passenger. So, typically if you think of how the system versus that. It's not possible. I mean, it's fairly fairly difficult to find out a random person who is who he or she is from their eyes. Okay. I mean, considering there are millions of people you can't just do that instantly there's no such technology. So in order to do so you need to find out who is coming so you just have to limit the people's window. Okay, so we have an integration with the airline. And then when someone checks into the counter and the airline notifies us hey someone is coming and I know their name and then we just registered the person into some sort of limited number of gallery. Okay, something like a 5000 people. And once you walk through the tunnel then it is possible it is easy to find out someone from their eyes among 5000 people. Okay, and once you pass through the tunnel, we just figured out you have passed or if your flight is off also you fly to take off maybe you don't decide to visit the tunnel, maybe you just didn't come to flight. You just removed from the gallery. And that way we always maintain a specific number of people that is registered in the gallery that could be recognized. So this whole system is just there's a passenger feeding system, and there's also a passenger consuming system. And in that sense, we utilize this pattern where there are some commands and then registering passengers and there's a system that just constructs the registered passengers table from the event logs and then once you once you go through the tunnel, it just finds that you if you registered find your relevant details and convey to the back end immigration system. That's under this kind of system. It was a very cool project I really enjoyed it. Yeah, that's wonderful. And that said, there is a certain once you commit yourself something like a security, it's actually a steep pattern. So it's, and it may be something you you're not willing to commit everything because it requires a lot of stamina to be fair, which I'll talk, I'll tell you why it is. In that sense, what I will suggest is that so when you develop a typical application can see the red line which is like the the the above front side is like a free of front end and the back end side is like your your back end. Those are you should consider fragmenting your architecture vertically, not just horizontally. That is, for example, it's like a boundary context, context concept, where you have for example an application you have an authentication stuff your transactions, for example, maybe a bank transaction, and there's a contact for example, you're managing. So you can choose different architectures for for different vertical slices. For example, for authentication, you can just use a crowd level. It's all fine. And for your more valuable, where it's more, you will get more benefits from secure s, you could just commit for for example for the transactions for this for this pattern. So it's, it's, it's, it's applicable to a single slice this this is a better way to to handle the complexity. After all you don't want to spend too much time on something that's already a sole problem like an authentication, but it's all up to you. So this is just, I just tried to give a brief overview, what is it about. As I said, it's as a summary. There is some sort of commands that's feeding the system, and then you just generate a set of set of events, and there's some sort of projection engine which is just to generate it. Why should I care. Right. So I can, people came up with this idea why this is important is so several problems that is actually people don't notice which I will just talk about these problems. One of the things is, which is the most important and you will, you will not find this definition and anywhere it just requires you sometimes also mental mental shift, just like you remember. When you talk to the C sharp guy. Hey, why do you use a sharper word. Why do you use function programming. It's very hard to explain, because it's just something you, you, you have this mind shift right and you know the answer but it's, it's a little hard to put on the words. So secret also it in some way it's it requires you to have some sort of mind shift. And the primary motivation to use why should I secure do security is that it is my personal primary reason it protects your domain. It's not about performance, not about concurrency, or other things you should you heard about security, but it protects your domain, and it protects your domain by separating it into two two pieces that that is the command and the query. Let's see how it does that. You develop a typical application. It's like in a crowd manner, and you have the user's table. And, well, it's a very simple table I have the user ID username and the password. And let's say your your company is going to a security audit, and somehow a new requirement came, and then your boss or manager asked you to, to answer the following query that how many times if they use your chain to your passwords. I'd like you to think about it and if you can make it make me can just talk back. Oh, you can record the state every time. Right stick in a database. Well, wait, are we confined to just that table. Like, is that the only table we have. It's up there. It's an open question. I mean, you do it like we do goodbye query on the username and you can get the frequency counts. I'm assuming that the ID is just an ID for the record ID and not the username. Would you, would you use the latest for a username and just make it make it. Yeah, but please note that there's there is no counter or something like here at this point of time right. How would you know how many times they they change. So every time the user changes password. The only thing changes the password column. Right. And how would you how would you count it. You need to count it somewhere. Every time they change it in plain text in a text file. And then you just go through with WC. I mean, you have to have a lot of people. Any time you call the change path function, you go ahead and you say a user ID in that table. And that day, I mean, anytime you call it. But if you do that, the world only starts when you start logging in. That's fine. But you guys aren't being creative enough. What you do is you say you can't change their password. And that is the solution. Zero. Password for it. Change data capture is never the answer until it's the answer, but it's never the answer. I'm using that capture right now. I mean, I'm assuming this table has, has the record of everything. So you just basically just do a group like where the question. But that's seriously, but change that a capture and SQL server only gives you like seven days by default. So if you were interested in the last seven days of user changing their passwords, then you're good. Well, okay. So effectively starting at the time you enable change. You make the users table, the log table. You could potentially query the SQL server logs to get all of the updates statements. Oh, that's, that's a little bit overkill, I would say. So let me just let me just wrap up. Thank you for your very creative ideas. The answer. We can send the rest of the meeting on this question. The password isn't thinking like honestly. It might be. So my new approach would be just to introduce a column just just that counts. It's a very near approach, but it would work. They just introduced a column here that is just a transfer change counts. Okay. That's not vulnerable enough. It doesn't match with three enterprise patterns. And architecture review. But once you add a column, then such a column, then the problem is you're effectively changing your data model, but also you're obligated to propagate this backwards all through all the way up to your application. That means now once I make such a change, I need to change my domain model. Perhaps, let's say I, as a, my, my name solution was to add a column. And then I, if I use something like an entry framework, in each, now I have to go to revisit my domain model, and then introduce a property that represents the change of number of number of password changes. That effectively says whenever someone wants to create something and that doesn't exist in my database, I need to, I need to change the core part of my domain. And every time you change your core, the core part of your domain, you need to make a deployment. And every deployment has the potential risk. You can introduce bugs. Well, this is this case is very naive and simple, but actually, it's what you're doing. So what's what security is trying to do is, if we can manage to separate these read concerns, perhaps we can get away with handling the subject queries, only by dealing the dealing with the change in the query part, which is non critical. Whereas you can keep your, your core domain unchanged, and which mitigates the risk. Okay. So that's the, that's the primary motivation why, why security is valuable. It protects your domain where it relinquishes. It just leaves you. Many, many times, whenever a change is happening, you can get away by not touching your core model. Okay, but so once. So are you making the argument that this allows you to keep a minimal database and push as much as possible into code. I wouldn't necessarily say database because again, let's we have to think of mentally we have the query and the command side of databases as well. And I'm, what I'm claiming is that the command side is your core model, which is more valuable, more critical. And you can get away without touching to that place where you will eventually have to touch because there's a new query you will have to touch to your query model. You will probably have to touch to your query database as well. But a mistake that would happen there, which would be far less critical that would happen in your command and query side, command, command side, sorry. So this is what does that answer your question. Yeah, yeah, yeah, that's super helpful. Thank you. So, so, as I said, this is this is the primary motive of secure as it or rather than the other benefits. So it protects your core domain. But we are not, we are not finished with this problem. So, once you add the solution, then the next question can arrive what will be the frequency. Then how many, how many times does it use a change their password within the seven days per period or just daily, something like that. Then you still can't answer that question in this name change. Well, you, you, you that you then have to resort creating another table, where it just timestamps every time a user chain, a user changes their data and then, well, and security event sourcing is actually event sourcing part of the security records everything happened in the system. Even if you want it or don't want it. And that way you never lose anything that happened to system as long as you're intended. So if there's a command change commands, sorry, password change command comes out. That would eventually yield a password change events or password change failed event for perhaps there's a policy against changing can fail or succeed. And then you will be tracking, even if you're not interested in password in this query in the first place, you will have all those events timestamped and sorted in your in your data store already. So you don't have to worry about, well, what if my boss asks me this query in the future. You don't have to think ahead. If you already record everything that happens in the system. Okay, but in that sense, it also helps you to protect your, your, your domain. So here's another example that event sourcing. And this is a little bit more different domain where you place orders in a typical crowd database we have the orders table and we can just create whenever an order is created. And in the secret event sourcing, what we, what we create is just the set of events. And I think this terminology is a little bit wrong here. You should say order place not order created because if you say created, it's in, it still leads to crowd mentality. We should use a little bit more proper naming as well. But eventually what you do is that whenever an order created order updated. So you just immediately you set you create an immediate set of events, and that just constitutes your your event low. And whereas there's again, starting from some sort of offset. There's an offset because you will system may be restarted and you just, there's no guarantee you will continue to run your system indefinitely. You record some offset and then from starting from a starting offset you just replay and I'll aggregate those events into the regular order table as we know it. So that's the event sourcing part. And that is also this is very understated when it comes to regular applications to handle concurrency. Let's talk about concurrency so concurrency represents here for example your applications are typical application and multiple users trying to access a single resource. And as I said it's a very underrated problem, and it's a very real problem. And he's actually written by distinguished engineer of Microsoft date folder which is the creator creator of sign alarm maybe you know him. And this is an example from to do in VC application. And there's something wrong with this code and it's not his fault because there was some limitation, which we talk about it. What do you think, what could good, what could go wrong with this code. What do you think. It can stop in the middle. Yeah. You're saving at the end. Okay. But assuming this is rather wrapping into into it. Well it will run into in in in a transaction. I mean, once you do that. So, let's think about a concurrency problem concurrency rate way of things let's say two people are trying to update or best for example, in one case one is one person is deleting this, this record well one is one is updating what's going to happen. So there's already a check here if you can see there's a if await TV to do and if if there's no it checks with any I think, and if there's no record there it will just return not found. Right, it's already some appears to be protected from that from some such cases, but it's actually not. So because databases work out handle the transactions in an isolated way. If consider to transaction one is trying to delete a record and then what the one is just trying to query it or save it or just insert it. So let's say you're trying to update a record. And before you update that record. Someone has deleted it. Right. And what would happen is that your, your, your update transaction will say, I suck. I successfully updated your record. That's what you get. But eventually you will have no update at all because you someone has deleted it. So it may look like a very subtle problem but even a simple crowd crowd application is vulnerable to this kind of thing. You may not worry about well. Maybe there are two few users in your system which will represent that concept. And they followed a smart guy and I talked about it and then in the next iteration he's somewhat improved as much as possible. Enter framework seven or for that different utility. And this is the same code for the. It's a newer commit for the same same code. And in this case what he does is calling the entry frameworks execute update I think instead of doing that. And most relational databases when you execute an update statement they will tell you how many rows affected the database returns that as an integer. Okay. And what this is what he's using just to just to circumvent that problem. Now, in this new version is checking if the rows affected is zero or not. If the rows affected is zero then apparently someone has deleted it. And it's somewhat helps the problem but it's still not a pure solution. Now, you can say, I have few users. Right. I don't care I'm not. I only have one user. And you may believe that you're not you're not you're not vulnerable to this kind of problem. But then think about you made a UI and then you're just user. Just click this button multiple times. And there's no guarantee which request when you work with TCP IP. There's no way you can know which request will go with the same first or second. And you can just create a very simple risk condition just by by by having a single year single single user. Well, I can disable the button. Right. It's just you I think I can prevent that problem. Then, well that means you're you're trusting your user. First of all, a malicious user can just undo this very easily I can open the HTML and then just try to corrupt your database. Maybe there is a colleague who doesn't like you in your company. There should be a web service and this time there, you have a far less control about over concurrency you're calling calling the service, and then can cause this kind of concurrency problems. Here's another problem. So when I learned about database transactions. In the first place, what I read about well we create a transaction you're transferring some amount of money from one account to another. If the transaction commits, all is good. If doesn't commit all is still good right because we are not going to since the transaction in asset database offers atomicity. You're never going to end up with a corrupt state, which is very good. And let's say when once we're trying to transfer some amount of money we're trying to first check the balance let's say we have a hard bound rule in an environment that you can't overdraw. We are going to check if your balance if you're if your balance having a amount of money, we're going to transfer the money right. But what's going to happen when you have concurrency. Then, let's say these two simultaneous transactions are trying to withdraw money from the same same account. Both of them are checking if there's enough balance if there's $1,000 in the first account and both are checking if there's enough balance both both code will say yes, there is enough bad. There is enough balance, but there's not enough balance for both transactions and since there's the threats to transactions are isolated. These things don't know about anything about each other. They are not aware of each other and they're going to both both succeed, and you will end up with your corrupt database record. You're going to end up with I don't know depending on the condition. The transaction will say well be successful to transfer your money, but actually, only one one will succeed, right. The concurrency problem does exist. And it's it's everywhere actually in even in a simple web application we don't think about much, but it's actually, I'm not concerned about the minor possibilities and it can happen. What can we do about it. In a typical way. If you use something like an interframer crowd bay is one way is to use optimistic concurrency or pessimistic concurrency in in optimistic concurrency we decorate our table with a version or timestamp column. And then every time we make a change in the row. We check if that we do it by update statement, we check if the update statement returns at rose affected. And how we do that in the in the update statement we introduce a where condition against the version column or timestamp. So that if only the timestamp matches or the version matches the update statement with succeed, but that's the optimistic concurrency we call. But if it fails, you need to retry. And there's a pessimistic concurrency part where you would just lock the row rely on the database. The database over locking the role. And then no other transaction can just read the row even you're looking at the locking at the role level. But then this is very vulnerable to deadlocks. It really happens a lot. If you if you try to use locking over a row so do two transactions trying to read the rows in opposite order then the database gets a well both transactions are locking each other then it will kill one of the transactions. So what can we do about it. So the solution that CQS is kind of architected would offer is just let's just make a proper domain during design. Let's define our transaction boundaries per aggregate in domain during design. The concept of aggregate is just it's something that represents a transaction boundary. And it also represents an invariant. So let's what is what is our invariant here and an account cannot overdraw. Then we can we can effectively create an aggregate and transaction boundary over per account. So in typical your if you apply some things like unit of work pattern, right, you create a transaction at the beginning of request you do a lot of things. And then you commit what you're doing is you're effectively creating that aggregate boundary in your entire domain. But that's that that that creates this kind of problems, whereas what we can do is we can create a transaction boundary for each, each aggregate. But then you have to you, you have to also coordinate them. So if you're familiar with two phase commit protocol in distributed transactions, this is something we have to do. We have to check if both transactions are succeed and then follow it. Let's see in some sort of sequence diagram how this would work in a bit more secure as pattern. And this will be a simplified version of it. And also talk about a little bit more detailed version of it. So there's a customer who who who is willing to transfer money so you can, you can see the arrows as a sequence diagram their numbers, the red arrows represents the commands, and the blue arrows represents the events. So we want to transfer the money there's a command handler just forwards the accepts the transfer money, and then it issues a command to the source account and stating that well, I need to transfer some amount of money. And then source account just reserves the amounts. Okay, just doesn't commit yet, but it just reserves that it's going to commit that. And then there's some sort of state machine, which I called sagas, which is a little wrong terminology, which takes it over from that point on and then it just it just communicates to the target target account. And then target account also gives it there. Okay. And then once once both both sides reserve their amounts and then the transfer process can confirm the transaction in the first account. And then, once once they get the confirmation, it does the confirmation for the second account. This traffic this chatted thing. And then this effectively solves the problem. Because now your transaction boundaries are is are restricted into per per aggregate. The challenge with this is what happened system is crash system crashes in any of between these steps need to recover. Right. If it crashes or like, let's say that your system shut down and step four, what would you do. Another thing that they really talk about it. So we talked about the security as protects your domain, talk about handles concurrency. Also, there's another annoyance with the typical crowd, the source of truth. I'd like to ask you. In your applications, you develop applications, what is the source of truth. No, I know the answer. The source of truth is reality. No, no, that's not a joke. I'm serious. The source of truth is reality. Everything else is just a weak reflection of that. That's true. That is true. The database is actually a part of reality as well. No, a database is a record of reality. I assure you the database exists in reality. It does, but it doesn't contain the reality of We have philosophy as part of this group. Yeah. That's right into it. We have humanities people, social scientists, philosophers. Actually, the comp side people are kind of already in this group. I would say that there might be situations where you might want to keep track of certain digital things that only just the database. There's no source of truth outside the database, like the password question. You're not going to go ahead and have a real password outside the database. It's not possible. If you have a real password, that's not math, but there's a database. John, would you like to respond to the idea that all reality is in the database? No, all of reality is not in the database. Hold on. I like to respond to John's comment and he has a valid point. I think he's not joking and it's true. But the problem with the reality being the outside world is if you take that as a source of truth, then you will end up the problem with stability. Because your application won't be aware, it's impossible for your application to be aware of the instantaneous reality of reality. Change is happening in reality outside the system. It's a fundamental problem. For something to be a source of truth for our application, it also must not be a tale. That's why the reality can't be the source of truth for your application. The thing is just your application's point of view, the information is not there. There's no guarantee there. But once you talk about source of truth as a database, which everyone acknowledged, then we also know that it's source of truth because it's not tale. It is there. We accept as the source of truth. It's the reality. We assume that's the reality. We accommodate that. So, 80 years ago, a guy named Pat Helen wrote this blog post that said, This data is like the night sky. And it's actually like fundamentally really important to understand this. Like if you go and look like get outside of Houston or whatever city you're in, go out in the country, you look up at the stars. Do you know what you're seeing? Do we have any astronomers? That's the light that left those stars many years ago. Yeah, millions of years, millions of years ago in some cases, right? And so that's always true about our databases. Our databases show us the truth of the past. It's actually really important to understand if you're designing applications is to understand that your truth is in the past. I will argue, as some of you know, I will argue that this is a solved problem. It was solved some time before the year 1400 CE in Europe. It may have been solved in Korea earlier than that. But the point is, double entry bookkeeping solves this problem by accepting the fact that you can't ever know exactly what the truth at a single point in time is. Yeah. That's what you call individual consistency. Yeah. It's why you're right about everything, honestly. Like, it's why CQRS makes sense is because it's the reality is that, like, things happen. We record our understanding of those things, right? And in some cases, you know, we have to go back and correct our understanding of reality. It's just the way it is. It's like, people who think two phase commit solve their problem don't understand the problem. They really don't. But anyway, I'll shut up and let you go. But for me, it's very pestering that I rely something like a source of truth as a database where I'm a developer, I like the source of truth to be my code. The rules that just I'm calling a lot of rules and then this is pestering me. I'm relying on the vendors. There's a database vendor. They have some sort of features in their database, they can just offer indexing, roll locking, etc. And then I somehow find it personally very, very annoying that I rely on the database that much. I'd like to reduce the database to just put it into its place to be a persistence engine, be a really persistent engine, but at least not from a developer's point of view, don't be the source of truth. So those will be really visit how this goes. But this, this, there we come the ACA dot net and the actor thing. But before we jump into the ACA dot net thing and just, I'd like to ask you another different questions, there's a functional programmers here so you just say you're developing a simple web application. And then the user submits a number and let's say five, six, and what you're doing is you need to accumulate this number. You need to do it in an immutable way in the memory, there is no database. How would you do it? Shall I repeat the question? The user submits some numbers like a five, six, seven, and what you do is you need to add these numbers constantly as the user submits the numbers. You need to do it this in the memory, but you, you're not going to be use an obviously immutable variable to hold this in the memory. How point to handle this. You would, you would store the number in some location and then change the variable to point at the new location so you can have it change in a comic way. Well, for example, let me just give you a little bit concise for F sharp users, you're not going, you're not allowed to use mutable keyword or you're not allowed to use any C sharp or that's a BCL level mutable collections. How would you do it? Or is it doable. You have to use mutable. It returns it. And returns it. Yeah, that's also that's supplement. That's it. It's like, you have some state. Yeah, you take a you take it, you apply it to the state. And you read. And then you have a new state that is a function that has applied the it to the state. I mean, that's the way it's done. Yeah, but how would you in practice in practice. So it's, it's, it's, it would be a shame, right. We talk about function programming, but it would be a shame if you can't do this if you can't solve this problem without using mutable variables. Right. So what, what I would do is in F sharp, there's something called a mailbox processor. Yeah. Which accepts a message. Well, I can't say it's really pure. Well, it does a lot of trading and a lot of plumbing there in the back end, but it really writes you allows you to write a recursion. And then you just listen for a message. And then you can just get the incoming number, add to the add to the current value, and then call the recursion, because it called call yourself recursively and then hold the state as the function parameter, and you will use no mutable variables. Why am I in this example because the actors actually somewhat works in a similar sense. And I could net is is is one of the frameworks that that just allows you to, to, to do this to do so. So, in a typical all object oriented programming, you have the object so an object is something like that accepts a mess, a message in form in forms of method call right there's a there's a there's an object. There's a cat object you call it meow, or just eat something, then you call these methods, just like that in an actor you just send the message instead. Okay, but the difference is that an object is is somewhat tied into him, it's just a pile of data, and it's pinned to a memory location, even though garbage collector moves it out, it still lives in a fixed location. So as an actor is a more broader abstract. So when you talk about the actor as an object. It doesn't leave. It doesn't, sorry, it doesn't pin into particular memory location with it's a more abstract concept it's not that it's, it is not just a pile of memory. It's floating in the, in the, in the, it's a, for example, it can transparently, you can access an actor for example, transparent from another machine, as if it's, it's, it's, it's living in your own machine so you have some sort of built in mechanism, where it can restart with his own site own life cycle, it can use a different memory location but you can still access the same actor on the same place, as if it's, it's there, even though the underlying objects change with some sort of it offers and after some offers there's some sort of object like an abstraction. And one of the things that occurs that offers you in a distributed environment is which we're going to talk. There's some sort of gossip protocol. So by using an academic you can just invent a cluster. And let's say there isn't there are three physical nodes here a B and C. And of course, protocol does this. Let's say you want to introduce this B and C nodes into your cluster. And they only know about a. Okay, so you said that you know the IP address so you configure that hey, you configure be that it should connect to a as an IP address and by using a gossip protocol, academic is allowed to propagate the information of B and C to each other. Okay. Even though B and C doesn't know about each other in the first place by connecting to a, a will tell about a will tell about each other so then able tell that be that hey there's there's a there's a C in this IP address, or a will tell to see that hey there's a there's a and when then B and C we will be able to connect. So you can build, build such clusters with with our current net. That's one of the things about it. Furthermore, this is where we're going to probably use our current net which is TQRS. I can offer some sort of cluster sharding mechanism when I read about cluster sharding I told us that very advanced concept that this is required for distributed computing. So I use it for my applications is even there's even though there's a single node. I still make use of it. And in our current cluster sharding you create an entity. And that entity could be it's an abstract concept. It's not like you create an entity just like using a new keyword and starting an object but it's it just pretends as if it existed since the beginning of time. So let's say you want to send a message to an entity that you have never created. You say that well I want to create an order with this ID. But they'll make that it will it will create that actor for you if it doesn't exist and it will just start that actor and it will just receive the record and it could be distributed if it's sharded into multiple physical nodes or virtual nodes, or it could be a single machine. But the class of sharding is what constitutes the your domain level aggregates as entity. They are not going to they call it entity but actually constitutes aggregates. How does it look like an aggregate an aggregate is like an entity. Let's call it takes a message and this message takes three parameters. One is the entity ID. It's like your, for example, your order ID, the shard ID if you are sharding for example you can geographically shard it you can say that the orders from USA is sharp a orders from Brazil is sharp B. And there's the message, which is like the place the command place order command. And then you construct the data structure, and then you just send this to the act to to to the, I mean you just dispatch this message, and it will find the relevant relevant actor, and it will just started. Okay. So, how does it not their processes like that let's say you have you have a login mechanism, then you can read the road just here represents a login command. And then the user actor just receives it, and then the size on the outcome. It could be either login succeed or login failed. This is what we did. This is what we told so far in my design pattern. There will be cases where you would start a saga. So what a saga is like it acts like a distributed transaction coordinator. Not every event will cause a saga start. For example, here, we have emitted the login successful event. And there, I designed a saga starter. It's another actor here, which can decide or not I mean, I mean it'll decide maybe a different saga needs to be started for this thing. So the saga do we'll we'll just visit in this next slide. So this will mean more broader picture and in a real application of how would you transfer some amount of money by using accurate net and using these, these actors. Here we have actually five actors. The saga starter is something like a global. So it exists in one once one single piece. The transaction the account sender and account receiver are three aggregates that are that constitutes our domain of it. The transaction saga is also another actor which represents the network which acts like a transaction coordinator here in the number one arrow we issue that transfer money and this this creates a transaction actor. And the next thing it just it issues it emits an event called transaction started the saga starter will say, well, okay, it will issue the third arrow. It will start it will start the saga. And once the saga started it will tell the saga saga started it started, and then it will tell the fifth arrow, it will tell the transaction entity to continue. Once we get the continue go the saga start this the the transaction will emit the sixth event that the transaction started. The transaction saga will coordinate the events. It looks like a chatty traffic but if you look at the each circle isolated way it's actually not that but chatty. On the left hand side, you can see that the transaction saga first will send the seventh arrow with reserve amount, the eight amount bill will say amount reserved, and then it will do the nine and 10 for the account reserve account receiver, it will also probably add a plus amount. And once both sides are completed with the amount reserved messages come, then you issue the complete complete to both sides, and you get the 12 and 14 messages to get that they're committed. And once they're committed, you issue the 15th arrow that you're notifying your transaction aggregate, and then you say it's complete and then the 17th arrow states that you're notifying your caller that all this all is completed. So, at any stage, if trans this transaction fails, let's say your process crashed, the transaction saga will book keep. What was the last number we have executed, let's say it was seven, then it will replay the replay the same message to the to the same actor, and that way, it is possible to just you can just continue the process even if the process crashes. Okay. And each of these actors just they offer their own invariance their own rule their own transaction boundaries. And then you can see all these blue arrows, whatever the message, they will land into the database as a persistent event. Okay, so you can say that well there's a transaction started. And then there's amount reserved they're completed. And then you will have a set of events that is that existing your database. So the question. Yes. Yeah, so, so every time a saga is sort of hitting the transaction saga. That's making a call to the database, or is that happening just in memory. Whenever you generate an event, whenever you generate an event, you persist that event. Okay, that's that's done by the actor and I'll show the how the code does that. Whenever you generate an event, you persist that event. And the actor itself is responsible for persistence here. Although it's a little bit less ideal sounds of separation of concerns it works well. So in regular objects we have the garbage collector. So I created these actors, right in the memory now they're floating somewhere. What will happen like five hours later, will they stay indefinitely in the memory. We need to garbage collect them and I cannot offer that mechanism called passivation. Passivation is something like an if an actor doesn't receive a message for two minutes, for example by default, it will remove it from the memory. But it will do it such a way that it will handle it in a graceful way. I mean you will never lose a message. Once it's doing that. Okay, this is called a preservation and this configure well there's there's a there's a configuration here so it's by default 120 seconds. There's another problem here, let's say your process crashed, right, and then you restart it. Who would, who would restart your saga, because saga was the continuation point. There's a concept called remember entities, where if you mark and an entity as remember entities there's switch for that. It will restart those entities automatically on the boot. When you put your application and typically this ideal for sagas, it will, it will create. It will restart those sagas, it will only restart those sagas, and then the sagas will just dispatch those even in the continued process. Let's look at that from some F chef so to the talk about too much theory. How would you create an actor with F sharp. Well you can it's just a very short thing actually even this is an FSX file. And well the, the hyperion thing isn't required you just reference the link, which is a rapper and F sharp rapper over aqua.net. You create an actor system. And what you do is you create a recursive function here, just as I, as I described, and you can see there's it's wrapped into an actor computation expression. And what we do is we let bang viewers, this just like it is very it looks very similar to mailbox processor, where we just receive it for the message. In this case the message tends to be a string. If the messages stop for example we return a special token call stop, which stops the actor. Or if it's an unhandled we return a special token here called unhandled, which logs and messages unhandled. And if it's anything else we're just printing the message here and we're just recursively calling our cell. So here what is the state, what do you think the state for this loop. So the rule is the recursion, the recursing parameter is the state. In this case it's unit. So that's our state. You can say there's no state. Because the unit is the is the one we are recursing but if it could be anything it could be a real object it could be a number that whatever we are recursing would be the kept in the memory. And in the below we can see how we create the spawn anonymous for example is one of the ways to construct actor. And then you can use this funny operator. Send the message to the actor. Okay, that's, it's also type safe so in this case if you use operator you can only pass a string, you can't pass an integer it won't compile. How would we handle the persistent one. It's slightly tricky. In this case we have a real state. So our we have a counter changed, I think it's used as the message, and the counter command which we can increment and decrement the state. And then we have to get state thing. In this case our loop has a variable called state. And by default it is initialized as zero you can see that at the bottom to there's a loop zero statement. And once you see once you start that then do the message it our actor will start listening messages. Once you share command ink in the below. We will capture that command message and that it checks if it's ink, you can see that it issues a special token called persist. Once I got it gets that message, it will persist event to database. Okay, that's how persistent them. And once the persistent succeeds. It will call this event thing it will you will get another message where that will match the event part of it. So you see the first persistent message, and then we recursively call our cell and we change the state again we just add the number in the, in the loop part in the event change return loop part. And that's how it works. This is how a simple persistent actor works. We just issue the commanding commanding commanding and then command decrement, and then also we can get the state, which we don't get the state for the actors for the real for the real case. We're, we're, we shouldn't do this. So, I got that as persistent mechanism first with several databases. It first, I mean, as a lot of database it works against SQL server it works and SQL light possible SQL MongoDB Oracle my SQL I use it it SQL server SQL light Oracle myself. Perhaps, I would say most ideal might be MongoDB because what you're you what you what you're storing is like a serialized form of the event. And probably it would it would make sense to use MongoDB but the other ones also work well, you are not going to create the JSON data directly. It also supports things like Cassandra, when I know, and Azure Cosmos DB, if you go to that extent. And this is how we do how the cluster sharding works. So, I'm not going to spend much time but eventually what you do is you pretend as an entity exist and you send the message to that there's a factory of it. You specify the shard ID and entity ID, and then you can send the message to that and this is how you you work against across the sharding with F sharp. There's an important cycle. Once you message, once you receive a message, you first validate the command. For example, you get a place order command, you first validate it maybe there's enough stock or not. Then you decide you generate any event. Let's say there's enough stock command place, so order place three, or order rejected. You apply the state, such as reducing the stock, you persist the event, the database, then you publish the event. You follow these five steps, and all of them would would happen automatically. There's nothing will come in between because the actors are, you see that there's a message you're listening. They will not accept a message unless you will you will run through a full cycle. Okay, so this this thing will happen in a single transaction. I have some personal side project, for example, where users, for example, make a calculation. And then, typically knock it out net. This is how I model my commands and events so that's it. For example, you can add a credit consumer credit or you can just a user can log in. And the outcomes of these events are just comments is is here. So notice the difference between a command and event is command represents something a demand that can fail. And event represents something that hasn't already happened, which cannot be undone. Okay, once an event has happened, it's done, it's cannot undo it, because it's happening in the past. And this is a well it's another snapshot of how I woke the the actor which I will not talk about much. And this is how a real actor looks like in in a shot on the on the left hand side so you can see that there's an important part called recovery. Whenever your actor crashes or just your clothes shut down your system, you need to restore the state. And by default, what the academic does is it plays all those events from scratch. And then you just reapply those events and then then that's how you restore the state. However, this may not be ideal. And the reason being is that if you have one million events, you don't want to replay them every time your system bootstraps. There's a mechanism for record and therefore it's called snapshot. So time to time you need to snapshot the current state, let's say every 100 message. And then it will first fetch that latest snapshot, and then replay the remaining events on top of it. This is built into a good as well. And while here's another code showing this is the apply state so once you get a get a get a new comment how would you change the thing in memory. So it's just a regular function there's nothing special about it you get the event you get the state and then you just alter the state and you just returned a new version of state. That's all about it. How does it look in the database. So you can see in the right hand side. There's the, the, the, this is how I could fulfill the database. And there's a persistent ID that looks like the, the, there's a column here persistent ID that shows actor name. There's a sequence number shows that what is the message number for this actor. There's some sort of manifest that is used for civilization. And there's a timestamp there's a payload, which is the actual stylized message. It's a shame I didn't show the payload itself. What about the read side. So in the read side. I can offer said something called Akka streams, where you can subscribe to a stream of events. So you don't need to go to database read manually. And it actually gives you a stream of events and you can just get those events and do your own aggregation and then fulfill your regular table. This is, for example, I'm using a scope provider here. I get a message called credit consumed in here I go to credit stable I found a table. I just did used to credit and I just commit. When I commit. I also commit the offset number, some number that that reminds me that was the last event I purchased in the same transaction. So that whenever I restart my process, I know what was the last event I created. So this is the commit part. I'm using a sequel provider here, and it's just commits the offset value and the regular table in the same transaction. In the same thing. So the offset title looks like this for each projection engine. I have a simple single line. And for example, there's the users projection engine here. This is usually how you will have one projection engine per application, but you have multiple ones. And then you have the offset count, as well as you can see this is the regular table. This is the crop table on the right hand side. That's actually the user here. Constructing. I have some live examples. One of them is I'll just show you, I have workshop here the source code is available. This is a live demo application I created for this workshop. You can order a pizza here. This is running on this full secure cycle. So something like that. You placed order. Well, it will ask me to log in. And you can play with it. Or if you're interested in in having the workshop. You can just contact me. But that's this is my this is pretty much about my presentation. It doesn't link to one. That's it. So once I placed order. You see there's a little bit of a synchronicity here it just shows the details a bit late. And through a web WebSocket it actually based on the events it reacts actually so you can see this is moving up now right now through the WebSocket connection. Thank you for listening. If you have any question, feel free to shoot. Will the pizza actually arrive. I know it's really late there. I'm surprised you're going to make it right now. Eventually it will arrive. Questions. This is a very dense topic. I know it's going to take a while to make a pizza. I know it's really late there. I'm surprised you're going to make it right now. Yeah, yeah. Eventually it will arrive. Questions. This is a very dense topic I know it's it's fairly. It's not easy to grasp at, but at first hearing, if you're not familiar. But I just my objective was to at least familiarize with concepts. We can have their own how your own ideas, how these things work, or maybe you can develop your own framework or use something existing one. But it's, it's, it's not easy to chew at first. So you need to one need to play and experiment. And you should consider the, as I said, as a summary, the motives, what benefits you get. So I told about I talked about how it helps you to protect your domain model from your changes. You have the all events recorded in your system, and you can just get away with some of the changes in the query side. It handles concurrency very well because actors are tested by default. So you will never have two messages at the same actor in the same actor at the same time. And as well as it actually gives you gives the developer the control back to you. You don't rely on the database as as the source of truth as much as before, you will have the control in your actor you will have the code I particularly enjoy this this part of the thing. When I when I use enter framework well I have entities hydrated from database, but you don't know if it is a single if it is the only entity at that time in the memory if you have to to concurrent requests then you have you will have multiple instances of the same ID, the same ID. And just, it's a bit of it becomes a very loose concept. On the drawback side, if you see there's a chatted traffic you need to manage you need to think worry about how to handle the transactions in a distributed way. It's not for faint hearted. So it's a trade off. I do have a question. And, you know, like, I've worked with C address before, but never in a ca. So, when your domain changes over time that maybe the, you know, the meaning of a command may, you know, suddenly morph over, you know, over time. And you're, you know, replaying your history. Are you doing some sort of versioning for your commands or how are you. How are you managing that change. That's a very legit question. So, command versioning isn't so much trouble but event versioning is a big trouble. The reason is that, in particular, once your events change, you, you're trying your from your persistence, you will get the earlier grudges on your events. Okay, then is, and you have to tackle with this. How would you this or this realize them and appropriately. So the ideal approach is that So I explained the events are represented discriminated unions. So the ideally you would create a newer version of the event as a, as a, as a newer, as a, as an under step of discriminated union and new discriminated union. That would work fine. But otherwise, if you want to, if you want to do it, you can also do control the deserialization because F sharp has some offering with the option types right. Then, while deserializing you can just say that well I introduced another sum of something. And then for the older versions of those events that it will be none. And then you will have the handle. One thing you need to be careful is that you should not share these events across your application much. I mean, sharing events is something very dangerous, because you make. If you share events and those events changes, then you make things very brittle. So it's, it's all although when we can think about I, if I have a event. Why don't I share it. If you want to, if you want your application to communicate with other applications. I would recommend using a separate set of events that's outside of your security event cycle. That would be my answer. So basically I would say I would suggest you create a newer version of those events and comments, rather than missing with all ones, if you can. I was just curious. So, you mentioned that you're using a WebSocket to notify the browser. Are there any good abstractions over that I mean I've had difficulties working directly with WebSockets like SignalR or something like that or do you have any recommendations in that direction. I used, there's something called Elmish Bridge. Oh, okay. Yeah, I'm familiar with that. Yes. Okay. And to be fair, it's documentation is super confusing and how to use it properly. It took quite a time for me. But that's what I use. I feel comfortable with it. It's a very good thing. So you have this Elmish loop in the client side and there's an Elmish loop in the service side. It just really complements it very well. That sounds nice. Thanks. One thing, one thing I just wanted to comment was that, you know, I found, so when Chris and I started working on this Valero project, I found owners repo out in the wild. I thought it was, it's really refreshing to see a nice sample project with, you know, some depth to it. You know, you talked earlier about how you wanted to give like a sort of a real world example. And I think that there's, in general, but then within the F-sharp community in particular, there's sort of an alarming lack of resources of how to actually put together a real world application. And so I was very grateful to see. This is what I was trying to address and my own capabilities, at least for my own part. And this is understandable. Function programming, I think still didn't make, didn't become the mainstream. And that's why we lack of these resources. And I think no one is perfectly sure how would you develop a simple application like a CRUD in a functional way. There are different ways, different things, but there's no one standard way just like it's established in the OOP world the way it is. So in my own capabilities, I try to address this thing. Yeah. Yeah, well, it's a great resource. So I think that is the perfect place to stop our recording. And after we stop the recording, we can continue our Q&A, but I want to thank you so much. This was wonderful. And so let's give him a big applause. Thank you. Thank you so much. Thank you.