 great to be here. So I'm Piotr Sonica. My name is SoRid because I come from Kraków. It's a beautiful city in Poland. If you've never been to Poland, it's really beautiful. So I invite you to come. We have some Ruby conferences as well. We have also beautiful mountains. So it's a really nice country. So really quickly about me. I'm a Ruby developer. You can find some of my open source projects on GitHub and follow me on Twitter. I'm Solnik everywhere. So if you wanted to say you had one job, I actually don't. I have three. So I'm part of a company called Powow. It's a Polish-Norwegian consultancy. I'm also working for Gitorius, which is a githosting platform that you can host yourself. And by the way, we're moving to Docker. It's like 80% done. I'm also working for an origin company called Evo, which is a chain of fitness clubs with a huge infrastructure built in Rails. So before I start, I wanted to talk a little bit about my experience as a Ruby developer so that you can know where I'm coming from with all this stuff. So I started working as a Ruby developer seven years ago. And in 2007, we were mostly working on startups. So every project was green field. Everything was really great. We were using Rails. We were writing a lot of Ruby code. And everything was smooth and just beautiful. But at some point, some of those startups actually succeeded. So suddenly, we started working on huge a couple of years old Rails apps. And at some point, it became a problem, right? It started to be really difficult to maintain those projects. And I started to think, why is it so hard to maintain a big Rails application, right? What's the cause of this problem? And initially, I thought that, yeah, maybe we could use different patterns. Maybe we could just use different libraries. But really, what we've been doing for the last couple of years seems to me like not solving the problem but working around the problems that we have. And what I realized is that the cause of this problem is just complexity that we have. And all the tools that we are using are extremely convenient so that we can move really fast. But we don't think about the complexity that we pull in when we start depending on external gems. So when we create a new Rails project, even if we don't include any additional gems, it's already a lot of complexity that we have without even writing any code. So then, we start to actually write some code so we build even more complexity on top of already existing complexity, right? So it's something we don't think about on a daily basis. So today, I want to talk about convenience versus simplicity. And even though the title of the stock may seem to be a little bit abstract, I actually try to make it more concrete. However, I'm going to start by some, by explaining some of those abstract terms. So convenience. When you look at the definition in dictionary, it says that convenience is the state of being able to proceed with something without difficulty, right? And when you think about it, it's exactly what happens when we use convenient tools like Rails. And if you remember this one, this is from a screen password, DHH showed how to build a block application in Rails in 15 minutes. It's pretty famous, you probably saw it. So this is it. This is the convenience. All the things that we're not doing, all the things we're not thinking about, we're just proceeding really quickly with our tasks, we're accomplishing our goals really quickly without thinking much about the problems that we're actually dealing with because a lot of those problems are solved by the libraries and frameworks that we are using. So on the other hand, we have simplicity. And again, when you look at the definition, it says simplicity is the quality or condition of being easy to understand or do. And it's a little bit tricky because we often say that something is convenient and like immediately connected with something that's simple. And it might be a little bit confusing because you see something that is simple, you think, okay, that's convenient, that's simple, I can simply just use it and it works. But you don't really think about what's inside, right? So what usually happens is that a lot of libraries and frameworks that are super convenient and really simple to use come with a lot of internal complexity, something that we just don't think about because we don't see it. So it's not our problem, right? So when it comes to complexity and ways of dealing with the problem of complexity, what programmers usually do is to focus on separation of concerns. If we have a huge problem, which is really difficult to solve, we try to like split it into smaller pieces, into smaller problems and solve them individually. And what I've noticed in the Ruby ecosystem that is probably inspired by Rails, we often focus on convenience first. We often focus on all the fancy DSLs and the convenience that should come right from the start. So when you look at, for example, active record, it's a great example of a convenient library. A library that solves a lot of different problems, problems that are really hard to solve, by the way. So when you look at a basic model, a basic active record model, it's just an empty class, right? And you might think that it's super simple, right? Because it's just a class. And you don't even have to write anything except defining the class to get a lot of functionality for free. If you want to create something and persist it in the database, it's also very simple. Just one method called passing params and you're done. Even if you want to do something more fancy, like find something, fetch something from the database, load it into memory and then do something with it and save it back to the database, it's still super simple. We just call like three methods here, right? So you might think it's also simple. I don't need to learn a lot. I'm just reading API documentation for like three minutes and I know what to do. So you think, yeah, that's simple. And really, I don't think it's simple. And the reason why it's not simple is that there are a lot of things going on under the hood and even though I don't see them, they do exist. And that's why I prefer to use the word convenient because it is also very convenient, but it is not simple. There's no simplicity here. There's a lot of internal complexity. It's just we don't see it. When it comes to separation of concerns, if we look at this create method and think about what's actually going on, we will realize that we are dealing with things like data coercion, which is a huge problem to solve by the way. There are a lot of really nasty things that you need to deal with when you want to have coercion. Setting default values, this is also something that happens under the hood. You might not think about it, but it exists. We do things like validation. And validation is also a really big problem to solve. And eventually, we do interact with the database. And interacting with the database is also a huge problem to solve. And this is like the basic stuff that happens under the hood. And if you're less lucky, you could have things like business logic hidden in life cycle hooks. All the before say, before validate, all this stuff, this is super complicated. And we do that. We also do things like handling nested data structure using accept nested attributes for, which is also super complicated thing to deal with. We also do things like data normalization through custom attribute writers and plenty of other stuff. So this is a lot of complexity. And we tend to hide it in one place, but it's just not a good thing to do. So when we want to talk about separation of concerns in this context, we might look at it in a way where we can use separate objects to handle separate concerns. So what I tend to do these days is to process parameters using a separate object, validate things using a separate object, and handle persistence by separate object as well. And whenever we talk about separating concerns, and whenever we talk about using separate objects, there's always at least one person who would say something like, well, that's more complicated. I used to have one object, now I have three. And I don't think it's a good way of thinking about it because separating concerns is actually something that leads to simplicity. Even though you have more objects, you still have better encapsulation, and those objects are smaller, and it's just easier to work with them. And one of the benefits that we have here is that we can always come up with a higher level abstraction, something that is more convenient than just encapsulate it and have just one method. And we have exactly the same convenience, but internally it is separated. Internally we have separate objects handling separate concerns. So this is like the benefit of separating concerns where you don't necessarily have to be concerned about many things. You can have a system that is built on top of more primitive tools, but it could expose a very convenient interface. But once some of those concerns become your problem, once something is your concern, for example, when you actually want to deal with coercion on your own or validation on your own, you always have a way of using a separate object, whereas in case of libraries like ActiveRecord or many other gems written in Ruby, where a lot of things are handled by just one thing, you just don't have that choice, because there are no separate objects that handle separate things. So you just cannot use them separately. So the next thing is data and behavior. This is also an interesting subject, because Ruby is an object-oriented language, obviously. So whenever we talk about object-oriented design, we like to say things like, yeah, it's all about objects and sending messages, right? Or behavior. And I think that this whole movement with design-driven development, we had a talk yesterday about it, it is a nice way of thinking about software, but quite often it actually leads to something that we could call accidental complexity. We may quite often introduce complexity that is not really needed, just because it feels like good to think about objects and the way they correspond to some real-world concepts. Like, for example, if we have an application, some kind of a system running, and it has users, right? So it's like natural for us to think about having a user object, because, well, it will represent a user of our system. So it feels like natural to design our system like that. But when we do this and when we focus on behavior so much, we may often use objects that are simply to be. And it's also really something really popular to do in Ruby, and especially in Rails, to use Active Record for everything. And as I said, if we have a user instance, and we have users in the real world, and we want to have something like displaying full name, it feels natural to just add a method called full name, because, well, our users know their full names, so our object should know its full name, right? So we do that, but we don't think about what's the actual requirement. And if our feature is to, I don't know, display a list of users with their full names in some kind of user interface, then the only thing that we need is the data and something really simple that knows how to display a full name, or how to return a full name, right? So what we do here is that we already have an object, we already have a model, and it represents users, so it's just convenient to just put methods there, just expand its behavior, because it feels natural. But what I'm usually doing these days is to just focus on the most basic stuff, on what's really, really needed for the system in order to work. So the data is really important. All we need is to just get the data and have some kind of an object that returns a full name. So it is like the essential part here to have just those two things in order to accomplish our task. This is obviously a very simple example, but it illustrates the philosophy here. And, you know, using this object is still very simple. So this is pretty much what convenience is. This is like some kind of a crappy coffee maker, but it's convenient, right? You just press a button and there goes coffee. But what I really prefer is this. This is V60. I had coffee here from V60. It was awesome. This is super, super simple, very basic tool, and it makes an awesome coffee. And this is pretty much the essential stuff. You focus on what's really, really important and you reject everything else. I would even say that sometimes it makes sense to be minimalistic. When you are minimalistic, you're just reducing complexity and you're just using just the thing that you need. Nothing else. So another interesting thing about data and behavior is immutability, which is also a little bit weird since Ruby, again, it's an object oriented language, so we are used to relying on mutable state. However, immutability is really something that can bite you and be very problematic. And here's a very simple example. So we have our presenter object. It receives some data hash. And the fact that this data hash can be changed by something else, something external, it can actually cause our presenter instance to just be broken. And this is absolutely terrible. It's just such a basic thing that we do and it can break our code. What's the point of doing that? So really, when it comes to immutability, when we're dealing with the data, I would really encourage you to just think about making the data structures immutable. In Ruby, we do that using freeze, right? Unfortunately, if we have nested data structures like this data hash, we might want to use some external tools like Ice9, which is a gem that gives you this crazy method called deep freeze, which will actually take this hash and freeze everything deeply. So if you try to change it in place, like mutated in place, it will raise runtime error, right? This is a little bit crazy, obviously, in Ruby. And it's slow. And it's actually really slow. But for the data structures, I'm actually using it. And it actually makes my code much more simpler. And I feel more confident when I'm relying on data structures that don't change. Another interesting gem that you could use when it comes to immutability is adamantium, which is even more crazy. It is a gem that makes your objects immutable, also by deep freezing them. So when it comes to freezing data structures, it's one thing. But when it comes to freezing all your objects, it's a completely different story. So I actually started using adamantium a couple of years ago. Initially, when we were working on Datamapper 2, which is now called ROM, we started with a very clear separation where we have commands and you have query methods. And it worked great. But then DanCop, maintainer of Datamapper and also the developer in ROM suggested that maybe we should try to make it more hardcore and actually start to use immutable objects all the time. So he created adamantium to enforce this style. I got really intrigued by that and I thought, well, this is a little bit crazy, but I'm going to try, right? So I started doing that and really it was tough. It took me a few months to just wrap my head around this concept and just change my style of writing code so that I will be creating objects that one has to change. And initially I hated it, but I really had this feeling that it will pay off. Like, at some point I will get it and it will be beneficial. And it actually started to make sense at some point. And after a few months, I noticed that my code is now way more simpler and I'm actually way more confident with everything that I do because I don't have mutable state. So adamantium works more or less like that. So if you have a class and you include adamantium, then you won't be able to change anything inside this object, the instance of this class. No matter how deeply you will go, how deep you will go, it will raise an error, but it's super slow. It's extremely, extremely slow. So under the hood it's using the Ice9 Jam that I showed you before. But I would actually like to encourage you to just play with it as an exercise and see how far can you go with it. It's a mind shift, but I think that it's actually worth the effort because it might change the way you think about writing code. It worked really great for me. I'm still using adamantium in some of my open source libraries and in some places in my projects for my clients. However, it is slow. So whenever I see that it slows down, thinks too much, I would just drop it. But the trick is that after a few months of writing code in this style, I actually so got used to it that I'm currently, I'm just unable to design something when objects are mutable. My brain no longer works like that. I just create objects and they won't change. They don't expose an interface where you can mutate them. I just mind shift, seriously. So this is something that is also related to convenience and simplicity because mutable state is actually convenient because you don't have to think about, like, you don't have to make many decisions up front. You just create some objects and then later on in runtime, they may or may not change depending on the context. Maybe I will have to do something extra to set some instance variable or not. It's just more convenient. Whereas objects that cannot change are less convenient, but you actually achieve simplicity in your code. So it is worth the effort. I highly recommend that. So next part is about relational model. This is a huge subject. When we think about, when we talk about relational model, we usually think about relational databases. And the trick here is that it's not really about the databases. It's not really about SQL because relational model is actually something that we can use to structure our data. And recently I read a paper called out of the tar pit, which is, which talks about dealing with complexity. And one of the biggest parts of this paper is about relational model and how it can simplify our systems. So the definition that they have is that the relational model has, despite its origins, nothing intrinsically to do with databases. Rather, it is an elegant approach to structuring data and means for manipulating such data and a mechanism for maintaining integrity and consistency of state. So when we talk about relational model, we actually talk about how we structure our data, how our data should look like in our system. We're not talking about how it's going to look like in the database. It's a separate concern. And also it gives us a way to deal with the data in a structured manner. So when it comes to Ruby and relational model, we actually have some pretty awesome libraries. So if we want to use relational model in Ruby, for example, we have a library called axiom. This is like the foundation for Ruby object mapper. And this library gives us an implementation of relational algebra. And with axiom, you can define relations. And as Luca said yesterday during his talk, relations are just sets with tuples and nothing else. It's a really, really simple concept. And when we want to define a structure of a relation, we simply define its header. And a header just defines what attributes a relation has and what data types we use. So then we have an interface for a manipulation. So for example, if we have relations, users, and tasks, we can simply insert data into those relations. And by the way, this is immutable. So users.insert returns a new instance of user relations. So the previous one is not being changed. Then we can use relational operations in order to create other relations. So we have things like join, rename, restrict, project, all this stuff is there. And then we can simply access data. So this is a really simple concept. You just have a set of tuples, nothing else, and a bunch of methods that you can use in order to manipulate the data and access the data. One of the interesting things is that you can actually do some crazy stuff like join to relations and then insert data into those relations. And axiom will actually distribute, if you are using an SQL database and you have two tables, it will actually distribute the rights to the insert methods, sorry, insert statements into separate tables. So this is pretty cool. And it's because there is this concept of data independence in relational model, and which says that it is a clear separation that is enforced between the logical data and its physical representation. So this is pretty much what Ruby object mapper is doing. We have a logical structure of our relations that we define in our application level. And the way it is actually starting the database is something completely different handled by a separate layer. Axiom handles that by using adapters for databases. So a really huge concept that we are experimenting with is using relations as first class citizens. It is an interesting concept. And what we usually do these days in Ruby, at least, is that most of the ORMs are using active record pattern. So the first class citizen in our system is a model. It is a class that gives us a query interface. So we have this model and we run some queries to get the data. And even though, for example, here we have a scope called active, so if we use the query interface of active record, we do get a relation back. Although the relation is not the first class citizen in our system, the model is and the instances of this model also work as the first class citizen in our system. So the major difference in philosophy here is that we would like to put relations in front. And when I say relations, I simply mean the data, right? Because relations is just data. So the basic implementation would be to have a relation registry where internally we define relations that we need in order to build other relations that we will expose publicly for our application. So we don't think about running queries in our application. We're thinking about the data. We're thinking about what data do we need and how it is being fetched from the database. It's just completely, completely separate concern. So here we just create a relation registry and we have access to active users. And active users is a relation that is the first class citizen in our system and it's just data. So the reason why this concept is, at least should be, better is that we achieve better composability and better encapsulation. And by composability, I mean if we're using relations and just relations, we can combine them, compose them to create other relations. And the order in which we are doing that is just not important. And not relying on order is one of the things that we should do in order to reduce complexity. And another thing is encapsulation. When we are using relations, we're talking about the data. We're talking about what data we need. We're not talking about how we fetch the data. So that's a huge difference. So if we take a look at an example where we want to find all the users without tasks. So we have users and they have tasks. We want to find all the users with no tasks. So in active record, we would like to use join, but this won't work because this produces an inner join. So what we need to do is to just use an SQL, a partial SQL, and use a left outer join. Yesterday we saw we can do this with Arial, with an object oriented interface. But still, we are talking about running a query here. We are talking about details like what kind of a join we should use, what kind of keys we are using in the on clause, and all this stuff that is just specific for a database. And my experience is that when I'm working on a bigger project where I have a lot of methods that return query objects, or scopes, we call them scopes, I simply lose confidence pretty quickly. I had many times I had a situation where it turned out at some point that all the crazy chaining that we did in some place of our system actually returns wrong data, which sometimes is not a big deal, but sometimes it can be a pretty huge bug. Since we are exposing data that are, for example, that should be, for example, hidden. So it's a big problem. And when it comes to relations as first class citizen, the concept here is that we are not composing queries, we're composing relations. And I know that it might sound a little bit confusing for you, since, as I said, active record query methods return relations as well. But we are still thinking in terms of queries, not in terms of relations. And the difference is that when we combine relations, we use relational algebra to do that. So we use relational operators to do things. And it is, again, it is like basic set theory. We're just using basic operations on set that has some tuples. And that's it. So if you want to achieve the same thing, find all the users without tasks, we're just using the difference operator. Or something that even looks nicer, just alias, which is a minus. So we say all the users minus the ones with tasks, which obviously gives us users without tasks. And the trick here is that all the relations, if we are using an SQL database, we can translate all the relations into an SQL query. Currently, the SQL generator in Axiom can do pretty much everything, although performance is obviously a problem. So we're now working on an optimizer that would make sure that we are running queries that are efficient. So all those ideas, we're trying to incorporate them within this project called Ruby ObjectMapper. I mentioned it before. It started as the second version of DataMapper project, but eventually we realized that it's just something completely new. So we decided to create a new project, give it a new name. And also initially, we thought that we're going to implement the DataMapper pattern as described by Martin Fowler. However, recently, we started thinking about doing some things differently, like using relations as the first class citizen. So the major focus in the project is to focus on relations, which means to focus on just the data. This is our primary concern right now to create an interface that gives you access to the data, which is as simple as possible, so that working with the data is just trivial. And we also want to really achieve clear separation between the database structure and your logical structure that you have in your system. And another big part of Ruby ObjectMapper is mapping to objects, which is like one of the core parts of the DataMapper pattern. So we have data in the database, and then you want to map the data to some objects. So initially, we thought that this is a huge thing in the project. But to be honest, right now, we're thinking that, yes, sometimes we might want to map things to something more sophisticated. But in many cases, we can just use the data tools, and that's it. So the next part is just simplicity. We're trying to narrow down the interfaces as much as possible. We want to have just one way of doing things, which is a little bit against the Ruby philosophy, but we just disagree with that. So we're trying to have, for example, for things like creating data, we just want to have one interface. We don't want to introduce many interfaces just because we want to have some optimization for a database, right? Like in ActiveRecord, you have methods like update attribute, update attributes, and other things that are there just because you sometimes want to use them because of performance, right? So we're trying to avoid that, and we're trying to move the optimization to a separate layer where an efficient SQL query will be generated. So when it comes to defining logical schema in Ruby ObjectMapper, this is pretty much a DSL on top of Axiom, which is also following the philosophy where we're focusing on building small tools that are then used by some higher level tools that are just a simple wrappers that simply expose a DSL that is convenient, right? However, ROM itself is pretty that simple internally. So in ROM, you can define relations in a pretty similar way as you do with Axiom. And one of the ideas that we have right now is to have ability to define which relations will be private, which means that they won't be accessible within your app. They are only there in order to create other relations that you will expose for your app, which we believe should give better encapsulation. So if you want to define external relations or public relations, you can just define them like that without passing the internal true argument. And you have access to all the relations that you define before, and you can just combine them however you want using relational algebra operators. And then ROM will simply expose everything that you defined. So in your app, you won't be creating queries. You won't be writing things that are tightly coupled to the structure of your database. You will be simply accessing the data. And important part here is that relations should be context aware, which means that here we have a user's task relation, which returns all the tasks for a particular user. So our context here is that we need the user ID. So this is one of the requirements. And it will work like that. So you will simply pass in the user ID, and you will get the data back. So this is the major difference because what we usually do is that this part here inside this blog, this is what we would usually write inside our application, like in a controller or somewhere else. It's available, so we do that, even though the best practice is to use scopes, etc. But the truth is, if something is available, then you're going to use it, right? Because it's simple, it's convenient, so you're going to just write it without thinking too much about it. So this is like the major difference here. So the next big part is mapping data to objects. But as I said, we're kind of changing our minds. And right now we're thinking that mapping is not such a big, such an important feature. But it can be helpful, it can be just handy. So we have something like a mapping, which is a way of defining how you want to map relations to some other objects. So ROM will create entity classes for you, and it will just create a way of instantiating those entity classes using the data from relations. So this is an example of a basic attribute mapping, so it would generate a task entity. It will return entities, like instances of this entity class, by using the attributes, right? We also support something like using embedded values. So you will be able to create aggregates. So here we would have a task entity that has a title, and it also has a user instance. And it will automatically generate those classes for you. And yeah, one thing that I forgot to mention is that in data mapping pattern, you can't really have dynamic things. So in active record, you do things like user first and then, I don't know, dot tasks, right? Here you have to define it upfront, because once you start accessing the data, it already needs to know what will be instantiated. And once it's instantiated, it doesn't have access to persistence layer, because it's separated. So that's like a major difference between active record and data map approach. Yeah, so the last part is just simplicity. Even though the whole ROM project is, it is complicated, because it's a lot of different problems. However, we are trying to solve them using separate libraries. So we have Axiom, we have Optimizer, we have Morpher for mapping. All this stuff is there so that ROM will simply use those tools and just expose DSL on top of those tools. So the focus is on simplicity, even though we have many, many libraries involved, we are still trying to achieve a very consistent interface, so that it will be just simple to use. So to wrap this up, ROM will give you a way of accessing the data. You won't be thinking in terms of relation, sorry, in terms of queries, you won't be thinking about your database columns, whatever, you will be just accessing relations and you will define those relations inside your logical schema definition. It will give you a simple way of mapping the data to some other objects if you want that. However, we think that in many cases you will be happy with just the data. We will also want to have a simple interface for inserting data. So there's no point in creating, I don't know, a user instance in order to save its data. Using a data hash is all you need. And we also want to support something like using the relations that you defined to manipulate them. So you can, for example, join many relations as a context for persisting an asset data structure and the system will distribute the individual operations to separate tables for you. Yeah, so embrace simplicity and convenience can come later. You can always look at things later and see how we can simplify stuff from the point of view of a user that is using your interfaces. I don't think that focusing on convenience so much right from the start is a good strategy. Yeah, and that's it. Thank you. Thanks, Peter. Any questions for him? One question. I've been walking around and asking different companies and developers about how far they go with the approach you described. And most of them are pretty happy with an active record. And they are maybe using additional use cases player, but for all the stuff they are happy. And do you have examples of maybe you have your own experience when you should go that far with operational concerns when you develop applications? I haven't written any application which would fully be based on those concepts. I'm using some of those concepts in some places in my applications. I'm really happy with those. Martin, one of the guys from the team is right now working on an application where he's using all this stuff. He implemented most of it already in a separate project. We're now collaborating together to get all this stuff into Ruby ObjectMapper. And he's extremely happy with this approach. He's been working on this application for a few months already. It's a lot of code already. And he's really confident that this approach really leads to just simplicity. But yeah, as you said, many people are happy with active record. Many people are happy with the way Rails works. I'm not questioning that Rails works for me in a lot of cases. I'm still happy using Rails. Something that I recently started doing was that I switched your SQL without using its model layer. I'm just using its query interface. And I'm doing something like I showed you in the slides. And I found it to be really great. I'm just focusing on the essential stuff. I'm just rejecting everything else. It feels good, but it's more work. It's just more work because I need to write more code. But still, sometimes it makes sense. Sometimes it doesn't, right? Depending on your context. But overall, I'm pretty confident that if your system is growing, then eventually you will appreciate an approach where you're just focusing on simplicity and less inconvenience. Okay, thank you. And do you think it makes more sense when you're starting to write a new application to start with your approach or it's okay to start with regular Rails way and then trying to switch, trying to reflect on it? I think that depends, right? If you're working on your own product and you got like better funding than you, then you can do whatever you want and it will probably be great. But usually you don't have this situation. So right now I would just leverage the power of the tools that I have and worry about things later. Yeah. Yeah, right now we just don't have the tools that I described today. They are not as mature as Rails and its ecosystem. It's just not there yet and it's going to take years to get there. So yeah, it's pretty, pretty much experimental stuff. So building things on top of experimental software is obviously pricey. So yeah. Okay, thank you. And the last question about the domain term. Harry tried to use it while he developed and then turned it off when you published the game? Jam or? No, no. No, I haven't. In some of my projects I just use it. Nobody complained. But I know that Marcus, another guy from the team, he had that use case. He used Adamantium in his project and then he had to turn it off because it was too slow. So the slowness you told about the it is gone after you turned it off. Yeah? Yeah, okay. Because you're not freezing everything deeply. Just a quick question. How do you handle validations like if you're just in general with the scheme? Yeah, I'm having something like a validator object. I'm currently, I'm just using the active model stuff because that's that's the most powerful thing that exists right now. One of one of the team members are I think he's still working on a library called Vanguard, which is like a library dedicated for validations that is completely separated from everything. But there are still some interesting problems to solve like, you know, if your validation procedure requires a database connection and what do you do and things like that. But yeah, in general I'm trying to use database constraints for certain things and rely on that. Right now Martin is using the other guy. Right now he's using an approach where he's just relying on constraints and catching errors from the driver if something wasn't sorry wasn't saved. He's just fetching error and producing an error message. He's doing that right now and he's still not super confident about like the implementation details but in general he's like moving towards a different direction where it should work for him pretty well. Since we're talking about implementing active model stuff, are you mostly using this to generate SQL query statements? Are you doing any like serializable stuff like JSON or anything with it? With what? With SQL? You're just like generating SQL queries or like statements? Are you doing anything with like JSON or anything like that? No, I'm just using it for generating queries. Alright, thanks Peter. If you guys have any questions after that I can look for him because we're running a little bit short on time. Thanks. Thank you.