Optimizing SQL and ORM Practices for High-Performance Applications - JSJ 650
In today's episode, Charles, Steve, and AJ, are joined by back-end engineer and team lead at Homebound, Stephen Haberman. We delve into the fascinating world of SQL c and its revolutionary approach to managing SQL queries with dedicated SQL files, delivering benefits such as reduced typing errors and pre-deployment checks. Stephen also walks us through the advantages and limitations of ORMs versus query builders like Prisma and Drizzle, sharing insights into Joyce ORM's unique philosophy and simplified CRUD operations.
Special Guests:
Stephen Haberman
Show Notes
In today's episode, Charles, Steve, and AJ, are joined by back-end engineer and team lead at Homebound, Stephen Haberman. We delve into the fascinating world of SQL c and its revolutionary approach to managing SQL queries with dedicated SQL files, delivering benefits such as reduced typing errors and pre-deployment checks. Stephen also walks us through the advantages and limitations of ORMs versus query builders like Prisma and Drizzle, sharing insights into Joyce ORM's unique philosophy and simplified CRUD operations.
They explore the intricacies of Domain Driven Design (DDD), its emphasis on ubiquitous language, and how it shapes business logic and storage management. AJ contributes by discussing the potential of SQL c and Slonik for dynamic query building. Additionally, they discuss Steven's innovative work with GraphFileWorker and GrafAST, highlighting the performance improvements in GraphQL backends. Whether you're intrigued by the technicalities of ORMs, the evolution of database tools, or just love a good anecdote, this episode packed with technical insights and lively discussions is one you won't want to miss. Join them on this journey into the world of database management and development!
Socials
Picks
- AJ - TypeScript to JSDoc
- AJ - MySQL to TypeScript
- AJ - sqlc
- AJ - Slonik (Node + Postgres)
- AJ - SwiftUI Essentials
- AJ - Introduction to SwiftUI
- AJ - Trump, but not saying dumb things
- Charles - Biblios | Board Game
- Charles - FreeStyle Libre 3 System | Continuous Glucose Monitoring
- Stephen - Grafast | Grafast
Transcript
Steven Haberman [00:00:05]:
Hey, folks. Welcome back
Charles Max Wood [00:00:06]:
to another episode of JavaScript Jabber. This week on our panel, we have AJ O'Neil.
AJ O'Neil [00:00:12]:
Yo. Yo. Yo. Coming at you live from a broken stator. No. Sorry. Not stator. Solenoid.
Charles Max Wood [00:00:22]:
Okay. We also have Steve Edwards.
Steve Edwards [00:00:26]:
Yo. Coming at you. Just one yo for me, from cloudy and cool Portland.
Charles Max Wood [00:00:32]:
I'm Charles Max Wood from Top End Devs. And, this week we have a special guest that is Steven Haberman. Steven, do you wanna introduce yourself? I don't think we've had you on before.
Steven Haberman [00:00:44]:
Yeah. Sure. I will do a singular Yo as well, coming from Omaha, Nebraska. And, yeah. Yeah. Really appreciate, you having me on. In terms of, intros, right now, I'm a back end, you know, team lead type engineer at Homebound. You mentioned construction.
Steven Haberman [00:01:03]:
So we're talking about Joyst or Joyst RM. Homebound's a residential construction startup. So we besides just building, SaaS software well, kind of the reason. We don't build SaaS software. We build software for the back end of, the main thing our company does is is build homes, build construction, residential homes. And, yeah, that's me.
Charles Max Wood [00:01:25]:
Yeah. So you talked about the Joist ORM. Yeah. I think you emailed me about it, and this that's how how I found it anyway. Mhmm. I'm just wondering as we get into this, first of all, what problem does it solve, and maybe that's tied up in why you built it?
Steven Haberman [00:01:44]:
Yeah. Sure. No. It's a great question. And so where where Joyce came from was, a few years ago, we were, setting up to build our back end stack. You know, we're a TypeScript shop. We do a lot of TypeScript on the front end, React, very, standard sort of stuff, and wanted to do very standard stuff on the back end as well. And we picked GraphQL as our, you know, layer in between, at the time, which we actually still enjoy.
Steven Haberman [00:02:10]:
I know, you know, that can be some that can be a tangent for later. But so we started off writing our GraphQL, back end in TypeScript and, you know, went to go pick an ORM because that's kinda what you do when you do these things. This is probably 2019 or so. And one of the things that we ran into just right away was just pervasive m plus ones and a GraphQL back end. So, you know, GraphQL is not like your typical endpoints. Right? Where, in a typical web endpoint, you know, slash authors or whatever, you know exactly what your endpoint's gonna do. So you can do one big query kinda upfront to, you know, preload your data as much as you can, and then let your, logic run, you know, afterwards. But GraphQL has such a dynamic, you know, there is no single endpoint.
Steven Haberman [00:02:57]:
Every query is so dynamic, that, you know, the engineer can't just upfront write the exact, you know, preload or query or or whatnot. That it's gonna magically load the data in a performant way. So, we've been using another or m or 2 at the time, but we're just really struggling with m plus ones. And so that was really, Joyce's first claim to fame is that, we had started out doing some cogeneration from the schema and that sort of thing, which is very standard now in a lot of ORMs. But, yeah, we're just wanted to fundamentally solve n plus ones. And so we, started out putting Joyce on top of, the Facebook data loader project, which uses this little, you know, event lit event loop tick trick, if you guys are familiar with that to, You know, if, you know, in the n plus one problem problem. Right? If I've got an author and I'm gonna read some books, and then the books, I'm gonna read the book reviews, it's really easy, for as you go down your object graph to, like, make a query for every single book's reviews over and over and over and over and over. Right? N plus 1.
Steven Haberman [00:04:02]:
I I guess, you know, let me know if you want me to go slower through the n plus one problem.
Steve Edwards [00:04:05]:
Well, yeah. I was I was gonna say I'll give a real quick definition. I wanted to get into that
Steven Haberman [00:04:09]:
real quick before
Steve Edwards [00:04:10]:
we look too far. So, basically, if you have, you know, your books and author problems, the n plus one problem is where you do a, you know, a query for I how would you put it? An author so if you have an author that has multiple books, you're doing a query for every book. Right? Give me this author and this book, this author and this book, this author and this book, whereas if to solve that problem, you can do one big query. Give me this author and all their books, you know, in one query. Mhmm. Altogether, all the book IDs, I guess. So that's the basic n plus one. I'm sure there's better explanations, but that's
Steven Haberman [00:04:46]:
No. And that's what I have. Yeah. And and it, it's really easy to have to happen. So Joyce is is an entity based ORM. So it is very inspired by, like, Ruby active record and, some of the other, OG entity ORMs. You you know, if you go all the way back to, you know, OG hibernate Java hibernate back in the day and those sort of things. But, there's pros and cons of of an entity ORM type approach where, you know, you think of your I I really like to think of a database schema as a graph, and a connected graph, and that sort of thing.
Steven Haberman [00:05:23]:
But, if you think of them as objects, it's really easy, which is kind of the slippery slope of of of leaky abstraction. Right? Because if you think of your entities as objects, which is what entity ORMs do, it's really easy for programmers to accidentally write for loops that cause database queries. Right? Because, if if you have an author object and you're like, oh, I'm just gonna ask for the books. You know, one of the things that ORM entity based ORMs do is is they do this lazy loading of, like, oh, you don't have the books, so go get those for you, which seems really nice. But as soon as you do that in a for loop, now you've you've got an n plus one. And that's been a problem in ORMs just, like, fundamentally forever. You know, as soon as you start doing and and what's what's annoying is when it's it's more obvious when it's in the small. You know, if you've got an endpoint and you're right in your one endpoint file, and and you've right there in the code, you've got a 4 loop.
Steven Haberman [00:06:20]:
You're like, well, I loaded the authors, and then within that, I'm loading the books. It's very obvious within this file, that I need to, you know, hoist my data loading up out of my my 4 loop. But what's kind of insidious about entity based ORMs is, is when you start running side effects and other, drive business logic like, you know, entity ORMs. They like to put methods inside the author class to do some business logic or have an author life cycle hook or or these sort of things. And as soon as some of those side effects, start, you know, accidentally or or sort of, what's the emergent behavior, being called in a loop, now, you know, you're back to an n plus one. And what was maybe interesting about GraphQL was just, like, how quickly that happened. Right? So, like, if you're in a Rails back end, you can go, you know, 2 or 3 years, and and, you know, fight your, you know you you have your every 2 weeks n plus one that somebody goes, and, you know, figures out a production where it's happening and tries to magically hoist the data loading up, to the top of the endpoint. And and that's just kind of a cost of doing business in in a big Rails back end.
Steven Haberman [00:07:25]:
And, but you can kinda get away with it, you know, until you your scale is too big or whatnot. And and maybe what's unique, and and maybe I think why GraphQL has maybe not been as popular as it could have been, is just how easy that is to happen. It happens right away in GraphQL. And so that was really what Joyce set out to solve, was we wanted to make a GraphQL background a back end that didn't suck to go right. Right? And, we leaned on this Facebook data loader, which did actually come out of the GraphQL community. It's it's you know, we're sitting on on shoulders of giants and those sort of things. But, maybe what's unique about Joyce is the the data loader pattern had been around for a long time, but engineers were generally expected to integrate it by hand. Right? You go into this GraphQL Resolver and do your data loader logic or and, you know, there's, I know the the GraphQL frameworks like the Fastifys and Mercurius and, and, those were things.
Steven Haberman [00:08:24]:
And, you know, they have the data loader pattern built into it, but you as the engineer had to go make use of it. And that's just boilerplatey, and and nobody does it, and and it's it's kind of annoying. So, Joyce's claim to fame was that it's, like every operation, asterisk, there's there's 1 or 2 that don't, especially, like, paginated. It's very hard to do, paginated, auto batching. But otherwise, like, every operation in Joyce auto batches through DataLoader. So if you ask for an author and you accidentally ask for an author in the loop and you ask for 50, that's, you know, one SQL call. If if you accidentally, or not even accidentally, you know, on purpose, load a bunch of books in a for loop or a bunch of books in a life cycle event or a bunch of, you know, in a GraphQL nested GraphQL Resolver. Basically, every operation in Joyce goes through a data loader for free and gets, auto batched.
Steven Haberman [00:09:19]:
And, yeah, that's what got us started down the path.
AJ O'Neil [00:09:24]:
How are you doing that? Do you do you await at the end? I'm actually looking for an example on your website Gotcha. To see if I if I can see what this looks like. But I'm imagining you must not await in the loop because the data obviously isn't there if you're waiting for it to batch. So you must await at the end of the loop or something like that, or or you're putting it in a callback or or something to some sort of handler rather than than a promise.
Steven Haberman [00:09:50]:
Yep. We had some good docs on let's see. If you go to goals and then avoiding n plus ones, over on the side, probably describes it pretty well, really soulfully. And, I mean, the wrinkle is that we we, sit on top of Node's promises. Promises are really amazing because they because they're on the event loop, and and you you always have to await them, which which it's ironic because in, like, 20 10, this was, like, everything you did in node had to do a callback, and it was really terrible. And every you know, everybody hated it. Yeah. But, you know, the the people do a node in 2010.
Steven Haberman [00:10:31]:
That that would that would you you were that was hardcore.
Charles Max Wood [00:10:33]:
But, Banging rocks together.
Steven Haberman [00:10:36]:
Yeah. Right. 100%. Oh, what's so ironic is is just how well, JavaScript is language and TypeScript, especially on top of it, have evolved since then to, you know, add, basic weight and all of these things such that, it's turned to what was really annoying, this inventive model of of only 1 thread at a time. It's a really a pretty pleasant, environment to work in. And so to get back to the what DataLoader does is, basically, because you have to await everything anyway, the promise in the event loop, is basically what sets a really fast timer for you. So, like, pretend we weren't in in JavaScript. We were in Java or, you know, OG Java or something like this.
Steven Haberman [00:11:15]:
And you're like, okay, well, I'm gonna do, you know, 10 wire calls or 20 wire calls, but I don't really know how many I'm gonna do. Right? Because before you start your for loop, you don't know if there's 5 books or 10 books or, you know, how many books that for loop's gonna go through. And so you kinda but but you don't you wanna make that first book call and not have it not go right away. Right? Because, like, as soon as the the IO leaves the server, you know, there's your n plus one. So you wanna go through your your proverbial for loop, you know. Maybe this is a GraphQL server run time or whatever, but, you know, let's think of it as a for loop. You want to, like, ask for book 1, ask for book 2, ask for book 3, ask for book 4, and and have these, like, not actually happen yet. You want them to just be, I'm gonna hurry up and jump to the the the term promises.
Steven Haberman [00:11:59]:
You want them to be a promise of a book. And you wanna wait until you've asked for all of the books. And there's the hard thing, is you don't know when you're done in in most environments. Right? So like an OG Java or something like this, you you'd write a for loop, and you would get to the end of the for loop. And then you would have to, like, tell the run time to, like, okay, I'm at the end of the for loop. Ask for all my books. You know, flush my book calls. And, you could do that, but nobody nobody does.
Steven Haberman [00:12:26]:
And so what's really interesting about Promises instead is that, the very first, you know, time you ask for a book, it puts a little, I wanna use the term poison builder, but that's not quite right. It it puts a little hint at the end of the event loop, which is gonna run right away. Right? Right? It's not like a setmillies 50 or a setmillies a 100. It just says like, you know,
AJ O'Neil [00:12:46]:
in just
Steven Haberman [00:12:47]:
a little bit, the next tick. Right. Flush flush my SQL calls. And that's it. Like that that's the end of the trick. And it's it's really, pretty surprising how such a simple little, idea, can, you know, fundamentally transform, the performance and ergonomics, right, of Joyce. Like with, Joyce and things using DataLoader, you get this really elegant, you know, emergent, auto batching that just works. It always works.
Steven Haberman [00:13:16]:
You don't have to do anything to get it.
AJ O'Neil [00:13:19]:
Yeah. I think that objection does something similar to this too. At least it does it with its query builder. You may have taken it a step further, and that you're you're exposing a query builder kind of implicitly. So as you're going through the loop, the query builder continues until you're done with the loop. I haven't actually
Steven Haberman [00:13:42]:
Mhmm. I
AJ O'Neil [00:13:42]:
don't know if I've actually tried this in objection to know whether or not it's doing something similar with with the n plus one problem. But it the query builder in general is built that way, but it's more of a a chaining type of thing. Like, you you can keep chaining the query builder, and then it waits until next tick to actually resolve the query builder into something. So by the time you await it, you're awaiting whatever is at the end of the chain, not what's at the beginning of the chain or where the chain collapses. I'm not really sure what the how the mechanism works, but I do know that it has it has similar magic where there's state management inside of the query builder that's waiting for that next tick in order to resolve the query builder. And this this looks this looks similar, but it's got more of a, a naive looking you know, like like, it looks naive.
Steven Haberman [00:14:40]:
Mhmm.
AJ O'Neil [00:14:41]:
And then you it look it looks like you have a dot each. So rather than using the for loop on it, you use it well, I'm I see where you're you're building the query. I don't see where you actually use the query. I saw one example. It looked like there was a dot each. Is that what you're providing so people don't people don't call for each, they call dot each?
Steven Haberman [00:15:03]:
I'm trying to find, the dot each that you're referencing. Oh, you might.
AJ O'Neil [00:15:08]:
I I Oh, that was that was an example of Ruby code.
Steven Haberman [00:15:11]:
Never mind. Yes. Sorry. Yeah. I I
Charles Max Wood [00:15:13]:
That is a very Ruby thing. Yes.
Steven Haberman [00:15:15]:
Yeah. Yeah. I, you know, I didn't actually use Rails for, like, years years years, but they just stuff Rails and ActiveRecord to, be thoroughly impressed with the ergonomics. And, and so Joyce is kind of, unashamedly, tries to, you know, borrow as much, ergonomics and and best practices as we can for ActiveRecord. And so and so you'll see some active record isms, especially in the docs of, you know, how well, and and particularly the n plus ones. I I guess that would be one thing. I think we kinda use this as a talking point is how, active record, I would assert, has not really solved, like, in in the same way that Joyce has, solved, n plus ones. You know, inactive record is is kind of this whack a mole job of finding where you need to do your load hint, you know, preload hint.
Steven Haberman [00:16:09]:
And, we can get into it maybe a little later, but but Joyce does have the concept, preload hints to make, all of your awaits go away, which which is maybe a tangent. And and so and, Joyce, you can do preload hints because you'll get more ergonomics and you don't have to, await code. But you don't have to. Like like, you'll still get this emergent, auto batching behavior even without and, it's interesting you mentioned the objection. I'll I'll have to go look. It's been a while since I've, you know, for sure taken a look at, the other ORMs around. I think a lot of the ORMs that I've seen, you know, do require these hints for the engineer to, like, know upfront what's gonna happen. You know, to know upfront that in my query, I need to ask for this, and in my query, I need to ask for this.
Steven Haberman [00:16:52]:
Because later somebody's gonna use it. Right? It's because later somebody's gonna do a for loop. And, that's really the the beauty of of the data loader approach is it's, there's, you know, any emergent behavior that actually accidentally runs accidentally or on purpose, runs in a loop, gets the, gets the auto batching.
AJ O'Neil [00:17:13]:
Okay. Yeah. So if I I would love it if with your n plus ones lazy loading in a loop example, if
Steven Haberman [00:17:19]:
Yeah.
AJ O'Neil [00:17:20]:
If it continued, like, the next one or three lines or whatever comes after this. Sure. I get I get what's happening there, but then I wonder how would I use this because it because, you know, every everything's alighted away as to how I use it. And just for the mental model of it, I'm Yeah. Like, do do I await it a final time, or do I what?
Steven Haberman [00:17:44]:
I see what you're saying. Maybe you go to the load safe relations, page right below this. You'll get a little bit of a few more syntax examples of, like, using axing the entities, and the relations on the entities. So we do wrap our relations, you know, so this would be author dot books. You know, that's the books relation. Or author dot publishers, the publisher of your base. And, and and some of the OG ORMs, like type ORM, at least back when I did it, and I'm 90% sure they still do that. And and even the Java ORMs, the hibernating superworld, would model those, like, as, the array directly.
Steven Haberman [00:18:21]:
Right? Author dot books is literally a book array. But it's not really because it has to be lazy loaded. Right? And and so then they do various proxy lazy loading magic to to make it look like a book array as soon as you access it. We go ahead and wrap all of our relations in, these little wrappers that you can either, ask to be loaded. So, like, on that load safe relations, you'll if if the publisher is not loaded yet, the type system knows about it. This is kind of the 10 the tangent that I was, alluding to earlier is that, when I used Type ORM back in the day, because of this, the type system would never know whether something was was, loaded or not. Right? If if you just gave me an author and, I wanted to get to the books, sure. I could do author dot books, but but I I didn't really know, whether that had been loaded or not.
Steven Haberman [00:19:11]:
And if it They're
AJ O'Neil [00:19:11]:
all monads. It's monads all the way down.
Steven Haberman [00:19:14]:
Well, you're getting yes. You're getting that. Yeah. And, so, you know
AJ O'Neil [00:19:21]:
Correct use of monads. Nice.
Steven Haberman [00:19:28]:
The no. Actually, well, you guys talked about effect recently. Right? How those guys, on the podcast. I think that's all I could buy. The TS effect. Or maybe I'm getting my podcast mixed up. Well, the the the Promise, Promise is basically a monad unless you talk to the TS effect people. And the TS effect people have strong opinions how, Promise is not the perfect monad, and they have their own effect, that is the more perfect, monad, which is fine, but I I I don't know.
Steven Haberman [00:20:00]:
I think it's a little, maybe academic, and and Promise seems just fine to me, I guess. But So for the
AJ O'Neil [00:20:07]:
for the people at home
Steven Haberman [00:20:09]:
Yeah.
AJ O'Neil [00:20:09]:
That have never encountered somebody who can both know what a monad is and explain it in a way that other people can understand at the same time, I am the singularity. Monad is simply an object that encapsulates a value that is not the value itself. So for example, if you have answer, answer is equal to 42, that's a value. If you were to wrap answer in a promise so that you have to do something else like call dot then or in some way unwrap it in order to get the value 42 out of it, that's a monad.
Steven Haberman [00:20:48]:
Yeah. And I think it's it's applicable here because I I think one of the things monads are great about is delaying evaluation. You know, to your example, when you ask for 42 and it's just like, 42 is right there. You know, there there's no ability to do, like, meta programming around that or or the you know? But if you're you know, you mentioned Monad wrapping the value that you have to ask for. The fact that Monads fundamentally it it promises, you know, is is if you squint a Monad, you have to ask it for its value. That that delayed, execution is what allows you to do fun things like auto batching in SQL calls.
Steve Edwards [00:21:25]:
So one thing that's interesting here in looking at this is I come from the I live in the PHP world of Laravel, and I'm seeing a heck of a lot of similarities here
Steven Haberman [00:21:34]:
Sure.
Steve Edwards [00:21:34]:
Just in terms of relationships and definitions and how you load them, how you get them, the syntax.
Steven Haberman [00:21:40]:
Mhmm. Hopefully, in a good way.
Steve Edwards [00:21:41]:
You're using yes. Yeah. You're using dot instead of, you know, as an arrow since p p versus node.
Steven Haberman [00:21:48]:
Mhmm. Mhmm.
Steve Edwards [00:21:48]:
But yeah. To so that to me, that looks, very similar.
Steven Haberman [00:21:54]:
Yeah. I mean, we we try to be very boring in a good way, and then, like, you know, but but still have the value adds that that, or or innovations that, make us different, so to say. But yeah. But yeah. You you know, AJ, you had mentioned, what does it just look like to even get the data out? That the this next load safe relations hopefully shows you it's very soon. You know, you go to you have an author, you go to your publisher, you ask for it. You ask for the books, you ask for the the things. Maybe, the the second code example of the load safe relations is an interesting thing to talk about, because it shows the difference between a like a dot load that returns a promise versus a dot get that returns it synchronously.
Steven Haberman [00:22:39]:
So promises are actually kind of annoying. They're very boilerplate because you've gotta await everything. Right? So if you've got, a little, you know, let's say, 10 to 20 line method and, you wanna go from, you know, the books to the book reviews to the review comments, and and and every single one of those is, is a promise. You know, you're gonna have to await promise all in your top loop. You're gonna have to wait, promise all your inner loop, and you're gonna have to wait, you know, promise all your 3rd loop. And it and, you know, and then flat map the promises together and something something something something. And, you can do it, but, you know, it it's I couldn't I you know, I guess I'd ask Chant GTP to write it for me the first time around. But, but what Joyce lets you do with these load safe relations is is if you do you know, so I just made a big deal about how, the auto batching of our SQL behavior is very emergent.
Steven Haberman [00:23:35]:
You you you don't have to declare load hints and preload hints to get that, performance of those. But if you do, you know, add a load hint, you know, one of these, like, I want the author and I want the publisher and the comments and the books, which I think is, you know, AJ, kinda like the objection query builder is is my guess of what that syntax looks like. I don't know. I've tried
AJ O'Neil [00:23:55]:
to forget it. I've I've tried to I've tried to erase it from my memory. I'm I'm done with ORMs, by the way. I'm Uh-huh. For Node and SQL c for everything else. Mhmm. ORMs, they've they've burned me too many times, and I I just can't find the value in the in
Steven Haberman [00:24:10]:
the network. Yes. Well, there's our second half of the of the recording, for sure. We can get to that. The but, you know, back to the the the loads versus the gets, is that if you do do these loads, which are optional, you don't have to for performance, it actually changes the types in the type system. So these get methods that let you like, there's no awaits now. Right? So, like, it used to be if I had a loop and a loop and a loop, I'd have to await every single time I touched a relation. If you do these load hints, we'll add in with because joist and the joist run time and the and the TypeScript type system knows the data is there, we'll add synchronous methods for you to be able to get at it.
Steven Haberman [00:24:52]:
Just do this get do this get. And it's as if it was, arrays in memory or entities in memory because it is now. And and we know that it is now. Right? Whereas if you hadn't done that load hint, we don't really know. You you know, there might be an I IO call there, and so you'd have to wait. But, I would say that's, probably the second on the list of what, you know, what makes things, what makes Joyce novel and pleasant is maybe this load safe relations to, just remove some of the await gunk that
AJ O'Neil [00:25:20]:
you end up having
Steven Haberman [00:25:21]:
in Node. You're
AJ O'Neil [00:25:23]:
you're telling me that by virtue of calling await author.books.loadonline3
Steven Haberman [00:25:31]:
Mhmm.
AJ O'Neil [00:25:32]:
That on line 4, the TypeScript checker knows that author.books.git exists, and it wouldn't know that if on line 3, I hadn't run the load?
Steven Haberman [00:25:46]:
Yeah. You know, if you if we're on the same we're on the load safe relations, we're in the second code block of that page.
AJ O'Neil [00:25:52]:
See the second code block of that page. Okay. Now I'm looking loads yeah. The very first section, now looking at the second code block. Okay. Author.publisher.git.
Steven Haberman [00:26:05]:
Yes.
AJ O'Neil [00:26:05]:
And you're saying you're saying that because oh, no. This is, oh, this is different. This is different. Okay. So it's looking at what load returns, and it's determining from what load returns. I was actually looking in the second section Mhmm. Where or is it the third section? I was I was a little bit further down. Okay.
AJ O'Neil [00:26:25]:
Yes. I was a little bit further down. I was looking at the, after it says yuck, and it's anyway, I I think I I think I get I think I get what's going on, but, no. My question still stands. So, Yuck, given this compilation, some ORMs in the JavaScript space, sometimes Fudge collections must be async. And then it and then it has 3 lines here. And so there's one line where it await dot load for author, And then there's another line
Steven Haberman [00:26:55]:
Oh, yeah.
AJ O'Neil [00:26:55]:
For await dot load the books, but that one is not doing books equals. Right. So the this one, the type checker still wouldn't know for certain that dot git exists because this one didn't do a books equals author dot books dot load. Right?
Steven Haberman [00:27:11]:
Right. Yeah.
AJ O'Neil [00:27:12]:
Okay. Okay. Alright. Now now I'm on board because TypeScript does a lot of magic. It does a lot of magic. And I have Sure. I have fought with some of that magic. And you were you were teaching me new I thought you were teaching me new magic that I needed to know.
AJ O'Neil [00:27:26]:
But but no. It's it's it's it's old magic. Old magic. Got it. I'm with you.
Steven Haberman [00:27:33]:
Right. Yeah. That that example could probably be cleaned up a little bit. I don't know why my camera keeps going out of focus. But, the intent was to show that, type ORM was probably the the ORM other ORM I've used the most, before writing Joyce did. And it was 5 years ago, so I have to, you know, add all sorts of disclaimers that maybe they fixed things. So it's time to turn the camera. Can you do it? That, you know, you'd have to, like, magically access a relation in one part of the code base to then, like, access it in another, and and it would just it would just work over there.
Steven Haberman [00:28:07]:
And and you wouldn't have to await it. And and I don't know. And it was kind of magic magic at a distance as I recall. But but disclaimers, that was a while ago. But
Steve Edwards [00:28:16]:
and
Steven Haberman [00:28:16]:
it was what that section was attempting to show, but, yeah, I can probably be spruced up a little bit. Cool.
AJ O'Neil [00:28:22]:
Alright. Well, I'm with you. I I think that this is, in some ways, I like like many good solutions, when you see it, it's obvious, and you wonder why doesn't everyone do it this way. Yes. Like, looking at it, it doesn't look like, oh, you did something super intelligent that required the brain of a 1000 men combined into 1. Sure. You know, it it looks it looks like, well, duh, of course, you do it this way. But other people weren't doing it this way, so you are the genius.
AJ O'Neil [00:28:49]:
You're the genius that discovered the simple way to do it.
Steven Haberman [00:28:52]:
Sure. I found I found Beta Loader first, I guess. But yes. Yeah. Yeah. I mean, that's kind of the intent. Is is that, again, you know, shout out to the Rails active record ethos of of boring is good. Right? You know, some of the other things that we do try and do well, I'm this might tiptoe AJ into your, like, ORMs, you know, are are terrible sort of thing.
Steven Haberman [00:29:13]:
We we try to, like, make first class notions around domain modeling. Right? So, like, we try to think of not just tables in the database, but try and think of, like, our entities as a graph. And, you know, how are we modeling the world? You know? I like domain driven design, although there there are, king there there are sign kind of some complexities and cargo quilting ish around some of the domain driven design stuff.
AJ O'Neil [00:29:39]:
But You'll you'll have to give me the simple explanation of domain driven design because with all of the, you know, the XDDs that exist, I,
Steven Haberman [00:29:50]:
I mean, it's an older notion from, so Eric Evans was the guy in, you know, probably 2010 or so, 2005 or so, that popularized the term. And and really a lot of it was, you know, ubiquitous language and and, engineers speaking in the same language as your business users and, you know, really modeling, the entities, in their world, you know, in the code and that sort of thing. And, for for me, that was the, you know, 80% of what domain driven sign was about anyway.
AJ O'Neil [00:30:21]:
Sorry. I heard words. What did you say? Take it take it one take it one layer lower. Like like, remove the the buzz the buzzwords from it if you can and and
Steven Haberman [00:30:33]:
well, so ubiquitous language is, like, you know, if the if you talk to your, you so I I do a lot of back office ish sort of software. Right? So so if I'm talking to a user of my software and they they call something a bill, I probably wanna call that a bill in the code base. Right? Like like, we wanna remove these sort of, like, talking past each other where, you know, I call the or or I don't I don't I call it something different, or I don't even have the concept of a bill, right, within the code base. Or, you know, for any of the other, you know, sort of workflow, you know, you know, I'm falling back on, like, you know, crud crud app, you know, crud apps and enterprise spreadsheets and those sort of things where you're you're making software for business users running a business that, you know, all of the business concepts have a matching concept in the code that kind of matches it as much as you can. And, you know, you don't want to yeah. As much as you can. And, so that's the the ubiquitous language side of things. And, and the domain driven design sort of things is kind of a set of patterns around, you know it really kind of I wanna say it's o o at the heart of it, but, you know, if there's a bill concept to the user, you probably have a bill entity.
Steven Haberman [00:31:49]:
And if the user has a, you know, bank account concept, you probably have a bank account concept and that sort of thing. So just, you know, modeling, the world that you're building your system around in your code base, I guess. That's a better explanation, hopefully.
AJ O'Neil [00:32:06]:
So so just more of a one to one between the way that you would speak about the business rules as in when a customer places an order, it puts an item in their shopping cart and then it triggers the payment. So you would you would just have a pretty much a one to one with that where, okay, then there's a shopping cart object, there's a customer object, there's a there's a payment object. So it's just just the the idea of being fairly fairly one to 1, not not having too many abstractions over what the the the need is for the customer to get done and the way the software design is built. Okay.
Steven Haberman [00:32:48]:
Yeah. Which I you know, you you we had mentioned that, you know, a lot of the joys isms, like, they they look very natural and and and kind of by, by default or whatnot. I think the ubiquitous language is kinda the same thing. I I don't think it's super innovative per se. It's just a term for, I think, probably what most people do by default anyway, you know, potentially. But, yeah. Well and so along the lines of the domain modeling side of things, we try to, you know, add some first class features on top of just just a table, just a database table and just columns. Right? So, we try to be very explicit about, well, we can get into some of our reactivity sort of things.
Steven Haberman [00:33:36]:
But, you know, even if you, start talking about database tables, you know, some of your tables are, you know, primitive columns, which is great. And some of them are are your foreign key columns, which are your relations, and and all all of that's fine. We wanna talk about, let's do cross entity validation rule. So, you know, while this might get AJ, we'll tiptoe into your, you know, just taste for ORMs sort of discussion, like, one of the things that I do, think entity ORMs, so and and the dichotomy between, so I've mentioned the term entity based ORM a lot. I would say the other style of working with data is query builders. Right? So the query builders of the node world are like the Prismas, Drizzle, are probably the big 2 these days. Kisley is another, if I'm saying their name right. But on the query builder side of the spectrum, you issue every single call that the ORM does, you do directly.
Steven Haberman [00:34:32]:
Right? You you make the query and it, the query builder just facilitates you doing that in a very, you know, nicer syntax than writing raw SQL. And and you, you know, hopefully, you'll get some type safety from it, because the query builder looks at your database schema and does some type checking of your TypeScript DSL and that sort of thing. So that's the
AJ O'Neil [00:34:52]:
Maybe maybe it does. Maybe it doesn't.
Steven Haberman [00:34:55]:
Sure. Yeah. Yeah. And, so so so those are the query builder. My my maybe slight quibble is that I I don't I almost don't consider those ORMs. I've I've got a blog blog post I wanna go write about, like, what the o in ORM means. And I guess I maybe this is just my I know this is my biases. But, the o in an ORM to me has always kinda meant an entity.
Steven Haberman [00:35:19]:
Right? Like, if I'm using an ORM, I expect there to be an
AJ O'Neil [00:35:23]:
o for ampity.
Steven Haberman [00:35:24]:
Yes. You know, I guess, is is really the term I'm looking for here. But, I mean
AJ O'Neil [00:35:30]:
Yeah. Yeah. Yeah.
Steven Haberman [00:35:31]:
For for the 10 to 15 years, I used ORMs, like, you know, the hibernates and the, JPAs and all of those other and active record. Right? Like, every ORM I've used up until, like, 3 or 4 years ago in the node community had entities. Maybe you had an author file, a book file, a book review file, a comment file, and maybe it was Java code or maybe it was Ruby code or whatever. And it seems like the node the go ahead.
AJ O'Neil [00:35:54]:
I I think that the common pattern is that the ORM is built on the query builder. And so the query builder moves through the ORM because you use the ORM, it uses the query builder, it returns you a partially built query builder object, then you add on dot select name age. And so the ORM is is giving you in many cases, it's giving you both because to the point of
Steven Haberman [00:36:25]:
That's true. You know,
AJ O'Neil [00:36:26]:
the conference slides of GraphQL Yeah. Why load the entire 10, 15 columns if all you need is is 2? And the answer to that is, of course, well, you're gonna need the other 10 or 15. Otherwise, you wouldn't have them. So you might as well load them and then just cache them.
Steven Haberman [00:36:41]:
That's cheap. We're, yeah, we're in a row oriented storage. So, no. You're you're you're right that for a long time and if you said an ORM, it did mean both. It meant you had, an author file and a book file and a book review file. But the ORMs came with the query builders, like the hibernates of the world, so that you could, you know ORMs, kind of by default, of of course, are really good at the very boring credit queries, like an insert, update, delete, of an author, bulk, you know, bulk review. They they can knock those things out any any day, every day. What gets hard is the queries that, like, oh, I wanna join and left join over here and then group by and then having and all of those other sort of things.
Steven Haberman [00:37:16]:
It's really where ORMs, are not so great, but historically have come with query builders, in them somewhere to to at least try and let you do that, which maybe another unique thing about Joyce, we don't have that. Like, I think that's a very hard problem to solve, and and I haven't decided, to tackle it yet. Just because I I mean, the stuff you can do in SQL, I'd rather just write SQL. Like, I think there's also Okay. Yeah. Yeah. Yeah. You know, that there's this economy where people think that, well, if you use an ORM, you have to do everything through the ORM.
Steven Haberman [00:37:45]:
Or if you do a query builder, you have to do everything through the query builder. And But
AJ O'Neil [00:37:49]:
now we're getting into interesting yeah. Now we're getting to a very interesting area. And I and and now I'm very, very interested to, you know, to to hear more about what you're saying. Because
Steven Haberman [00:37:58]:
Sure.
AJ O'Neil [00:37:58]:
I I think that from my perspective, from what I've seen, you know, being in software the last 20 years, and and ORMs have existed longer than that. But from what I've seen, the r ORM came about because Postgres became popular. And suddenly people wanted the the, you know, the hoity toity people that were using Postgres my rather than MySQL. Or the people that just wanted to do the lowly people that were using SQLite rather than MySQL. Mhmm. They wanted to be able to say my open source project is for you too. And so rather than having their project work really well with MySQL, they started making compromises so that it would work just as poorly with Postgres or with SQLite as it would work with MySQL. That from my from my framing, that's how ORMs came about was instead of let's let's just use the tools of the database well, let's castrate them so we might as well just be using Mongo.
Steven Haberman [00:39:01]:
Yeah. That's an interesting
AJ O'Neil [00:39:02]:
Except Mongo didn't exist yet.
Steven Haberman [00:39:04]:
Right. Right. Right. Right. No. You you're right. There is a race to, like, the lowest common denominator across databases, you know, for the ORMs that, and so, you know, Joyce is very tiny, and and so we only support post grade, right now, which is not really on purpose, so to say. That's just the only thing that, we've needed, personally.
Steven Haberman [00:39:24]:
But Has your hoity toity? No. We're small. I I just I don't have any I'm
AJ O'Neil [00:39:29]:
I'm teasing. I'm teasing because I'm saying
Steven Haberman [00:39:31]:
the I I don't have no fees. Nobody's paying me to go to go write them, my SQL driver. If you want, like,
AJ O'Neil [00:39:35]:
I don't know. You never do. I hope you never do. Yeah. I hope that you just keep because some of the great projects out there, they as they grow, they start saying, oh, well, we are like, this is happening with SQL c. Right? SQL c was a Postgres only thing. And now they're like, okay. Well, we're also gonna support MySQL, and we're also gonna support SQLite.
AJ O'Neil [00:39:56]:
And rather than just supporting Go, which I'm totally fine with them doing the JSON format because that's a way of abstraction that seems right. They're they're like, oh, and we're gonna have a a a TypeScript specific driver, and we're gonna have a Python specific. And so now the project's kind of you know,
Steven Haberman [00:40:11]:
it Yep. Yep.
AJ O'Neil [00:40:13]:
Like, I I guess it's not a paid product, so you can't complain. The author's gonna do whatever the author wants to do. But instead of chasing dollars, the author's chasing stars, which means that now you get more stars by introducing to a new community once you've captured the stars of one community. So making your Postgres driver better isn't going to get you but another 10% of stars. Creating a MySQL driver is going to double your stars. Right? And and so then the quality of the Postgres driver or at least the response time to issues with the Postgres driver go down when it's like, but this is why I wanted it. So I hope you never support MySQL.
Steven Haberman [00:40:53]:
Well, wait.
AJ O'Neil [00:40:53]:
Not because my SQL is bad, but just because if you could focus on doing one thing well Yeah. Then it'll work well.
Steven Haberman [00:41:01]:
Yeah. You You
Charles Max Wood [00:41:02]:
go ahead. Go go ahead, Steven, and I'll jump in.
Steven Haberman [00:41:05]:
Well, Well, I was gonna say, I should just hang up now because because, like, with with it's Joyce doesn't have a lot of users. And one of the reasons I'm here is to, like, hey, a lot of people should use Joyce. I I you know, we think it's great. We're we're kind of fanboys of it, obviously, and and I'd love for more people to use it. But they're gonna ask for more things. They're gonna ask for SQL support, or MySQL support, and they're gonna ask for this, and they're gonna ask for this. And and I really, have qualms, you you know, go back back and forth. Like, when your project's small and and dedicated, you can do whatever you want to it.
Steven Haberman [00:41:32]:
And, and we can do that now. But, Just
AJ O'Neil [00:41:36]:
charge money. Just charge money. Just say it's it's it's $30 a year. It's $99 a year for,
Steven Haberman [00:41:41]:
like, the
AJ O'Neil [00:41:42]:
next features.
Charles Max Wood [00:41:44]:
I'm gonna say my say stays. I'm gonna say what I'm thinking here because, I mean, so much of this kinda cuts both ways, if you know what I mean. Right? Mhmm. So it it really pays off to have a focused ORM that just does the stuff that people wanna do. Right? And and to make the case, right, if you're using an ORM for Mongo, it only supports Mongo. Right?
Steven Haberman [00:42:08]:
Yeah.
Charles Max Wood [00:42:09]:
If if there's if there's something else that kinda looks if you squint at it like Mongo and kinda works if you squint at it like Mongo. Nobody's writing extensions for those other systems. Right? And I get that we're kind of in a world where, yeah, all of the different SQL based systems use SQL.
Steven Haberman [00:42:30]:
Right? They're 90% the same if you squint.
Charles Max Wood [00:42:32]:
Right. So so, you know, so you can kinda flirt with it. But Yeah. The the thing that I'm seeing too, right, is so I, you know, it's funny because we've all kinda said, I I work in not JavaScript most of the time these days or, you know, something like that. Right? Yeah. Laravel or Go or, in my case, Ruby. One thing that I've seen with this is with the with the Ruby with active record, yeah, you use the Postgres driver, and then active record takes advantage of that to to query the database. But if you want other features that Postgres provides that are not, you you know, specifically provided by active record or specifically provided by that driver, you can pull in other libraries that add the functionality.
Charles Max Wood [00:43:19]:
And so it really depends on what your goal is, in my opinion. Right? Is your goal just to solve the particular problem that you guys have? Right? Because if that's the case and it does a really good job of it, then, yeah, other people who are using PostgreSQL, and are writing back end code, I'm presuming you're using express or something. You're right. Yeah.
Steven Haberman [00:43:41]:
Fastify. That's for sure.
Charles Max Wood [00:43:42]:
Pulling pull in joist. Right? Makes sense. Yeah. If you're using MySQL, then and and you really want a joist like thing Yes. You can fork it or you can find something else. But yeah.
AJ O'Neil [00:43:57]:
Just just give people a script that installs Postgres correctly with the user setup to be able to create data.
Steven Haberman [00:44:03]:
There we go. Yeah. I I do think well, you mentioned active record. I I think active record has walked the line really well of supporting a lot of, databases. And I Yeah.
Charles Max Wood [00:44:12]:
But it does not like, I use Postgres, and it does not do everything that Postgres does. It does a vast majority of the things that most people use, and so it does a really good job there. But it does do everything.
Steven Haberman [00:44:23]:
Yeah. I I think some of this might get back to, like, like, the, you know, when do you use the ORM and when do you just use a, write SQL in a query builder. Right? And and that, I my my impression and and maybe it's my bias and my assumption is that a lot of people have been burned by the the ORMs of the world. I'm sure there's a lot of reasons, and, hey, Jamie, we can get to yours when you get to. But but is this, like, obsession with putting everything that some projects have, not every, but but a lot of projects have with, like, making everything go through the ORM. Right? Which then, you know, Charles, you run into. Like, well, the ORM doesn't do this for grade or doesn't do that for, you know, MySQL or whatnot. And, I I don't have that strict of an opinion about it insofar as, like, I I think ORMs that do 90% of your applications boring CRUD queries, right, which which is by far the far, far majority of queries we do is super boring CRUD.
Steven Haberman [00:45:14]:
That is probably exactly the same SQL across 5 to 8 top databases. Right? I think Joyce really can pretty easily support the MySQLs and SQLites and all of those for the subset of, you know, really common CRUD queries. And then, like, you know, when you need to escape hatch out to, like, the, you know, whatever left join syntax that only post create supports, I think that's perfectly fine. Go use your, you know, just write go write some raw SQL and do some, you know, low level queries where you need it. And, I I think that happens so, when when you need it, you you really need it, but it happens so frequently in a large application. It's, like, sub 5% of the time, probably, 5, 10% of the time, that you can still get a ton of benefit from the entity, ORM side of things for all of the super boilerplate stuff. And and and also for the that super boilerplate stuff, I think, is also what's most common commonly supported across the, you know, most popular databases. So so we are post grade, right now, but, only but I I don't think it'll be a big shift from our vision to pull in a, MySQL or or something like that, when we get to when we get to it.
AJ O'Neil [00:46:23]:
So so tell me more about raw dogging the SQL.
Steven Haberman [00:46:26]:
Yeah. How do you
AJ O'Neil [00:46:28]:
how do you approach that? Sure. Because it it seems like it I again, back to the why ORMs exist. I think they started out because people wanted to support SQLite and Postgres in their MySQL projects. That's what it seems like. But then once they were there, it started to kind of, like functional programming was also, you know, hitting one of its, one of its phases. And so it's like, oh, well, look. I could do the training. I could do I do all the functional programming.
AJ O'Neil [00:47:00]:
Functional programming is more amenable to relational algebra as opposed to the Java style programming that it was, you know, existed at the time that this stuff seemed to be really taking off from from, you know, my point in history, which I'm you know, I missed a bunch of it because I came in kind of not I I thought I was in the early days. Maybe I was more towards the middle of it than I thought. But, anyway, so so you've got that. And then but so then the whole thing is, well, you know, now it's typed, and now it works in your language. And now and so and so SQL became the bad guy. It's like, well, the ORM isn't just so that you can support multiple databases. It's actually because it is the morally superior choice. Good people use ORMs because they're good people.
AJ O'Neil [00:47:48]:
And and so then so so it's like, well, if you buy into the idea of an ORM, then you're a good person. And if you're a good person, you're not gonna raw dog the sequel, are you? Because then you lose your portability, and then you lose your functional programming, and then you lose all the things that are so enlightened. So how how do you have this the economy where you're gonna say use jo joyce.rm, but, actually, yeah, RawDog the SQL when you need to.
Steven Haberman [00:48:15]:
I don't know. I just do. I mean, the, I I
AJ O'Neil [00:48:20]:
Excellent.
Steven Haberman [00:48:22]:
Well, I I I mean, I've I've tried to use ORMs in the past that, you know, you you you get their DSLs get so contorted to try and support every little thing in SQL that you'd wanna do in a TypeScript DSL and that sort of thing. But but you're just, you know, why you know, even if it's typed or like, I really love types. Right? I I really love static typing. I love code, you know, generating looking at the database schema and pulling those, you know, like the active what an active record does. Like like that, you know, it's really what, Joyce tries to do. Granted, I cogent time so the TypeScript comp compiler can see it. But, like, there's a limit to where, like, let's just write some SQL. And I I think especially because it just doesn't happen that often.
Steven Haberman [00:49:04]:
Right? Like, and I that's what makes me feel not so bad about it. Right? Like like, if I had a 100,000 line code base and 50,000 of it were, like, entities and the other 50,000 were, you know, raw. SQL. And it it was very hard to see when you you would use each and and you you, you know there were little camps of, like, on this one you you know, which one do you use and and that sort of thing. But, at at least on the projects, that we've got going on so far, like like, it's really pretty obvious that you, or at least seems like it, that that, you know, you do use the ORM for as much as you can, but then those last few and in terms of what it actually looks like, we do have a a little bit of glue. So right now, Joyce sits on top of Connex, which is just another it's one of these query builders. It's like the key sleep, and, that's what Joyce itself sends the queries through. And so we use the same connection pool as as as Connex, if I'm saying that right.
Steven Haberman [00:49:53]:
And, so if you if you
AJ O'Neil [00:49:55]:
do It's after the Lego alternative.
Steven Haberman [00:49:57]:
Yeah. Yeah. Yeah. And so, when you want to, you know, BroadRock your SQL, you just get the Connex, DSL from the same, I mean, I say DSL, but but there's it is a DSL, but it's it's it's much lower level. It's much closer than SQL. It's not and it's not as typed in that sort of thing. And, you just do a few of them, and, you know, make sure you write tests. And I don't know.
Steven Haberman [00:50:20]:
I don't care. The code ends up being cleaner. And, yeah. Oh, I I wanted to follow the tangent. You had mentioned that, you know, ORMs were really great for cross database compatibility. Actually, I I don't know if that's the case. I I know I know that that is a purported benefit of the ORMs, but just like how often have you really seen a project migrate databases? Like, it's just like
AJ O'Neil [00:50:39]:
Well, that that's the thing. Like,
Charles Max Wood [00:50:41]:
good boy.
Steven Haberman [00:50:42]:
It's not
AJ O'Neil [00:50:43]:
gonna happen. I think that there's an impetus. Right? I mean, you have to go back to the root cause. What's the root cause?
Steven Haberman [00:50:49]:
Well, I believe Yeah.
AJ O'Neil [00:50:50]:
The root cause is more stars. And back then, there wasn't GitHub, but still, download count on SourceForge. Right? Yeah. That's
Steven Haberman [00:50:58]:
Yeah.
AJ O'Neil [00:50:58]:
That I think is the thing, is that people wanted to see the number tick. Because if you're not getting paid in dollars, you wanna get paid in social credit. And I I I believe that what it was is they wanted to get other people in their community to watch that download ticker when SourceForge go up.
Steven Haberman [00:51:14]:
Oh, I'll give you that. That's that is an interesting assertion. I'll have to think about that. The whole, like, you know, then you mentioned the SQL c goes after, the the all of the SQLite users and that sort of thing. I don't know. I'll step back a little bit. Like, more than, like, cross database, can like, I'm gonna we use, AWS Aurora at, at Homebound. It's amazing.
Steven Haberman [00:51:33]:
I'm gonna run on Aurora for the next, you know, 20 years if I can. Like, it you it just gets as big as you, you know, want it to, and granted you have to pay for it. But it's an amazing product, and, I I have no desire to run on anything other than that. But, oh, but that's not why I use the ORM. Why I use the ORM is business variant enforcement. Right? So, validation rules, such that, you know, what I my my just incredulity with the query builder approach is, like, you know, let's say I I'm in my author endpoint. I I'm in my save author endpoint, and I'm gonna do an insert an an update. Let's say I'm gonna update the author.
Steven Haberman [00:52:12]:
Okay. So somebody raw dogs an update to the author table. What business rules did they check? Well, you know, before they switched that first name, before they updated the, you know, book title, or before they they increased the the book rating? And, like, how many derived values? Derived validation rules and derived values are trying to watch whatever they just updated. Right? So, you know, let's say that the author has a star count. Right? And or or, you know, these sort of, you know, direct active record has some counter caches that that we we haven't quite flown that yet. But just in general, the idea of, you know, after you update, this row in the database, something else needs to know about it. And that's why I use ORMs. I I would just be super scared of, like, raw dogging an s an update to an author and forgetting what else did I have to do.
Steven Haberman [00:52:57]:
You know, what what other validation rules did I have to run? What other, drive values should I have to update? And those are the 2 things. We you know, we we're kind of into the 3rd phase of what Joist is amazing at. You know, m plus 1, and, you know, avoidance was the first one. Second one is, those, you know, populate hints to to move get rid of await gunk. And the third one is this, like, not only validation rules and and, life cycle hooks, like active record has the you know, we have active record cell before flushes and before updates. We do cross entity reactivity, wow, which is kind of a fancy marketing phrase from it. So I I guess I am kinda putting on my my marketing hat here. But, so you know on the front end, reactivity is a a big catchphrase, right, of of when you update the component over here, you know, the reactivity is updating all of the component.
Steven Haberman [00:53:45]:
You update state, you know, you update state once and then it gets broadcast out.
AJ O'Neil [00:53:50]:
Oh, I've heard about it. I haven't seen it, but I've heard about it.
Steven Haberman [00:53:53]:
Yeah. Sure. Well, Joyce basically brings that concept to the back end. So, like, in a in a Joyce entity, when you update an author, and let's say the author first name or the author last name, we will watch not only for, like, validation rules on the author itself, like, you know, the but the really simple ones are are the validation rules you'll see in Azad or some sort of schema based, parser that they just look just at the field and just at the primitive values in the field. Is it too long or is it too short? Is it an email regex? Is it not null or whatever? And those are fine. You know, that's that's what Azad can do for you. But, you know, when you start talking business invariance, this gets back to, like, some of the ubiquitous language in domain driven design. When you go talk to your, you know, your business users and they're like, well, I I have this this rule.
Steven Haberman [00:54:39]:
I use the term invariant. This business rule that I want to just always be true. You know, I want this to always be true. And it's probably not gonna look at just what the first name is. Is the first name too long or too too short? Right? It it might look at, well, our you know, the first name can't be the last name or or, you know, it's gonna look at multiple fields at once. Right? Just on with 1 on, one entity. But then it's also very common for, like, the the rules to want to, like, look across entities. Like, well, if my author is, has some sort of status.
Steven Haberman [00:55:09]:
Right? If if my author is, employed, then my other validation rule in the books like, the books can be, you know, sold or something like this. Right? And so these sort of cross and variant validation rules, that's why I use ORMs. And and and I I hope I, you know, I can't speak for others, but that's that's what I would assume is is, an an attraction to the ORM is is not just like abstraction from the SQL database I'm using.
AJ O'Neil [00:55:38]:
So I guess in that sense, I build my own ORM because I prefer to have Yes. Business logic in a separate layer from storage logic. Sure. I see these these two things as fundamentally different. And as I, you know, I'm going through and refactoring code and, like like, looking through projects as as I tend to do being, you know, consultant. Mhmm. I I think that the worst like, the weakest abstractions are the ones that combine storage and messaging with business logic because business logic is the most likely to change. And so anytime that storage and messaging are together with business logic or, you know, either one of those are together with business logic, then it it just it's always a nightmare when x needs to change.
AJ O'Neil [00:56:31]:
Well, now you have to go change y and z as well. You know? So I'm I'm very I'm very much a business logic goes in the business logic place.
Steven Haberman [00:56:41]:
Yeah.
AJ O'Neil [00:56:42]:
And that's so the the fundamentally, my stack, my ideal stack is routing is global. Business logic is per component. Storage is more or less global slash hierarchical. But but, like, the business logic uses the storage. It's not in the storage. And then messaging, likewise. Messaging might be global with, like, some hierarchical component to it. But Yeah.
AJ O'Neil [00:57:09]:
The business logic uses the messaging. So what I'll do, which you don't see this in a lot of code bases because people like to abstract it away, because I want a function that's like save that's going to do the business logic, do the storage logic, and do the message logic altogether. What I'll do is I I'll literally, like, call the get function, take the data, call the business function on the data, and then take the result and then call the messaging function. But then then whenever it's time to refactor, whenever business logic changes, it's like, I gotta go and just change that one thing. I don't have to go change my my storage module or my messaging module or or whatever. Sure.
Steven Haberman [00:57:50]:
Yeah. No. I mean, what you're saying reminds me a lot of, I mean, I've see I've seen those architectures in the past. I've worked in those code bases, and, it's a it's a very familiar argument. I guess, I I especially saw it, you know, 15, you know, 20 years ago in the Java world, there's a very strong push to have well, the term's the same. POJOS, you know, plain old, although this was Java. Now you, you know, plain old JavaScript object or plain old Java object. You know, pass between your layers, and you had to have a storage layer, and that was the only place they could put, like, data into your your, your POJOS.
Steven Haberman [00:58:22]:
I guess, what, you know, I think this is what I learned from active record and, the the pattern in general, but then also Ruby, the implementation, is that, if your storage matches this gets to kind of the domain model, the concept, and the ubiquitous language. If your storage schema matches what your, you know, Pojo is supposed to be anyway, the storage layer just goes away. Right? It it it there is no storage layer anymore. You know, that's that's what the active record pattern fundamentally does. And I think, there is an assumption there that you can control your schema. Right? So, like, you know, 20 years ago when your schema was controlled by the Oracle database admin that you had to submit scripts to once a week for him to maybe add a table if you ask nicely enough. Right? And all of these other sort of things. You had a really shitty database schemas.
Steven Haberman [00:59:07]:
Right? They were just ugly, and and they were wrong, and they they modeled the data, you know, had ugly names and that sort of thing. And so the ORMs way back in the day, like hibernates of the world, part of what they tried to do was, like, fix the terrible database schema. Right? You would write your mapping files or your storage layer to try and and, you know, get the data out of the super ugly database and put it into your super pristine o o POJO layer. Right? That was all, you know, your ivory tower of, what you really wanted it to be. And, to me that's that's where the whole, you know, ORMs or the Vietnam of computer science, came from, is that, the the yeah. This notion that that you have, oh, right. The object relational mismatch. You know, that'll get, you know, thrown around as in, like, somehow objects are just finally different from relations.
Steven Haberman [00:59:55]:
I don't I don't think that they are. Like, you know, I think if you they don't have to be anyway. I think they were back in the day when you had super terrible terrible oracle database schemas that you wanted to map onto your different set of, you know, objects. You know, that was an impedance, but that that was not because of the technologies. That was just, you know, because your schemas were so terrible. But, you know, if you have the freedom to make your your, you know, database schema what it really should be, you know, if if you have an author, you have an author's table. If you have a book, you have a book's table. And, you know, the columns match what you want them to be, and you can change them with migrations extremely quickly in the CICD pipeline.
Steven Haberman [01:00:32]:
I think that impedance goes away, and you start thinking of your your relational database as a graph database, really, just a graph database that scales really well because for whatever reason graph data graph databases haven't really taken off and can't, you know, whatever. But, you know, you you you think of your relational database as a graph database. And now your storage layer, you're coming back to where you put your business logic. There is no storage layer. The ORM just does it. And so now what the entities become is not a storage layer. They are the business logic layer. Right? So when you're you know, you say, well, I'll have my business logic off somewhere else.
Steven Haberman [01:01:04]:
This is one of my, criticisms of the query builders is that you have to do just what you did. So, like, Joyce and our entities, we provide a framework for business logic. And we've we've attempted to vet it and attempted to organize it and attempted to, you know, design a really pleasant way to organize your business logic. I wanna say, like, separate from your storage layer, but there is no storage layer. That's kind of the point. Such that Well, there there is
AJ O'Neil [01:01:29]:
a storage layer. It's just abstracted in some way. I mean, there's obviously there is a storage layer.
Charles Max Wood [01:01:38]:
Active record does this by convention. Right? And so you don't think about it because it's mostly invisible.
Steven Haberman [01:01:46]:
Right.
Charles Max Wood [01:01:46]:
And I think I think that's what you're saying, Steven. Yeah. And what I find is that this probably works 95% of the time, and then the other 5% of the time, you have to go play the game of, okay. I've got something that's a little more complicated than just business logic in this one narrow vein of users, for example. Right? And so, what I wind up doing is I wind up creating some other entity that manages that business logic and that workflow and all the things that are involved in that. You can call it a component. You can call it a service. You can call it whatever you want.
Charles Max Wood [01:02:21]:
But, yeah, you wind up solving that in a different way. And I I think sometimes people get into the arena of saying, I don't like ORMs because they don't solve things in this 5 percent or 3% of the time. Yeah. Exactly. And the reality is is it's like, look. It does all this stuff for me the other 95 to 97% of the time. And so I'm gonna use it because it gets all of this garbage out of the way, and it makes all of the storage stuff invisible to me, and it gives me a place to put the stuff that I care about. And then, yeah, I'm gonna have to go, and I'm gonna have to special case this other crap.
Steven Haberman [01:02:55]:
Yeah. Which is fine. Yeah.
AJ O'Neil [01:02:56]:
And that is actually my plug for SQL c is that Nice. It gets all of the crap out of the way, but there's the only constraints that it has is that it can't do meta table stuff. Like, for example and I don't think active record does this either. Like, if you wanted to create a table dynamically, like, let's say that you were doing something like Snowflake, where you need to create tables on the fly to represent CSVs that people are importing. SQL c is not the right tool for that job. Sure. But that is in your, like, 0.1%, I I think. Like, it's very rare that you need to do Yeah.
AJ O'Neil [01:03:44]:
Meta manipulations on a table in an application that you're, like, multi vendoring your application in that kind of way. But, like, for all the stuff that
Charles Max Wood [01:03:53]:
that may be better anyway.
AJ O'Neil [01:03:55]:
But all the stuff that an ORM is gonna do, typically, SQL c is gonna do for you. It's just that you just write the SQL, and you write the SQL as specific as you want. And what it does is it uses the the Postgres query builder. Like, it it links to the c code. And so it runs the c code, and then it gets back basically the the like, it knows what the the c code object is gonna be, and then it translates that to JSON, and then translates that to Go. Or in the case of Go, it might do direct because they didn't have the JSON adapter. The JSON adapter came before they created the adapter that goes to the other languages like Python and TypeScript. Originally, it was just straight from Postgres to Go.
Steven Haberman [01:04:39]:
But Mhmm.
AJ O'Neil [01:04:39]:
Anyway so it it hasn't it it reads from the Postgres specific type system into a broad type system into the languages type system. And so you get all of the typing. You get all of the objects. It's very easy to yeah. Any anyway, so so that that's where that's where SQL c in particular, I think, is is the best in class. Although, it's it's probably not something many people have a mental model for because as far as I know, it's the only one of its kind. It's it's another one of those obvious ideas where once you see it, it's like, oh, why haven't we been doing this for the last 20, 30 years? But Yeah. You know, again, no but nobody did it.
Steven Haberman [01:05:25]:
It is a cute approach. I I I I do like the the no well, for my my caveat would be for, you know, when Charles said the last 2 to 3, you know, 4% of things that are really gnarly, and and you have to, like, read, reach outside of the box. I think the SQL c approach is really pretty novel and great for giving you a file to just write your super one off query and that sort of thing. I guess for the other 95% of things, I don't used to. What's that?
Charles Max Wood [01:05:49]:
I don't think I've ever used SQL c.
Steven Haberman [01:05:51]:
SQL c? Yeah. I don't know if
AJ O'Neil [01:05:53]:
they have a Ruby adapter.
Steven Haberman [01:05:55]:
Yeah. I mean, but yeah. The the concept, is, you
Charles Max Wood [01:05:59]:
know playing more and more in the JavaScript realm anyway. Anyway, sorry I keep jumping in.
Steven Haberman [01:06:04]:
Oh, no. That's fine. No.
AJ O'Neil [01:06:05]:
No. No. Obviously.
Steven Haberman [01:06:07]:
The, well, yeah. So so the the TLDR of SQL, see, is that usually, you know, when we talk about raw docking SQL. Right? So usually raw docking SQL in most, languages is you just go do an embedded SQL string, you know, inside of your
AJ O'Neil [01:06:21]:
And you lose the types.
Steven Haberman [01:06:22]:
And you and you lose the types. And you're just building a a great big SQL statement, as a string. And maybe you use a string builder or or maybe you, you know, you somehow piece together what is in your language fundamentally a string.
AJ O'Neil [01:06:33]:
And then then you have a typo in in in the the name of people where you transpose the o and the e, and you don't find out until you deploy.
Steven Haberman [01:06:41]:
And so what's noble about SQL c is they have you write this instead, your your query in a dedicated file outside of your, you know, your language, whether it's Go or TypeScript or whatever called, like, you know, my query dot SQL, you know, get authors dot SQL or, you know, read authors dot SQL or insert authors dot SQL. And you write literally the the SQL that's gonna go to the database, and you get it used variable in interpolation, like dollar sign 1, dollar sign 2. And then what they do is they just, you know, they they parse that SQL, type check it, and then generate a little binding around it that says like, oh, if you, you know, they cogent out a wrapper that's a method, you know, a a method that will really just load that little SQL file and then call it. So it really is a pretty neat way to get, like, you out of, like, writing raw doc SQL inside of strings in the database or or sorry, in your in your TypeScript file or your Golang file into, like, what is actually a SQL file. No. I actually think that's pretty great. My my disclaimer would be, like, for those 3 to 4 to 5 percent of cases where I want to be raw talking SQL, and the other 95%, which is like the super boring update authors CRUD statement, that not only is very boilerplate to write the the, you know, update authors at SQL, which which, you know, I don't wanna write, but maybe you could say it's not fine. But all of the invariance that I need to go make sure still pass.
Steven Haberman [01:07:56]:
Right? Like, sure, I updated the author. What other, you know, business rules or
AJ O'Neil [01:08:01]:
But but that's all in your business logic. That's all in your business logic. So that's that's still there. Like, you still get that. You don't you don't bypass that.
Steven Haberman [01:08:10]:
Does SQL c have a way to tell you how to structure your business logic, or that's just, like, on you to figure out a way to do
AJ O'Neil [01:08:16]:
it? Well, I mean, you do it the same way you do it anywhere else. Right? Whether you're using SQL or not. So you just SQL c takes care of the storage layer, and you you but okay. I mean, I don't wanna I don't wanna soon. And we can do it. I don't wanna go too deep into
Charles Max Wood [01:08:31]:
these. So
Steven Haberman [01:08:32]:
Sure. Yeah. Maybe one one last thing, about it is that I think the the core builders of the world, and and this is I would include SQL c in that, but also the Prismas and and Drizzle and all of these. Leave as an exercise to the reader how to, structure their business logic. Right? Like like, when to invoke it, how to structure it, where to put it. And that actually is is the most the thing that the Joyce is focused on. It's it's like, sure, 80% well, you know, 60% of this is an RN to get data out of your database. The other 40% is a way to structure your business logic instead of everybody having to kinda make up their own and hope they they do it right and, and those sort of things.
Steven Haberman [01:09:11]:
Grant, it it is a very opinionated way to structure it because it uses entities and it uses life cycle hooks and it uses some reactivity. Is it it but it is opinionated and
AJ O'Neil [01:09:22]:
That that's interesting. And and I think that psychologically, there's there's an effect there that that's really valid because people, you know, people go both ways about frameworks. You know? Like, I love a framework because it it guides me. I hate frameworks because it constricts me.
Steven Haberman [01:09:38]:
Right.
AJ O'Neil [01:09:39]:
And I and I think that, you could have a framework that is here's how to put your you know, where to put your business logic, and then here's where you plug in your storage adapter. But I think that people are more familiar with the idea that the ORM is going to be the framework that dictates business logic rules with the data associations.
Steven Haberman [01:10:00]:
Yeah. Which is what we do. Yeah. Bread and butter. Yep. Yep.
Charles Max Wood [01:10:05]:
Cool. Well, I think this has been so interesting to just kinda listen in on more than participate in. Usually, I'm jabbering all the time. Sure. But, if people wanna learn more, where do they go find more information?
Steven Haberman [01:10:19]:
Yeah. Sure. You know, so we're joyce dashormpiodi0. And you had mentioned it, and if you just Google for joyceoram, we do kinda come up higher in the in the results. We've got a GitHub project. Feel free to oh, and, oh, we use that as Slack, but what's the thing that you have to say? It's Discord, you know. Discord. Actually, I have to make sure I'm logged into that when if I if I mention it.
Steven Haberman [01:10:43]:
But, yeah. Feel free to to to stop by. You know, wanna make the disclaimer for the audience that that the the Orem you use is is a big bet on your code base. Right? And and so we we take very seriously that if you structure your code base around Joyce, that that you're taking a bet, and we really, do, respect and appreciate that. But, yeah. We would love to have, anybody kick the tires and, point us out. You know, AJ, you found a few things in the docs that could probably be for stuff. We'd love to have, you know, any issues, around those things to help the onboarding process or, things that we're missing.
Steven Haberman [01:11:15]:
We'd really appreciate it.
Charles Max Wood [01:11:19]:
Cool. Well, let's go ahead and do our picks. Now it sounds like you may have listened to an episode of the show, so you probably know what picks are. But just for anyone who's new, I I haven't said this in a while, but picks are basically shout outs about anything. So I usually do board games. We've had other people, on Ruby Rogues. We had picks, and they you know, one guy did beer picks every week. You know, people pick TV shows.
Charles Max Wood [01:11:45]:
People pick tech stuff too. Right? I mean, this is a technical show. We've had people pick political candidates, though I'm not jazzed about that all the time because people have feels about that. Right? And that's not really what we're about. But if if you care about it, you can say it. So Sure. Anyway, let's go ahead and start with Steve, and then we'll work our way, through the panel.
Steve Edwards [01:12:09]:
Yeah, Steven. First of all, I'd like to point out I appreciate that you spell your first name the correct way, not with an s p v e n.
Steven Haberman [01:12:16]:
Sure.
Steve Edwards [01:12:17]:
I meant to note that at the beginning.
Charles Max Wood [01:12:19]:
I'm playing that back for my brother about 8 times.
Steve Edwards [01:12:23]:
What's funny is and I I think I might have mentioned this before. I have a brother named Steven. He's spelled with a v. He's adopted. And so he was already named that when my parents adopted. So we're big Steven, little Steve, or I prefer handsome Steve, not too handsome Steve. You know? It just depends Nice. Context.
Steve Edwards [01:12:40]:
Uh-huh. But, anyway, in regards to to, picks, my picks are generally the highlight of any episode in there, my dad jokes of the week. So, be prepared to laugh yourself silly. Just kidding. Alright. So for instance, I asked my wife being a she's a rather nontechnical person, shall we say. I asked her why her password was spelled out Snow White and the 7 dwarves. And she said, I was told it had it to be at least 8 characters.
AJ O'Neil [01:13:14]:
Thank you. I got it.
Steve Edwards [01:13:17]:
Yeah. That
Charles Max Wood [01:13:18]:
was better than most of the ones he comes up with. So
Steven Haberman [01:13:21]:
That was freaking
Steve Edwards [01:13:23]:
Yeah. I was I was sitting in traffic the other day, and that's probably why I got run over. Right. And then question of the week, if dentists make their money off of people with bad teeth, why should I trust a toothpaste that 9 out of 10 dentists recommend? It's all about self interest. You know?
AJ O'Neil [01:13:46]:
Got them. I
Charles Max Wood [01:13:48]:
I I think that's a fair caveat.
Steve Edwards [01:13:50]:
Nope. It was like I'll give you caveat. Anyway
AJ O'Neil [01:13:56]:
I think 9 out of 10 dentists recommend all of the toothpastes.
Steve Edwards [01:14:00]:
Right. Just Annie, please use something. Those are my picks.
Charles Max Wood [01:14:04]:
9 out of 10 dentists that we paid to say so. Anyway,
Steven Haberman [01:14:09]:
that would
AJ O'Neil [01:14:10]:
be asterisk. Alright. So since we're on this topic of SQL, I I'm just gonna throw down there's a typescript to JS doc module that'll be linked. It's called t s hyphen 2 hyphen j s doc. It's exactly what it sounds because I don't like TypeScript. I hate TypeScript. I think TypeScript is an abomination. You know this.
AJ O'Neil [01:14:30]:
I love types. And I love that the TypeScript checker is getting better and better at being able to interpret JavaScript in JavaScript types. And I hope that that goes forward. I'd love to see one day where, you know, maybe collectively, we can just all drop TypeScript because the TypeScript checker is so good at JavaScript types that you don't even need to annotate anymore. It just gets it. That would be amazing. That's that's like Zig level I don't know. The other thing is there's a module called MySQL dump t s, MySQL hyphen dump hyphen t s, hyphen t s.
AJ O'Neil [01:15:04]:
And this will allow you, of course, to dump tables out of your MySQL database and then get the TypeScript of them. And then you can run the TypeScript to JSDoc to get the JSDoc of them, and then you can start to you can start to make your code better in the sense of being able to have type checking, you know, misspellings checked, etcetera.
Charles Max Wood [01:15:24]:
And add Joyce to them.
AJ O'Neil [01:15:27]:
Yeah. I I don't think that you would need if you're going this route, I don't I think Joyce is solving this problem for you. If you're adopting Joist, I don't think you'd need these. But this would be in the case where you have an existing project and you're trying to get certain parts of that project in a in a better way so that you can feel safer and sleep better at night about it. Then, of course, SQL c. SQL c, like I said, it's kind of like a reverse SQL, c query builder because you just write the SQL, and then it gives you the queries. And it's not a binding, just to be clear. It is well, I mean, it is a binding from the perspective that it uses the SQL driver.
AJ O'Neil [01:16:11]:
But it it's it's not it's not calling that that well, it it builds it builds out it it builds it out. It's not it's not copying well, it is copying from the file. It's not using the file you created. Anyway, you you can see what it is. But SQL c, I I think is the smartest approach because it seems like it covers not the 95%, but the 99.5% in terms of as long as you don't need to do meta table manipulations, it's got your back. And it's and since you have to learn SQL anyway, query builders don't alleviate your need to learn SQL. If they did, then I'd say, yeah. Let's get on the query builder.
AJ O'Neil [01:16:52]:
But the truth of the matter is, at the end of the day, chatgpt is gonna be bomb awesome at generating SQL for you. And it's gonna be mediocre at best at generating queries in your query builder of choice. Well, I I don't know. I haven't I haven't tried it with that specific use case in the most recent version, but my previous experience what with it was, it does awesome at SQL, and it's really mediocre when it comes to the SQL abstractions. So SQL c is something that seems to pair really well with LLMs in terms of being able to get the statistically likely correct SQL, which SQL really lends itself incredibly well to statistical analysis. Like, that's a match made in heaven. Then Slonik. Slonik is kind of a different approach, in terms of you are putting your queries inside of templates inside of your JavaScript code.
AJ O'Neil [01:17:50]:
But it is you it's kind of a middle ground between SQL c and a query builder, and that it it's doing the query building dynamically, but you are getting the type checking on it. But SQL c, I think I I think SQL c is the real gold, but Slonak is something that's certainly an interesting option. And then you've got, template blocks that are SQL tagged, and so you can get highlighting and stuff like that. And then, so that's the SQL stuff. Got out of the way. 2 other quick things. SwiftUI seems like amazing, and the Android jet Jetpack Compose is either it's either the clone of SwiftUI or SwiftUI is the clone of that. And, you know, Apple likes to perfect things when it clones them and then pretend like it's the first because it's so good that, you know, they knock it out of the park when they do it.
AJ O'Neil [01:18:40]:
But there's 2 talks, SwiftUI Essentials, an introduction to SwiftUI. And if I close my eyes, what I hear is React, React, React, React. But when I open my eyes, what I see looks more like Vue, and like, oh, this actually this actually looks like it would work. Because there's there's the there's the promise of React, and then there's the reality that we're all kind of familiar with. SwiftUI seems to be both the promise and the reality of React. I'm really interested to get more into it. And then last thing, I am gonna make a political pick. I oh, Trump just makes me so, can we not have good choices? But then but then every time every time I think we're the dregs.
AJ O'Neil [01:19:21]:
We're the bottom of the barrel. Can this get any worse? Then it's like he does an interview that's with people that are a different audience. Because when he speaks to the general public, I'm just like, oh, please no. But then sometimes when he speaks to a specific audience, it's like all of a sudden he's a genius that understands how the world works. And so he gave this interview or did this this presentation and q and a with Frontline, and, like, everything that he said was actually intelligent. And then I had to challenge all my beliefs again. Those are my
Steven Haberman [01:19:58]:
picks. Whatever.
Charles Max Wood [01:20:02]:
Yeah. I think everybody who listens to this show on a regular basis knows that I am heavily politically involved. I'm just not gonna comment, on at least not here. I am working on some politically focused shows. And if you don't agree with my opinions and you don't wanna hear them, don't listen to that show. I'm gonna jump in with a couple of things. So I'm gonna do a board game pick really quickly. And, that game is what did we play last time? We played Biblios.
Charles Max Wood [01:20:34]:
That's what we played. So if you haven't played Biblios, it's a card game. I'm gonna try and do this in less than a minute. But, effectively, you have, dice that are set out, and it's if it's the score for getting the most, books of that color. And so and then there are cards that let you change the dice so you can make it 1 higher or 1 lower. And then you're either, capturing your card out of the cards that you drew. You're picking a card that somebody else didn't want on their turn or you're bidding on cards with gold after all the cards have been picked. And so and and then whoever has the most in whatever color you get those dice, whoever has the most pips showing on the tops of their dice that they won wins.
Charles Max Wood [01:21:22]:
It's it's more or less that simple. Board game geek rates it. I I don't have it up in front of me, but it was, like, 1.78 or something like that. So it's very approachable if you're a casual gamer, fun game, probably a half hour game with 4 players. So I'm gonna pick Biblios. And then I I've got a couple of other picks. I went to my doctor a couple weeks ago. Maybe I don't talk about this as much, but I I have type 2 diabetes.
Charles Max Wood [01:21:53]:
And, the doctor prescribed me, among other things, this it's it's a blood glucose monitor. Now the ones that I've used in the past, you poke your finger, you bleed onto a little test strip, and you have to remember to do it on a regular basis, and I'm not so good at that. And so I would run into the issue where, you know, I'd show up at the doctors, and he's like, have you been testing your blood sugar? My answer was always not for a few months. So he prescribed me this, system. It's called the Freestyle Libre 3, and, I'm not sure if you can even see it on the camera, but I've got one.
Steven Haberman [01:22:35]:
Yeah. You can kinda
Charles Max Wood [01:22:36]:
see it right there on my arm. So, you know, it it friends that have those. Yeah. It connects to my phone, and so I'm much better at checking my blood sugar because I'll, you know, periodically look. And, it's also it's funny. I can't remember which book it was, but there was a book that talked about the concept of keys keystone habits, and those are the habits that get you to do all of the other things right. So if you're eating right, then you have a tendency to exercise because you're thinking about your fitness more and things like that. And so this has been good for me because it's kind of a reminder.
Charles Max Wood [01:23:12]:
I'll check my blood sugar, and then I'll remember I haven't taken my medicine yet. And so, anyway so there are things like that that kinda come out of it. But, anyway, it's really cool. I've had a little bit of trouble with them staying on. So last night, I woke up in the middle of the night because I got an alert on my phone that said that my blood sugar was dangerously low. And so, you know, I went downstairs and ate something to try and get it to go up. And then when I came back upstairs, it said that the sensor was no longer working, and it was dangerously low because it had actually come out of my arm and then had gotten poked back into my arm, but not all the way. And so the tissue it was testing was not right.
Charles Max Wood [01:23:55]:
It was given at a bad reading. So I I have had some weird issues with it. I put this one on this morning, right, to replace it. The nice thing is, though, is that I went on the website for the company, and, apparently, they'll replace them if they come out early. So, I just requested a new one, because I have to pay for them. My insurance doesn't cover these, and they're, like, 20, $25 a pop, but they last for, like, 2 weeks at a time. So, anyway, cool stuff. I really, really dig it.
Charles Max Wood [01:24:24]:
And then lastly, I'm just gonna put in a brief plug for JavaScript geniuses. One of the things I think really helps people level up is if you're talking to other people on a regular basis, doing things like meetups, and so I'm providing all of those. So if you join JavaScript geniuses, you'll get access to I'm gonna start doing videos that walk you through different, JavaScript themes. So maybe I'll do a video on Joyce. I don't know. It it's not on my it's not on my list yet, but we'll see. Anyway Yeah. Yeah.
Charles Max Wood [01:24:54]:
So we'll get into other stuff, maybe Vite or, you know, doing agentic AI or things like that. There's all kinds of stuff I wanna figure out how to do with JavaScript. So we'll do that, and I'll demo it, or I'll have people come on and demo it. So maybe we'll have Steve come and talk to us about, or Steven come and talk to us about, Joyce. Anyway, we also do accountability calls on Monday. There's a book club, and we're getting into the AI book from Obi Fernandez right now. We also do a personal development book. We're doing, Awaken the Giant Within by Tony Robbins, and, you can come to as much or as little of this as you want.
Charles Max Wood [01:25:32]:
But, anyway, so it's just a way of doing community based learning and then, you know, giving you videos that walk through stuff. So, go to javascriptgeniuses.com. I will have that up this afternoon, and then you can, go and join the fun. Steven, what are your picks?
Steven Haberman [01:25:52]:
Yeah. Well, I came in without one, so I'm just gonna have one. It's a project called, Grafast, g a r, fast, Grafast. And it's by this guy, Benjie, out of the UK. He also does, well, Charles, you've done, active record Ruby stuff, Sidekick, right, in the Ruby community. So this guy Yep. Kinda has the node version of that. Graph file worker is the name of Graph file worker is probably his main, project, right now.
Steven Haberman [01:26:20]:
And we use the GraphFileWorker as, like, our sidekick. And it works great. We, you know, we like it. And, really props to him. He's trying to go the, you know, make a business out of it. Right? Like, not chasing after VC money, but trying to do some support and upgrades and that sort of thing, which is really amazing. You know, props to him.
Charles Max Wood [01:26:41]:
That's what they did with Sidekicks. So Yeah.
Steven Haberman [01:26:44]:
I can't remember
Charles Max Wood [01:26:45]:
the guy's name, but yeah.
Steven Haberman [01:26:46]:
Oh, I would've known it had you not asked me. But, yes. The well, so anyway, one of Benjie's other projects, other than graph file workers is GrafAST, which is really, like a ground up rethinking of how a GraphQL run time should be. So it doesn't change GraphQL syntax or GraphQL clients or how, you know, how anybody really talks to GraphQL server. But it fundamentally, like so Joyce has to when we went through all of Joyce, like, using promises to, like, fix up all of, you know, all of the n plus ones that would have happened, GRIFAST is a really that that just, like, fundamentally happens with how most GraphQL servers, are implemented. Like, when you, you know, the Apollo in in the GraphQL community or in the Node community, we have Apollo server and Mercurius and oh, you know, there's probably 2 or 3 or 4 others. But they all work this really inefficient way. Of, if if you go from an author to a book to a book review, it just like it hammers, like, each layer down in the graph is just call, call, call, call, call, call, call.
Steven Haberman [01:27:48]:
It it just, like, fundamentally is, as you get down in the graph, treating every single graph node as its own call. And this Grafas thing just, like, really flips it on its head. And and even as you go down the graph, it's it's making one call, for for all of the nodes that you're processing. So I think it has a really great opportunity to, undo a lot of the performance sort of, like, hideousness that most GraphQL, things either have to just, you know, back ends either have to just deal with or patch around, which is what we did in Joyce. And, yeah, it's still a super small project, and, I I need to spend more time with it, but that is my pick. I think it's pretty neat. Awesome.
Charles Max Wood [01:28:34]:
Alright. Well, if people wanna connect with you, where where do they find you?
Steven Haberman [01:28:38]:
Yeah. Sure. You know, the joyce or o orm. Io. I do have a blog that I need to get to. It's, I'm a little bit embarrassed about the name. It's draconianoverlord.com, but I picked it a long time ago I love it. When I was younger and a little more, idealistic.
Steven Haberman [01:28:53]:
Maybe not idealistic. But
AJ O'Neil [01:28:56]:
Draconian Overlord is idealistic.
Steven Haberman [01:28:58]:
Yeah. Right. Yeah. There was a bit, but, Aspirational. I guess it depends on what your ideals are. Yeah. Right. But, also, the I I the domain name was available.
Steven Haberman [01:29:08]:
Like like, I I thought of it 15 years ago, and it's like, holy shit. The domain name's available. So, anyway, that's my blog. And, you know, a lot of the writing is kinda older from my earlier, you know, Java sort of heyday back in the day. But, yeah, I I need to post more stuff there if anybody wants to come by. But Joyce would be the main place. You know, love to have anybody drop by and say hi.
AJ O'Neil [01:29:30]:
Alright. Cool. And I I do want to say, I like the philosophy of Joyce. I I wanna I just I just wanna make it clear because I'm the naysayer out of the group. Like, I'm the one who's always, like, skeptic. I don't believe it's gonna work. Why would anybody wanna use this? And I I like the philosophy. You really got me when you said, well, if you need the fancy stuff that's the 5%, like, just go do the sequel.
AJ O'Neil [01:29:57]:
That that's that that that you're gonna focus on just be the good just be good at the stuff that is the simple that people need the most, and not try to cater towards the stuff where people really should just go do the sequel. That that philosophy makes me believe that this is going to have an hopefully, an eternal advantage over a lot of the other ones where they try to give you these, like, halfway kind of things. So that that's the main point, but it looks it looks good. I and and like I said, I like it looks obvious. It looks like, well, it doesn't take a genius to figure this out. It did, but it's you know, when you look at it, it looks it looks obvious.
Steven Haberman [01:30:40]:
Yeah. No. I appreciate it. I I mean, that's high praise, for the the the looking obvious is totally the goal. That's what we're after. So really appreciate that.
Charles Max Wood [01:30:49]:
Yeah. By the way, it was Mike Perham that is the psychic guy.
Steven Haberman [01:30:53]:
Actually, I I don't think I could have told you that. I completely forgotten his name. But yes. Yeah. That sounds right.
Charles Max Wood [01:30:58]:
Yeah. We've had him on Ruby Rogues. He's a terrific guy. Anyway, let's go ahead and wrap it up. Till next time folks. Max out.
Hey, folks. Welcome back
Charles Max Wood [00:00:06]:
to another episode of JavaScript Jabber. This week on our panel, we have AJ O'Neil.
AJ O'Neil [00:00:12]:
Yo. Yo. Yo. Coming at you live from a broken stator. No. Sorry. Not stator. Solenoid.
Charles Max Wood [00:00:22]:
Okay. We also have Steve Edwards.
Steve Edwards [00:00:26]:
Yo. Coming at you. Just one yo for me, from cloudy and cool Portland.
Charles Max Wood [00:00:32]:
I'm Charles Max Wood from Top End Devs. And, this week we have a special guest that is Steven Haberman. Steven, do you wanna introduce yourself? I don't think we've had you on before.
Steven Haberman [00:00:44]:
Yeah. Sure. I will do a singular Yo as well, coming from Omaha, Nebraska. And, yeah. Yeah. Really appreciate, you having me on. In terms of, intros, right now, I'm a back end, you know, team lead type engineer at Homebound. You mentioned construction.
Steven Haberman [00:01:03]:
So we're talking about Joyst or Joyst RM. Homebound's a residential construction startup. So we besides just building, SaaS software well, kind of the reason. We don't build SaaS software. We build software for the back end of, the main thing our company does is is build homes, build construction, residential homes. And, yeah, that's me.
Charles Max Wood [00:01:25]:
Yeah. So you talked about the Joist ORM. Yeah. I think you emailed me about it, and this that's how how I found it anyway. Mhmm. I'm just wondering as we get into this, first of all, what problem does it solve, and maybe that's tied up in why you built it?
Steven Haberman [00:01:44]:
Yeah. Sure. No. It's a great question. And so where where Joyce came from was, a few years ago, we were, setting up to build our back end stack. You know, we're a TypeScript shop. We do a lot of TypeScript on the front end, React, very, standard sort of stuff, and wanted to do very standard stuff on the back end as well. And we picked GraphQL as our, you know, layer in between, at the time, which we actually still enjoy.
Steven Haberman [00:02:10]:
I know, you know, that can be some that can be a tangent for later. But so we started off writing our GraphQL, back end in TypeScript and, you know, went to go pick an ORM because that's kinda what you do when you do these things. This is probably 2019 or so. And one of the things that we ran into just right away was just pervasive m plus ones and a GraphQL back end. So, you know, GraphQL is not like your typical endpoints. Right? Where, in a typical web endpoint, you know, slash authors or whatever, you know exactly what your endpoint's gonna do. So you can do one big query kinda upfront to, you know, preload your data as much as you can, and then let your, logic run, you know, afterwards. But GraphQL has such a dynamic, you know, there is no single endpoint.
Steven Haberman [00:02:57]:
Every query is so dynamic, that, you know, the engineer can't just upfront write the exact, you know, preload or query or or whatnot. That it's gonna magically load the data in a performant way. So, we've been using another or m or 2 at the time, but we're just really struggling with m plus ones. And so that was really, Joyce's first claim to fame is that, we had started out doing some cogeneration from the schema and that sort of thing, which is very standard now in a lot of ORMs. But, yeah, we're just wanted to fundamentally solve n plus ones. And so we, started out putting Joyce on top of, the Facebook data loader project, which uses this little, you know, event lit event loop tick trick, if you guys are familiar with that to, You know, if, you know, in the n plus one problem problem. Right? If I've got an author and I'm gonna read some books, and then the books, I'm gonna read the book reviews, it's really easy, for as you go down your object graph to, like, make a query for every single book's reviews over and over and over and over and over. Right? N plus 1.
Steven Haberman [00:04:02]:
I I guess, you know, let me know if you want me to go slower through the n plus one problem.
Steve Edwards [00:04:05]:
Well, yeah. I was I was gonna say I'll give a real quick definition. I wanted to get into that
Steven Haberman [00:04:09]:
real quick before
Steve Edwards [00:04:10]:
we look too far. So, basically, if you have, you know, your books and author problems, the n plus one problem is where you do a, you know, a query for I how would you put it? An author so if you have an author that has multiple books, you're doing a query for every book. Right? Give me this author and this book, this author and this book, this author and this book, whereas if to solve that problem, you can do one big query. Give me this author and all their books, you know, in one query. Mhmm. Altogether, all the book IDs, I guess. So that's the basic n plus one. I'm sure there's better explanations, but that's
Steven Haberman [00:04:46]:
No. And that's what I have. Yeah. And and it, it's really easy to have to happen. So Joyce is is an entity based ORM. So it is very inspired by, like, Ruby active record and, some of the other, OG entity ORMs. You you know, if you go all the way back to, you know, OG hibernate Java hibernate back in the day and those sort of things. But, there's pros and cons of of an entity ORM type approach where, you know, you think of your I I really like to think of a database schema as a graph, and a connected graph, and that sort of thing.
Steven Haberman [00:05:23]:
But, if you think of them as objects, it's really easy, which is kind of the slippery slope of of of leaky abstraction. Right? Because if you think of your entities as objects, which is what entity ORMs do, it's really easy for programmers to accidentally write for loops that cause database queries. Right? Because, if if you have an author object and you're like, oh, I'm just gonna ask for the books. You know, one of the things that ORM entity based ORMs do is is they do this lazy loading of, like, oh, you don't have the books, so go get those for you, which seems really nice. But as soon as you do that in a for loop, now you've you've got an n plus one. And that's been a problem in ORMs just, like, fundamentally forever. You know, as soon as you start doing and and what's what's annoying is when it's it's more obvious when it's in the small. You know, if you've got an endpoint and you're right in your one endpoint file, and and you've right there in the code, you've got a 4 loop.
Steven Haberman [00:06:20]:
You're like, well, I loaded the authors, and then within that, I'm loading the books. It's very obvious within this file, that I need to, you know, hoist my data loading up out of my my 4 loop. But what's kind of insidious about entity based ORMs is, is when you start running side effects and other, drive business logic like, you know, entity ORMs. They like to put methods inside the author class to do some business logic or have an author life cycle hook or or these sort of things. And as soon as some of those side effects, start, you know, accidentally or or sort of, what's the emergent behavior, being called in a loop, now, you know, you're back to an n plus one. And what was maybe interesting about GraphQL was just, like, how quickly that happened. Right? So, like, if you're in a Rails back end, you can go, you know, 2 or 3 years, and and, you know, fight your, you know you you have your every 2 weeks n plus one that somebody goes, and, you know, figures out a production where it's happening and tries to magically hoist the data loading up, to the top of the endpoint. And and that's just kind of a cost of doing business in in a big Rails back end.
Steven Haberman [00:07:25]:
And, but you can kinda get away with it, you know, until you your scale is too big or whatnot. And and maybe what's unique, and and maybe I think why GraphQL has maybe not been as popular as it could have been, is just how easy that is to happen. It happens right away in GraphQL. And so that was really what Joyce set out to solve, was we wanted to make a GraphQL background a back end that didn't suck to go right. Right? And, we leaned on this Facebook data loader, which did actually come out of the GraphQL community. It's it's you know, we're sitting on on shoulders of giants and those sort of things. But, maybe what's unique about Joyce is the the data loader pattern had been around for a long time, but engineers were generally expected to integrate it by hand. Right? You go into this GraphQL Resolver and do your data loader logic or and, you know, there's, I know the the GraphQL frameworks like the Fastifys and Mercurius and, and, those were things.
Steven Haberman [00:08:24]:
And, you know, they have the data loader pattern built into it, but you as the engineer had to go make use of it. And that's just boilerplatey, and and nobody does it, and and it's it's kind of annoying. So, Joyce's claim to fame was that it's, like every operation, asterisk, there's there's 1 or 2 that don't, especially, like, paginated. It's very hard to do, paginated, auto batching. But otherwise, like, every operation in Joyce auto batches through DataLoader. So if you ask for an author and you accidentally ask for an author in the loop and you ask for 50, that's, you know, one SQL call. If if you accidentally, or not even accidentally, you know, on purpose, load a bunch of books in a for loop or a bunch of books in a life cycle event or a bunch of, you know, in a GraphQL nested GraphQL Resolver. Basically, every operation in Joyce goes through a data loader for free and gets, auto batched.
Steven Haberman [00:09:19]:
And, yeah, that's what got us started down the path.
AJ O'Neil [00:09:24]:
How are you doing that? Do you do you await at the end? I'm actually looking for an example on your website Gotcha. To see if I if I can see what this looks like. But I'm imagining you must not await in the loop because the data obviously isn't there if you're waiting for it to batch. So you must await at the end of the loop or something like that, or or you're putting it in a callback or or something to some sort of handler rather than than a promise.
Steven Haberman [00:09:50]:
Yep. We had some good docs on let's see. If you go to goals and then avoiding n plus ones, over on the side, probably describes it pretty well, really soulfully. And, I mean, the wrinkle is that we we, sit on top of Node's promises. Promises are really amazing because they because they're on the event loop, and and you you always have to await them, which which it's ironic because in, like, 20 10, this was, like, everything you did in node had to do a callback, and it was really terrible. And every you know, everybody hated it. Yeah. But, you know, the the people do a node in 2010.
Steven Haberman [00:10:31]:
That that would that would you you were that was hardcore.
Charles Max Wood [00:10:33]:
But, Banging rocks together.
Steven Haberman [00:10:36]:
Yeah. Right. 100%. Oh, what's so ironic is is just how well, JavaScript is language and TypeScript, especially on top of it, have evolved since then to, you know, add, basic weight and all of these things such that, it's turned to what was really annoying, this inventive model of of only 1 thread at a time. It's a really a pretty pleasant, environment to work in. And so to get back to the what DataLoader does is, basically, because you have to await everything anyway, the promise in the event loop, is basically what sets a really fast timer for you. So, like, pretend we weren't in in JavaScript. We were in Java or, you know, OG Java or something like this.
Steven Haberman [00:11:15]:
And you're like, okay, well, I'm gonna do, you know, 10 wire calls or 20 wire calls, but I don't really know how many I'm gonna do. Right? Because before you start your for loop, you don't know if there's 5 books or 10 books or, you know, how many books that for loop's gonna go through. And so you kinda but but you don't you wanna make that first book call and not have it not go right away. Right? Because, like, as soon as the the IO leaves the server, you know, there's your n plus one. So you wanna go through your your proverbial for loop, you know. Maybe this is a GraphQL server run time or whatever, but, you know, let's think of it as a for loop. You want to, like, ask for book 1, ask for book 2, ask for book 3, ask for book 4, and and have these, like, not actually happen yet. You want them to just be, I'm gonna hurry up and jump to the the the term promises.
Steven Haberman [00:11:59]:
You want them to be a promise of a book. And you wanna wait until you've asked for all of the books. And there's the hard thing, is you don't know when you're done in in most environments. Right? So like an OG Java or something like this, you you'd write a for loop, and you would get to the end of the for loop. And then you would have to, like, tell the run time to, like, okay, I'm at the end of the for loop. Ask for all my books. You know, flush my book calls. And, you could do that, but nobody nobody does.
Steven Haberman [00:12:26]:
And so what's really interesting about Promises instead is that, the very first, you know, time you ask for a book, it puts a little, I wanna use the term poison builder, but that's not quite right. It it puts a little hint at the end of the event loop, which is gonna run right away. Right? Right? It's not like a setmillies 50 or a setmillies a 100. It just says like, you know,
AJ O'Neil [00:12:46]:
in just
Steven Haberman [00:12:47]:
a little bit, the next tick. Right. Flush flush my SQL calls. And that's it. Like that that's the end of the trick. And it's it's really, pretty surprising how such a simple little, idea, can, you know, fundamentally transform, the performance and ergonomics, right, of Joyce. Like with, Joyce and things using DataLoader, you get this really elegant, you know, emergent, auto batching that just works. It always works.
Steven Haberman [00:13:16]:
You don't have to do anything to get it.
AJ O'Neil [00:13:19]:
Yeah. I think that objection does something similar to this too. At least it does it with its query builder. You may have taken it a step further, and that you're you're exposing a query builder kind of implicitly. So as you're going through the loop, the query builder continues until you're done with the loop. I haven't actually
Steven Haberman [00:13:42]:
Mhmm. I
AJ O'Neil [00:13:42]:
don't know if I've actually tried this in objection to know whether or not it's doing something similar with with the n plus one problem. But it the query builder in general is built that way, but it's more of a a chaining type of thing. Like, you you can keep chaining the query builder, and then it waits until next tick to actually resolve the query builder into something. So by the time you await it, you're awaiting whatever is at the end of the chain, not what's at the beginning of the chain or where the chain collapses. I'm not really sure what the how the mechanism works, but I do know that it has it has similar magic where there's state management inside of the query builder that's waiting for that next tick in order to resolve the query builder. And this this looks this looks similar, but it's got more of a, a naive looking you know, like like, it looks naive.
Steven Haberman [00:14:40]:
Mhmm.
AJ O'Neil [00:14:41]:
And then you it look it looks like you have a dot each. So rather than using the for loop on it, you use it well, I'm I see where you're you're building the query. I don't see where you actually use the query. I saw one example. It looked like there was a dot each. Is that what you're providing so people don't people don't call for each, they call dot each?
Steven Haberman [00:15:03]:
I'm trying to find, the dot each that you're referencing. Oh, you might.
AJ O'Neil [00:15:08]:
I I Oh, that was that was an example of Ruby code.
Steven Haberman [00:15:11]:
Never mind. Yes. Sorry. Yeah. I I
Charles Max Wood [00:15:13]:
That is a very Ruby thing. Yes.
Steven Haberman [00:15:15]:
Yeah. Yeah. I, you know, I didn't actually use Rails for, like, years years years, but they just stuff Rails and ActiveRecord to, be thoroughly impressed with the ergonomics. And, and so Joyce is kind of, unashamedly, tries to, you know, borrow as much, ergonomics and and best practices as we can for ActiveRecord. And so and so you'll see some active record isms, especially in the docs of, you know, how well, and and particularly the n plus ones. I I guess that would be one thing. I think we kinda use this as a talking point is how, active record, I would assert, has not really solved, like, in in the same way that Joyce has, solved, n plus ones. You know, inactive record is is kind of this whack a mole job of finding where you need to do your load hint, you know, preload hint.
Steven Haberman [00:16:09]:
And, we can get into it maybe a little later, but but Joyce does have the concept, preload hints to make, all of your awaits go away, which which is maybe a tangent. And and so and, Joyce, you can do preload hints because you'll get more ergonomics and you don't have to, await code. But you don't have to. Like like, you'll still get this emergent, auto batching behavior even without and, it's interesting you mentioned the objection. I'll I'll have to go look. It's been a while since I've, you know, for sure taken a look at, the other ORMs around. I think a lot of the ORMs that I've seen, you know, do require these hints for the engineer to, like, know upfront what's gonna happen. You know, to know upfront that in my query, I need to ask for this, and in my query, I need to ask for this.
Steven Haberman [00:16:52]:
Because later somebody's gonna use it. Right? It's because later somebody's gonna do a for loop. And, that's really the the beauty of of the data loader approach is it's, there's, you know, any emergent behavior that actually accidentally runs accidentally or on purpose, runs in a loop, gets the, gets the auto batching.
AJ O'Neil [00:17:13]:
Okay. Yeah. So if I I would love it if with your n plus ones lazy loading in a loop example, if
Steven Haberman [00:17:19]:
Yeah.
AJ O'Neil [00:17:20]:
If it continued, like, the next one or three lines or whatever comes after this. Sure. I get I get what's happening there, but then I wonder how would I use this because it because, you know, every everything's alighted away as to how I use it. And just for the mental model of it, I'm Yeah. Like, do do I await it a final time, or do I what?
Steven Haberman [00:17:44]:
I see what you're saying. Maybe you go to the load safe relations, page right below this. You'll get a little bit of a few more syntax examples of, like, using axing the entities, and the relations on the entities. So we do wrap our relations, you know, so this would be author dot books. You know, that's the books relation. Or author dot publishers, the publisher of your base. And, and and some of the OG ORMs, like type ORM, at least back when I did it, and I'm 90% sure they still do that. And and even the Java ORMs, the hibernating superworld, would model those, like, as, the array directly.
Steven Haberman [00:18:21]:
Right? Author dot books is literally a book array. But it's not really because it has to be lazy loaded. Right? And and so then they do various proxy lazy loading magic to to make it look like a book array as soon as you access it. We go ahead and wrap all of our relations in, these little wrappers that you can either, ask to be loaded. So, like, on that load safe relations, you'll if if the publisher is not loaded yet, the type system knows about it. This is kind of the 10 the tangent that I was, alluding to earlier is that, when I used Type ORM back in the day, because of this, the type system would never know whether something was was, loaded or not. Right? If if you just gave me an author and, I wanted to get to the books, sure. I could do author dot books, but but I I didn't really know, whether that had been loaded or not.
Steven Haberman [00:19:11]:
And if it They're
AJ O'Neil [00:19:11]:
all monads. It's monads all the way down.
Steven Haberman [00:19:14]:
Well, you're getting yes. You're getting that. Yeah. And, so, you know
AJ O'Neil [00:19:21]:
Correct use of monads. Nice.
Steven Haberman [00:19:28]:
The no. Actually, well, you guys talked about effect recently. Right? How those guys, on the podcast. I think that's all I could buy. The TS effect. Or maybe I'm getting my podcast mixed up. Well, the the the Promise, Promise is basically a monad unless you talk to the TS effect people. And the TS effect people have strong opinions how, Promise is not the perfect monad, and they have their own effect, that is the more perfect, monad, which is fine, but I I I don't know.
Steven Haberman [00:20:00]:
I think it's a little, maybe academic, and and Promise seems just fine to me, I guess. But So for the
AJ O'Neil [00:20:07]:
for the people at home
Steven Haberman [00:20:09]:
Yeah.
AJ O'Neil [00:20:09]:
That have never encountered somebody who can both know what a monad is and explain it in a way that other people can understand at the same time, I am the singularity. Monad is simply an object that encapsulates a value that is not the value itself. So for example, if you have answer, answer is equal to 42, that's a value. If you were to wrap answer in a promise so that you have to do something else like call dot then or in some way unwrap it in order to get the value 42 out of it, that's a monad.
Steven Haberman [00:20:48]:
Yeah. And I think it's it's applicable here because I I think one of the things monads are great about is delaying evaluation. You know, to your example, when you ask for 42 and it's just like, 42 is right there. You know, there there's no ability to do, like, meta programming around that or or the you know? But if you're you know, you mentioned Monad wrapping the value that you have to ask for. The fact that Monads fundamentally it it promises, you know, is is if you squint a Monad, you have to ask it for its value. That that delayed, execution is what allows you to do fun things like auto batching in SQL calls.
Steve Edwards [00:21:25]:
So one thing that's interesting here in looking at this is I come from the I live in the PHP world of Laravel, and I'm seeing a heck of a lot of similarities here
Steven Haberman [00:21:34]:
Sure.
Steve Edwards [00:21:34]:
Just in terms of relationships and definitions and how you load them, how you get them, the syntax.
Steven Haberman [00:21:40]:
Mhmm. Hopefully, in a good way.
Steve Edwards [00:21:41]:
You're using yes. Yeah. You're using dot instead of, you know, as an arrow since p p versus node.
Steven Haberman [00:21:48]:
Mhmm. Mhmm.
Steve Edwards [00:21:48]:
But yeah. To so that to me, that looks, very similar.
Steven Haberman [00:21:54]:
Yeah. I mean, we we try to be very boring in a good way, and then, like, you know, but but still have the value adds that that, or or innovations that, make us different, so to say. But yeah. But yeah. You you know, AJ, you had mentioned, what does it just look like to even get the data out? That the this next load safe relations hopefully shows you it's very soon. You know, you go to you have an author, you go to your publisher, you ask for it. You ask for the books, you ask for the the things. Maybe, the the second code example of the load safe relations is an interesting thing to talk about, because it shows the difference between a like a dot load that returns a promise versus a dot get that returns it synchronously.
Steven Haberman [00:22:39]:
So promises are actually kind of annoying. They're very boilerplate because you've gotta await everything. Right? So if you've got, a little, you know, let's say, 10 to 20 line method and, you wanna go from, you know, the books to the book reviews to the review comments, and and and every single one of those is, is a promise. You know, you're gonna have to await promise all in your top loop. You're gonna have to wait, promise all your inner loop, and you're gonna have to wait, you know, promise all your 3rd loop. And it and, you know, and then flat map the promises together and something something something something. And, you can do it, but, you know, it it's I couldn't I you know, I guess I'd ask Chant GTP to write it for me the first time around. But, but what Joyce lets you do with these load safe relations is is if you do you know, so I just made a big deal about how, the auto batching of our SQL behavior is very emergent.
Steven Haberman [00:23:35]:
You you you don't have to declare load hints and preload hints to get that, performance of those. But if you do, you know, add a load hint, you know, one of these, like, I want the author and I want the publisher and the comments and the books, which I think is, you know, AJ, kinda like the objection query builder is is my guess of what that syntax looks like. I don't know. I've tried
AJ O'Neil [00:23:55]:
to forget it. I've I've tried to I've tried to erase it from my memory. I'm I'm done with ORMs, by the way. I'm Uh-huh. For Node and SQL c for everything else. Mhmm. ORMs, they've they've burned me too many times, and I I just can't find the value in the in
Steven Haberman [00:24:10]:
the network. Yes. Well, there's our second half of the of the recording, for sure. We can get to that. The but, you know, back to the the the loads versus the gets, is that if you do do these loads, which are optional, you don't have to for performance, it actually changes the types in the type system. So these get methods that let you like, there's no awaits now. Right? So, like, it used to be if I had a loop and a loop and a loop, I'd have to await every single time I touched a relation. If you do these load hints, we'll add in with because joist and the joist run time and the and the TypeScript type system knows the data is there, we'll add synchronous methods for you to be able to get at it.
Steven Haberman [00:24:52]:
Just do this get do this get. And it's as if it was, arrays in memory or entities in memory because it is now. And and we know that it is now. Right? Whereas if you hadn't done that load hint, we don't really know. You you know, there might be an I IO call there, and so you'd have to wait. But, I would say that's, probably the second on the list of what, you know, what makes things, what makes Joyce novel and pleasant is maybe this load safe relations to, just remove some of the await gunk that
AJ O'Neil [00:25:20]:
you end up having
Steven Haberman [00:25:21]:
in Node. You're
AJ O'Neil [00:25:23]:
you're telling me that by virtue of calling await author.books.loadonline3
Steven Haberman [00:25:31]:
Mhmm.
AJ O'Neil [00:25:32]:
That on line 4, the TypeScript checker knows that author.books.git exists, and it wouldn't know that if on line 3, I hadn't run the load?
Steven Haberman [00:25:46]:
Yeah. You know, if you if we're on the same we're on the load safe relations, we're in the second code block of that page.
AJ O'Neil [00:25:52]:
See the second code block of that page. Okay. Now I'm looking loads yeah. The very first section, now looking at the second code block. Okay. Author.publisher.git.
Steven Haberman [00:26:05]:
Yes.
AJ O'Neil [00:26:05]:
And you're saying you're saying that because oh, no. This is, oh, this is different. This is different. Okay. So it's looking at what load returns, and it's determining from what load returns. I was actually looking in the second section Mhmm. Where or is it the third section? I was I was a little bit further down. Okay.
AJ O'Neil [00:26:25]:
Yes. I was a little bit further down. I was looking at the, after it says yuck, and it's anyway, I I think I I think I get I think I get what's going on, but, no. My question still stands. So, Yuck, given this compilation, some ORMs in the JavaScript space, sometimes Fudge collections must be async. And then it and then it has 3 lines here. And so there's one line where it await dot load for author, And then there's another line
Steven Haberman [00:26:55]:
Oh, yeah.
AJ O'Neil [00:26:55]:
For await dot load the books, but that one is not doing books equals. Right. So the this one, the type checker still wouldn't know for certain that dot git exists because this one didn't do a books equals author dot books dot load. Right?
Steven Haberman [00:27:11]:
Right. Yeah.
AJ O'Neil [00:27:12]:
Okay. Okay. Alright. Now now I'm on board because TypeScript does a lot of magic. It does a lot of magic. And I have Sure. I have fought with some of that magic. And you were you were teaching me new I thought you were teaching me new magic that I needed to know.
AJ O'Neil [00:27:26]:
But but no. It's it's it's it's old magic. Old magic. Got it. I'm with you.
Steven Haberman [00:27:33]:
Right. Yeah. That that example could probably be cleaned up a little bit. I don't know why my camera keeps going out of focus. But, the intent was to show that, type ORM was probably the the ORM other ORM I've used the most, before writing Joyce did. And it was 5 years ago, so I have to, you know, add all sorts of disclaimers that maybe they fixed things. So it's time to turn the camera. Can you do it? That, you know, you'd have to, like, magically access a relation in one part of the code base to then, like, access it in another, and and it would just it would just work over there.
Steven Haberman [00:28:07]:
And and you wouldn't have to await it. And and I don't know. And it was kind of magic magic at a distance as I recall. But but disclaimers, that was a while ago. But
Steve Edwards [00:28:16]:
and
Steven Haberman [00:28:16]:
it was what that section was attempting to show, but, yeah, I can probably be spruced up a little bit. Cool.
AJ O'Neil [00:28:22]:
Alright. Well, I'm with you. I I think that this is, in some ways, I like like many good solutions, when you see it, it's obvious, and you wonder why doesn't everyone do it this way. Yes. Like, looking at it, it doesn't look like, oh, you did something super intelligent that required the brain of a 1000 men combined into 1. Sure. You know, it it looks it looks like, well, duh, of course, you do it this way. But other people weren't doing it this way, so you are the genius.
AJ O'Neil [00:28:49]:
You're the genius that discovered the simple way to do it.
Steven Haberman [00:28:52]:
Sure. I found I found Beta Loader first, I guess. But yes. Yeah. Yeah. I mean, that's kind of the intent. Is is that, again, you know, shout out to the Rails active record ethos of of boring is good. Right? You know, some of the other things that we do try and do well, I'm this might tiptoe AJ into your, like, ORMs, you know, are are terrible sort of thing.
Steven Haberman [00:29:13]:
We we try to, like, make first class notions around domain modeling. Right? So, like, we try to think of not just tables in the database, but try and think of, like, our entities as a graph. And, you know, how are we modeling the world? You know? I like domain driven design, although there there are, king there there are sign kind of some complexities and cargo quilting ish around some of the domain driven design stuff.
AJ O'Neil [00:29:39]:
But You'll you'll have to give me the simple explanation of domain driven design because with all of the, you know, the XDDs that exist, I,
Steven Haberman [00:29:50]:
I mean, it's an older notion from, so Eric Evans was the guy in, you know, probably 2010 or so, 2005 or so, that popularized the term. And and really a lot of it was, you know, ubiquitous language and and, engineers speaking in the same language as your business users and, you know, really modeling, the entities, in their world, you know, in the code and that sort of thing. And, for for me, that was the, you know, 80% of what domain driven sign was about anyway.
AJ O'Neil [00:30:21]:
Sorry. I heard words. What did you say? Take it take it one take it one layer lower. Like like, remove the the buzz the buzzwords from it if you can and and
Steven Haberman [00:30:33]:
well, so ubiquitous language is, like, you know, if the if you talk to your, you so I I do a lot of back office ish sort of software. Right? So so if I'm talking to a user of my software and they they call something a bill, I probably wanna call that a bill in the code base. Right? Like like, we wanna remove these sort of, like, talking past each other where, you know, I call the or or I don't I don't I call it something different, or I don't even have the concept of a bill, right, within the code base. Or, you know, for any of the other, you know, sort of workflow, you know, you know, I'm falling back on, like, you know, crud crud app, you know, crud apps and enterprise spreadsheets and those sort of things where you're you're making software for business users running a business that, you know, all of the business concepts have a matching concept in the code that kind of matches it as much as you can. And, you know, you don't want to yeah. As much as you can. And, so that's the the ubiquitous language side of things. And, and the domain driven design sort of things is kind of a set of patterns around, you know it really kind of I wanna say it's o o at the heart of it, but, you know, if there's a bill concept to the user, you probably have a bill entity.
Steven Haberman [00:31:49]:
And if the user has a, you know, bank account concept, you probably have a bank account concept and that sort of thing. So just, you know, modeling, the world that you're building your system around in your code base, I guess. That's a better explanation, hopefully.
AJ O'Neil [00:32:06]:
So so just more of a one to one between the way that you would speak about the business rules as in when a customer places an order, it puts an item in their shopping cart and then it triggers the payment. So you would you would just have a pretty much a one to one with that where, okay, then there's a shopping cart object, there's a customer object, there's a there's a payment object. So it's just just the the idea of being fairly fairly one to 1, not not having too many abstractions over what the the the need is for the customer to get done and the way the software design is built. Okay.
Steven Haberman [00:32:48]:
Yeah. Which I you know, you you we had mentioned that, you know, a lot of the joys isms, like, they they look very natural and and and kind of by, by default or whatnot. I think the ubiquitous language is kinda the same thing. I I don't think it's super innovative per se. It's just a term for, I think, probably what most people do by default anyway, you know, potentially. But, yeah. Well and so along the lines of the domain modeling side of things, we try to, you know, add some first class features on top of just just a table, just a database table and just columns. Right? So, we try to be very explicit about, well, we can get into some of our reactivity sort of things.
Steven Haberman [00:33:36]:
But, you know, even if you, start talking about database tables, you know, some of your tables are, you know, primitive columns, which is great. And some of them are are your foreign key columns, which are your relations, and and all all of that's fine. We wanna talk about, let's do cross entity validation rule. So, you know, while this might get AJ, we'll tiptoe into your, you know, just taste for ORMs sort of discussion, like, one of the things that I do, think entity ORMs, so and and the dichotomy between, so I've mentioned the term entity based ORM a lot. I would say the other style of working with data is query builders. Right? So the query builders of the node world are like the Prismas, Drizzle, are probably the big 2 these days. Kisley is another, if I'm saying their name right. But on the query builder side of the spectrum, you issue every single call that the ORM does, you do directly.
Steven Haberman [00:34:32]:
Right? You you make the query and it, the query builder just facilitates you doing that in a very, you know, nicer syntax than writing raw SQL. And and you, you know, hopefully, you'll get some type safety from it, because the query builder looks at your database schema and does some type checking of your TypeScript DSL and that sort of thing. So that's the
AJ O'Neil [00:34:52]:
Maybe maybe it does. Maybe it doesn't.
Steven Haberman [00:34:55]:
Sure. Yeah. Yeah. And, so so so those are the query builder. My my maybe slight quibble is that I I don't I almost don't consider those ORMs. I've I've got a blog blog post I wanna go write about, like, what the o in ORM means. And I guess I maybe this is just my I know this is my biases. But, the o in an ORM to me has always kinda meant an entity.
Steven Haberman [00:35:19]:
Right? Like, if I'm using an ORM, I expect there to be an
AJ O'Neil [00:35:23]:
o for ampity.
Steven Haberman [00:35:24]:
Yes. You know, I guess, is is really the term I'm looking for here. But, I mean
AJ O'Neil [00:35:30]:
Yeah. Yeah. Yeah.
Steven Haberman [00:35:31]:
For for the 10 to 15 years, I used ORMs, like, you know, the hibernates and the, JPAs and all of those other and active record. Right? Like, every ORM I've used up until, like, 3 or 4 years ago in the node community had entities. Maybe you had an author file, a book file, a book review file, a comment file, and maybe it was Java code or maybe it was Ruby code or whatever. And it seems like the node the go ahead.
AJ O'Neil [00:35:54]:
I I think that the common pattern is that the ORM is built on the query builder. And so the query builder moves through the ORM because you use the ORM, it uses the query builder, it returns you a partially built query builder object, then you add on dot select name age. And so the ORM is is giving you in many cases, it's giving you both because to the point of
Steven Haberman [00:36:25]:
That's true. You know,
AJ O'Neil [00:36:26]:
the conference slides of GraphQL Yeah. Why load the entire 10, 15 columns if all you need is is 2? And the answer to that is, of course, well, you're gonna need the other 10 or 15. Otherwise, you wouldn't have them. So you might as well load them and then just cache them.
Steven Haberman [00:36:41]:
That's cheap. We're, yeah, we're in a row oriented storage. So, no. You're you're you're right that for a long time and if you said an ORM, it did mean both. It meant you had, an author file and a book file and a book review file. But the ORMs came with the query builders, like the hibernates of the world, so that you could, you know ORMs, kind of by default, of of course, are really good at the very boring credit queries, like an insert, update, delete, of an author, bulk, you know, bulk review. They they can knock those things out any any day, every day. What gets hard is the queries that, like, oh, I wanna join and left join over here and then group by and then having and all of those other sort of things.
Steven Haberman [00:37:16]:
It's really where ORMs, are not so great, but historically have come with query builders, in them somewhere to to at least try and let you do that, which maybe another unique thing about Joyce, we don't have that. Like, I think that's a very hard problem to solve, and and I haven't decided, to tackle it yet. Just because I I mean, the stuff you can do in SQL, I'd rather just write SQL. Like, I think there's also Okay. Yeah. Yeah. Yeah. You know, that there's this economy where people think that, well, if you use an ORM, you have to do everything through the ORM.
Steven Haberman [00:37:45]:
Or if you do a query builder, you have to do everything through the query builder. And But
AJ O'Neil [00:37:49]:
now we're getting into interesting yeah. Now we're getting to a very interesting area. And I and and now I'm very, very interested to, you know, to to hear more about what you're saying. Because
Steven Haberman [00:37:58]:
Sure.
AJ O'Neil [00:37:58]:
I I think that from my perspective, from what I've seen, you know, being in software the last 20 years, and and ORMs have existed longer than that. But from what I've seen, the r ORM came about because Postgres became popular. And suddenly people wanted the the, you know, the hoity toity people that were using Postgres my rather than MySQL. Or the people that just wanted to do the lowly people that were using SQLite rather than MySQL. Mhmm. They wanted to be able to say my open source project is for you too. And so rather than having their project work really well with MySQL, they started making compromises so that it would work just as poorly with Postgres or with SQLite as it would work with MySQL. That from my from my framing, that's how ORMs came about was instead of let's let's just use the tools of the database well, let's castrate them so we might as well just be using Mongo.
Steven Haberman [00:39:01]:
Yeah. That's an interesting
AJ O'Neil [00:39:02]:
Except Mongo didn't exist yet.
Steven Haberman [00:39:04]:
Right. Right. Right. Right. No. You you're right. There is a race to, like, the lowest common denominator across databases, you know, for the ORMs that, and so, you know, Joyce is very tiny, and and so we only support post grade, right now, which is not really on purpose, so to say. That's just the only thing that, we've needed, personally.
Steven Haberman [00:39:24]:
But Has your hoity toity? No. We're small. I I just I don't have any I'm
AJ O'Neil [00:39:29]:
I'm teasing. I'm teasing because I'm saying
Steven Haberman [00:39:31]:
the I I don't have no fees. Nobody's paying me to go to go write them, my SQL driver. If you want, like,
AJ O'Neil [00:39:35]:
I don't know. You never do. I hope you never do. Yeah. I hope that you just keep because some of the great projects out there, they as they grow, they start saying, oh, well, we are like, this is happening with SQL c. Right? SQL c was a Postgres only thing. And now they're like, okay. Well, we're also gonna support MySQL, and we're also gonna support SQLite.
AJ O'Neil [00:39:56]:
And rather than just supporting Go, which I'm totally fine with them doing the JSON format because that's a way of abstraction that seems right. They're they're like, oh, and we're gonna have a a a TypeScript specific driver, and we're gonna have a Python specific. And so now the project's kind of you know,
Steven Haberman [00:40:11]:
it Yep. Yep.
AJ O'Neil [00:40:13]:
Like, I I guess it's not a paid product, so you can't complain. The author's gonna do whatever the author wants to do. But instead of chasing dollars, the author's chasing stars, which means that now you get more stars by introducing to a new community once you've captured the stars of one community. So making your Postgres driver better isn't going to get you but another 10% of stars. Creating a MySQL driver is going to double your stars. Right? And and so then the quality of the Postgres driver or at least the response time to issues with the Postgres driver go down when it's like, but this is why I wanted it. So I hope you never support MySQL.
Steven Haberman [00:40:53]:
Well, wait.
AJ O'Neil [00:40:53]:
Not because my SQL is bad, but just because if you could focus on doing one thing well Yeah. Then it'll work well.
Steven Haberman [00:41:01]:
Yeah. You You
Charles Max Wood [00:41:02]:
go ahead. Go go ahead, Steven, and I'll jump in.
Steven Haberman [00:41:05]:
Well, Well, I was gonna say, I should just hang up now because because, like, with with it's Joyce doesn't have a lot of users. And one of the reasons I'm here is to, like, hey, a lot of people should use Joyce. I I you know, we think it's great. We're we're kind of fanboys of it, obviously, and and I'd love for more people to use it. But they're gonna ask for more things. They're gonna ask for SQL support, or MySQL support, and they're gonna ask for this, and they're gonna ask for this. And and I really, have qualms, you you know, go back back and forth. Like, when your project's small and and dedicated, you can do whatever you want to it.
Steven Haberman [00:41:32]:
And, and we can do that now. But, Just
AJ O'Neil [00:41:36]:
charge money. Just charge money. Just say it's it's it's $30 a year. It's $99 a year for,
Steven Haberman [00:41:41]:
like, the
AJ O'Neil [00:41:42]:
next features.
Charles Max Wood [00:41:44]:
I'm gonna say my say stays. I'm gonna say what I'm thinking here because, I mean, so much of this kinda cuts both ways, if you know what I mean. Right? Mhmm. So it it really pays off to have a focused ORM that just does the stuff that people wanna do. Right? And and to make the case, right, if you're using an ORM for Mongo, it only supports Mongo. Right?
Steven Haberman [00:42:08]:
Yeah.
Charles Max Wood [00:42:09]:
If if there's if there's something else that kinda looks if you squint at it like Mongo and kinda works if you squint at it like Mongo. Nobody's writing extensions for those other systems. Right? And I get that we're kind of in a world where, yeah, all of the different SQL based systems use SQL.
Steven Haberman [00:42:30]:
Right? They're 90% the same if you squint.
Charles Max Wood [00:42:32]:
Right. So so, you know, so you can kinda flirt with it. But Yeah. The the thing that I'm seeing too, right, is so I, you know, it's funny because we've all kinda said, I I work in not JavaScript most of the time these days or, you know, something like that. Right? Yeah. Laravel or Go or, in my case, Ruby. One thing that I've seen with this is with the with the Ruby with active record, yeah, you use the Postgres driver, and then active record takes advantage of that to to query the database. But if you want other features that Postgres provides that are not, you you know, specifically provided by active record or specifically provided by that driver, you can pull in other libraries that add the functionality.
Charles Max Wood [00:43:19]:
And so it really depends on what your goal is, in my opinion. Right? Is your goal just to solve the particular problem that you guys have? Right? Because if that's the case and it does a really good job of it, then, yeah, other people who are using PostgreSQL, and are writing back end code, I'm presuming you're using express or something. You're right. Yeah.
Steven Haberman [00:43:41]:
Fastify. That's for sure.
Charles Max Wood [00:43:42]:
Pulling pull in joist. Right? Makes sense. Yeah. If you're using MySQL, then and and you really want a joist like thing Yes. You can fork it or you can find something else. But yeah.
AJ O'Neil [00:43:57]:
Just just give people a script that installs Postgres correctly with the user setup to be able to create data.
Steven Haberman [00:44:03]:
There we go. Yeah. I I do think well, you mentioned active record. I I think active record has walked the line really well of supporting a lot of, databases. And I Yeah.
Charles Max Wood [00:44:12]:
But it does not like, I use Postgres, and it does not do everything that Postgres does. It does a vast majority of the things that most people use, and so it does a really good job there. But it does do everything.
Steven Haberman [00:44:23]:
Yeah. I I think some of this might get back to, like, like, the, you know, when do you use the ORM and when do you just use a, write SQL in a query builder. Right? And and that, I my my impression and and maybe it's my bias and my assumption is that a lot of people have been burned by the the ORMs of the world. I'm sure there's a lot of reasons, and, hey, Jamie, we can get to yours when you get to. But but is this, like, obsession with putting everything that some projects have, not every, but but a lot of projects have with, like, making everything go through the ORM. Right? Which then, you know, Charles, you run into. Like, well, the ORM doesn't do this for grade or doesn't do that for, you know, MySQL or whatnot. And, I I don't have that strict of an opinion about it insofar as, like, I I think ORMs that do 90% of your applications boring CRUD queries, right, which which is by far the far, far majority of queries we do is super boring CRUD.
Steven Haberman [00:45:14]:
That is probably exactly the same SQL across 5 to 8 top databases. Right? I think Joyce really can pretty easily support the MySQLs and SQLites and all of those for the subset of, you know, really common CRUD queries. And then, like, you know, when you need to escape hatch out to, like, the, you know, whatever left join syntax that only post create supports, I think that's perfectly fine. Go use your, you know, just write go write some raw SQL and do some, you know, low level queries where you need it. And, I I think that happens so, when when you need it, you you really need it, but it happens so frequently in a large application. It's, like, sub 5% of the time, probably, 5, 10% of the time, that you can still get a ton of benefit from the entity, ORM side of things for all of the super boilerplate stuff. And and and also for the that super boilerplate stuff, I think, is also what's most common commonly supported across the, you know, most popular databases. So so we are post grade, right now, but, only but I I don't think it'll be a big shift from our vision to pull in a, MySQL or or something like that, when we get to when we get to it.
AJ O'Neil [00:46:23]:
So so tell me more about raw dogging the SQL.
Steven Haberman [00:46:26]:
Yeah. How do you
AJ O'Neil [00:46:28]:
how do you approach that? Sure. Because it it seems like it I again, back to the why ORMs exist. I think they started out because people wanted to support SQLite and Postgres in their MySQL projects. That's what it seems like. But then once they were there, it started to kind of, like functional programming was also, you know, hitting one of its, one of its phases. And so it's like, oh, well, look. I could do the training. I could do I do all the functional programming.
AJ O'Neil [00:47:00]:
Functional programming is more amenable to relational algebra as opposed to the Java style programming that it was, you know, existed at the time that this stuff seemed to be really taking off from from, you know, my point in history, which I'm you know, I missed a bunch of it because I came in kind of not I I thought I was in the early days. Maybe I was more towards the middle of it than I thought. But, anyway, so so you've got that. And then but so then the whole thing is, well, you know, now it's typed, and now it works in your language. And now and so and so SQL became the bad guy. It's like, well, the ORM isn't just so that you can support multiple databases. It's actually because it is the morally superior choice. Good people use ORMs because they're good people.
AJ O'Neil [00:47:48]:
And and so then so so it's like, well, if you buy into the idea of an ORM, then you're a good person. And if you're a good person, you're not gonna raw dog the sequel, are you? Because then you lose your portability, and then you lose your functional programming, and then you lose all the things that are so enlightened. So how how do you have this the economy where you're gonna say use jo joyce.rm, but, actually, yeah, RawDog the SQL when you need to.
Steven Haberman [00:48:15]:
I don't know. I just do. I mean, the, I I
AJ O'Neil [00:48:20]:
Excellent.
Steven Haberman [00:48:22]:
Well, I I I mean, I've I've tried to use ORMs in the past that, you know, you you you get their DSLs get so contorted to try and support every little thing in SQL that you'd wanna do in a TypeScript DSL and that sort of thing. But but you're just, you know, why you know, even if it's typed or like, I really love types. Right? I I really love static typing. I love code, you know, generating looking at the database schema and pulling those, you know, like the active what an active record does. Like like that, you know, it's really what, Joyce tries to do. Granted, I cogent time so the TypeScript comp compiler can see it. But, like, there's a limit to where, like, let's just write some SQL. And I I think especially because it just doesn't happen that often.
Steven Haberman [00:49:04]:
Right? Like, and I that's what makes me feel not so bad about it. Right? Like like, if I had a 100,000 line code base and 50,000 of it were, like, entities and the other 50,000 were, you know, raw. SQL. And it it was very hard to see when you you would use each and and you you, you know there were little camps of, like, on this one you you know, which one do you use and and that sort of thing. But, at at least on the projects, that we've got going on so far, like like, it's really pretty obvious that you, or at least seems like it, that that, you know, you do use the ORM for as much as you can, but then those last few and in terms of what it actually looks like, we do have a a little bit of glue. So right now, Joyce sits on top of Connex, which is just another it's one of these query builders. It's like the key sleep, and, that's what Joyce itself sends the queries through. And so we use the same connection pool as as as Connex, if I'm saying that right.
Steven Haberman [00:49:53]:
And, so if you if you
AJ O'Neil [00:49:55]:
do It's after the Lego alternative.
Steven Haberman [00:49:57]:
Yeah. Yeah. Yeah. And so, when you want to, you know, BroadRock your SQL, you just get the Connex, DSL from the same, I mean, I say DSL, but but there's it is a DSL, but it's it's it's much lower level. It's much closer than SQL. It's not and it's not as typed in that sort of thing. And, you just do a few of them, and, you know, make sure you write tests. And I don't know.
Steven Haberman [00:50:20]:
I don't care. The code ends up being cleaner. And, yeah. Oh, I I wanted to follow the tangent. You had mentioned that, you know, ORMs were really great for cross database compatibility. Actually, I I don't know if that's the case. I I know I know that that is a purported benefit of the ORMs, but just like how often have you really seen a project migrate databases? Like, it's just like
AJ O'Neil [00:50:39]:
Well, that that's the thing. Like,
Charles Max Wood [00:50:41]:
good boy.
Steven Haberman [00:50:42]:
It's not
AJ O'Neil [00:50:43]:
gonna happen. I think that there's an impetus. Right? I mean, you have to go back to the root cause. What's the root cause?
Steven Haberman [00:50:49]:
Well, I believe Yeah.
AJ O'Neil [00:50:50]:
The root cause is more stars. And back then, there wasn't GitHub, but still, download count on SourceForge. Right? Yeah. That's
Steven Haberman [00:50:58]:
Yeah.
AJ O'Neil [00:50:58]:
That I think is the thing, is that people wanted to see the number tick. Because if you're not getting paid in dollars, you wanna get paid in social credit. And I I I believe that what it was is they wanted to get other people in their community to watch that download ticker when SourceForge go up.
Steven Haberman [00:51:14]:
Oh, I'll give you that. That's that is an interesting assertion. I'll have to think about that. The whole, like, you know, then you mentioned the SQL c goes after, the the all of the SQLite users and that sort of thing. I don't know. I'll step back a little bit. Like, more than, like, cross database, can like, I'm gonna we use, AWS Aurora at, at Homebound. It's amazing.
Steven Haberman [00:51:33]:
I'm gonna run on Aurora for the next, you know, 20 years if I can. Like, it you it just gets as big as you, you know, want it to, and granted you have to pay for it. But it's an amazing product, and, I I have no desire to run on anything other than that. But, oh, but that's not why I use the ORM. Why I use the ORM is business variant enforcement. Right? So, validation rules, such that, you know, what I my my just incredulity with the query builder approach is, like, you know, let's say I I'm in my author endpoint. I I'm in my save author endpoint, and I'm gonna do an insert an an update. Let's say I'm gonna update the author.
Steven Haberman [00:52:12]:
Okay. So somebody raw dogs an update to the author table. What business rules did they check? Well, you know, before they switched that first name, before they updated the, you know, book title, or before they they increased the the book rating? And, like, how many derived values? Derived validation rules and derived values are trying to watch whatever they just updated. Right? So, you know, let's say that the author has a star count. Right? And or or, you know, these sort of, you know, direct active record has some counter caches that that we we haven't quite flown that yet. But just in general, the idea of, you know, after you update, this row in the database, something else needs to know about it. And that's why I use ORMs. I I would just be super scared of, like, raw dogging an s an update to an author and forgetting what else did I have to do.
Steven Haberman [00:52:57]:
You know, what what other validation rules did I have to run? What other, drive values should I have to update? And those are the 2 things. We you know, we we're kind of into the 3rd phase of what Joist is amazing at. You know, m plus 1, and, you know, avoidance was the first one. Second one is, those, you know, populate hints to to move get rid of await gunk. And the third one is this, like, not only validation rules and and, life cycle hooks, like active record has the you know, we have active record cell before flushes and before updates. We do cross entity reactivity, wow, which is kind of a fancy marketing phrase from it. So I I guess I am kinda putting on my my marketing hat here. But, so you know on the front end, reactivity is a a big catchphrase, right, of of when you update the component over here, you know, the reactivity is updating all of the component.
Steven Haberman [00:53:45]:
You update state, you know, you update state once and then it gets broadcast out.
AJ O'Neil [00:53:50]:
Oh, I've heard about it. I haven't seen it, but I've heard about it.
Steven Haberman [00:53:53]:
Yeah. Sure. Well, Joyce basically brings that concept to the back end. So, like, in a in a Joyce entity, when you update an author, and let's say the author first name or the author last name, we will watch not only for, like, validation rules on the author itself, like, you know, the but the really simple ones are are the validation rules you'll see in Azad or some sort of schema based, parser that they just look just at the field and just at the primitive values in the field. Is it too long or is it too short? Is it an email regex? Is it not null or whatever? And those are fine. You know, that's that's what Azad can do for you. But, you know, when you start talking business invariance, this gets back to, like, some of the ubiquitous language in domain driven design. When you go talk to your, you know, your business users and they're like, well, I I have this this rule.
Steven Haberman [00:54:39]:
I use the term invariant. This business rule that I want to just always be true. You know, I want this to always be true. And it's probably not gonna look at just what the first name is. Is the first name too long or too too short? Right? It it might look at, well, our you know, the first name can't be the last name or or, you know, it's gonna look at multiple fields at once. Right? Just on with 1 on, one entity. But then it's also very common for, like, the the rules to want to, like, look across entities. Like, well, if my author is, has some sort of status.
Steven Haberman [00:55:09]:
Right? If if my author is, employed, then my other validation rule in the books like, the books can be, you know, sold or something like this. Right? And so these sort of cross and variant validation rules, that's why I use ORMs. And and and I I hope I, you know, I can't speak for others, but that's that's what I would assume is is, an an attraction to the ORM is is not just like abstraction from the SQL database I'm using.
AJ O'Neil [00:55:38]:
So I guess in that sense, I build my own ORM because I prefer to have Yes. Business logic in a separate layer from storage logic. Sure. I see these these two things as fundamentally different. And as I, you know, I'm going through and refactoring code and, like like, looking through projects as as I tend to do being, you know, consultant. Mhmm. I I think that the worst like, the weakest abstractions are the ones that combine storage and messaging with business logic because business logic is the most likely to change. And so anytime that storage and messaging are together with business logic or, you know, either one of those are together with business logic, then it it just it's always a nightmare when x needs to change.
AJ O'Neil [00:56:31]:
Well, now you have to go change y and z as well. You know? So I'm I'm very I'm very much a business logic goes in the business logic place.
Steven Haberman [00:56:41]:
Yeah.
AJ O'Neil [00:56:42]:
And that's so the the fundamentally, my stack, my ideal stack is routing is global. Business logic is per component. Storage is more or less global slash hierarchical. But but, like, the business logic uses the storage. It's not in the storage. And then messaging, likewise. Messaging might be global with, like, some hierarchical component to it. But Yeah.
AJ O'Neil [00:57:09]:
The business logic uses the messaging. So what I'll do, which you don't see this in a lot of code bases because people like to abstract it away, because I want a function that's like save that's going to do the business logic, do the storage logic, and do the message logic altogether. What I'll do is I I'll literally, like, call the get function, take the data, call the business function on the data, and then take the result and then call the messaging function. But then then whenever it's time to refactor, whenever business logic changes, it's like, I gotta go and just change that one thing. I don't have to go change my my storage module or my messaging module or or whatever. Sure.
Steven Haberman [00:57:50]:
Yeah. No. I mean, what you're saying reminds me a lot of, I mean, I've see I've seen those architectures in the past. I've worked in those code bases, and, it's a it's a very familiar argument. I guess, I I especially saw it, you know, 15, you know, 20 years ago in the Java world, there's a very strong push to have well, the term's the same. POJOS, you know, plain old, although this was Java. Now you, you know, plain old JavaScript object or plain old Java object. You know, pass between your layers, and you had to have a storage layer, and that was the only place they could put, like, data into your your, your POJOS.
Steven Haberman [00:58:22]:
I guess, what, you know, I think this is what I learned from active record and, the the pattern in general, but then also Ruby, the implementation, is that, if your storage matches this gets to kind of the domain model, the concept, and the ubiquitous language. If your storage schema matches what your, you know, Pojo is supposed to be anyway, the storage layer just goes away. Right? It it it there is no storage layer anymore. You know, that's that's what the active record pattern fundamentally does. And I think, there is an assumption there that you can control your schema. Right? So, like, you know, 20 years ago when your schema was controlled by the Oracle database admin that you had to submit scripts to once a week for him to maybe add a table if you ask nicely enough. Right? And all of these other sort of things. You had a really shitty database schemas.
Steven Haberman [00:59:07]:
Right? They were just ugly, and and they were wrong, and they they modeled the data, you know, had ugly names and that sort of thing. And so the ORMs way back in the day, like hibernates of the world, part of what they tried to do was, like, fix the terrible database schema. Right? You would write your mapping files or your storage layer to try and and, you know, get the data out of the super ugly database and put it into your super pristine o o POJO layer. Right? That was all, you know, your ivory tower of, what you really wanted it to be. And, to me that's that's where the whole, you know, ORMs or the Vietnam of computer science, came from, is that, the the yeah. This notion that that you have, oh, right. The object relational mismatch. You know, that'll get, you know, thrown around as in, like, somehow objects are just finally different from relations.
Steven Haberman [00:59:55]:
I don't I don't think that they are. Like, you know, I think if you they don't have to be anyway. I think they were back in the day when you had super terrible terrible oracle database schemas that you wanted to map onto your different set of, you know, objects. You know, that was an impedance, but that that was not because of the technologies. That was just, you know, because your schemas were so terrible. But, you know, if you have the freedom to make your your, you know, database schema what it really should be, you know, if if you have an author, you have an author's table. If you have a book, you have a book's table. And, you know, the columns match what you want them to be, and you can change them with migrations extremely quickly in the CICD pipeline.
Steven Haberman [01:00:32]:
I think that impedance goes away, and you start thinking of your your relational database as a graph database, really, just a graph database that scales really well because for whatever reason graph data graph databases haven't really taken off and can't, you know, whatever. But, you know, you you you think of your relational database as a graph database. And now your storage layer, you're coming back to where you put your business logic. There is no storage layer. The ORM just does it. And so now what the entities become is not a storage layer. They are the business logic layer. Right? So when you're you know, you say, well, I'll have my business logic off somewhere else.
Steven Haberman [01:01:04]:
This is one of my, criticisms of the query builders is that you have to do just what you did. So, like, Joyce and our entities, we provide a framework for business logic. And we've we've attempted to vet it and attempted to organize it and attempted to, you know, design a really pleasant way to organize your business logic. I wanna say, like, separate from your storage layer, but there is no storage layer. That's kind of the point. Such that Well, there there is
AJ O'Neil [01:01:29]:
a storage layer. It's just abstracted in some way. I mean, there's obviously there is a storage layer.
Charles Max Wood [01:01:38]:
Active record does this by convention. Right? And so you don't think about it because it's mostly invisible.
Steven Haberman [01:01:46]:
Right.
Charles Max Wood [01:01:46]:
And I think I think that's what you're saying, Steven. Yeah. And what I find is that this probably works 95% of the time, and then the other 5% of the time, you have to go play the game of, okay. I've got something that's a little more complicated than just business logic in this one narrow vein of users, for example. Right? And so, what I wind up doing is I wind up creating some other entity that manages that business logic and that workflow and all the things that are involved in that. You can call it a component. You can call it a service. You can call it whatever you want.
Charles Max Wood [01:02:21]:
But, yeah, you wind up solving that in a different way. And I I think sometimes people get into the arena of saying, I don't like ORMs because they don't solve things in this 5 percent or 3% of the time. Yeah. Exactly. And the reality is is it's like, look. It does all this stuff for me the other 95 to 97% of the time. And so I'm gonna use it because it gets all of this garbage out of the way, and it makes all of the storage stuff invisible to me, and it gives me a place to put the stuff that I care about. And then, yeah, I'm gonna have to go, and I'm gonna have to special case this other crap.
Steven Haberman [01:02:55]:
Yeah. Which is fine. Yeah.
AJ O'Neil [01:02:56]:
And that is actually my plug for SQL c is that Nice. It gets all of the crap out of the way, but there's the only constraints that it has is that it can't do meta table stuff. Like, for example and I don't think active record does this either. Like, if you wanted to create a table dynamically, like, let's say that you were doing something like Snowflake, where you need to create tables on the fly to represent CSVs that people are importing. SQL c is not the right tool for that job. Sure. But that is in your, like, 0.1%, I I think. Like, it's very rare that you need to do Yeah.
AJ O'Neil [01:03:44]:
Meta manipulations on a table in an application that you're, like, multi vendoring your application in that kind of way. But, like, for all the stuff that
Charles Max Wood [01:03:53]:
that may be better anyway.
AJ O'Neil [01:03:55]:
But all the stuff that an ORM is gonna do, typically, SQL c is gonna do for you. It's just that you just write the SQL, and you write the SQL as specific as you want. And what it does is it uses the the Postgres query builder. Like, it it links to the c code. And so it runs the c code, and then it gets back basically the the like, it knows what the the c code object is gonna be, and then it translates that to JSON, and then translates that to Go. Or in the case of Go, it might do direct because they didn't have the JSON adapter. The JSON adapter came before they created the adapter that goes to the other languages like Python and TypeScript. Originally, it was just straight from Postgres to Go.
Steven Haberman [01:04:39]:
But Mhmm.
AJ O'Neil [01:04:39]:
Anyway so it it hasn't it it reads from the Postgres specific type system into a broad type system into the languages type system. And so you get all of the typing. You get all of the objects. It's very easy to yeah. Any anyway, so so that that's where that's where SQL c in particular, I think, is is the best in class. Although, it's it's probably not something many people have a mental model for because as far as I know, it's the only one of its kind. It's it's another one of those obvious ideas where once you see it, it's like, oh, why haven't we been doing this for the last 20, 30 years? But Yeah. You know, again, no but nobody did it.
Steven Haberman [01:05:25]:
It is a cute approach. I I I I do like the the no well, for my my caveat would be for, you know, when Charles said the last 2 to 3, you know, 4% of things that are really gnarly, and and you have to, like, read, reach outside of the box. I think the SQL c approach is really pretty novel and great for giving you a file to just write your super one off query and that sort of thing. I guess for the other 95% of things, I don't used to. What's that?
Charles Max Wood [01:05:49]:
I don't think I've ever used SQL c.
Steven Haberman [01:05:51]:
SQL c? Yeah. I don't know if
AJ O'Neil [01:05:53]:
they have a Ruby adapter.
Steven Haberman [01:05:55]:
Yeah. I mean, but yeah. The the concept, is, you
Charles Max Wood [01:05:59]:
know playing more and more in the JavaScript realm anyway. Anyway, sorry I keep jumping in.
Steven Haberman [01:06:04]:
Oh, no. That's fine. No.
AJ O'Neil [01:06:05]:
No. No. Obviously.
Steven Haberman [01:06:07]:
The, well, yeah. So so the the TLDR of SQL, see, is that usually, you know, when we talk about raw docking SQL. Right? So usually raw docking SQL in most, languages is you just go do an embedded SQL string, you know, inside of your
AJ O'Neil [01:06:21]:
And you lose the types.
Steven Haberman [01:06:22]:
And you and you lose the types. And you're just building a a great big SQL statement, as a string. And maybe you use a string builder or or maybe you, you know, you somehow piece together what is in your language fundamentally a string.
AJ O'Neil [01:06:33]:
And then then you have a typo in in in the the name of people where you transpose the o and the e, and you don't find out until you deploy.
Steven Haberman [01:06:41]:
And so what's noble about SQL c is they have you write this instead, your your query in a dedicated file outside of your, you know, your language, whether it's Go or TypeScript or whatever called, like, you know, my query dot SQL, you know, get authors dot SQL or, you know, read authors dot SQL or insert authors dot SQL. And you write literally the the SQL that's gonna go to the database, and you get it used variable in interpolation, like dollar sign 1, dollar sign 2. And then what they do is they just, you know, they they parse that SQL, type check it, and then generate a little binding around it that says like, oh, if you, you know, they cogent out a wrapper that's a method, you know, a a method that will really just load that little SQL file and then call it. So it really is a pretty neat way to get, like, you out of, like, writing raw doc SQL inside of strings in the database or or sorry, in your in your TypeScript file or your Golang file into, like, what is actually a SQL file. No. I actually think that's pretty great. My my disclaimer would be, like, for those 3 to 4 to 5 percent of cases where I want to be raw talking SQL, and the other 95%, which is like the super boring update authors CRUD statement, that not only is very boilerplate to write the the, you know, update authors at SQL, which which, you know, I don't wanna write, but maybe you could say it's not fine. But all of the invariance that I need to go make sure still pass.
Steven Haberman [01:07:56]:
Right? Like, sure, I updated the author. What other, you know, business rules or
AJ O'Neil [01:08:01]:
But but that's all in your business logic. That's all in your business logic. So that's that's still there. Like, you still get that. You don't you don't bypass that.
Steven Haberman [01:08:10]:
Does SQL c have a way to tell you how to structure your business logic, or that's just, like, on you to figure out a way to do
AJ O'Neil [01:08:16]:
it? Well, I mean, you do it the same way you do it anywhere else. Right? Whether you're using SQL or not. So you just SQL c takes care of the storage layer, and you you but okay. I mean, I don't wanna I don't wanna soon. And we can do it. I don't wanna go too deep into
Charles Max Wood [01:08:31]:
these. So
Steven Haberman [01:08:32]:
Sure. Yeah. Maybe one one last thing, about it is that I think the the core builders of the world, and and this is I would include SQL c in that, but also the Prismas and and Drizzle and all of these. Leave as an exercise to the reader how to, structure their business logic. Right? Like like, when to invoke it, how to structure it, where to put it. And that actually is is the most the thing that the Joyce is focused on. It's it's like, sure, 80% well, you know, 60% of this is an RN to get data out of your database. The other 40% is a way to structure your business logic instead of everybody having to kinda make up their own and hope they they do it right and, and those sort of things.
Steven Haberman [01:09:11]:
Grant, it it is a very opinionated way to structure it because it uses entities and it uses life cycle hooks and it uses some reactivity. Is it it but it is opinionated and
AJ O'Neil [01:09:22]:
That that's interesting. And and I think that psychologically, there's there's an effect there that that's really valid because people, you know, people go both ways about frameworks. You know? Like, I love a framework because it it guides me. I hate frameworks because it constricts me.
Steven Haberman [01:09:38]:
Right.
AJ O'Neil [01:09:39]:
And I and I think that, you could have a framework that is here's how to put your you know, where to put your business logic, and then here's where you plug in your storage adapter. But I think that people are more familiar with the idea that the ORM is going to be the framework that dictates business logic rules with the data associations.
Steven Haberman [01:10:00]:
Yeah. Which is what we do. Yeah. Bread and butter. Yep. Yep.
Charles Max Wood [01:10:05]:
Cool. Well, I think this has been so interesting to just kinda listen in on more than participate in. Usually, I'm jabbering all the time. Sure. But, if people wanna learn more, where do they go find more information?
Steven Haberman [01:10:19]:
Yeah. Sure. You know, so we're joyce dashormpiodi0. And you had mentioned it, and if you just Google for joyceoram, we do kinda come up higher in the in the results. We've got a GitHub project. Feel free to oh, and, oh, we use that as Slack, but what's the thing that you have to say? It's Discord, you know. Discord. Actually, I have to make sure I'm logged into that when if I if I mention it.
Steven Haberman [01:10:43]:
But, yeah. Feel free to to to stop by. You know, wanna make the disclaimer for the audience that that the the Orem you use is is a big bet on your code base. Right? And and so we we take very seriously that if you structure your code base around Joyce, that that you're taking a bet, and we really, do, respect and appreciate that. But, yeah. We would love to have, anybody kick the tires and, point us out. You know, AJ, you found a few things in the docs that could probably be for stuff. We'd love to have, you know, any issues, around those things to help the onboarding process or, things that we're missing.
Steven Haberman [01:11:15]:
We'd really appreciate it.
Charles Max Wood [01:11:19]:
Cool. Well, let's go ahead and do our picks. Now it sounds like you may have listened to an episode of the show, so you probably know what picks are. But just for anyone who's new, I I haven't said this in a while, but picks are basically shout outs about anything. So I usually do board games. We've had other people, on Ruby Rogues. We had picks, and they you know, one guy did beer picks every week. You know, people pick TV shows.
Charles Max Wood [01:11:45]:
People pick tech stuff too. Right? I mean, this is a technical show. We've had people pick political candidates, though I'm not jazzed about that all the time because people have feels about that. Right? And that's not really what we're about. But if if you care about it, you can say it. So Sure. Anyway, let's go ahead and start with Steve, and then we'll work our way, through the panel.
Steve Edwards [01:12:09]:
Yeah, Steven. First of all, I'd like to point out I appreciate that you spell your first name the correct way, not with an s p v e n.
Steven Haberman [01:12:16]:
Sure.
Steve Edwards [01:12:17]:
I meant to note that at the beginning.
Charles Max Wood [01:12:19]:
I'm playing that back for my brother about 8 times.
Steve Edwards [01:12:23]:
What's funny is and I I think I might have mentioned this before. I have a brother named Steven. He's spelled with a v. He's adopted. And so he was already named that when my parents adopted. So we're big Steven, little Steve, or I prefer handsome Steve, not too handsome Steve. You know? It just depends Nice. Context.
Steve Edwards [01:12:40]:
Uh-huh. But, anyway, in regards to to, picks, my picks are generally the highlight of any episode in there, my dad jokes of the week. So, be prepared to laugh yourself silly. Just kidding. Alright. So for instance, I asked my wife being a she's a rather nontechnical person, shall we say. I asked her why her password was spelled out Snow White and the 7 dwarves. And she said, I was told it had it to be at least 8 characters.
AJ O'Neil [01:13:14]:
Thank you. I got it.
Steve Edwards [01:13:17]:
Yeah. That
Charles Max Wood [01:13:18]:
was better than most of the ones he comes up with. So
Steven Haberman [01:13:21]:
That was freaking
Steve Edwards [01:13:23]:
Yeah. I was I was sitting in traffic the other day, and that's probably why I got run over. Right. And then question of the week, if dentists make their money off of people with bad teeth, why should I trust a toothpaste that 9 out of 10 dentists recommend? It's all about self interest. You know?
AJ O'Neil [01:13:46]:
Got them. I
Charles Max Wood [01:13:48]:
I I think that's a fair caveat.
Steve Edwards [01:13:50]:
Nope. It was like I'll give you caveat. Anyway
AJ O'Neil [01:13:56]:
I think 9 out of 10 dentists recommend all of the toothpastes.
Steve Edwards [01:14:00]:
Right. Just Annie, please use something. Those are my picks.
Charles Max Wood [01:14:04]:
9 out of 10 dentists that we paid to say so. Anyway,
Steven Haberman [01:14:09]:
that would
AJ O'Neil [01:14:10]:
be asterisk. Alright. So since we're on this topic of SQL, I I'm just gonna throw down there's a typescript to JS doc module that'll be linked. It's called t s hyphen 2 hyphen j s doc. It's exactly what it sounds because I don't like TypeScript. I hate TypeScript. I think TypeScript is an abomination. You know this.
AJ O'Neil [01:14:30]:
I love types. And I love that the TypeScript checker is getting better and better at being able to interpret JavaScript in JavaScript types. And I hope that that goes forward. I'd love to see one day where, you know, maybe collectively, we can just all drop TypeScript because the TypeScript checker is so good at JavaScript types that you don't even need to annotate anymore. It just gets it. That would be amazing. That's that's like Zig level I don't know. The other thing is there's a module called MySQL dump t s, MySQL hyphen dump hyphen t s, hyphen t s.
AJ O'Neil [01:15:04]:
And this will allow you, of course, to dump tables out of your MySQL database and then get the TypeScript of them. And then you can run the TypeScript to JSDoc to get the JSDoc of them, and then you can start to you can start to make your code better in the sense of being able to have type checking, you know, misspellings checked, etcetera.
Charles Max Wood [01:15:24]:
And add Joyce to them.
AJ O'Neil [01:15:27]:
Yeah. I I don't think that you would need if you're going this route, I don't I think Joyce is solving this problem for you. If you're adopting Joist, I don't think you'd need these. But this would be in the case where you have an existing project and you're trying to get certain parts of that project in a in a better way so that you can feel safer and sleep better at night about it. Then, of course, SQL c. SQL c, like I said, it's kind of like a reverse SQL, c query builder because you just write the SQL, and then it gives you the queries. And it's not a binding, just to be clear. It is well, I mean, it is a binding from the perspective that it uses the SQL driver.
AJ O'Neil [01:16:11]:
But it it's it's not it's not calling that that well, it it builds it builds out it it builds it out. It's not it's not copying well, it is copying from the file. It's not using the file you created. Anyway, you you can see what it is. But SQL c, I I think is the smartest approach because it seems like it covers not the 95%, but the 99.5% in terms of as long as you don't need to do meta table manipulations, it's got your back. And it's and since you have to learn SQL anyway, query builders don't alleviate your need to learn SQL. If they did, then I'd say, yeah. Let's get on the query builder.
AJ O'Neil [01:16:52]:
But the truth of the matter is, at the end of the day, chatgpt is gonna be bomb awesome at generating SQL for you. And it's gonna be mediocre at best at generating queries in your query builder of choice. Well, I I don't know. I haven't I haven't tried it with that specific use case in the most recent version, but my previous experience what with it was, it does awesome at SQL, and it's really mediocre when it comes to the SQL abstractions. So SQL c is something that seems to pair really well with LLMs in terms of being able to get the statistically likely correct SQL, which SQL really lends itself incredibly well to statistical analysis. Like, that's a match made in heaven. Then Slonik. Slonik is kind of a different approach, in terms of you are putting your queries inside of templates inside of your JavaScript code.
AJ O'Neil [01:17:50]:
But it is you it's kind of a middle ground between SQL c and a query builder, and that it it's doing the query building dynamically, but you are getting the type checking on it. But SQL c, I think I I think SQL c is the real gold, but Slonak is something that's certainly an interesting option. And then you've got, template blocks that are SQL tagged, and so you can get highlighting and stuff like that. And then, so that's the SQL stuff. Got out of the way. 2 other quick things. SwiftUI seems like amazing, and the Android jet Jetpack Compose is either it's either the clone of SwiftUI or SwiftUI is the clone of that. And, you know, Apple likes to perfect things when it clones them and then pretend like it's the first because it's so good that, you know, they knock it out of the park when they do it.
AJ O'Neil [01:18:40]:
But there's 2 talks, SwiftUI Essentials, an introduction to SwiftUI. And if I close my eyes, what I hear is React, React, React, React. But when I open my eyes, what I see looks more like Vue, and like, oh, this actually this actually looks like it would work. Because there's there's the there's the promise of React, and then there's the reality that we're all kind of familiar with. SwiftUI seems to be both the promise and the reality of React. I'm really interested to get more into it. And then last thing, I am gonna make a political pick. I oh, Trump just makes me so, can we not have good choices? But then but then every time every time I think we're the dregs.
AJ O'Neil [01:19:21]:
We're the bottom of the barrel. Can this get any worse? Then it's like he does an interview that's with people that are a different audience. Because when he speaks to the general public, I'm just like, oh, please no. But then sometimes when he speaks to a specific audience, it's like all of a sudden he's a genius that understands how the world works. And so he gave this interview or did this this presentation and q and a with Frontline, and, like, everything that he said was actually intelligent. And then I had to challenge all my beliefs again. Those are my
Steven Haberman [01:19:58]:
picks. Whatever.
Charles Max Wood [01:20:02]:
Yeah. I think everybody who listens to this show on a regular basis knows that I am heavily politically involved. I'm just not gonna comment, on at least not here. I am working on some politically focused shows. And if you don't agree with my opinions and you don't wanna hear them, don't listen to that show. I'm gonna jump in with a couple of things. So I'm gonna do a board game pick really quickly. And, that game is what did we play last time? We played Biblios.
Charles Max Wood [01:20:34]:
That's what we played. So if you haven't played Biblios, it's a card game. I'm gonna try and do this in less than a minute. But, effectively, you have, dice that are set out, and it's if it's the score for getting the most, books of that color. And so and then there are cards that let you change the dice so you can make it 1 higher or 1 lower. And then you're either, capturing your card out of the cards that you drew. You're picking a card that somebody else didn't want on their turn or you're bidding on cards with gold after all the cards have been picked. And so and and then whoever has the most in whatever color you get those dice, whoever has the most pips showing on the tops of their dice that they won wins.
Charles Max Wood [01:21:22]:
It's it's more or less that simple. Board game geek rates it. I I don't have it up in front of me, but it was, like, 1.78 or something like that. So it's very approachable if you're a casual gamer, fun game, probably a half hour game with 4 players. So I'm gonna pick Biblios. And then I I've got a couple of other picks. I went to my doctor a couple weeks ago. Maybe I don't talk about this as much, but I I have type 2 diabetes.
Charles Max Wood [01:21:53]:
And, the doctor prescribed me, among other things, this it's it's a blood glucose monitor. Now the ones that I've used in the past, you poke your finger, you bleed onto a little test strip, and you have to remember to do it on a regular basis, and I'm not so good at that. And so I would run into the issue where, you know, I'd show up at the doctors, and he's like, have you been testing your blood sugar? My answer was always not for a few months. So he prescribed me this, system. It's called the Freestyle Libre 3, and, I'm not sure if you can even see it on the camera, but I've got one.
Steven Haberman [01:22:35]:
Yeah. You can kinda
Charles Max Wood [01:22:36]:
see it right there on my arm. So, you know, it it friends that have those. Yeah. It connects to my phone, and so I'm much better at checking my blood sugar because I'll, you know, periodically look. And, it's also it's funny. I can't remember which book it was, but there was a book that talked about the concept of keys keystone habits, and those are the habits that get you to do all of the other things right. So if you're eating right, then you have a tendency to exercise because you're thinking about your fitness more and things like that. And so this has been good for me because it's kind of a reminder.
Charles Max Wood [01:23:12]:
I'll check my blood sugar, and then I'll remember I haven't taken my medicine yet. And so, anyway so there are things like that that kinda come out of it. But, anyway, it's really cool. I've had a little bit of trouble with them staying on. So last night, I woke up in the middle of the night because I got an alert on my phone that said that my blood sugar was dangerously low. And so, you know, I went downstairs and ate something to try and get it to go up. And then when I came back upstairs, it said that the sensor was no longer working, and it was dangerously low because it had actually come out of my arm and then had gotten poked back into my arm, but not all the way. And so the tissue it was testing was not right.
Charles Max Wood [01:23:55]:
It was given at a bad reading. So I I have had some weird issues with it. I put this one on this morning, right, to replace it. The nice thing is, though, is that I went on the website for the company, and, apparently, they'll replace them if they come out early. So, I just requested a new one, because I have to pay for them. My insurance doesn't cover these, and they're, like, 20, $25 a pop, but they last for, like, 2 weeks at a time. So, anyway, cool stuff. I really, really dig it.
Charles Max Wood [01:24:24]:
And then lastly, I'm just gonna put in a brief plug for JavaScript geniuses. One of the things I think really helps people level up is if you're talking to other people on a regular basis, doing things like meetups, and so I'm providing all of those. So if you join JavaScript geniuses, you'll get access to I'm gonna start doing videos that walk you through different, JavaScript themes. So maybe I'll do a video on Joyce. I don't know. It it's not on my it's not on my list yet, but we'll see. Anyway Yeah. Yeah.
Charles Max Wood [01:24:54]:
So we'll get into other stuff, maybe Vite or, you know, doing agentic AI or things like that. There's all kinds of stuff I wanna figure out how to do with JavaScript. So we'll do that, and I'll demo it, or I'll have people come on and demo it. So maybe we'll have Steve come and talk to us about, or Steven come and talk to us about, Joyce. Anyway, we also do accountability calls on Monday. There's a book club, and we're getting into the AI book from Obi Fernandez right now. We also do a personal development book. We're doing, Awaken the Giant Within by Tony Robbins, and, you can come to as much or as little of this as you want.
Charles Max Wood [01:25:32]:
But, anyway, so it's just a way of doing community based learning and then, you know, giving you videos that walk through stuff. So, go to javascriptgeniuses.com. I will have that up this afternoon, and then you can, go and join the fun. Steven, what are your picks?
Steven Haberman [01:25:52]:
Yeah. Well, I came in without one, so I'm just gonna have one. It's a project called, Grafast, g a r, fast, Grafast. And it's by this guy, Benjie, out of the UK. He also does, well, Charles, you've done, active record Ruby stuff, Sidekick, right, in the Ruby community. So this guy Yep. Kinda has the node version of that. Graph file worker is the name of Graph file worker is probably his main, project, right now.
Steven Haberman [01:26:20]:
And we use the GraphFileWorker as, like, our sidekick. And it works great. We, you know, we like it. And, really props to him. He's trying to go the, you know, make a business out of it. Right? Like, not chasing after VC money, but trying to do some support and upgrades and that sort of thing, which is really amazing. You know, props to him.
Charles Max Wood [01:26:41]:
That's what they did with Sidekicks. So Yeah.
Steven Haberman [01:26:44]:
I can't remember
Charles Max Wood [01:26:45]:
the guy's name, but yeah.
Steven Haberman [01:26:46]:
Oh, I would've known it had you not asked me. But, yes. The well, so anyway, one of Benjie's other projects, other than graph file workers is GrafAST, which is really, like a ground up rethinking of how a GraphQL run time should be. So it doesn't change GraphQL syntax or GraphQL clients or how, you know, how anybody really talks to GraphQL server. But it fundamentally, like so Joyce has to when we went through all of Joyce, like, using promises to, like, fix up all of, you know, all of the n plus ones that would have happened, GRIFAST is a really that that just, like, fundamentally happens with how most GraphQL servers, are implemented. Like, when you, you know, the Apollo in in the GraphQL community or in the Node community, we have Apollo server and Mercurius and oh, you know, there's probably 2 or 3 or 4 others. But they all work this really inefficient way. Of, if if you go from an author to a book to a book review, it just like it hammers, like, each layer down in the graph is just call, call, call, call, call, call, call.
Steven Haberman [01:27:48]:
It it just, like, fundamentally is, as you get down in the graph, treating every single graph node as its own call. And this Grafas thing just, like, really flips it on its head. And and even as you go down the graph, it's it's making one call, for for all of the nodes that you're processing. So I think it has a really great opportunity to, undo a lot of the performance sort of, like, hideousness that most GraphQL, things either have to just, you know, back ends either have to just deal with or patch around, which is what we did in Joyce. And, yeah, it's still a super small project, and, I I need to spend more time with it, but that is my pick. I think it's pretty neat. Awesome.
Charles Max Wood [01:28:34]:
Alright. Well, if people wanna connect with you, where where do they find you?
Steven Haberman [01:28:38]:
Yeah. Sure. You know, the joyce or o orm. Io. I do have a blog that I need to get to. It's, I'm a little bit embarrassed about the name. It's draconianoverlord.com, but I picked it a long time ago I love it. When I was younger and a little more, idealistic.
Steven Haberman [01:28:53]:
Maybe not idealistic. But
AJ O'Neil [01:28:56]:
Draconian Overlord is idealistic.
Steven Haberman [01:28:58]:
Yeah. Right. Yeah. There was a bit, but, Aspirational. I guess it depends on what your ideals are. Yeah. Right. But, also, the I I the domain name was available.
Steven Haberman [01:29:08]:
Like like, I I thought of it 15 years ago, and it's like, holy shit. The domain name's available. So, anyway, that's my blog. And, you know, a lot of the writing is kinda older from my earlier, you know, Java sort of heyday back in the day. But, yeah, I I need to post more stuff there if anybody wants to come by. But Joyce would be the main place. You know, love to have anybody drop by and say hi.
AJ O'Neil [01:29:30]:
Alright. Cool. And I I do want to say, I like the philosophy of Joyce. I I wanna I just I just wanna make it clear because I'm the naysayer out of the group. Like, I'm the one who's always, like, skeptic. I don't believe it's gonna work. Why would anybody wanna use this? And I I like the philosophy. You really got me when you said, well, if you need the fancy stuff that's the 5%, like, just go do the sequel.
AJ O'Neil [01:29:57]:
That that's that that that you're gonna focus on just be the good just be good at the stuff that is the simple that people need the most, and not try to cater towards the stuff where people really should just go do the sequel. That that philosophy makes me believe that this is going to have an hopefully, an eternal advantage over a lot of the other ones where they try to give you these, like, halfway kind of things. So that that's the main point, but it looks it looks good. I and and like I said, I like it looks obvious. It looks like, well, it doesn't take a genius to figure this out. It did, but it's you know, when you look at it, it looks it looks obvious.
Steven Haberman [01:30:40]:
Yeah. No. I appreciate it. I I mean, that's high praise, for the the the looking obvious is totally the goal. That's what we're after. So really appreciate that.
Charles Max Wood [01:30:49]:
Yeah. By the way, it was Mike Perham that is the psychic guy.
Steven Haberman [01:30:53]:
Actually, I I don't think I could have told you that. I completely forgotten his name. But yes. Yeah. That sounds right.
Charles Max Wood [01:30:58]:
Yeah. We've had him on Ruby Rogues. He's a terrific guy. Anyway, let's go ahead and wrap it up. Till next time folks. Max out.
Optimizing SQL and ORM Practices for High-Performance Applications - JSJ 650
0:00
Playback Speed: