 Thank you. I'm Vinicius Pacheco. I'm from Brazil. I have a funny accent. I'm based on Argentina. And I'm a senior software engineer at Eventbrite. And it's a very cool company. And without the support from this company, it's impossible to be here. I'm coming from Mendoza. It was 20 hours in flight. So Mendoza is in China. And please, a applause for this company. They are amazing. Thank you. If you don't know me, every time I gave normally, Star Wars talk. And today, it's not different. So after this moment, I can't hear you. Okay. Now, it's better. I released a book earlier this year in January. And the content of this talk, the subject of this talk, make part of my book. There's the link on my Twitter, too, if you want to buy. The ebook is very cheap. I think it's just 9 pounds, something like this. And let's start. Our agenda. What is CQRS? When can we apply this? Understanding CQRS, applying, there is a live code. And the common mistakes. When you see a new order on the screen, there is a live code. Okay. It's the rule. So what is CQRS? Someone here has been working with CQRS. Just to know. A couple of people. Someone know what is a QRS or listen to something about this pattern. Okay, great. So there's no doubt. Cuman, query, responsibility, segregation. It's what means CQRS. It was a pattern documented by Greg Young. And he told this about the pattern in 2010. Basically, where do you have just one object responsible to change things in the server and to retrieve data in the server, you will split this in two different segments that one will be responsible to write and another one responsible to read. So when can we use CQRS? There is a Chewbacca. I love Chewbacca. He's fine. So the normal architecture, thinking the normal application architecture. No, no, no. It's not this architecture. This one. There is a UI or API, a domain, a repository, a model that's responsible to connect with the DB and to write and to read stuff and could have a controller or something like this. It is our bootstrap application. So it's an instance of my bootstrap application and it's connected with my storage. And when I deliver a business to the internet, there is a word that's very dangerous to my business. This word is success. And why? With success, there are more customers, more clients, more people connected with me and now I have a problem. And why? My application has a limit and I will rent a new machine. Okay. It's great. And this process is repeated over and over and over again and I have a new instance and another instance and now I could figure out that my scalability is not more linear. My second instance could have a linear scalability like, okay, I have, I don't know, 10,000 requests per second and now I have 20,000 requests per second. But there is a moment that my scalability is not the same. I cannot scale 50% or it's just 10% for each new instance. And why? Because maybe your issue is not in your application but in the storage. And there is another instance that doesn't scale very well and now it's over. My storage starts to create too much latency or there are very, he's very responsible to do things that is not prepared to do. And my business is out. It's a sad day. So there is a first option to try to scale to solve my problem. And do you know what is this option? Someone knows? Someone? No? No? And master's slave. It is my first option. There's a slave, you know, like a slave from Java, the rut. And yeah, she's a slave. Yeah, okay. Master's slave. And there is my application. Now I have the master's slave and I'm just replicating the data from my master and my master is going to receive all the writing process and I'm going to replicate this to my slave that will be responsible to retrieve the data. But in fact, I'm not optimizing the data. I'm not optimizing the queries. I'm just replicating the data. And it's very hard to measure how many slaves I have. And when my problem is in the writing process, my problem is to write, it's very difficult to figure out how I could improve stuff on master. And it's not the solution for this specifically kind of issue. Okay. It's a good approach, but not the solution. And there is another stuff, event or consistency. If you don't have the good conscience that, okay, there's in my mind, I would like to use event or consistency. Okay, it's okay. Event or consistency is good sometimes. But if you don't have this in your mind that accidentally you are using event or consistency, it's an issue for you. Okay. And there is a second option. Do you know what is this option? Someone knows? Someone knows. Mind, remember like control. No. It's closed, but it's not command. Someone? Someone? No? Okay. It's cache. Because it's memory, you know, like my trick. So, yeah, bro, erase your mind. Like saying, yeah. It's great. So it's a good strategy. Now, I'm put a cache and it's real. Remove some have processes over my database. And it's okay. But I'm not optimizing the queries yet. And I'm optimizing that segment that normally is not so expensive than the right process. So read normally, usually, is easy than write things on DDB. And I'm trying to optimize my issue that's write and read, just optimizing the read process. Okay. And there is another stuff that's very hard. If you are old in IT, you know that there are two things that's very difficult. The first one is name it classes. And the second one is invalid cache. So, and now I have data synchronization. The first one is valid cache. Okay. So, it's a pleasure, but I can't hear you. Sorry. It's the year. When secure s is utile, when my start is a bottleneck, definitely you could use this pattern as a solution. When I have complex queries to my ORM and they could optimize these queries. And when they have a big number of users updating a small dataset and the data could be outdated. In fact, if you think on the Facebook feed or in the Instagram, every time you are consuming data, that is outdated. And why? Because when you are looking, someone updates the feed. So, it's a ventral consistency every time. It's not, okay, I have my consistency, it's very well, it's totally right. No, no, no, no, no. It's not true. It's not true. In fact, for business that a huge number of users are updating a small dataset or a small piece of code like a feed, you have ventral consistency every time. And for this, secure s is a good pattern. So, understanding secure s. Teach me, sad ray. I don't like the last two movies, but yeah, I prefer, Star Wars has just six movies. And the cartoons, I like the cartoons. Come back. Yeah. Oh, look, look, look, we will appear here. Yeah, you will see, you will see, you will see. Not boo yet. There is a good motivation. Crerostack in the common stack. Basically, the secure s is divided in two big pieces. The crerostack that's responsible to retrieve data and the command stack that's responsible to, to administrate my writing processes. Okay. The crerostack is simpler than the command stack. It's synchronized normally. And it presumes flat queries. Do you know what's a flat query? Someone don't know what's a flat query? Okay. A query could have joins. It's a simple explanation about flat queries. It's a poor explanation about flat queries. A flat query is every query that I'm going to optimize the data to reduce the number of joins that I'm going to do in my database. So, if I know which kind of data I'm going to retrieve, I will prepare this data to return with just one index or two index, but not doing joins and going to the deep level on my data. So, it's basically this. And the command stack is potentially a synchronous. Has a behavior centric. So, each command looks like a use case. And has an imperative fashion. So, it's not more just a post for my endpoint user. No, the endpoint is an imperative command like create user or update the user name or something like this. It's a command. And the command handlers just return success or failure. Like I accept your request, but I don't know what happened. I don't know what will be the result. And the command updates the own entity that make parts of the command stack. And going to dispatch events that there is an event component that will be responsible to update or to normalize the order DB or the order storage that responsible, that the responsible is the query stack. Synchronization. There are four ways to synchronize data using CQRS that's like by the book. So, the first one is the automatic update. The automatic update is like I receive a data from my put process, my pulse or put, my command. And now I go into send an event that is totally synchronous using RPC or binary communication or REST. It doesn't matter. But the component responsible to normalize the DBs will do this stuff instantaneously. So, there is the update possible. Update possible is the most common synchronization in CQRS. So, the command going to dispatch an event and the storage is information on a bus or on a broker or on a queue. And the component will be responsible to consume this event and normalize the DB on the query stack. But there is all the time of the word to do this. The third option is the control update. So, I go into update to normalize my DBs every two minutes is an example. There is a ground responsible to normalize the data. And the other option is the update on demand. So, when I receive a get to my query stack, the query stack is going to check, hey, I'm outdated. If I'm outdated, I'm going to say, hey, please, come on, give me the data. And they're going to be created a new event that the query stack is going to consume and write on the DB. So, queuing. It's a diagram that there are many, many diagrams about CQRS. And I like specifically this one. And why? Because it's like, if you follow this diagram, you could use all these synchronization styles, okay? And it's very flexible diagram. So, there is a client, you weigh API internet that's going to talk with my public-facing if we are thinking services. And my public-facing going to deliver a command. The command will encue the information and my domain layer gets the information and the domain knows what is necessary to do. And the command will update my normal ICB. That's my source of through. Normally, this one here is a C called DB. And going to dispatch an event, this event will be encue it. And a component, an event component will start to consume the skill and write this stuff in the normal ICB with time. Or I'm going to write this here directly, but normally with time, usually with time. And this normalize DB is very common to see no C calls here. Or document DBs. It's common. It's not mandatory, okay? But the main point is this command will create the flat query. So optimize the stuff here to be fine easily by this request. So, let's figure out something here. Applying CQRS, if there is a Yorda, there is a life code. So, all the code is on this link. Okay. There is a small project, a project using CQRS. It's just for the Python. You could download this and do some experiments. I'm using the framework in this example. Docker, Mongo, Postgrease, and ReptamiQL. So, it's the same diagram. But now I changed the names of the components to be clear what's going to happen in our service. It is a user service. Okay. So let's see how long time I have. I have time. So, my create user, it's the imperative command. And there is a convention that every event, we will name it in the past. So, user created. If I dispatch another event, you'll be in the past too. So, let's see. No. Let's come back. Now, the code. Let's figure out what we have here. There is my Docker compose. The code stack, the DB is a Mongo. A Mongo DB here. It's a Mongo DB. The command stack is a Postgrease. There is my command stack here. Okay. My Postgrease. And I'm using SQL to write a ReptamiQL. Okay. And my user service. The user services entities are the user model. Okay. And my permissions model. I could have two permissions. Admin or user. So, I'm going to do a post and I will write a new user and the permission that the users, this user have and is it. There is the order entities or structures that they're going to use in my Mongo DB. Okay. The service. I could write this in different models. Modules like domain module, repository module, this kind of things. But I wrote all the code in the same file to be easy to navigate. Okay. There is the framework and some configurations. But it's my API. Okay. My API. There is a reference to my query stack. And it is my post. My post is the first layer on my command stack. This post going to receive the data from my request. Validated for the payload. It's a valid payload. And prepared a cluster of RPC communication to do a sync RPC and to put this on my, on my queue. And my queue. And I create a location. And I go into this patch and 202 event with the location where will be the data. When the data obviously going to be consumed by my query stack. Okay. And my API that are an API to get all users paginated. And the user by ID. And the user by permission. So, I going to get, I want to get all the users that has the same permission. It could be a join on my DB because I have two different entities. But won't be. You'll be a flat query. So, there is my command stack. And inside my command stack, I put my user domain. It could be another module. Domain. But now it's there. So, my command stack, I have a, it's just to use the framework. It's a dispatcher. An instance of event dispatcher. And an instant of the DB. Now, I create my entity. I commit this. And a dispatcher event. That's user created. With the data. And I will dispatch another event to create the relationship between permissions and users. That is my permission user related. Okay. Could be a broker. So, I could have two different event components. List them the same event using a broker. But I'm dispatching two events. Just to be easy to look what happened. And there is my event component. So, look at this. The user queue, the domain, your dispatch user created. And now I go into show the component. The component going to list them the user created event. And the get this stuff, create the data and normalize the data on my MongoDB. The other stuff is I going to get my permissions user related. And create a new structure. Look if my permission was created or not. If not, I go into create one. If it was created, I will just append this user structure on the permission that's existing on my DB. So, in this event, on this event, I'm optimizing the data. And why? Because I removed the possibility to use joins. Because all my data was prepared to be retrieved with just one ID. That is the admin ID. Or the user, the permission ID, sorry. And now the query stack. The query stack, there are just end points using RPC to communicate with my API. The first end point gets the information from the MongoDB. The second end point gets paginated information about users. And my get user permissions by permissions is exactly that going to find on the flat query. And if you take a look, is the same query, the same style of query that I'm using to get a user by ID. So it's very easy. It's not expensive this search through my database. So let's see if my containers are not running. Oh, it's fine. And let's start to consume to send the data. So first, I go into get the info. There's nothing. No users. And now, I go into insert the first user. That's me. It's just a simple test. And this user is another main. Okay. Sent it. There is, he was accepted. Okay. I don't know what happened. And there is a location with my data. Okay. And now, if I find here, there is my user. Okay. I go into create another two users. The other one is Vinicius. That's me again. And it's another main. Was accepted. And now, I go into create the Vinicius. But now, as a user, I don't remember if Vinicius was accepted. Let's see this was too fast to me. No, it's was not the last. Now, so if I find here, there are three users. Admin, admin and user. But I have the user description, but not the description user. So now, I go into find just my users that the permission is admin. And there is my query using CQRS. So my data was moved to my query stack. And now, there is the admin permission with the description. And all the users that are an admin. And then the query, there is no joins. It's a flat query. So now, I go into find my user. And there is the other user. That's just a user. The usability is the same as the normal application. So to my user, it's not so different. And if you look at this, okay, it's the same that I have been using in my life. But the main point is now, let's come back to this. If my normalize the B, fall on down, it's broken for some motivation or lock it, it's broken for some reason. I don't stop at my query stack. And my users will consume the data. And if my query stack is over, I could write in stuff. Obviously, the issue is it's just a user service. It's not so critical. But thinking due payment. You could receive a payment, but not retrieving the report about the payment. But you are selling stuff yet. It's important, I think so. And once in another job that I have, the disk of the normalize the B broke. And we maintained the application running. It was like a monkey test. We maintained the application running because all the writing process kept stopped on the queue. And it was a storage in the queue. When we restarted the B using the slave, we could reproduce all the stuff on the the B. And we don't lost the data. And we don't lose the data. We don't lose the data. But it was just a moment that the normalize the B doesn't receive the data. And it is amazing. It's very scalable and maintainable and obviously make your application stable. So, and it's simple. Simple. It's not so hard. So, common mistakes. And for common mistakes, there is a Jar Jar Binks. It's a common mistake. Jar Jar Binks is a common mistake. Okay. Yeah, Jar Jar Binks, thank you. So, but it's not the guy in the new movie. I don't know why Benicio del Toro did the last Star Wars was terrible. Rose character. Rose and Jar Jar Binks. I don't know. I don't know why Benicio del Toro did the last Star Wars was terrible. Rose character. Rose and Jar Jar Binks. I don't know. Jar Binks eat some insects. I don't know. Some bugs. So, CQRS and event sourcing must be applied together. It's not true. It's a common mistake. There is an example that I'm just using CQRS. They have different proposals and they work very well together like Han Solo and Chewbacca. But they have different proposals. One is to improve performance and scalability and stability. And another one is to create a streaming history about your data. So, if you're using event sourcing, you could reproduce the data in a moment of the time and to know what happened. So, CQRS going to improve your stability and performance and make a better application for you. So, CQRS requires eventual consistency. Eventual consistency is the most common usage. It's the most common scenario in CQRS. But if you try to use the first option of synchronization that I shown, it's not eventual consistency. It's not totally eventual consistency. Try to be fast. But it's not mandatory. Eventual consistency in CQRS. CQRS depends on queues and message brokers. It's a good practice, but not mandatory. So, you could use CQRS trying to trigger at some events or using logs from your data like MySQL logs or something like this. There are many stages that you could use. I like to use queues and message brokers because I think that's easy to create an intervention or to monitor it. CQRS is easy. It's not easy. And why? There are more things to monitor. There are 2DBS to take care. There are many stuff in your stack that isn't in a normal application, in the normal architecture that we look at early. So, CQRS is not easy to implement, but not so complex as we think. You know, if go the tools, you could have a good implementation. CQRS is architecture. No, it's not architecture. It's a pattern inside your architecture. So, it's a good pattern that is cross platform. It's not for Java or Python or for Go or doesn't matter. It's for everyone could apply CQRS as a pattern. It's not an architecture. And my English teacher told me she's from Dublin and told me that it's very funny. I don't know. CQRS is the best thing since the slice of bread. And she told me, oh, it's so funny. This is slice of bread. So, Sarah, thank you by the English class. I'm bad. And again, there's my book. If you would like to learn something more than CQRS or other patterns, there is an interesting pattern that I documented that the caching first is interesting and another pattern is internal for service and communication patterns. It's very steeper than lunch here and the dinner. So, they book, obviously. And there's a link. Please give milk for my kids. I don't have kids, but yeah, my cats. And may the CQRS be with you. And, okay. Thank you. So, any questions? Please come up here. So, I have a question. Okay. Yeah. So, I have a question. I came in slightly late, so I probably missed it, which is my bad. I'm sorry. And maybe missed the very introduction. And also it's quite new to me. So, I'd like to clarify my understanding. So, what I glean from is that you use two databases. You have your normal normalised database, which is your canonicalised data store and you have an unnormalised database, which is specifically optimised for the queries that you need. So, the straight queries can go to the denormalised database and that provides the primary advantage of the pattern you are advocating. Did I get that right? If I understand your question, yes. My idea is create the CQRS stack responsible just to retrieve the data. So, should be the most optimised as possible. And you could apply cache and all the stuff over this stack. I don't apply to make the example because I would like to make it simple to see. But you could take care of this CQRS stack, this CQRS DB, like all the orders DB, but all the source of through the DB. But the main idea is optimise this segment of your stack as possible. And does this mean the way you have schema changes, you have to apply migrations to, or you have to apply migrations to both databases, where you have new queries, you have to generate a whole new set of data into your second database. Sure. My entities are different on both the Bs. So, my entities, my migrations, it's another stuff, okay? I'm doing this. Some people just try to reflect the same entities. But it's like presuming flat queries is not mandatory to use flat queries. If you try to use flat queries, it's, I see that you should, maybe you should create a new entities, specifically for the CQRS stack. It was a really interesting talk and I enjoyed it and learned from it. Thank you. Okay. I basically went for the same. So, when you are going into the right part that you need to scale and you say it in the start of the talk, how are you actually going to scale? So, you are going to have different great instances with different great databases with different schemas or how is the approach for that? For the command part. To the command part, the main idea is command normally is thinking, I will use a practical example. MongoDB in the version two. To put something in MongoDB in the version two, block the read. Okay. In the version two. Not more in the version three. But maybe for your business, it's interesting to use the Mongo engine. So, using CQRS, you could totally divide this. The simple separation of stacks improves performance because now the writing process want to lock the credit process. The scalability using master's lives and different instances and this kind of things is practically the same. The main goal of the pattern is segregated responsibilities to make this more resilient and improve performance to don't make that one operation lock the other. It's the main idea. But the instance control of the bees and this kind of stuff is the same approach. So, the right improvement. So, how are you actually going to scale the right part? That's what I mean. So, you are going to queue and you want to deal with the queue that if it's delayed, the queue will be taking or? You could apply charging as an example that will be very optimized and it's not so optimized in some engines for CQRS stack. Because what happened with some engines using charging for DB? You have an instance that's responsible to administrate all the other DBs that comes, is going to write because that's more idle will get the request and write on DB. But to find maybe it's not so interesting because you're going to receive the request by the same charging and that should find in various the data why all this data was not propagated for all the charging. And in using CQRS, it's not an issue. And why? Because you are not interesting to use this collected data from the charging because the charging is just a source of true. It's improved performance on the writing segment. And your data is streamed on the Kafka or Web to MQ or Active MQ, and it was right in the CQRS stack that's responsible to retrieve the data. So that could have another approach to scaleability different than charging. And it's just an example about, oh, you could use charging, you could use master slave decide, you could use all the stuff that is fast to read but it's slowly to get data. And this kind of approach is not more an issue for your business requires to retrieve too much search. Okay. Thank you. Hi. When you were talking about the different strategies to synchronize the two stacks, you talked about the synchronize, the event basis, that it's the one that you explained and then you talk about the, if I understand good, the query stack ask for an update when he knows that it's outdated, it's how he knows that it's outdated. There are some approach to use this. It's the more harder to apply. It's the hard way to apply. And it's very, usually the people create like a semaphore in the streaming too, like on the streaming, you put the semaphore in the Kafka and okay, I'm very outdated from this because the data stream it's there or it's full and I'm going to get the information from the common stack. And there are the logs of the DB that you could consume in this and the check. Okay. My DB logs are very full. I don't, I move in DB logs from different segments of your server and okay, there is, it's full of logs and I should consume these logs to create my query, to improve my query stack. There are two different approach. One is that's more common. Okay. Once it's looking the bus and to see if there is a sign out to consume the data. And another one is looking the DB logs that it was, you reserve the specific part. And a very common approach is using like a JVM separation that's the Eden and the old part of DB logs. And when you consume the data, you move the Eden to the old part of the logs. And if the Eden is full, it's time to get the data again. And the logs is optimized to use to element, to bring the sufficient information to register on the query stack. Was clear or was, yeah, we could talk, it's hard, we could talk and more common. You'll be interesting. More questions? Okay. Thanks for the talk. I really enjoyed it. It seems to me that when writing to say the local flat database or the MongoDB, whatever it is, your data predominantly comes from the events, at least in this example. However, when you start a new application running, a new service, presumably in other scenarios, you need to be able to read the data from the relational database that stores the chronicle representation. And it seems to me that there's some complexity there in the sense that you need to be able to write to the local database using two different sources of information. You need to be able to have the logic to do the right space on events or do the right space on the relational database. I was wondering if you find that's a problem for you or how you manage that complexity or those two different kind of pieces of logic in your implementations? Yes. It's one of the drawbacks using CQRS. Mainly, if you want to create specialized queries, if you just want to replicate and segregate the search and the find and the right process, it's okay. It's not a consequence. But if you want to create flat queries, it will be a consequence. You will have the two different... I'm going to show you something here. If you look, my model, specifically for this business, I'm using an user and there is the... it's my postgres, okay, two tables. And there is a document for the user that's going to get the user information, just user. And I create a struct to create a meta document here. So I have different entities and I have different logics and it will be a normal scenario inside CQRS if you try to create flat queries. The mistake that you should take care of is don't split the domain rules between the event component and the domain. So it's a normal mistake. Here on my domain, I prepare the data to be consumed by my event component, okay, all the data. I'm dispatching two events. That's not a good practice, but I'm dispatching just to show the stuff. But it's very common to see something like this. Oh, I would like to create a relationship between permissions and users. And I don't want to have both entities being consumed in the same domain. So it's like consumed two repositories in the same domain. And the people move the second part to here. And it's a real mistake because you start to split the domain. And it's a mistake. But two different entities, two different logics, one specialized to write and another one specialized to read is exactly what CQRS means. Okay. Thank you again. And so enjoy the lunch. Thank you. I'm able to answer you. Thank you.