Leveraging SQLite in Web Development - RUBY 630
Stephen Margheim is the Head of Engineering at Test IO. They explore the world of web development with a focus on the use of SQLite, a powerful and often underestimated database tool. They dive deep into the capabilities and potential of SQLite for web applications. The episode covers a range of topics, from the evolving feasibility and challenges of handling concurrent web requests to the misconceptions surrounding SQLite's performance limitations. They discuss the potential limitations of SQLite in handling massive write throughput and its suitability for various application scales, highlighting the considerations related to expected growth and performance requirements.
Special Guests:
Stephen Margheim
Show Notes
Stephen Margheim is the Head of Engineering at Test IO. They explore the world of web development with a focus on the use of SQLite, a powerful and often underestimated database tool. They dive deep into the capabilities and potential of SQLite for web applications. The episode covers a range of topics, from the evolving feasibility and challenges of handling concurrent web requests to the misconceptions surrounding SQLite's performance limitations. They discuss the potential limitations of SQLite in handling massive write throughput and its suitability for various application scales, highlighting the considerations related to expected growth and performance requirements.
Join them as they delve into the practicality and benefits of using minimal software components, the simplicity and efficiency of a simple system using a Rails app with SQLite, and the advantage of branch-specific database setup. From the evolving capabilities of SQLite to the practical considerations of web development, this episode offers valuable insights for developers at all levels.
Sponsors
Socials
- LinkedIn: Stephen Margheim
Transcript
Charles Max Wood [00:00:05]:
Hey, welcome back to another episode of the Ruby ropes podcast. This week on our panel, we have Valentino Stoll.
Stephen Margheim [00:00:13]:
Hey now.
Charles Max Wood [00:00:14]:
I'm Charles Max Wood from Top End Devs. We already have people coming in on the live stream, which is awesome. I think they're all coming in on, Twitter. We have a special guest this week that is Steven Margine. Steven, welcome to the show. Do you want to introduce yourself real quick?
Stephen Margheim [00:00:32]:
Yes. Thank you for having me. As you said, my name is Steven. I am living here in Berlin, Germany, though I am originally American. Just got married earlier this month.
Charles Max Wood [00:00:45]:
I saw that on Instagram. Congratulations.
Stephen Margheim [00:00:48]:
Yeah. Thank you. And excited to be here and talk about SQLite and rails.
Charles Max Wood [00:00:55]:
Very cool. So, where do we start? I'm just gonna give a little bit of context because, I mean, I've used SQLite, but I mean, everything I do, I do on Postgres. I think most Rails developers go that way. But I think SQLite is also the default if you start a new Rails project, or at least it used to be. Anymore, I just tell it, no, I I want Postgres. So yeah. If you know, you're talking about SQLite like it's a serious database on Twitter.
Stephen Margheim [00:01:32]:
I know. Weird. Right?
Charles Max Wood [00:01:34]:
I know. I I couldn't think of a better way to put it, but the way you talk about it and the way we talked about it on the Ruby Dev Summit, it made it you made it sound like you could honestly use this in other places, and I've heard other people being interviewed. I I think somebody from PlanetScale or one of the Internet hosted databases was talking about how SQLite is the real deal now too, not just MySQL or Postgres. So yeah. Is it the real deal, and why change our minds?
Valentino Stoll [00:02:10]:
Well, it is the real
Stephen Margheim [00:02:11]:
deal, but like with any database, and this is, I think, the the key point, there are trade offs. So at, like, a very high level, just my sort of sense of things. Right? Like, Postgres is great because it comes with a lot of functionality out of the box, and it has a really rich community of developers and, set of extensions. So I you wanna be doing stuff with vector databases. You've got PG vector. You can plug that into your Postgres database. But compare that with MySQL and the Vitesse sort of layer that can be put on top of that and the scaling that has been done in the last 2 decades on MySQL. There aren't the same sort of solutions that are as battle tested
Valentino Stoll [00:03:18]:
at the
Stephen Margheim [00:03:18]:
same level of scale for Postgres. Right? So something like PlanetScale, which is sitting on top of Vtest, is a relatively unique offering for MySQL. And then SQLite has, I think, a unique sort of value proposition because it offers you, like, the full range of SQL. Like, there's there's really nothing that you need to do with SQL, the language that SQLite doesn't offer. You can, if you want to, run it in a client server architecture. The Libsquel project, which is a a fork of of the SQLite code base by the Terso, guys, And the platform that they are building on top of that is, like, bringing the client server architecture on top of SQLite for edge computing. But you have the option, which is unique with SQLite, right, to run it on your application server machine right next to your rails process and just simply remove network latency as a consideration. And I think that the major, like, shift that has been happening in web development lately has been a growing recognition that SQLite is production grade software for web applications with the caveat that you do have to configure it to be ready to use for web applications.
Stephen Margheim [00:05:11]:
And where I think there has been this odd disconnect is that there's been the sense like, oh, yeah, Postgres, MySQL. These are obviously web application databases. Just get them up and and you're ready to go. But, of course, you have to configure those as well. Like, there there isn't really a database that is completely blind plug and play. And as people have started lowering that barrier to entry and just started to, demonstrate, hey. There is a lot of power here. There's a lot of flexibility here.
Stephen Margheim [00:05:46]:
This is a a model for building and deploying applications that offers some unique value adds, whether it's to developer experience or to performance or to simplicity of deployment. And I think it really is just a question of education around what it takes to get a robust, resilient production grade, deployment of an application backed by SQLite out into the world, and that education has been growing in the last couple of years. So, yes, it is the real deal.
Charles Max Wood [00:06:26]:
So I want you you said production grade, like, 12 times. I I wasn't counting. I'm just throwing the number out there. But, what do you mean by production grade?
Stephen Margheim [00:06:39]:
Yeah. So I think that there have been 3 major barriers to using SQLite out of the box in a web application. And I think it has led to the sense that SQLite isn't production grade. So the first barrier is concurrency. So everyone who has read even a little bit about using SQLite for a web application will very quickly come across people claiming, hey, you absolutely could never use this for a web application because in order to have a web server that can deal with even just a reasonable amount of requests coming in, you're going to take advantage of the stateless nature of HTTP and deal with multiple web requests concurrently with your application process. But SQLite running on that same machine is going to linearize your interactions with the database. And by default, if you don't touch anything, you're using the original model that they have for ensuring transactionality, you're gonna have linear operations whether they're reads or writes. So if you want to do anything, you do them 1 at a time.
Stephen Margheim [00:08:03]:
So the fact that you have concurrent web requests is negated. You you everything bottlenecks at your database, and people say, of course, that's never gonna scale. Now there are 2 key points to make on this barrier. The first one is people really too quickly forget to do, like, the basic math on if you remove latency, and you give yourself some headroom, So you go from talking to a Postgres database over a web connection, which can take, you know, some number of milliseconds to talking directly in process to SQLite, which can take some number of microseconds, you have 10, 100, up to 1,000 more opportunities to do things right when you move from milliseconds to microseconds. So even as you linearize things, you're dealing with different orders of magnitude of latency, and that gives you possibilities. And then the second one is that you can configure SQLite to have concurrent reads. But as of now, there is no way to get concurrent rights. So out of the box.
Stephen Margheim [00:09:20]:
SQLite is linear operations. Web applications tend to deal with concurrent operations, and people think, well, that's a hard a hard no, but it isn't. That's barrier 1. Barrier 2, and I'll just stop at barrier 2, it's the main one or these are the main 2, would be around backups. Right? People are like, hey. This is ridiculous. If you want to have, something that's like making money on the Internet or is in some way trying to be valuable, you need to make sure that it's resilient. Something happens.
Stephen Margheim [00:09:57]:
We know how the world is. The service can get unplugged or storms come in. Who knows what? Right? If you have everything running on one machine, including your persistent data and that machine goes down and your persistent data is now gone, well, it's easy to spin up a new machine in a new application process, not so easy to recover lost data. So the fact that SQLite is on that same machine that you don't have network latency is a vulnerability for persisting your data and keeping your system resilient to system failures. And in the last couple of years, there have been a number of tools that have been built to backup SQLite databases to some other place and to make it easy to take those backups and spin up a new instance of that database somewhere else. The probably the most well known one now, the one that I have used the most is a project called LightStream, which just streams rights to your SQLite database to an s3 bucket or or really any s3 compatible bucket service and has a very simple CLI. You can just pull it back down onto any machine. So when I say production grade, I I tend to mean these kinds of ideas where people think about, like, sure, I can do this, like, quick script on my laptop, and it's nice to have, some quasi persistent storage.
Stephen Margheim [00:11:27]:
But if I'm trying to build a business, if I'm trying to build a SaaS, if I'm trying to build an application that I want to have some meaningful presence on the Internet, I'm gonna need to have the ability to handle concurrent Web requests. I'm going to need to have the ability to spin up new Web servers with my application and keep my data persistent across them. And there wasn't always a clear story for how simple or easy or possible that was to do with SQL app. And that story is being written much more clearly now.
Valentino Stoll [00:11:58]:
First of all, you have a great series, blog series that we should link to on, you know, successful usage of SQLite and Rails and configuration and performance metrics and all kinds of great stuff, that I think people should read and dive into. And I guess, like, my biggest you know, I've been on the same boat of incorrectly thinking for the longest time that SQLite is not performing and, oh, like, don't use in production, but, you know, sure in development or whatever, you know, testing or, you know, even just like small, like, hobby apps, sure could be, you know, fine. But once you get above a certain level or scale or whatever it may be, then it you know, don't use it. And I I'm sure I don't I'm not alone thinking this. Right? Yeah.
Stephen Margheim [00:12:47]:
Not at all.
Valentino Stoll [00:12:48]:
And so right? So you do shed quite a lot of light on, you know, okay, there's a lot of buts in a lot of those, you know, ways of thinking. And I definitely agree with you there, and I'm kind of curious, like, to get some further insight there on well, like, what are the limitations? Right? Like, what point do you hit SQLite and then it no longer work for your app? Right? Because I think that's where a lot of people are still hesitant to dive into it because they still don't know what that barrier is. And then you it's one of those things where, okay, you don't know it till you know it, and then it's too late. And then you're trying to scramble to find another solution. Right? So, like, what are those things? Right? Like, what what should you be looking out for, to know if SQLite is the right option for you?
Stephen Margheim [00:13:43]:
Yeah, it's a good question. It's the question I get most often. And there are a few different angles to take on an answer. One of them is where are you comfortable in investing your right. So if you're someone who has you're trying to start up a side project. You're you're hoping to to get some money with it or just sort of do something of interest and value, and you have a decade of experience with Postgres, and really feel comfortable, like, with the path to evolving a system over time with postcards, you know, just stick with them. These days. It's there's really not actually a lot of limitations with sequelae.
Stephen Margheim [00:14:53]:
So here's here's, like, the first big one that used to be more of a limitation. Right? So there's a major difference between SQLite and Postgres, MySQL, Oracle, like, pick any of the others. Most database engines follow the client server architecture. So it's like you have you you minimally have 2 different processes and and most of the time you have 2 different machines. You've got a machine running your application. You've got a machine running your database. And you most often, right, have multiple clients, have multiple machines running your application and one machine running running your database, and you talk to your database through web requests.
Charles Max Wood [00:15:38]:
Mhmm.
Stephen Margheim [00:15:39]:
And there are, like, there's been decades decades of exploration or, like, different ways to scale that kind of architecture, to make that kind of architecture resilient. And when you go from an embedded database, there's one machine, there's one process. Everything is just happening right there to, you know, something like. GitHub scale, Shopify scale, like, you there's no vertical scaling will never be able to handle that. You're going to have to horizontally scale. So then how do you horizontally scale when your database is living on each machine? That that was a problem. That has been a problem for a long time. And so I I have said, you know, if you are starting a project and the way that it succeeds is it gets to that scale.
Stephen Margheim [00:16:31]:
Right? Like, if you go and get venture money, you probably should have chosen my sequel from day 1. Right? Like you're you're shooting for PlanetScale, not TM, from day 1. But that's actually not even a technical limitation anymore. So whether it is the predecessor to the LightStream project, Light FS, from Ben Johnson at fly I o, which is a tool to have a replicated logical database spread across multiple machines, SQLite database, obviously, or whether you're using a platform like Terso, which as I said, like, brings that client server architecture, but also allows you to have read replicas on each of your machines, and it'll, you know, manage consistency for you. Like, there are now there are others. There are multiple tools now to allow you to horizontally scale a SQLite database. So is is that particular scaling path as battle tested as like the test on my sequel. No, it's not been around for 2 decades You don't have a company like youtube.
Stephen Margheim [00:17:53]:
That's running it. So, again, it goes back to, like, your your risk profile. If you think on day 1, I really want to be at that scale, you know, you probably should just use MySQL and V test. Right? Because the why take the risk if you know that's where you're going? But for someone who is, like, unsure of what the future looks like, I really do think that there are so many wins that you get on day 1 week 1 year 1 with the developer experience and the performance characteristics and the power and simplicity of like leaning into vertical scaling for as far as that will take you that you should really give SQLite a long look. And you can fall back on the security bill. Like, if you really do get very successful, sex successful such that, like, vertical scaling can't work for you anymore, you don't have to change databases necessarily. But the other thing that's true is, like, if you do get to that scale, you're probably making money and probably good money. And at that point, you probably could change databases if you want to.
Stephen Margheim [00:19:12]:
And going from a SQLite schema, which is, you know, it's gonna be a looser schema typically to post cross for my sequel. I think is generally easier than the reverse direction. So I talked around your answer. The short answer is I really can't think of, like, really hard limits, to be perfectly honest with you. But I do think that there are different risk profiles, and there are different reasons why you might or might not choose to use it. But, like, as of today well, okay. I say that, of course, I should say out loud. There is the one key limitation, right, which is if you have, like, massive right throughput, if you're building an analytics platform to compete with Google Analytics and you're just gonna get like, the core of your business is you need to deal with massive amounts of rights.
Stephen Margheim [00:20:06]:
Don't choose SQLite today. That would be a hard limitation. They are working on concurrent rights, so that limitation might not be true in 1 year. But for today, I would not build a analytics platform on top of SQLite. How about that?
Valentino Stoll [00:20:28]:
Yeah. That makes sense. I mean, I'm thinking more I mean, we should also not build an APM with SQLite.
Stephen Margheim [00:20:37]:
Yeah. Again, it it does sort of, like, come back to your your expected growth profile. I have built an APM with Sequoia. It's a very, like it's an internal small one. Right? But I was like, I'm not expecting if, you know, the the 37 signals crew have talked about load testing their SQLite backed campfire application. And on the biggest machines that they have, you know, with their cloud exit, they're they're running their own machines in a in a data center. Like, their beefiest machines, they're getting, 50,000 concurrent requests. Are there APMs that could handle that? Like, yes.
Stephen Margheim [00:21:25]:
Right. If you like, I wanna build a business and I am either the next app signal or I have failed, yeah, I I probably would not choose SQLite on day 1. Again, my my sort of hot take on this is, in all of the recent Internet drama aside, I personally would probably choose either SQLite or PlanetScale on day 1. Those are the 2 options I would choose. Like, I'm either going for big scale, and I know that. Like, that's the characteristics of the app I'm building, or I'm just doing regular scale. And SQLite handles regular scale, quote, unquote, right, like, good luck getting if you can build an application and and you have 50,000 concurrent requests, like, good on you. You have you have definitely succeeded.
Stephen Margheim [00:22:17]:
So short answer is maybe, you know, honestly, maybe.
Valentino Stoll [00:22:25]:
It's it's just funny to me because SQLite comes out of the box of the reels. And for the longest time, you know, you question it, like, everybody's using SQLite. And the more you use reels and you the more, like, one off apps that you start to make. Right? Like, even just, like, trying something out, like, it's great. It does most of what you need. Right? Like and I feel like most people won't even hit the limitations of it or see any side effects of that, you know, until much much later to your point where there is an actual, you know, limitation and you have the need, the financial, you know, ability to to navigate that. Right? And I feel like most people won't even get there, you know, to be honest. And, I mean, in in all honesty, thanks to the Shopify folks for all of their efforts with it, as far as, like, you know, LightStream as an example.
Valentino Stoll [00:23:23]:
But, you know, all all of the other integrations to just make it super straightforward to get set up and and operational, like, I don't know. I feel like, why bother? Why bother having like, I'm definitely coming around to that, off the cloud, idea for for it specifically of, you know, why have all these extra services, that just aren't needed, and it's just to help you scale maybe?
Stephen Margheim [00:23:58]:
Right? Yeah, I mean, this has been one of my, like, major realizations and principles that drive a lot of my personal interest in the topic is recognition that like, for me myself, I really am trying to be conscientious about fighting off unnecessary complexity. Like, it's just swarming around us, and especially like, for where we are at in the evolution of the Internet and the economy of the Internet. Right? Like, everything is a SaaS now. Everything is a product now. It's like, hey. You need authentication? Here's the SaaS you buy. You need, emails? Here's the SaaS you buy. It's and it is you know, it just, like, grates on me to see how, like, common the, I don't know, the mind virus.
Stephen Margheim [00:25:01]:
I'll be sassy. Is that the correct way to build a web application, a service, a business is to sign up for 15 different SaaS platforms. Mhmm. Stitch your things together have no real ownership or understanding of like, what your ranking app is doing, then like, I mean, and we've been seeing more and more of it. Right? Like and then you actually get some success or more commonly, the actual noise of the Internet and the the people who just like doing naughty things and having their little bot farms run. And you just like, boom. All of a sudden, like, whoops. Like, I have a bill for $10,000 from this one service for this month.
Stephen Margheim [00:26:00]:
And, yeah, as you said, I mean, it's like it's actual, like, statistics. Like, most applications are not going to actually need like there's real value there. I'm not saying that most of these businesses shouldn't exist. They should exist, but most people shouldn't pay for them. Right? Like we servers are cheap. Servers are easy. Like, I'm no DevOps genius. I'm certainly not an ops genius.
Stephen Margheim [00:26:25]:
I barely can use Docker, you know, but I have spun up many, many servers in my day, and it's not, rocket science. I have maintained them. That's also not rocket science. It's not incredibly stressful. It can be when you make like mistakes. And that's why this concept of production grade is important and to have a sense of like, what does it mean? You know, to give to give one specific example? I had an application that we use at work for business that provides profit running on SQLite. And I had been thinking for a while, you know, I really need to go in and install LightStream and set that up, but it didn't get around to it. And then one day I was cleaning up and renaming my applications to make them more consistent.
Stephen Margheim [00:27:27]:
And I did not recognize that in the little web platform that when I rename an application, what it's gonna do on the server is it's gonna do our MRF and then, redeploy. And it wiped my SQLite database. You know? And I spent, like, a full day trying to recover it from memory, and it did not work. And I I had to go back to the business and, yeah. You know? That was a shitty day. And I had to put in backups after that. Right? So this is why I do bring up production. It's like, yeah, you know, you can foot gun yourself, but you can set up backups for post grads or my sequel or anything.
Stephen Margheim [00:28:08]:
But, like, none of these things are difficult, and I it just saddens me to think that so many developers and especially newcomers, like, come into web development and think like, a, you have to understand docker and kubernetes and Serverless you have to pay for 15 saas platforms. It's like man, it's gonna take a PhD in web development and at least $500 a month to even like start to do something It's like that just isn't true. Like more people can get started with less, crap and less upfront money. And I really want to make it as widely known as possible. Like, there's there is this alternative path. You know, you can just go get a DigitalOcean droplet, put a rail server in a SQLite database like you have one machine, and you can grow that. You just, in your little DigitalOcean dashboard. Like, you could just bump it up over time and you can do that for a long time.
Stephen Margheim [00:29:10]:
Like, go and look at the biggest machine on there. It's really big and it can handle a lot of requests And SQL, I can handle a lot of requests. And these things, like, can be cheap, and they can be simple. And that opens up opens up so much opportunity for, like, experimentation and more people coming in and trying things out and That's like that's what drives the passion behind it. Right? It's like doesn't have to be this other way.
Valentino Stoll [00:29:35]:
Yeah. I feel you on the mindset. Thing. Yeah. It just reminds me of CGI. Right? Like, back in the day, you you had a directory CGI, and you uploaded a programmable file, and it ran. And, you know, it was that easy. Yeah.
Valentino Stoll [00:29:54]:
Everybody had FTP client or whatever. You know, you just uploaded the file, and then you are ready to go. And, like, people ran, like, legit businesses off of it, you know, where, you know, guitar tab sites or, like, you know, all all of the original search engines, you know. It was just like a handful of programmatical files in a directory somewhere, and it just ran. And I feel like, you know, may maybe we're, like, a little bit beyond that. Right? But it should still be that easy. You know? It's like the underlying technologies haven't really changed that much. You know, like, you still have servers and clients and a browser, you know, and it's it's those three things.
Stephen Margheim [00:30:42]:
Yeah.
Valentino Stoll [00:30:42]:
Yeah. I was just Why make it more busy?
Charles Max Wood [00:30:46]:
I was just gonna add with all the different SaaS products you can add. Right? So top end devs for a long time ran the authentication through one of the authentication authentication services out there that you pay for. And yeah, it was more work to set up and manage that than it was for me. Eventually, I just switched it back over to device. Right. Because I set it up once and then, yeah, occasionally I have to help somebody reset their password or something stupid. Right? Hey. Oh, yeah.
Charles Max Wood [00:31:17]:
I jacked that up. Let me fix you. Right. And, and yeah, I feel this on the rest of the infrastructure too. Right? I mean, one of the things I really like about Kamal is that it kind of does that. Right? So it pulls down the Postgres, Docker image. It pulls down the red as a Docker image. It pulls down, you know, a Ruby Docker image and then runs my Docker file against it.
Charles Max Wood [00:31:41]:
And then it says, hey, that's over there and that's over there and that's it. Right. And load balancer. It does a load balancer too. And, and that, that's what I love about this. So yeah. Having something simple where it's just like, oh, yeah. It's just gonna run alongside the the app the app server.
Charles Max Wood [00:31:57]:
Right? Run alongside Puma or whatever. Yeah. This is beautiful. Right? I don't have to fuss about it.
Stephen Margheim [00:32:07]:
Yeah. Exactly. And then on top of it, you get, like, these really nice benefits of like, it's, I would recommend for developers to just like, spin up an app and throw it up somewhere. Right? Use Kamala, use Hashbox, like, use it or, like, do it quick. Do it easy and just, like, play around and get a feel for what it feels like on, like, 2 fronts. And this is where it, like, really sold me, and I, like, became passionate about it. So the one is it is it's just really nice to have a simple enough system that you can keep it in your head. And so the fewer moving parts, the simpler the system.
Stephen Margheim [00:32:56]:
And, like, I have these applications that I have built at works, you know, sort of like these r and d applications that, I am effectively the sole developer and maintainer of them. And, you know, I'm an engineering manager. I'm in a lot of calls. I have, like, these 30 minute windows sometimes between calls. And I have to debug production issues that come up. And I can actually do that. I can go from, like, I haven't heard anything. I get a Slack message.
Stephen Margheim [00:33:28]:
I read the problem. From that moment to I have checked that the fix is live and fixes the problem in production, I have consistently been able to do that inside of a 30 minute window for over a year. And that is like a magical feeling. I I I'd every single time I do it, I'm like, wow. This feels amazing compared to most of my work experience. And that is, like, driven by I have a Rails app and SQLite installed. That is it. I have nothing else.
Stephen Margheim [00:34:03]:
I don't have Redis. I don't have I have nothing. I have, like, 4 different SQL databases. Right? I've got my Q database and my cache database and my models database. Or, you know, production databases, what it's called. But I have this one piece of software. And that piece of software, I don't have to do anything weird or fancy. It just runs inside of my application process.
Stephen Margheim [00:34:29]:
There's nothing to, like, spin up. I don't need to have a proc file necessarily, and it's just is there. And that, like, developer experience is so nice. And then, like, on top of it, it's just like a file. And so if I need to, which I've done many times, right, like a production issue comes in and I can tell, you know, some data has gotten out of sync here, but I don't know exactly how or where or what I need to dig into the data. And I can literally, like, do a safe backup. I can use the fact that I have these LightStream back because I can just tell LightStream on my laptop, hey. Replicate the database to my laptop, please.
Stephen Margheim [00:35:10]:
As of right now, what is the current state of the data? So I get a a mirror of the production database on my laptop. I spin up the app on local host. I've got all the production data, and I can mess around and figure out, like, where is the where did the data go wrong? Where's the bug in the background job that messed this up? And I know it's completely safe. I don't have to remember to do the dash dash sandbox in my Rails console or any of that. And it it's like, you know, one CLI command to get it down there. And there's, like, so many of these little things. You know? Whether it's the one of the first articles I wrote was on doing database branching locally with Git. And it's, like, the simplest thing in the world to set up with rails.
Stephen Margheim [00:35:55]:
And it just removes an entire class of problem that has annoyed me for a decade of web development when you're working across these different branches and your, you know, your schema gets borked. And there's just like they stack. They stack all these things. And then at the very end of it, you're like, oh, man. Every single database operation I have done went from n number of milliseconds to n number of microseconds. Like, I just got a 100 x performance improvement. You know? Like, action pack is my bottleneck for all of the rails apps that run the stack. You know? So that is awesome.
Valentino Stoll [00:36:36]:
Real quick. Just dive in deeper to the, the branch specific databases you're talking about because I thought this was fascinating reading through this. Like, how does that setup work, and and what are you saving there?
Stephen Margheim [00:36:48]:
Yeah. It's, it's a really nice feature. Let me start off by explaining, like, the problem. So here's the scenario that many of your listeners are likely to have experience. You're working in a feature branch, so you git checkout dashb feature a. You get to work. It's a long running feature branch. Kinda complicated.
Stephen Margheim [00:37:11]:
As a part of the feature work, you have to make changes to your schema. So you generate, let's say, 2 different migration files. You add in a new table and you have, renamed a couple of columns on an existing table. While you are in the middle of working on this feature branch, a major production issue is reported and a bug fix needs to be made. Someone has created a hotfix branch, and they ask you to review it. You're like, okay. I did the code review, but I wanna make sure before we push this live that, like, the fix is actually doing what we wanted to do. So you git checkout hotfix 1 and run your application, and things aren't working.
Stephen Margheim [00:38:02]:
Maybe, like, your Rails app won't even boot. Maybe as you boot into the app, things are thinning. Like, what in the world is going on? What is, like, what is broken here? Something is very clearly broken. And what has happened is that the schema changes that you made to your single only local, you know, development database in feature branch a are still there when you checked out hotfix 1. But hotfix 1 doesn't expect those changes to be there. You rename some tables or some columns on some tables. And the code in hopfix a expects the database to be in the schema that existed in main, but your schema locally is different. And so database and the app have a mismatch, and things blow up.
Stephen Margheim [00:38:44]:
Yeah. Ugh. This is so annoying. So you have to, like, get your database state back into a correct place and then be able to once you're done reviewing that hopex or however, you know, you you change branches and you get back into the feature work, you wanna bring those changes back. So that's, like, the problem, and it's, an annoying problem. And there are various gems out there to try to help you with that. Here is the simplest, most resilient possible way to solve that problem. If you could, in some magical way, have every single git branch have a completely separate database, well, then, definitely, you would never have this problem.
Stephen Margheim [00:39:24]:
That would be nice. Now when you're running Postgres, that might be tricky, might be possible, or it might just be computationally expensive or space events. Who knows? I've not really honestly tried it. But with SQLite, it is both cheap and easy, and all that it requires is you take advantage of the fact that the database YAML file that Rails uses is processed by ERB. So you can just throw some ERB in there. And in that ERB, you can run shell commands. So you can just plop in there. Hey.
Stephen Margheim [00:40:00]:
What is my current git branch name, please? And you can make that the name of your database. So now you have dynamic database names. Then the only other thing you need, SQLite itself will automatically touch non existent database. So if you say SQLite, please open database a. That file doesn't exist. SQLite will just create an empty file. So all you need is to ensure that when you start your Rails app, if your database hasn't been loaded, right, run your migrations, load the schema, however you do it, that it is. Right? So you just wanna say, take whatever the current encoded version of my schema is in my repository and run that.
Stephen Margheim [00:40:50]:
So what I typically do, and I think what's in the article is, like, it will run your migrations. And you can do an after prepare block in your development dot erb configuration file. So with those two changes, what you have done is you have set up a system where whenever you change git branches and in any form, you boot your rails app. So that can be starting the rail server that can be starting your rails console that can be using the rails runner. It will create, if it doesn't exist, a new database file. It will run all of your migrations and get the state set up. If a database file does exist, but there are some new migrations, it'll just run those new migrations and get the state to where it needs to be. And you can then enhance that if you wanted to.
Stephen Margheim [00:41:43]:
That's, like, where I stopped in the article. I need to write some more about it, but it's it's very easy to enhance that and, like, you can do seeding. You know, you can have generic seeds that are always run so you can have a baseline set of data that's populated into all of your branches. You can set up some branch specific seeding, such that you, and you can make that more generic like around scenarios. There's all kinds of fun things. But in general, you have the ability to have completely isolated, like, actually separate databases for each of your git branches. And so it simply becomes impossible to run into the super, super annoying when it happens because it's like, you know, you're completely blocking me in the moment where I don't wanna have to deal with any of this these schema conflicts as you move across git branches.
Valentino Stoll [00:42:33]:
That's interesting. I I mean, how do you do you do you not mind data getting blown away between branches at that point, or have you solved that problem and, like, you know, stream some updates?
Stephen Margheim [00:42:48]:
Yeah. So for, local development, I have ended up with a mix of a couple of things. And I have a couple of later blog posts, about this, but I should honestly finish up writing some of the other stuff I've done. But in general, I tend to start off with just like a generic seeds file. It's like, let me have some usable data. And, yeah, that 75% of the time, that is sufficient. For some applications, I have ended up in a place where it's like, well, I have kind of built up a whether it's like pulling down a production database or pulling down a staging database, like, I want to keep this across, branches. And, I have just written some Ruby scripts, basically.
Stephen Margheim [00:43:54]:
I have a I have a blog post about this. So it's like, you know, DB clone. And I just say, okay, I wanna take this database, and I want to clone it into a new file with this name. And then I am just wiring up the name that I point to in my data c able to that. And there's some automations you can layer on top to connect that to get if you want. For the most part, what I have found is, like, when I want to control the actual data, the schema and the data, I was like, I want this file that, I sort of move away from the automatic Git branching stuff, and I just manually go in and say, comment out my default database line and database YAML and just point it at a particular file. So if you were to look at, like, my laptop for most of the apps I work in and you look in my storage directory, on average, you will probably see at least 12 different SQL I three files in there. So I just create a bunch of these different scenarios.
Stephen Margheim [00:45:00]:
I pulled down production on this date. I pulled down staging on that date. I've created this git branch and that git branch, and they all live there. And sometimes I manually point my app to one of them, or branch off and just do manual branching as if it were getting me like, well, I wanna sort of play with the schema and the data in this direction, give that a name, and wire the app up to that. And it's all, it's, like, quite simple, but it is quite nice to be able to, like, have that flexibility. Your schema, your data, you have the the full range of, like, logical branching that you could do with Git and, text files with your database.
Valentino Stoll [00:45:46]:
Yeah. It's super cool.
Stephen Margheim [00:45:48]:
Yeah. I mean,
Valentino Stoll [00:45:48]:
look looking more looking more at the, configurations you got for, like, having multiple databases, all SQLite. Like, do you find that there's, like, a limitation point of, like, too many databases of the same SQLite server, like, surveying for, or or where it's just, like, becomes too unmanageable to, like, reason about all of the different things. Right? Because I saw you have, like, solid errors, which is kind of interesting where you're, like, you know, storing all of your errors off to its own database. Cache, I imagine too. Right? Like, you start like stacking up all these different databases. Is there is there a limit to the madness? Or is it like, still pretty reasonable, you know, for everything that you'd need?
Stephen Margheim [00:46:38]:
So if there is a limit, I haven't hit it. The most databases that I have in production is, like, 6, I think. And, like, operationally, that it's nowhere close to that. I'm not even sure if there is a limit. But conceptually, no. It hasn't been that bad. What I have found is, like, you know, for the nature of the system, I'm gonna have this bucket no matter what. I'm gonna have to do some kind of IO or some for an object of this type no matter what.
Stephen Margheim [00:47:13]:
And for me, it is a conceptual win to keep the actual operational infrastructure there like the same. You know, I I have been able to become a master of rails and sequel. That's it. And I can do everything I need. So I don't know all of the Redis commands. I don't know all of the Redis data structures. I have a passing awareness of them, and I wouldn't know how to optimize a Redis instance for caching. I don't know how to optimize a Redis instance for background jobs.
Stephen Margheim [00:48:03]:
I don't know is would Redis be a great choice or a terrible choice for the back end for something like solid errors, you know, storing exceptions that happen in your application somewhere. So being able to leverage a flexible, powerful tool across these different problem domains and, you know, give myself the challenge, but also give myself the time to become a master. Like, I know how to optimize SQL queries for caching. You know, I know I've spent time and I've thought about that, and it's just SQL. And I know that language, and I know it well. And I know how to optimize, like, out of structure tables and what kind of queries to run and make sure I know how to optimize, SQL and SQLite for a background job queue. I know how to do that for errors. And each one of those, I am able to leverage expertise that I have gained in the past ones.
Stephen Margheim [00:49:06]:
You know? Like, there's a lot of overlap. So if you wanna have a good schema for your active record models, a lot of the wisdom and principles that are you're gonna learn in that problem area are gonna roll over when you're like, well, what if what would it look like to back a a queue, a job queue with SQL? Okay. Let me think about how to, you know, scheme that out. What kinds of queries? How do I wanna deal with this stuff? And it is and what's really nice in the rails ecosystem as 37 signals has gotten into building new applications, has gotten into SQLite, and, has been exploring the benefits of reducing the number of moving parts and publishing more of these solid star gem solid cue, solid cash, solid cable, I imagine is being worked on is that I don't even have to be the only expert. You know? There is now a community of experts, and I read through the like, for example, the solid Q source code and. Rosa did a way better job at it than I did. You know? So it's like, I just get to take advantage of the fact that she is a really top notch developer who spent a lot of time thinking very deeply about how to structure a queuing system backed by some persistent SQL database. And I just get to run bundle add.
Stephen Margheim [00:50:50]:
You know? Mhmm. So I haven't gotten anywhere close to a limit, and I have actually found, like, every single time I do it, I'm like, you know. I should have more databases like I'm right now working on another gem, which is like the conceptual sibling to solid errors. I think I've named it solid metrics, right, which is just let me keep track of the metrics. Oh, you know? I wanna know them. I don't have super high needs. I don't have a lot of customizability. I just need to know the the basics, rails, instruments itself already.
Stephen Margheim [00:51:26]:
You know, it's the same thing with Aries. It's all instrumented. I just wanna put them somewhere and put a very basic web UI on top of it. Mhmm. And, you know, I've got, like, 3 more ideas on top of it. So probably, you know, come back to me in 2 years. I'll probably have, like, 12 different databases in some application somewhere in production and might not be ready to stop there either.
Charles Max Wood [00:51:48]:
Very cool. So I guess my question is because you you said I know how to optimize SQLite for a queue. I know how to optimize it for something like solid air. I know how to optimize it for, you know, whatever else. How do I figure that out? I mean, do I just Stack Overflow the thing or I don't know how to tweak SQLite for my use case?
Stephen Margheim [00:52:15]:
Well, I'll start by just distinguishing one one small point, which is that, you know, for for those particular domains, that's just SQL, not SQLite. You know? Like, what what kinds of tables with what kinds of columns and what kinds of indices?
Charles Max Wood [00:52:29]:
You're talking to structures
Stephen Margheim [00:52:30]:
and not query structure. If you know? So somebody, you know, Mike had to think about which, Redis data structures and Redis commands should I use to have a resilient and performant job back end. And other people I've thought about if I've been to, like, have those same behaviors, but I wanted to back it with a relational database, how should I structure my tables? What kinds of indices should I have? What kinds of queries should I write? How do I do that resiliently and performantly? That's a SQL problem. Okay. But when it comes to SQLite, I would say there are sort of 2 parts to an answer to your question. So one part is one of my goals is to make the amount that you or anyone else would have to learn about SQLite to make it work incredibly well for a Rails application specifically and for a web application more generally as close to 0 as possible.
Charles Max Wood [00:53:32]:
Right? So, you know, we That's what I want to as the user.
Stephen Margheim [00:53:36]:
Yeah. I think it's what I would have wanted where I not the person who got, you know, sort of infected with the bug of really getting into it. But one of the great levers that is available in using a web application framework is that these kinds of things can be pushed into the framework itself. So, you know, we made a number of changes to the default configuration for SQLite as a part of Rail 7 1. And that like just there were 6 changes. I have a whole blog post about it like those exchanges alone make a massive difference. And if you had taken if you take a default Rail 7 0 application and put it on the Internet, you're gonna experience pain. And if you put a Rail 7 1 app SQLite application on the Internet, you will experience notably less pain.
Stephen Margheim [00:54:31]:
But still some pain and we are solving the major pain points at the rails level itself. So whether it's improving concurrency or improving the performance of talking to SQLite sort of like the Ruby and and c bridge. I really want to have as much of that live in the framework as possible. But, of course, as for anything, like, your app is gonna have some special, use cases, some things where you're gonna have to move beyond the framework. And so, like, how do you learn to take advantage of Sequoia? And I would say that there are, like, complete three things I would recommend. So the first one is the SQLite docs are extensive. And, I I personally find them quite approachable. I mean, like, the it's not just like, here's all the C code.
Stephen Margheim [00:55:36]:
And it's not just like, here's the, the interfaces. There's, I mean, it's been around for 30 plus years. And you can see they've talked about just about everything that's in there. And it has a nice little search bar at the top. And they also have a form and you can search that there, and there's just a lot of valuable content there and you can really find a lot of answers to many questions. Just search the forums, search the docs. So reach for that first. Secondly, for, like, situations where, you know, I sort of have this unique problem or I kind of want to do this somewhat unique feature.
Stephen Margheim [00:56:22]:
How can I do that with SQLite? There is a quite. I mean, fairly robust you know, I don't know numbers. I I haven't dug deep into postgres, but there are a lot of SQLite extensions. And, they add all kinds of different functionality. So whether it's, you know, the hot new stuff of storing vectors in your database so that you can run some form of AI feature inside of your application. There's a SQLite extension for that. You know? There there is the equivalent of pg vector for SQLite. You can add it in.
Stephen Margheim [00:56:58]:
You can store vectors. You can query them and retrieve them and and many, many others. So start there. You know? See, like, hey. Is there an extension to do this? And then the third one would be if those things fail, there really has been a growing number of people, interested in working with this. And the online community, in my experience has been very welcoming and very positive. And you can just throw something up on Twitter on Stack Overflow. And I think you're very likely to get some useful and good responses.
Charles Max Wood [00:57:43]:
Super cool. Well, we're kind of at the end of our time. Was there anything else that you wanted to make sure that you covered, Valentino?
Valentino Stoll [00:57:50]:
There was something I'm trying to think of it, but
Charles Max Wood [00:57:52]:
he had you at machine learning. I know.
Valentino Stoll [00:57:54]:
Yeah. I know. I got sidetracked in my head. I I have a lot of questions there, but, Yeah. I guess, like, have you hit any limitations as far as, like, I think of, like, as an example, you know, JSON columns and postgres or doing, you know, database views or things like that where, you know, maybe SQLite doesn't have the feature. Have you found many limitations in that regard, that where you had previously, you know, reached for a certain tool that you no longer have available because of the the database limitation?
Stephen Margheim [00:58:34]:
So the short answer is no. But let me just add, like, I really hope people can will just believe me, I guess, when I say that I really I'm not like, feeling right? SQLite is not paying me any money. I am not making any money by talking about it. I'm not trying to get you to, you know, buy my SQLite SaaS or anything. So this is I'm not just trying to, like, be a hype man. There's there's no value or utility in it for me.
Charles Max Wood [00:59:06]:
Right.
Stephen Margheim [00:59:07]:
It is interesting that, like, it I was in the exact same boat. Like, I don't know what it is. There's just like something, you know, a general myth on the Internet. It's like SQLite is anemic. Just doesn't have a lot of functionality. It's small. It's weak. It's like, nope.
Stephen Margheim [00:59:24]:
JSON columns, got them. JSON operators, got them. Generated columns, Got them. Views. Got them. Store generated columns. Got them. Honestly, the there are really only 2 features I've been like, you know, it'd be really cool if SQLite added them.
Stephen Margheim [00:59:42]:
So one is, gin indexes from Postgres. Like, that's just a really useful I mean, generic, index. It's nice to have. SQLite doesn't have it. So you can have SQLite columns, but you can't index them as easily. And if you wanted to do something like that, you do have a workaround. Like, you can make a stored generated column. So, like, extract out the parts that you want to index as a as a store generated column and then index that sort of generated column and query against that.
Stephen Margheim [01:00:18]:
But doesn't have gin. Gin would be nice. And then, of course, right, like, it would be cool if you could do concurrent rights. That would be great. You can't. But, that would be nice. Aside from that, I personally have not come across any feature that I have needed to or wanted to build that SQLite didn't provide. And I was in fact, surprised, actually, as I dug into it more like, oh, okay.
Stephen Margheim [01:00:54]:
SQL actually does support, like, basically, the full you know, it supports the full SQL standard and a lot of the stuff that isn't in the standard that, you know, Postgres or MySQL, like, this would be a nice feature. So I was like, sure. It sounds like a nice feature. I'll add it. So I'm not just a blind hype man, and I don't think SQLite is the solution to all things, but really genuinely think there are a lot of limitations like we need to start fighting back against this myth that it is an anemic tool. It's the most widely used database in the world. It's the best test database in the world. It's one of the it is older than the other 2 major databases, MySQL and Postgres.
Stephen Margheim [01:01:37]:
Like, it is resilient. It is powerful. It is well tested. It is flexible. It is easy to learn. There really aren't reasons to not use it unless you're building the next, you know, fathom analytics and you really do need 1,000,000 rights per second, then, yep, there's a reason not to use it.
Valentino Stoll [01:02:03]:
Just one last note. There's a famous, you know, learning experiment where if you wanted to, like, learn a new language as an example, there's a build your own SQLite database kind of tutorial that lots of people follow, because it does, like, you know, everybody wants, like, a REPL. Right? Like, everybody wants to be able to store data, read data from files. Right? And, like, SQLite does all of these things that are very just common patterns for languages. You have to learn to do the core tenants of whatever it is that make it be a database, like, from a file system, which is kind of interesting. So, speaking of pics, you know, I I might as well pick that. It's like how to build a SQLite database. But I've definitely started one in Rust, which is just for fun.
Valentino Stoll [01:02:55]:
And it's it's amazing how simple, like, as you mentioned, SQLite, you know, it really is under the hood, as far as storing things. And this is fun. It made me think about it.
Charles Max Wood [01:03:08]:
Cool. Alright. Well, I'm gonna push us to picks. Valentino, you got some picks?
Valentino Stoll [01:03:15]:
Yeah. I've I've been loving a llama, which I know has been mentioned on the show before, and by others, but it is a a way to run local inference on your machine against many, different open source large language models. It's kind of fantastic. It runs as a server, so you can serve many different models, optimized automatically with whatever GPU you're running, and you configure it to offload some of that to the CPU. And it's pretty fast and just it has saved so much time just like investigating and evaluating other models that are out there. And you can even build your own models and serve those locally, which is kind of wild. So I highly recommend checking it out if you haven't.
Charles Max Wood [01:04:03]:
Awesome. I'm gonna jump in with my board game pick first. So I'm gonna I went to Salt Con, which is a local, board game, convention. And I really had a good time, just hanging out with one of my buddies the whole time and we ran into some other people we knew there. So, anyway, it was awesome. So shout shout out to SaltCon if you're in or around Utah. They're doing another one in June, and I'm hoping to get a ticket to that one. I haven't bought one yet, but we're we're kinda doing that thing.
Charles Max Wood [01:04:43]:
Also, before I do that, I should probably mention that I am looking for work. So if you're hiring contract or full time, I would love to hear it. Chucktopendevs.com. Alright. So the game I'm going to pick is the game I played there. It's called apiary. And, so board game geek, I'm just gonna warn you. This one's on the more complicated end.
Charles Max Wood [01:05:08]:
It was definitely fun. There were some unique things, but board game geek has a, has a weight of 2.96 on it. That's out of 5. So, you know, there are fours and fives and usually those ones will run for hours. APRE did not. I think it took us an hour to play it with 4 players, but it's, it's pretty involved. So, if you don't like the games where you have a ton of stuff to keep track of, then this isn't the one for you. But if you want one that has some mechanics and, you know, you have to kind of figure out what strategy you're going to jump on, it's a terrific game.
Charles Max Wood [01:05:43]:
It was a, it was a lot of fun. It's kind of a blend between like worker placement and, I don't know. There were some pretty unique mechanics. So, every time your, every time you placed your worker, if there wasn't room for your worker, then you would bump somebody else off the board And that bee would go back to the hive, but it would get promoted. And then once you got promoted, if a 4 got promoted, it hibernate and then go back to 1, right, instead of level 4. And so anyway, but the number on the bee and the number of the other bees on a particular spot also determine what you could do there. And so anyway, and the number fours also have, unique abilities at each space. So anyway, lots of stuff, just really, really interesting game.
Charles Max Wood [01:06:38]:
It was almost too much. There were almost too many things going on, to make it just super laid back fun. But anyway, I did really enjoy the game. And, it's it's on my list is one that I may eventually go by. So I'm gonna pick it now. If you didn't pick up on the theme, apiary is, like an aviary is for birds. Apiary is for bees, and it's space bees. So you're adding on to your spaceship and stuff like that.
Charles Max Wood [01:07:09]:
So, anyway so, yeah, so that's my board game pick. And, yeah, I'm I'm actually just exhausted because I've been working on been working on a bunch of stuff for Super Tuesday because I'm involved in, state politics stuff here. So I'm just going to end my picks there and just remind you if you want to hire me to let me know. Steven, what are your picks?
Stephen Margheim [01:07:43]:
Yeah. So I am friends with Bull Drapper who built and maintains the Flex Gem, if anybody's heard of that. And if you haven't, let me give you a quick intro there. Flex is a Vue component gem for Ruby. Not the Vue component gem, but the gem for for writing views in Ruby. And specifically, it does everything in Ruby. Right? So it maps elements to method names and attributes to keyword arguments and children to blocks. It's a really great gem.
Stephen Margheim [01:08:32]:
And specifically, lately, the core team has been working on a really awesome feature that I want to make sure as many people as possible know about because I actually think it can, you know, I hate to even say these words, but I think it could possibly revolutionize how we do, our our rails applications. And so what is the feature? The feature is selective rendering on the server side. So conceptually, it is very similar to how turbo frames work. Right? So you have a turbo frame on your page. It has ID turbo frame 1, And you click a link inside of that turbo frame the way that would be managed by rails presently. It's like that link gets sent up to your application. The controller processes it, finds the appropriate view, renders that view, sends that view back down to the client. On the client side, there is JavaScript that says, oh, you know, this is a response from a turbo frame request that we made.
Stephen Margheim [01:09:40]:
We made that request from turbo frame 1. Let's parse this view and find where Turbo Frame 1 sits inside of it. We'll pull it out, throw all the rest of it away and replace the contents of turbo frame 1 with the new contents of turbo frame 1. So you on the server, you're rendering everything, so you have some waste. But you have the benefit that you get to use your existing rails routes. You get to keep all of your existing, controller logic, rendering logic, database access logic. So you you treat it as if it's just a regular page visit. But you have excess content that is sent in the response.
Stephen Margheim [01:10:34]:
And then on the client side, you have to take all of that content. You have to parse it and find the subsection, to pull it out and replace the frame. The feature that Flex is adding now allows you to do that exact same thing, but all on the server side. Right? So you send a request up from turbo frame 1. You say, hey. I want to run frame 1. It's just a regular link to a regular normal route. Controller receives it, goes to render it.
Stephen Margheim [01:11:08]:
It's rendering a flex view and not an action pack view. And that flex view is past the content that that or that context. Like, hey. We want turbo frame 1. And so now all of your flex views, it'll start rendering, and it's just gonna no op all of those methods, you know. So your HTML, your body tag, your h one tag, your all of that. Okay. Those are methods we're just gonna no op them until it finds the method that has ID turtle frame 1.
Stephen Margheim [01:11:42]:
It's like, oh, okay. Now it's time to actually render. And so then Flex will render all of that content, package it up, and send back just that div or section frame, whatever. You know? So you get 2 or I guess 3 big benefits. So the one is you get to keep the same simplicity of your real application getting to be structured as if all of the interactions you're doing are standard stateless HTTP interactions pull full page refreshes. You don't have to set up a whole sort of, like, separate components namespace where you render specific things. But you get the second benefit of sending the minimally small payloads over the wire, only the content that you need, with the third benefit being that you only have to render the content that you need. So your rendering times actually speed up as well.
Stephen Margheim [01:12:50]:
So this is available now in, like, the alpha release of flex. It will be, generally available when they release version 110. And, we're doing a lot of thinking and a lot of work now to really make the integration with Hotwire and Turbo as seamless as possible. But I think that this kind of general shift in thinking, and leveraging these kinds of tools is going to be really, useful and valuable for Rails applications. So that is my pick, black selective rendering.
Charles Max Wood [01:13:35]:
Awesome. Very cool. Alright. One last question. If people want to find you on the Internet, where are you? Yeah.
Stephen Margheim [01:13:42]:
So I have at fractalmind on Twitter and GitHub. My blog is fractalmind.get hub.io. And if you want to meet up in person, or you just want to get more confident and comfortable with building Rails applications with SQLite, I am going to be at RailsConf in Detroit in May, and I am hosting or leading a workshop there on the 2nd day on building Rails applications with SQLite. And we're gonna cover everything that I know in as much as that as possible. So the goal is that coming out of that, everyone will feel comfortable and confident with, using this stack and using these tools. So a lot of, exercises and content there, it'll be a fun to our workshop. And, otherwise, happy to meet up, have a soda with, anyone in Detroit as well if you're gonna be there for rails comp.
Charles Max Wood [01:14:47]:
Awesome. Alright. Well, let's go ahead and wrap up. Thanks for coming, Steven. This was awesome.
Stephen Margheim [01:14:54]:
Thank you.
Charles Max Wood [01:14:56]:
Alright. Till next time, folks. Max out.
Hey, welcome back to another episode of the Ruby ropes podcast. This week on our panel, we have Valentino Stoll.
Stephen Margheim [00:00:13]:
Hey now.
Charles Max Wood [00:00:14]:
I'm Charles Max Wood from Top End Devs. We already have people coming in on the live stream, which is awesome. I think they're all coming in on, Twitter. We have a special guest this week that is Steven Margine. Steven, welcome to the show. Do you want to introduce yourself real quick?
Stephen Margheim [00:00:32]:
Yes. Thank you for having me. As you said, my name is Steven. I am living here in Berlin, Germany, though I am originally American. Just got married earlier this month.
Charles Max Wood [00:00:45]:
I saw that on Instagram. Congratulations.
Stephen Margheim [00:00:48]:
Yeah. Thank you. And excited to be here and talk about SQLite and rails.
Charles Max Wood [00:00:55]:
Very cool. So, where do we start? I'm just gonna give a little bit of context because, I mean, I've used SQLite, but I mean, everything I do, I do on Postgres. I think most Rails developers go that way. But I think SQLite is also the default if you start a new Rails project, or at least it used to be. Anymore, I just tell it, no, I I want Postgres. So yeah. If you know, you're talking about SQLite like it's a serious database on Twitter.
Stephen Margheim [00:01:32]:
I know. Weird. Right?
Charles Max Wood [00:01:34]:
I know. I I couldn't think of a better way to put it, but the way you talk about it and the way we talked about it on the Ruby Dev Summit, it made it you made it sound like you could honestly use this in other places, and I've heard other people being interviewed. I I think somebody from PlanetScale or one of the Internet hosted databases was talking about how SQLite is the real deal now too, not just MySQL or Postgres. So yeah. Is it the real deal, and why change our minds?
Valentino Stoll [00:02:10]:
Well, it is the real
Stephen Margheim [00:02:11]:
deal, but like with any database, and this is, I think, the the key point, there are trade offs. So at, like, a very high level, just my sort of sense of things. Right? Like, Postgres is great because it comes with a lot of functionality out of the box, and it has a really rich community of developers and, set of extensions. So I you wanna be doing stuff with vector databases. You've got PG vector. You can plug that into your Postgres database. But compare that with MySQL and the Vitesse sort of layer that can be put on top of that and the scaling that has been done in the last 2 decades on MySQL. There aren't the same sort of solutions that are as battle tested
Valentino Stoll [00:03:18]:
at the
Stephen Margheim [00:03:18]:
same level of scale for Postgres. Right? So something like PlanetScale, which is sitting on top of Vtest, is a relatively unique offering for MySQL. And then SQLite has, I think, a unique sort of value proposition because it offers you, like, the full range of SQL. Like, there's there's really nothing that you need to do with SQL, the language that SQLite doesn't offer. You can, if you want to, run it in a client server architecture. The Libsquel project, which is a a fork of of the SQLite code base by the Terso, guys, And the platform that they are building on top of that is, like, bringing the client server architecture on top of SQLite for edge computing. But you have the option, which is unique with SQLite, right, to run it on your application server machine right next to your rails process and just simply remove network latency as a consideration. And I think that the major, like, shift that has been happening in web development lately has been a growing recognition that SQLite is production grade software for web applications with the caveat that you do have to configure it to be ready to use for web applications.
Stephen Margheim [00:05:11]:
And where I think there has been this odd disconnect is that there's been the sense like, oh, yeah, Postgres, MySQL. These are obviously web application databases. Just get them up and and you're ready to go. But, of course, you have to configure those as well. Like, there there isn't really a database that is completely blind plug and play. And as people have started lowering that barrier to entry and just started to, demonstrate, hey. There is a lot of power here. There's a lot of flexibility here.
Stephen Margheim [00:05:46]:
This is a a model for building and deploying applications that offers some unique value adds, whether it's to developer experience or to performance or to simplicity of deployment. And I think it really is just a question of education around what it takes to get a robust, resilient production grade, deployment of an application backed by SQLite out into the world, and that education has been growing in the last couple of years. So, yes, it is the real deal.
Charles Max Wood [00:06:26]:
So I want you you said production grade, like, 12 times. I I wasn't counting. I'm just throwing the number out there. But, what do you mean by production grade?
Stephen Margheim [00:06:39]:
Yeah. So I think that there have been 3 major barriers to using SQLite out of the box in a web application. And I think it has led to the sense that SQLite isn't production grade. So the first barrier is concurrency. So everyone who has read even a little bit about using SQLite for a web application will very quickly come across people claiming, hey, you absolutely could never use this for a web application because in order to have a web server that can deal with even just a reasonable amount of requests coming in, you're going to take advantage of the stateless nature of HTTP and deal with multiple web requests concurrently with your application process. But SQLite running on that same machine is going to linearize your interactions with the database. And by default, if you don't touch anything, you're using the original model that they have for ensuring transactionality, you're gonna have linear operations whether they're reads or writes. So if you want to do anything, you do them 1 at a time.
Stephen Margheim [00:08:03]:
So the fact that you have concurrent web requests is negated. You you everything bottlenecks at your database, and people say, of course, that's never gonna scale. Now there are 2 key points to make on this barrier. The first one is people really too quickly forget to do, like, the basic math on if you remove latency, and you give yourself some headroom, So you go from talking to a Postgres database over a web connection, which can take, you know, some number of milliseconds to talking directly in process to SQLite, which can take some number of microseconds, you have 10, 100, up to 1,000 more opportunities to do things right when you move from milliseconds to microseconds. So even as you linearize things, you're dealing with different orders of magnitude of latency, and that gives you possibilities. And then the second one is that you can configure SQLite to have concurrent reads. But as of now, there is no way to get concurrent rights. So out of the box.
Stephen Margheim [00:09:20]:
SQLite is linear operations. Web applications tend to deal with concurrent operations, and people think, well, that's a hard a hard no, but it isn't. That's barrier 1. Barrier 2, and I'll just stop at barrier 2, it's the main one or these are the main 2, would be around backups. Right? People are like, hey. This is ridiculous. If you want to have, something that's like making money on the Internet or is in some way trying to be valuable, you need to make sure that it's resilient. Something happens.
Stephen Margheim [00:09:57]:
We know how the world is. The service can get unplugged or storms come in. Who knows what? Right? If you have everything running on one machine, including your persistent data and that machine goes down and your persistent data is now gone, well, it's easy to spin up a new machine in a new application process, not so easy to recover lost data. So the fact that SQLite is on that same machine that you don't have network latency is a vulnerability for persisting your data and keeping your system resilient to system failures. And in the last couple of years, there have been a number of tools that have been built to backup SQLite databases to some other place and to make it easy to take those backups and spin up a new instance of that database somewhere else. The probably the most well known one now, the one that I have used the most is a project called LightStream, which just streams rights to your SQLite database to an s3 bucket or or really any s3 compatible bucket service and has a very simple CLI. You can just pull it back down onto any machine. So when I say production grade, I I tend to mean these kinds of ideas where people think about, like, sure, I can do this, like, quick script on my laptop, and it's nice to have, some quasi persistent storage.
Stephen Margheim [00:11:27]:
But if I'm trying to build a business, if I'm trying to build a SaaS, if I'm trying to build an application that I want to have some meaningful presence on the Internet, I'm gonna need to have the ability to handle concurrent Web requests. I'm going to need to have the ability to spin up new Web servers with my application and keep my data persistent across them. And there wasn't always a clear story for how simple or easy or possible that was to do with SQL app. And that story is being written much more clearly now.
Valentino Stoll [00:11:58]:
First of all, you have a great series, blog series that we should link to on, you know, successful usage of SQLite and Rails and configuration and performance metrics and all kinds of great stuff, that I think people should read and dive into. And I guess, like, my biggest you know, I've been on the same boat of incorrectly thinking for the longest time that SQLite is not performing and, oh, like, don't use in production, but, you know, sure in development or whatever, you know, testing or, you know, even just like small, like, hobby apps, sure could be, you know, fine. But once you get above a certain level or scale or whatever it may be, then it you know, don't use it. And I I'm sure I don't I'm not alone thinking this. Right? Yeah.
Stephen Margheim [00:12:47]:
Not at all.
Valentino Stoll [00:12:48]:
And so right? So you do shed quite a lot of light on, you know, okay, there's a lot of buts in a lot of those, you know, ways of thinking. And I definitely agree with you there, and I'm kind of curious, like, to get some further insight there on well, like, what are the limitations? Right? Like, what point do you hit SQLite and then it no longer work for your app? Right? Because I think that's where a lot of people are still hesitant to dive into it because they still don't know what that barrier is. And then you it's one of those things where, okay, you don't know it till you know it, and then it's too late. And then you're trying to scramble to find another solution. Right? So, like, what are those things? Right? Like, what what should you be looking out for, to know if SQLite is the right option for you?
Stephen Margheim [00:13:43]:
Yeah, it's a good question. It's the question I get most often. And there are a few different angles to take on an answer. One of them is where are you comfortable in investing your right. So if you're someone who has you're trying to start up a side project. You're you're hoping to to get some money with it or just sort of do something of interest and value, and you have a decade of experience with Postgres, and really feel comfortable, like, with the path to evolving a system over time with postcards, you know, just stick with them. These days. It's there's really not actually a lot of limitations with sequelae.
Stephen Margheim [00:14:53]:
So here's here's, like, the first big one that used to be more of a limitation. Right? So there's a major difference between SQLite and Postgres, MySQL, Oracle, like, pick any of the others. Most database engines follow the client server architecture. So it's like you have you you minimally have 2 different processes and and most of the time you have 2 different machines. You've got a machine running your application. You've got a machine running your database. And you most often, right, have multiple clients, have multiple machines running your application and one machine running running your database, and you talk to your database through web requests.
Charles Max Wood [00:15:38]:
Mhmm.
Stephen Margheim [00:15:39]:
And there are, like, there's been decades decades of exploration or, like, different ways to scale that kind of architecture, to make that kind of architecture resilient. And when you go from an embedded database, there's one machine, there's one process. Everything is just happening right there to, you know, something like. GitHub scale, Shopify scale, like, you there's no vertical scaling will never be able to handle that. You're going to have to horizontally scale. So then how do you horizontally scale when your database is living on each machine? That that was a problem. That has been a problem for a long time. And so I I have said, you know, if you are starting a project and the way that it succeeds is it gets to that scale.
Stephen Margheim [00:16:31]:
Right? Like, if you go and get venture money, you probably should have chosen my sequel from day 1. Right? Like you're you're shooting for PlanetScale, not TM, from day 1. But that's actually not even a technical limitation anymore. So whether it is the predecessor to the LightStream project, Light FS, from Ben Johnson at fly I o, which is a tool to have a replicated logical database spread across multiple machines, SQLite database, obviously, or whether you're using a platform like Terso, which as I said, like, brings that client server architecture, but also allows you to have read replicas on each of your machines, and it'll, you know, manage consistency for you. Like, there are now there are others. There are multiple tools now to allow you to horizontally scale a SQLite database. So is is that particular scaling path as battle tested as like the test on my sequel. No, it's not been around for 2 decades You don't have a company like youtube.
Stephen Margheim [00:17:53]:
That's running it. So, again, it goes back to, like, your your risk profile. If you think on day 1, I really want to be at that scale, you know, you probably should just use MySQL and V test. Right? Because the why take the risk if you know that's where you're going? But for someone who is, like, unsure of what the future looks like, I really do think that there are so many wins that you get on day 1 week 1 year 1 with the developer experience and the performance characteristics and the power and simplicity of like leaning into vertical scaling for as far as that will take you that you should really give SQLite a long look. And you can fall back on the security bill. Like, if you really do get very successful, sex successful such that, like, vertical scaling can't work for you anymore, you don't have to change databases necessarily. But the other thing that's true is, like, if you do get to that scale, you're probably making money and probably good money. And at that point, you probably could change databases if you want to.
Stephen Margheim [00:19:12]:
And going from a SQLite schema, which is, you know, it's gonna be a looser schema typically to post cross for my sequel. I think is generally easier than the reverse direction. So I talked around your answer. The short answer is I really can't think of, like, really hard limits, to be perfectly honest with you. But I do think that there are different risk profiles, and there are different reasons why you might or might not choose to use it. But, like, as of today well, okay. I say that, of course, I should say out loud. There is the one key limitation, right, which is if you have, like, massive right throughput, if you're building an analytics platform to compete with Google Analytics and you're just gonna get like, the core of your business is you need to deal with massive amounts of rights.
Stephen Margheim [00:20:06]:
Don't choose SQLite today. That would be a hard limitation. They are working on concurrent rights, so that limitation might not be true in 1 year. But for today, I would not build a analytics platform on top of SQLite. How about that?
Valentino Stoll [00:20:28]:
Yeah. That makes sense. I mean, I'm thinking more I mean, we should also not build an APM with SQLite.
Stephen Margheim [00:20:37]:
Yeah. Again, it it does sort of, like, come back to your your expected growth profile. I have built an APM with Sequoia. It's a very, like it's an internal small one. Right? But I was like, I'm not expecting if, you know, the the 37 signals crew have talked about load testing their SQLite backed campfire application. And on the biggest machines that they have, you know, with their cloud exit, they're they're running their own machines in a in a data center. Like, their beefiest machines, they're getting, 50,000 concurrent requests. Are there APMs that could handle that? Like, yes.
Stephen Margheim [00:21:25]:
Right. If you like, I wanna build a business and I am either the next app signal or I have failed, yeah, I I probably would not choose SQLite on day 1. Again, my my sort of hot take on this is, in all of the recent Internet drama aside, I personally would probably choose either SQLite or PlanetScale on day 1. Those are the 2 options I would choose. Like, I'm either going for big scale, and I know that. Like, that's the characteristics of the app I'm building, or I'm just doing regular scale. And SQLite handles regular scale, quote, unquote, right, like, good luck getting if you can build an application and and you have 50,000 concurrent requests, like, good on you. You have you have definitely succeeded.
Stephen Margheim [00:22:17]:
So short answer is maybe, you know, honestly, maybe.
Valentino Stoll [00:22:25]:
It's it's just funny to me because SQLite comes out of the box of the reels. And for the longest time, you know, you question it, like, everybody's using SQLite. And the more you use reels and you the more, like, one off apps that you start to make. Right? Like, even just, like, trying something out, like, it's great. It does most of what you need. Right? Like and I feel like most people won't even hit the limitations of it or see any side effects of that, you know, until much much later to your point where there is an actual, you know, limitation and you have the need, the financial, you know, ability to to navigate that. Right? And I feel like most people won't even get there, you know, to be honest. And, I mean, in in all honesty, thanks to the Shopify folks for all of their efforts with it, as far as, like, you know, LightStream as an example.
Valentino Stoll [00:23:23]:
But, you know, all all of the other integrations to just make it super straightforward to get set up and and operational, like, I don't know. I feel like, why bother? Why bother having like, I'm definitely coming around to that, off the cloud, idea for for it specifically of, you know, why have all these extra services, that just aren't needed, and it's just to help you scale maybe?
Stephen Margheim [00:23:58]:
Right? Yeah, I mean, this has been one of my, like, major realizations and principles that drive a lot of my personal interest in the topic is recognition that like, for me myself, I really am trying to be conscientious about fighting off unnecessary complexity. Like, it's just swarming around us, and especially like, for where we are at in the evolution of the Internet and the economy of the Internet. Right? Like, everything is a SaaS now. Everything is a product now. It's like, hey. You need authentication? Here's the SaaS you buy. You need, emails? Here's the SaaS you buy. It's and it is you know, it just, like, grates on me to see how, like, common the, I don't know, the mind virus.
Stephen Margheim [00:25:01]:
I'll be sassy. Is that the correct way to build a web application, a service, a business is to sign up for 15 different SaaS platforms. Mhmm. Stitch your things together have no real ownership or understanding of like, what your ranking app is doing, then like, I mean, and we've been seeing more and more of it. Right? Like and then you actually get some success or more commonly, the actual noise of the Internet and the the people who just like doing naughty things and having their little bot farms run. And you just like, boom. All of a sudden, like, whoops. Like, I have a bill for $10,000 from this one service for this month.
Stephen Margheim [00:26:00]:
And, yeah, as you said, I mean, it's like it's actual, like, statistics. Like, most applications are not going to actually need like there's real value there. I'm not saying that most of these businesses shouldn't exist. They should exist, but most people shouldn't pay for them. Right? Like we servers are cheap. Servers are easy. Like, I'm no DevOps genius. I'm certainly not an ops genius.
Stephen Margheim [00:26:25]:
I barely can use Docker, you know, but I have spun up many, many servers in my day, and it's not, rocket science. I have maintained them. That's also not rocket science. It's not incredibly stressful. It can be when you make like mistakes. And that's why this concept of production grade is important and to have a sense of like, what does it mean? You know, to give to give one specific example? I had an application that we use at work for business that provides profit running on SQLite. And I had been thinking for a while, you know, I really need to go in and install LightStream and set that up, but it didn't get around to it. And then one day I was cleaning up and renaming my applications to make them more consistent.
Stephen Margheim [00:27:27]:
And I did not recognize that in the little web platform that when I rename an application, what it's gonna do on the server is it's gonna do our MRF and then, redeploy. And it wiped my SQLite database. You know? And I spent, like, a full day trying to recover it from memory, and it did not work. And I I had to go back to the business and, yeah. You know? That was a shitty day. And I had to put in backups after that. Right? So this is why I do bring up production. It's like, yeah, you know, you can foot gun yourself, but you can set up backups for post grads or my sequel or anything.
Stephen Margheim [00:28:08]:
But, like, none of these things are difficult, and I it just saddens me to think that so many developers and especially newcomers, like, come into web development and think like, a, you have to understand docker and kubernetes and Serverless you have to pay for 15 saas platforms. It's like man, it's gonna take a PhD in web development and at least $500 a month to even like start to do something It's like that just isn't true. Like more people can get started with less, crap and less upfront money. And I really want to make it as widely known as possible. Like, there's there is this alternative path. You know, you can just go get a DigitalOcean droplet, put a rail server in a SQLite database like you have one machine, and you can grow that. You just, in your little DigitalOcean dashboard. Like, you could just bump it up over time and you can do that for a long time.
Stephen Margheim [00:29:10]:
Like, go and look at the biggest machine on there. It's really big and it can handle a lot of requests And SQL, I can handle a lot of requests. And these things, like, can be cheap, and they can be simple. And that opens up opens up so much opportunity for, like, experimentation and more people coming in and trying things out and That's like that's what drives the passion behind it. Right? It's like doesn't have to be this other way.
Valentino Stoll [00:29:35]:
Yeah. I feel you on the mindset. Thing. Yeah. It just reminds me of CGI. Right? Like, back in the day, you you had a directory CGI, and you uploaded a programmable file, and it ran. And, you know, it was that easy. Yeah.
Valentino Stoll [00:29:54]:
Everybody had FTP client or whatever. You know, you just uploaded the file, and then you are ready to go. And, like, people ran, like, legit businesses off of it, you know, where, you know, guitar tab sites or, like, you know, all all of the original search engines, you know. It was just like a handful of programmatical files in a directory somewhere, and it just ran. And I feel like, you know, may maybe we're, like, a little bit beyond that. Right? But it should still be that easy. You know? It's like the underlying technologies haven't really changed that much. You know, like, you still have servers and clients and a browser, you know, and it's it's those three things.
Stephen Margheim [00:30:42]:
Yeah.
Valentino Stoll [00:30:42]:
Yeah. I was just Why make it more busy?
Charles Max Wood [00:30:46]:
I was just gonna add with all the different SaaS products you can add. Right? So top end devs for a long time ran the authentication through one of the authentication authentication services out there that you pay for. And yeah, it was more work to set up and manage that than it was for me. Eventually, I just switched it back over to device. Right. Because I set it up once and then, yeah, occasionally I have to help somebody reset their password or something stupid. Right? Hey. Oh, yeah.
Charles Max Wood [00:31:17]:
I jacked that up. Let me fix you. Right. And, and yeah, I feel this on the rest of the infrastructure too. Right? I mean, one of the things I really like about Kamal is that it kind of does that. Right? So it pulls down the Postgres, Docker image. It pulls down the red as a Docker image. It pulls down, you know, a Ruby Docker image and then runs my Docker file against it.
Charles Max Wood [00:31:41]:
And then it says, hey, that's over there and that's over there and that's it. Right. And load balancer. It does a load balancer too. And, and that, that's what I love about this. So yeah. Having something simple where it's just like, oh, yeah. It's just gonna run alongside the the app the app server.
Charles Max Wood [00:31:57]:
Right? Run alongside Puma or whatever. Yeah. This is beautiful. Right? I don't have to fuss about it.
Stephen Margheim [00:32:07]:
Yeah. Exactly. And then on top of it, you get, like, these really nice benefits of like, it's, I would recommend for developers to just like, spin up an app and throw it up somewhere. Right? Use Kamala, use Hashbox, like, use it or, like, do it quick. Do it easy and just, like, play around and get a feel for what it feels like on, like, 2 fronts. And this is where it, like, really sold me, and I, like, became passionate about it. So the one is it is it's just really nice to have a simple enough system that you can keep it in your head. And so the fewer moving parts, the simpler the system.
Stephen Margheim [00:32:56]:
And, like, I have these applications that I have built at works, you know, sort of like these r and d applications that, I am effectively the sole developer and maintainer of them. And, you know, I'm an engineering manager. I'm in a lot of calls. I have, like, these 30 minute windows sometimes between calls. And I have to debug production issues that come up. And I can actually do that. I can go from, like, I haven't heard anything. I get a Slack message.
Stephen Margheim [00:33:28]:
I read the problem. From that moment to I have checked that the fix is live and fixes the problem in production, I have consistently been able to do that inside of a 30 minute window for over a year. And that is like a magical feeling. I I I'd every single time I do it, I'm like, wow. This feels amazing compared to most of my work experience. And that is, like, driven by I have a Rails app and SQLite installed. That is it. I have nothing else.
Stephen Margheim [00:34:03]:
I don't have Redis. I don't have I have nothing. I have, like, 4 different SQL databases. Right? I've got my Q database and my cache database and my models database. Or, you know, production databases, what it's called. But I have this one piece of software. And that piece of software, I don't have to do anything weird or fancy. It just runs inside of my application process.
Stephen Margheim [00:34:29]:
There's nothing to, like, spin up. I don't need to have a proc file necessarily, and it's just is there. And that, like, developer experience is so nice. And then, like, on top of it, it's just like a file. And so if I need to, which I've done many times, right, like a production issue comes in and I can tell, you know, some data has gotten out of sync here, but I don't know exactly how or where or what I need to dig into the data. And I can literally, like, do a safe backup. I can use the fact that I have these LightStream back because I can just tell LightStream on my laptop, hey. Replicate the database to my laptop, please.
Stephen Margheim [00:35:10]:
As of right now, what is the current state of the data? So I get a a mirror of the production database on my laptop. I spin up the app on local host. I've got all the production data, and I can mess around and figure out, like, where is the where did the data go wrong? Where's the bug in the background job that messed this up? And I know it's completely safe. I don't have to remember to do the dash dash sandbox in my Rails console or any of that. And it it's like, you know, one CLI command to get it down there. And there's, like, so many of these little things. You know? Whether it's the one of the first articles I wrote was on doing database branching locally with Git. And it's, like, the simplest thing in the world to set up with rails.
Stephen Margheim [00:35:55]:
And it just removes an entire class of problem that has annoyed me for a decade of web development when you're working across these different branches and your, you know, your schema gets borked. And there's just like they stack. They stack all these things. And then at the very end of it, you're like, oh, man. Every single database operation I have done went from n number of milliseconds to n number of microseconds. Like, I just got a 100 x performance improvement. You know? Like, action pack is my bottleneck for all of the rails apps that run the stack. You know? So that is awesome.
Valentino Stoll [00:36:36]:
Real quick. Just dive in deeper to the, the branch specific databases you're talking about because I thought this was fascinating reading through this. Like, how does that setup work, and and what are you saving there?
Stephen Margheim [00:36:48]:
Yeah. It's, it's a really nice feature. Let me start off by explaining, like, the problem. So here's the scenario that many of your listeners are likely to have experience. You're working in a feature branch, so you git checkout dashb feature a. You get to work. It's a long running feature branch. Kinda complicated.
Stephen Margheim [00:37:11]:
As a part of the feature work, you have to make changes to your schema. So you generate, let's say, 2 different migration files. You add in a new table and you have, renamed a couple of columns on an existing table. While you are in the middle of working on this feature branch, a major production issue is reported and a bug fix needs to be made. Someone has created a hotfix branch, and they ask you to review it. You're like, okay. I did the code review, but I wanna make sure before we push this live that, like, the fix is actually doing what we wanted to do. So you git checkout hotfix 1 and run your application, and things aren't working.
Stephen Margheim [00:38:02]:
Maybe, like, your Rails app won't even boot. Maybe as you boot into the app, things are thinning. Like, what in the world is going on? What is, like, what is broken here? Something is very clearly broken. And what has happened is that the schema changes that you made to your single only local, you know, development database in feature branch a are still there when you checked out hotfix 1. But hotfix 1 doesn't expect those changes to be there. You rename some tables or some columns on some tables. And the code in hopfix a expects the database to be in the schema that existed in main, but your schema locally is different. And so database and the app have a mismatch, and things blow up.
Stephen Margheim [00:38:44]:
Yeah. Ugh. This is so annoying. So you have to, like, get your database state back into a correct place and then be able to once you're done reviewing that hopex or however, you know, you you change branches and you get back into the feature work, you wanna bring those changes back. So that's, like, the problem, and it's, an annoying problem. And there are various gems out there to try to help you with that. Here is the simplest, most resilient possible way to solve that problem. If you could, in some magical way, have every single git branch have a completely separate database, well, then, definitely, you would never have this problem.
Stephen Margheim [00:39:24]:
That would be nice. Now when you're running Postgres, that might be tricky, might be possible, or it might just be computationally expensive or space events. Who knows? I've not really honestly tried it. But with SQLite, it is both cheap and easy, and all that it requires is you take advantage of the fact that the database YAML file that Rails uses is processed by ERB. So you can just throw some ERB in there. And in that ERB, you can run shell commands. So you can just plop in there. Hey.
Stephen Margheim [00:40:00]:
What is my current git branch name, please? And you can make that the name of your database. So now you have dynamic database names. Then the only other thing you need, SQLite itself will automatically touch non existent database. So if you say SQLite, please open database a. That file doesn't exist. SQLite will just create an empty file. So all you need is to ensure that when you start your Rails app, if your database hasn't been loaded, right, run your migrations, load the schema, however you do it, that it is. Right? So you just wanna say, take whatever the current encoded version of my schema is in my repository and run that.
Stephen Margheim [00:40:50]:
So what I typically do, and I think what's in the article is, like, it will run your migrations. And you can do an after prepare block in your development dot erb configuration file. So with those two changes, what you have done is you have set up a system where whenever you change git branches and in any form, you boot your rails app. So that can be starting the rail server that can be starting your rails console that can be using the rails runner. It will create, if it doesn't exist, a new database file. It will run all of your migrations and get the state set up. If a database file does exist, but there are some new migrations, it'll just run those new migrations and get the state to where it needs to be. And you can then enhance that if you wanted to.
Stephen Margheim [00:41:43]:
That's, like, where I stopped in the article. I need to write some more about it, but it's it's very easy to enhance that and, like, you can do seeding. You know, you can have generic seeds that are always run so you can have a baseline set of data that's populated into all of your branches. You can set up some branch specific seeding, such that you, and you can make that more generic like around scenarios. There's all kinds of fun things. But in general, you have the ability to have completely isolated, like, actually separate databases for each of your git branches. And so it simply becomes impossible to run into the super, super annoying when it happens because it's like, you know, you're completely blocking me in the moment where I don't wanna have to deal with any of this these schema conflicts as you move across git branches.
Valentino Stoll [00:42:33]:
That's interesting. I I mean, how do you do you do you not mind data getting blown away between branches at that point, or have you solved that problem and, like, you know, stream some updates?
Stephen Margheim [00:42:48]:
Yeah. So for, local development, I have ended up with a mix of a couple of things. And I have a couple of later blog posts, about this, but I should honestly finish up writing some of the other stuff I've done. But in general, I tend to start off with just like a generic seeds file. It's like, let me have some usable data. And, yeah, that 75% of the time, that is sufficient. For some applications, I have ended up in a place where it's like, well, I have kind of built up a whether it's like pulling down a production database or pulling down a staging database, like, I want to keep this across, branches. And, I have just written some Ruby scripts, basically.
Stephen Margheim [00:43:54]:
I have a I have a blog post about this. So it's like, you know, DB clone. And I just say, okay, I wanna take this database, and I want to clone it into a new file with this name. And then I am just wiring up the name that I point to in my data c able to that. And there's some automations you can layer on top to connect that to get if you want. For the most part, what I have found is, like, when I want to control the actual data, the schema and the data, I was like, I want this file that, I sort of move away from the automatic Git branching stuff, and I just manually go in and say, comment out my default database line and database YAML and just point it at a particular file. So if you were to look at, like, my laptop for most of the apps I work in and you look in my storage directory, on average, you will probably see at least 12 different SQL I three files in there. So I just create a bunch of these different scenarios.
Stephen Margheim [00:45:00]:
I pulled down production on this date. I pulled down staging on that date. I've created this git branch and that git branch, and they all live there. And sometimes I manually point my app to one of them, or branch off and just do manual branching as if it were getting me like, well, I wanna sort of play with the schema and the data in this direction, give that a name, and wire the app up to that. And it's all, it's, like, quite simple, but it is quite nice to be able to, like, have that flexibility. Your schema, your data, you have the the full range of, like, logical branching that you could do with Git and, text files with your database.
Valentino Stoll [00:45:46]:
Yeah. It's super cool.
Stephen Margheim [00:45:48]:
Yeah. I mean,
Valentino Stoll [00:45:48]:
look looking more looking more at the, configurations you got for, like, having multiple databases, all SQLite. Like, do you find that there's, like, a limitation point of, like, too many databases of the same SQLite server, like, surveying for, or or where it's just, like, becomes too unmanageable to, like, reason about all of the different things. Right? Because I saw you have, like, solid errors, which is kind of interesting where you're, like, you know, storing all of your errors off to its own database. Cache, I imagine too. Right? Like, you start like stacking up all these different databases. Is there is there a limit to the madness? Or is it like, still pretty reasonable, you know, for everything that you'd need?
Stephen Margheim [00:46:38]:
So if there is a limit, I haven't hit it. The most databases that I have in production is, like, 6, I think. And, like, operationally, that it's nowhere close to that. I'm not even sure if there is a limit. But conceptually, no. It hasn't been that bad. What I have found is, like, you know, for the nature of the system, I'm gonna have this bucket no matter what. I'm gonna have to do some kind of IO or some for an object of this type no matter what.
Stephen Margheim [00:47:13]:
And for me, it is a conceptual win to keep the actual operational infrastructure there like the same. You know, I I have been able to become a master of rails and sequel. That's it. And I can do everything I need. So I don't know all of the Redis commands. I don't know all of the Redis data structures. I have a passing awareness of them, and I wouldn't know how to optimize a Redis instance for caching. I don't know how to optimize a Redis instance for background jobs.
Stephen Margheim [00:48:03]:
I don't know is would Redis be a great choice or a terrible choice for the back end for something like solid errors, you know, storing exceptions that happen in your application somewhere. So being able to leverage a flexible, powerful tool across these different problem domains and, you know, give myself the challenge, but also give myself the time to become a master. Like, I know how to optimize SQL queries for caching. You know, I know I've spent time and I've thought about that, and it's just SQL. And I know that language, and I know it well. And I know how to optimize, like, out of structure tables and what kind of queries to run and make sure I know how to optimize, SQL and SQLite for a background job queue. I know how to do that for errors. And each one of those, I am able to leverage expertise that I have gained in the past ones.
Stephen Margheim [00:49:06]:
You know? Like, there's a lot of overlap. So if you wanna have a good schema for your active record models, a lot of the wisdom and principles that are you're gonna learn in that problem area are gonna roll over when you're like, well, what if what would it look like to back a a queue, a job queue with SQL? Okay. Let me think about how to, you know, scheme that out. What kinds of queries? How do I wanna deal with this stuff? And it is and what's really nice in the rails ecosystem as 37 signals has gotten into building new applications, has gotten into SQLite, and, has been exploring the benefits of reducing the number of moving parts and publishing more of these solid star gem solid cue, solid cash, solid cable, I imagine is being worked on is that I don't even have to be the only expert. You know? There is now a community of experts, and I read through the like, for example, the solid Q source code and. Rosa did a way better job at it than I did. You know? So it's like, I just get to take advantage of the fact that she is a really top notch developer who spent a lot of time thinking very deeply about how to structure a queuing system backed by some persistent SQL database. And I just get to run bundle add.
Stephen Margheim [00:50:50]:
You know? Mhmm. So I haven't gotten anywhere close to a limit, and I have actually found, like, every single time I do it, I'm like, you know. I should have more databases like I'm right now working on another gem, which is like the conceptual sibling to solid errors. I think I've named it solid metrics, right, which is just let me keep track of the metrics. Oh, you know? I wanna know them. I don't have super high needs. I don't have a lot of customizability. I just need to know the the basics, rails, instruments itself already.
Stephen Margheim [00:51:26]:
You know, it's the same thing with Aries. It's all instrumented. I just wanna put them somewhere and put a very basic web UI on top of it. Mhmm. And, you know, I've got, like, 3 more ideas on top of it. So probably, you know, come back to me in 2 years. I'll probably have, like, 12 different databases in some application somewhere in production and might not be ready to stop there either.
Charles Max Wood [00:51:48]:
Very cool. So I guess my question is because you you said I know how to optimize SQLite for a queue. I know how to optimize it for something like solid air. I know how to optimize it for, you know, whatever else. How do I figure that out? I mean, do I just Stack Overflow the thing or I don't know how to tweak SQLite for my use case?
Stephen Margheim [00:52:15]:
Well, I'll start by just distinguishing one one small point, which is that, you know, for for those particular domains, that's just SQL, not SQLite. You know? Like, what what kinds of tables with what kinds of columns and what kinds of indices?
Charles Max Wood [00:52:29]:
You're talking to structures
Stephen Margheim [00:52:30]:
and not query structure. If you know? So somebody, you know, Mike had to think about which, Redis data structures and Redis commands should I use to have a resilient and performant job back end. And other people I've thought about if I've been to, like, have those same behaviors, but I wanted to back it with a relational database, how should I structure my tables? What kinds of indices should I have? What kinds of queries should I write? How do I do that resiliently and performantly? That's a SQL problem. Okay. But when it comes to SQLite, I would say there are sort of 2 parts to an answer to your question. So one part is one of my goals is to make the amount that you or anyone else would have to learn about SQLite to make it work incredibly well for a Rails application specifically and for a web application more generally as close to 0 as possible.
Charles Max Wood [00:53:32]:
Right? So, you know, we That's what I want to as the user.
Stephen Margheim [00:53:36]:
Yeah. I think it's what I would have wanted where I not the person who got, you know, sort of infected with the bug of really getting into it. But one of the great levers that is available in using a web application framework is that these kinds of things can be pushed into the framework itself. So, you know, we made a number of changes to the default configuration for SQLite as a part of Rail 7 1. And that like just there were 6 changes. I have a whole blog post about it like those exchanges alone make a massive difference. And if you had taken if you take a default Rail 7 0 application and put it on the Internet, you're gonna experience pain. And if you put a Rail 7 1 app SQLite application on the Internet, you will experience notably less pain.
Stephen Margheim [00:54:31]:
But still some pain and we are solving the major pain points at the rails level itself. So whether it's improving concurrency or improving the performance of talking to SQLite sort of like the Ruby and and c bridge. I really want to have as much of that live in the framework as possible. But, of course, as for anything, like, your app is gonna have some special, use cases, some things where you're gonna have to move beyond the framework. And so, like, how do you learn to take advantage of Sequoia? And I would say that there are, like, complete three things I would recommend. So the first one is the SQLite docs are extensive. And, I I personally find them quite approachable. I mean, like, the it's not just like, here's all the C code.
Stephen Margheim [00:55:36]:
And it's not just like, here's the, the interfaces. There's, I mean, it's been around for 30 plus years. And you can see they've talked about just about everything that's in there. And it has a nice little search bar at the top. And they also have a form and you can search that there, and there's just a lot of valuable content there and you can really find a lot of answers to many questions. Just search the forums, search the docs. So reach for that first. Secondly, for, like, situations where, you know, I sort of have this unique problem or I kind of want to do this somewhat unique feature.
Stephen Margheim [00:56:22]:
How can I do that with SQLite? There is a quite. I mean, fairly robust you know, I don't know numbers. I I haven't dug deep into postgres, but there are a lot of SQLite extensions. And, they add all kinds of different functionality. So whether it's, you know, the hot new stuff of storing vectors in your database so that you can run some form of AI feature inside of your application. There's a SQLite extension for that. You know? There there is the equivalent of pg vector for SQLite. You can add it in.
Stephen Margheim [00:56:58]:
You can store vectors. You can query them and retrieve them and and many, many others. So start there. You know? See, like, hey. Is there an extension to do this? And then the third one would be if those things fail, there really has been a growing number of people, interested in working with this. And the online community, in my experience has been very welcoming and very positive. And you can just throw something up on Twitter on Stack Overflow. And I think you're very likely to get some useful and good responses.
Charles Max Wood [00:57:43]:
Super cool. Well, we're kind of at the end of our time. Was there anything else that you wanted to make sure that you covered, Valentino?
Valentino Stoll [00:57:50]:
There was something I'm trying to think of it, but
Charles Max Wood [00:57:52]:
he had you at machine learning. I know.
Valentino Stoll [00:57:54]:
Yeah. I know. I got sidetracked in my head. I I have a lot of questions there, but, Yeah. I guess, like, have you hit any limitations as far as, like, I think of, like, as an example, you know, JSON columns and postgres or doing, you know, database views or things like that where, you know, maybe SQLite doesn't have the feature. Have you found many limitations in that regard, that where you had previously, you know, reached for a certain tool that you no longer have available because of the the database limitation?
Stephen Margheim [00:58:34]:
So the short answer is no. But let me just add, like, I really hope people can will just believe me, I guess, when I say that I really I'm not like, feeling right? SQLite is not paying me any money. I am not making any money by talking about it. I'm not trying to get you to, you know, buy my SQLite SaaS or anything. So this is I'm not just trying to, like, be a hype man. There's there's no value or utility in it for me.
Charles Max Wood [00:59:06]:
Right.
Stephen Margheim [00:59:07]:
It is interesting that, like, it I was in the exact same boat. Like, I don't know what it is. There's just like something, you know, a general myth on the Internet. It's like SQLite is anemic. Just doesn't have a lot of functionality. It's small. It's weak. It's like, nope.
Stephen Margheim [00:59:24]:
JSON columns, got them. JSON operators, got them. Generated columns, Got them. Views. Got them. Store generated columns. Got them. Honestly, the there are really only 2 features I've been like, you know, it'd be really cool if SQLite added them.
Stephen Margheim [00:59:42]:
So one is, gin indexes from Postgres. Like, that's just a really useful I mean, generic, index. It's nice to have. SQLite doesn't have it. So you can have SQLite columns, but you can't index them as easily. And if you wanted to do something like that, you do have a workaround. Like, you can make a stored generated column. So, like, extract out the parts that you want to index as a as a store generated column and then index that sort of generated column and query against that.
Stephen Margheim [01:00:18]:
But doesn't have gin. Gin would be nice. And then, of course, right, like, it would be cool if you could do concurrent rights. That would be great. You can't. But, that would be nice. Aside from that, I personally have not come across any feature that I have needed to or wanted to build that SQLite didn't provide. And I was in fact, surprised, actually, as I dug into it more like, oh, okay.
Stephen Margheim [01:00:54]:
SQL actually does support, like, basically, the full you know, it supports the full SQL standard and a lot of the stuff that isn't in the standard that, you know, Postgres or MySQL, like, this would be a nice feature. So I was like, sure. It sounds like a nice feature. I'll add it. So I'm not just a blind hype man, and I don't think SQLite is the solution to all things, but really genuinely think there are a lot of limitations like we need to start fighting back against this myth that it is an anemic tool. It's the most widely used database in the world. It's the best test database in the world. It's one of the it is older than the other 2 major databases, MySQL and Postgres.
Stephen Margheim [01:01:37]:
Like, it is resilient. It is powerful. It is well tested. It is flexible. It is easy to learn. There really aren't reasons to not use it unless you're building the next, you know, fathom analytics and you really do need 1,000,000 rights per second, then, yep, there's a reason not to use it.
Valentino Stoll [01:02:03]:
Just one last note. There's a famous, you know, learning experiment where if you wanted to, like, learn a new language as an example, there's a build your own SQLite database kind of tutorial that lots of people follow, because it does, like, you know, everybody wants, like, a REPL. Right? Like, everybody wants to be able to store data, read data from files. Right? And, like, SQLite does all of these things that are very just common patterns for languages. You have to learn to do the core tenants of whatever it is that make it be a database, like, from a file system, which is kind of interesting. So, speaking of pics, you know, I I might as well pick that. It's like how to build a SQLite database. But I've definitely started one in Rust, which is just for fun.
Valentino Stoll [01:02:55]:
And it's it's amazing how simple, like, as you mentioned, SQLite, you know, it really is under the hood, as far as storing things. And this is fun. It made me think about it.
Charles Max Wood [01:03:08]:
Cool. Alright. Well, I'm gonna push us to picks. Valentino, you got some picks?
Valentino Stoll [01:03:15]:
Yeah. I've I've been loving a llama, which I know has been mentioned on the show before, and by others, but it is a a way to run local inference on your machine against many, different open source large language models. It's kind of fantastic. It runs as a server, so you can serve many different models, optimized automatically with whatever GPU you're running, and you configure it to offload some of that to the CPU. And it's pretty fast and just it has saved so much time just like investigating and evaluating other models that are out there. And you can even build your own models and serve those locally, which is kind of wild. So I highly recommend checking it out if you haven't.
Charles Max Wood [01:04:03]:
Awesome. I'm gonna jump in with my board game pick first. So I'm gonna I went to Salt Con, which is a local, board game, convention. And I really had a good time, just hanging out with one of my buddies the whole time and we ran into some other people we knew there. So, anyway, it was awesome. So shout shout out to SaltCon if you're in or around Utah. They're doing another one in June, and I'm hoping to get a ticket to that one. I haven't bought one yet, but we're we're kinda doing that thing.
Charles Max Wood [01:04:43]:
Also, before I do that, I should probably mention that I am looking for work. So if you're hiring contract or full time, I would love to hear it. Chucktopendevs.com. Alright. So the game I'm going to pick is the game I played there. It's called apiary. And, so board game geek, I'm just gonna warn you. This one's on the more complicated end.
Charles Max Wood [01:05:08]:
It was definitely fun. There were some unique things, but board game geek has a, has a weight of 2.96 on it. That's out of 5. So, you know, there are fours and fives and usually those ones will run for hours. APRE did not. I think it took us an hour to play it with 4 players, but it's, it's pretty involved. So, if you don't like the games where you have a ton of stuff to keep track of, then this isn't the one for you. But if you want one that has some mechanics and, you know, you have to kind of figure out what strategy you're going to jump on, it's a terrific game.
Charles Max Wood [01:05:43]:
It was a, it was a lot of fun. It's kind of a blend between like worker placement and, I don't know. There were some pretty unique mechanics. So, every time your, every time you placed your worker, if there wasn't room for your worker, then you would bump somebody else off the board And that bee would go back to the hive, but it would get promoted. And then once you got promoted, if a 4 got promoted, it hibernate and then go back to 1, right, instead of level 4. And so anyway, but the number on the bee and the number of the other bees on a particular spot also determine what you could do there. And so anyway, and the number fours also have, unique abilities at each space. So anyway, lots of stuff, just really, really interesting game.
Charles Max Wood [01:06:38]:
It was almost too much. There were almost too many things going on, to make it just super laid back fun. But anyway, I did really enjoy the game. And, it's it's on my list is one that I may eventually go by. So I'm gonna pick it now. If you didn't pick up on the theme, apiary is, like an aviary is for birds. Apiary is for bees, and it's space bees. So you're adding on to your spaceship and stuff like that.
Charles Max Wood [01:07:09]:
So, anyway so, yeah, so that's my board game pick. And, yeah, I'm I'm actually just exhausted because I've been working on been working on a bunch of stuff for Super Tuesday because I'm involved in, state politics stuff here. So I'm just going to end my picks there and just remind you if you want to hire me to let me know. Steven, what are your picks?
Stephen Margheim [01:07:43]:
Yeah. So I am friends with Bull Drapper who built and maintains the Flex Gem, if anybody's heard of that. And if you haven't, let me give you a quick intro there. Flex is a Vue component gem for Ruby. Not the Vue component gem, but the gem for for writing views in Ruby. And specifically, it does everything in Ruby. Right? So it maps elements to method names and attributes to keyword arguments and children to blocks. It's a really great gem.
Stephen Margheim [01:08:32]:
And specifically, lately, the core team has been working on a really awesome feature that I want to make sure as many people as possible know about because I actually think it can, you know, I hate to even say these words, but I think it could possibly revolutionize how we do, our our rails applications. And so what is the feature? The feature is selective rendering on the server side. So conceptually, it is very similar to how turbo frames work. Right? So you have a turbo frame on your page. It has ID turbo frame 1, And you click a link inside of that turbo frame the way that would be managed by rails presently. It's like that link gets sent up to your application. The controller processes it, finds the appropriate view, renders that view, sends that view back down to the client. On the client side, there is JavaScript that says, oh, you know, this is a response from a turbo frame request that we made.
Stephen Margheim [01:09:40]:
We made that request from turbo frame 1. Let's parse this view and find where Turbo Frame 1 sits inside of it. We'll pull it out, throw all the rest of it away and replace the contents of turbo frame 1 with the new contents of turbo frame 1. So you on the server, you're rendering everything, so you have some waste. But you have the benefit that you get to use your existing rails routes. You get to keep all of your existing, controller logic, rendering logic, database access logic. So you you treat it as if it's just a regular page visit. But you have excess content that is sent in the response.
Stephen Margheim [01:10:34]:
And then on the client side, you have to take all of that content. You have to parse it and find the subsection, to pull it out and replace the frame. The feature that Flex is adding now allows you to do that exact same thing, but all on the server side. Right? So you send a request up from turbo frame 1. You say, hey. I want to run frame 1. It's just a regular link to a regular normal route. Controller receives it, goes to render it.
Stephen Margheim [01:11:08]:
It's rendering a flex view and not an action pack view. And that flex view is past the content that that or that context. Like, hey. We want turbo frame 1. And so now all of your flex views, it'll start rendering, and it's just gonna no op all of those methods, you know. So your HTML, your body tag, your h one tag, your all of that. Okay. Those are methods we're just gonna no op them until it finds the method that has ID turtle frame 1.
Stephen Margheim [01:11:42]:
It's like, oh, okay. Now it's time to actually render. And so then Flex will render all of that content, package it up, and send back just that div or section frame, whatever. You know? So you get 2 or I guess 3 big benefits. So the one is you get to keep the same simplicity of your real application getting to be structured as if all of the interactions you're doing are standard stateless HTTP interactions pull full page refreshes. You don't have to set up a whole sort of, like, separate components namespace where you render specific things. But you get the second benefit of sending the minimally small payloads over the wire, only the content that you need, with the third benefit being that you only have to render the content that you need. So your rendering times actually speed up as well.
Stephen Margheim [01:12:50]:
So this is available now in, like, the alpha release of flex. It will be, generally available when they release version 110. And, we're doing a lot of thinking and a lot of work now to really make the integration with Hotwire and Turbo as seamless as possible. But I think that this kind of general shift in thinking, and leveraging these kinds of tools is going to be really, useful and valuable for Rails applications. So that is my pick, black selective rendering.
Charles Max Wood [01:13:35]:
Awesome. Very cool. Alright. One last question. If people want to find you on the Internet, where are you? Yeah.
Stephen Margheim [01:13:42]:
So I have at fractalmind on Twitter and GitHub. My blog is fractalmind.get hub.io. And if you want to meet up in person, or you just want to get more confident and comfortable with building Rails applications with SQLite, I am going to be at RailsConf in Detroit in May, and I am hosting or leading a workshop there on the 2nd day on building Rails applications with SQLite. And we're gonna cover everything that I know in as much as that as possible. So the goal is that coming out of that, everyone will feel comfortable and confident with, using this stack and using these tools. So a lot of, exercises and content there, it'll be a fun to our workshop. And, otherwise, happy to meet up, have a soda with, anyone in Detroit as well if you're gonna be there for rails comp.
Charles Max Wood [01:14:47]:
Awesome. Alright. Well, let's go ahead and wrap up. Thanks for coming, Steven. This was awesome.
Stephen Margheim [01:14:54]:
Thank you.
Charles Max Wood [01:14:56]:
Alright. Till next time, folks. Max out.
Leveraging SQLite in Web Development - RUBY 630
0:00
Playback Speed: