 because then he explained a bunch of stuff and I don't have to. My name's Ken. I'm one half of Infinite Red with Todd. I've been doing Ruby since 2004 or so. And I'm mostly a back-end kind of guy, so this is my thing. And I'm really excited by how big this crowd is and how quickly our little community seems to be growing. So I'm going to talk to you about CDQ, what it is, how you use it, and some of the motivation behind its creation. Core Data is really great. And Lori just told you a bunch about that, but sort of the essence for me is that it lets you work with your models as objects, as a graph of object, and it will handle how to make that fit into memory pretty much. And on a mobile device that's really important. So it really is awesome, but there's some assembly required. So this is actually, if you ordered a Rolls Royce in like 1920, this is what you got. And you'd have to take it to your coach builder, like you do, and have them fit it with doors and roofs and all the things that you need as an actual human to use it. So this is what I kind of aimed to do. Like, I also kind of went and looked around at the available libraries and things were in a pretty immature state of the time. But I wanted to make a nice body to go with Core Data's chassis. I really, really hate Xcode. I really, honestly, I hate most IDE's. Hi JetBrains guys, sorry. When I code Java, I do use IntelliJ, but so I would like to be able to work with Core Data. I do not want to have to open Xcode ever in order to do that. So how can you improve software you don't control? How Apple controls it? I can't make the interface any better than it is. And the answer, of course, is you can wrap around it. Now some of the libraries out there, I would say we're trying to make Core Data behave like Active Record or something else, and that was not what I wanted to do. I wanted Core Data to be Core Data. I also wanted ways that you could easily escape whatever I was writing so that if you needed to do something more complicated, you didn't have to throw everything out in order to kind of go down all the way to bare metal. You could use bare metal where you needed it and not where you don't. So I wanted something that would automate the complex or sort of needlessly obscure ways that it does things but still give you the freedom to do whatever you need to do. This is going to make sense hopefully by the end of the talk. So traditionally you would use Xcode and its data modeling tool. I think even if you like GUI Dev tools, that their data modeling tool is really pretty terrible. And so you remember those inverse relationships that Laurie was talking about? It gives you no help doing these. You have to set them up like two or three times for each relation. It just made me want to shoot things. So I made this. So when you do use that tool, what it gives you at the end of that process is basically an XML file or rather a directory full of XML files. Each one is a version of your schema. And the one really great thing about doing it that way is that it gives you automatic migration. If you deliver your model in this bundle, it will load it all up at once, wire up all your relationship and if it sees version one here and your stored data that it finds is on that version and there's another version here, it will figure out how to migrate that for you. Subject to some restrictions. But first I would say a very large percentage of the use cases out there if you can avoid things like column renames, those automatic migrations will work well. I really, really wanted to keep this, having tried to do migrations by hand already. So I just made a DSL that gets translated into the same XML format that data modeling uses. And so you see at the top there's a version number and if you ever need a new version, you just make a copy of this and change the version number so that your app always has a record of all the different versions you use. And you remember the inverse relationships? Well, I don't have to do anything with them because it just smartly figures out what they should be. You can override it, but by default it doesn't make you. I think a lot of people give up on Core Data, frankly, because it just seems like a lot. And it can seem like a better idea to use something simpler. And I think it's often actually not a better idea for the reasons I mentioned before, because if you're using something that is not as smart about it, how it uses memory, you can get yourself into trouble later on. So even if you don't think that you have a data set big enough for Core Data, it can still be a good idea to go ahead and start with it. But how can I make it more appealing for not only me to use it, but for anybody to use it? And the first step is probably just to make it easier to set up. You saw all that stuff that Larry was doing, and I'm going to show you what Xcode helps you if you ask it to. If you ask it to. So if you set up a new project, just an objective scene, you check the little box that says use Core Data. This is what it does. It sort of vomits this into your application delegate. Right? And it's not even doing any sort of like really sort of special complex setup. It's just a very normal sort of setup. And if you want to do anything more exotic, and there's lots of exotic, genuinely useful things you can do with your stack, you're kind of on your own. So that's how it works in CDQ. It makes some reasonable assumptions, right? So, for example, it assumes that you want your database file and your data model file named the same name as your app, and that you'll find those in your document directory. Pretty reasonable assumptions for 95% of apps. And this model, this one only has one context, which is also what Xcode did to you. A little aside about context. So, contacts are kind of roughly like the object equivalent of a transaction. It's a single, coherent place where your objects can live temporarily or permanently. And you can nest them and stack them, and they have different kinds, and they do have different properties, so I'll talk about that in just a second. So, if anything that you want to do doesn't fit into the assumptions that we're making, you can override any of them in any layer. So, this first example here, this is using a two-context layout. This one's pretty common. So what it does is it has a private queue concurrency type on the bottom right next to the store coordinator, and that will do its saves in a private thread outside the main thread. And the reason you might want to do that is so that your main thread isn't sitting there waiting for your data to stay. And then on top of that is the main one, which is what your main thread interacts with. So when you save, it goes down the stack, saves to your main queue, and then saves to your private queue. Very common. If anybody's familiar with Magical Records, Magical Records uses this. But there's also cases where something like RESTKit, it wants to own the contacts. It wants to set those up for you. And so in that case, that's fine. CDQ just skips all of the low-level setup, and you tell it what contacts you use, and you're on your way. This is how you create and destroy objects. Does the Win&Baggle make any more sense now? It looks just like Active Record pretty much. You're not having to interact with contacts at this point. You can anytime you want to, but you don't have to. So 90% of the time, you can kind of operate blissfully unaware of them. The only thing that you do have to know is this down at the bottom, which is you don't save objects. You never save objects. You add the objects to the contacts, which we're doing for you, and save the contacts. So one of my goals is to make sure that coordinates gotchas become encapsulated as code instead of transmitted as lore. And there's a lot of lore in core data. There's things that you have to do right, and you just have to know. It won't complain. It might not blow up right away. It might just work. And I'm going to give you a couple of examples. In that private queue contact, if you're using those, they work great. But every time you save that contact, you have to remember to do it in a perform block. Because otherwise, it will just run in your main thread. And that might look like it works just fine the first time. Someone else, somewhere else, does it the right way? You now have a race condition and you can get corrupted data. So instead of making you remember that every time, that's all you do. As it walks down the stack that you've created, when it finds one that's a private queue contact, it does this for you. It's also notifying the application that you're doing something expensive in the background. And please, please give us a little extra time if the user tries to quit in the middle of it. Also really important. So this is what's sort of scary about it. Which is that there's things you can do if you don't, you didn't happen to read that paragraph in the documentation that will result in corrupted data for your users. And so I really want to paper around those things and this is one of those cases. And this is why I love open source. This was submitted as a patch. This is something I was actually doing wrong. Which is that when you get out a set for a has many type relationship, you think you could just say, oh, I'm going to stick something into this set and now I have put another thing in that relationship. No. It will let you do it. It will happily put something into that set and it will have no idea you've done so. You have to actually specifically request a special mutable set that has been instrumented to do that the way you think. So this is how you do it in CDQ. Because it's already encapsulated that. What just happened? It really doesn't like my animation anyway. So not so much pretty really as readable code that looks like what it does. Code that's easy to sort of intuitively brass and see that it did right. So these are some queries. At first glance, it looks kind of like Active Records. It's not really. It's a little different from Active Records. I tried to make it so that you can always tack just another method on the end, rather than having to do special little subqueries that you pass into a method or something like that. And for the most part, that does work like that. You can also use core data's native query syntax, which is what this is here. I figure a lot of people in this room probably would not want to do that. But if you do or if you happen to need to do something really complex, that can work too. Scopes. So I love scopes. And you can give them a block so that they're parameterized. They're basically just queries that are saved with a name. It's like they are in Active Records. And you can have them refer to each other. Like small and medium are being defined in terms of the size range. And you can sort of chain them together along with whatever other queries you want to add into them. And under the hood, all this is doing is creating an NSFetch request for you. So what that means is if you want to use the NSFetch results controller, that's all you have to do. You can just pull that out at any point and do whatever you need with it. I've made it easy to print out your objects on the command line. There is kind of a native format that they have, which I think is really terrible. It's kind of this big garbage dump of your whole tree. So I made that nice wish list. So there is a lot more that we could be doing. Callbacks. Now what's going on? Callbacks. So you can do something like callbacks natively. You basically have to, you put an observer onto the context and you listen for stuff happening on it. But instead of giving you it on a per object basis, it gives you this big hash full of like, here are the inserts, here are the updates, here are the deletes. You have to go hunt for your object and do it that way. It would be nice to have something that was nice to yourself with that. Lightweight validations. Again, you can kind of put some of that stuff in your data model. You can override some methods, but it's all fairly complex. It should be pretty doable, but it's not in there yet. A ResKit integration. So you can use it with ResKit right now, but there's a few sharp edges. And ResKit itself, there's a lot that's good about it, and it's really, really complicated. So it seems like the collective Ruby brain trust probably could do better. But that would be nice. Friendlier error messages. This is definitely a common complaint, is that it's very cryptic if something goes wrong. And there's people, I think, who have attempted to make this a little better, but we could go further. Manual migrations. This is when I get asked a lot from iOS people who have been dealing with this already, which is that if whatever you're doing doesn't work with automatic migration, it can be a huge, huge pain in the neck. And the only reason that we haven't really tackled this is that we just haven't needed it yet. So what would be most helpful here is if somebody actually gets to that point where they need to do manual migrations, call us. We would love to have a concrete use case for that. So there you go. I don't want to break the core data. I want to make it easier, safer, prettier. And I would really love more people to be using it. So thanks. Any questions?