Whiskey Web and Whatnot

A whiskey fueled fireside chat with your favorite web developers.


20: Discovering Ember, Adopting Orbit, and Unlocking Optimization with Chris Thoburn (runspired)

Show Notes

Runspired's journey with Ember began just like Chuck's, Robbie's, and many who've come before them — with confusion, hesitancy, and gradual infatuation.  The year was 2008 and runspired was launching an app. Somewhere along the way, he realized that if he wanted to build the collaborative web-first application he envisioned, he needed to build in JavaScript.  Sifting through Angular and React, nothing stuck. When he finally stumbled upon Ember, the pitfalls and confusion were obvious and almost immediately he abandoned the framework. But runspired soon realized that features within Ember matched the ideas he began developing in his own framework years prior. Suddenly, everything clicked and today runspired is an Ember aficionado with big ideas on the future of framework and the secrets to cutting edge optimization. In this episode, Robbie, Chuck, and runspired discuss flaws in the developer community, why Orbit is useful, shifting the approach to API frameworks, and why JSON:API and GraphQL are a match made in developer heaven.  Key Takeaways * [01:37] - A whiskey review. * [11:26] - How runspired's journey in the Ember community evolved.  * [20:22] - What runspired thinks about RedwoodJS and API frameworks.  * [24:03] - Why Orbit is flawed but incredibly useful.  * [29:45] - What's missing from the developer community.  * [36:01] - Why JSON:API and GraphQL are a perfect marriage.  * [41:59] - What Ember Data cares about. * [48:01] - A conversation about whatnot including Chris' dive into professional running.  * [55:55] - A cause runspired cares about in the Ember community.  Quotes [18:30] - "I've never found a reason to want to re-evaluate Ember as my main framework. Every time I've had a complaint, it's evolved to satisfy that complaint with time." ~ runspired [https://www.instagram.com/runspired/] [23:00] - "So many of the problems that I see applications encounter late in their life cycles are problems where the API framework just wasn't set up well in the first place. And if they had had a better framework for building APIs and understanding how applications are maybe going to mature, and how that API is going to need to evolve as the application matures, they probably would have been set up for better success." ~ runspired [https://www.instagram.com/runspired/] [24:42] - "Orbit, in my opinion, is the gold standard of data libraries for the front-end right now. Because it solves every problem that you don't know you have yet. But that's also its big flaw because it has found the end architecture that you've got to evolve to if you end up with those problems." ~ runspired [https://www.instagram.com/runspired/] Links * EmberFest [https://emberfest.eu] * Balcones Whiskey [https://balconesdistilling.com] * Ember [https://emberjs.com] * Whiskey Web and Whatnot: Chuck's Origin Story: Career Pivots and Learning to Love Ember [https://www.whiskeywebandwhatnot.fm/chucks-origin-story-career-pivots-and-learning-to-love-ember/] * Whiskey Web and Whatnot: Robbie's Origin Story: Learning to Code, Learning to Hire, and Taking the Entrepreneurial Leap [https://www.whiskeywebandwhatnot.fm/robbies-origin-story-learning-to-code-learning-to-hire-and-taking-the-entrepreneurial-leap/] * Whiskey Web and Whatnot: Ember vs. React, Jamstack, and Holes in the Hiring Process with Chris Manson [https://www.whiskeywebandwhatnot.fm/ember-vs-react-jamstack-and-holes-in-the-hiring-process-with-chris-manson/] * Whiskey Web and Whatnot: RedwoodJS, Develo [https://www.whiskeywebandwhatnot.fm/redwoodjs-developer-experience-and-developing-for-scale-with-tom-preston-werner/] --- Send in a voice message: https://podcasters.spotify.com/pod/show/whiskey-web-and-whatnot/message


Robbie Wagner: [00:09] What's going on, everybody? Welcome to another Whiskey Web and Whatnot with myself, Robbie Wagner, and my co-host, as always, Charles W. Carpenter III, and our guest today, Chris Thoburn, who you probably never heard his real name ever. You probably have seen him as Runspired.

Chris Thoburn: [00:29] Yeah. I don't know if I give out my real name. You may have spoiled it.

Robbie Wagner: [00:34] Okay, we'll redact that.

Chris Thoburn: [00:37] I'm teasing. I'm teasing. Actually, the real fun one, I revealed this at what was it? Ember Camp? No, not Ember Camp. What's the one in Europe?

Robbie Wagner: [0047] Fest.

Chris Thoburn: [00:48] Ember Fest. I gave a talk at Ember Fest a few years ago, and in theme with Naming Things is Hard, I revealed that my first name is not actually Chris. It's James.

Robbie Wagner: [01:00] Okay.

Chris Thoburn: [01:00] But I go by Chris, which is my middle name. So naming things is hard.

Chuck Carpenter: [01:05] Yeah, naming things is hard. I don't go by Charles William Carpenter III. It's just too much for people to say.

Chris Thoburn: [01:12] I'm going to start calling Charles William Carpenter III because it sounds very prestigious, very regal.

Chuck Carpenter: [01:19] Yeah. I need to rebrand myself on the Internet. I feel like at age 44. It's a time to really do that.

Chris Thoburn: [01:28] Yeah.

Chuck Carpenter: [01:28] It's like a reboot for me. I'm only half dead. Anyway, should we whiskey? Oh, no.

Robbie Wagner: [01:36] We were discussing before this before we started up recording that we a little bit messed up. Runspired and I have the same whiskey, and Chuck has something else, a similar one, but it's very, like it's barrel proof, I guess.

Chuck Carpenter: [01:54] Yeah, a single barrel. And I guess it would be barrel-proof, too, because that's definitely high-proof. So they just took it, bottled it right out of one barrel? Or even if they proved it down, it wasn't much.

Robbie Wagner: [02:08] Let's see. This is Balcones, I guess, is how you say it.

Chuck Carpenter:[02:13] Is it Balcones or Balcones?

Chris Thoburn: [02:15] I have no idea. It's one of those words I've never heard someone else pronounce. In my head, I was saying Balcones. But it's probably all wrong.

Chuck Carpenter: [02:24] Since it's Austin. Right. I could see Balcones being how it was more regionally pronounced. So the caveat, Robbie, is that this is the third time this has happened, and that's probably because we're not in the same exact place, buying from the same exact store.

Robbie Wagner: [02:40] Yeah. Virginia is the problem. Really? There's no variety. I had to go to several different liquor stores over the past week to get the ones for the next episodes, so that was fun.

Chuck Carpenter: [02:55] Is it more fun than carrying into your office a box with six different bottles than you already have six in the office? Because that's the circumstance I'm in right now.

Robbie Wagner: [03:04] Oh, I've I've got you see that trunk behind me? I've got at least 20 whiskeys in that. Like it's getting to be a problem, for sure. But anyway, I digress.

Chris Thoburn: [03:18] I've been wondering because at a bottle a week, this is quite a lot to get through in a week's time.

Chuck Carpenter: [03:26] Yeah.

Chris Thoburn: [03:26] At what point does this become the employee gift? Oh, Merry Christmas. Here.

Chuck Carpenter: [03:30] Yeah. I had been sharing them with some friends and family here and there, especially the ones I didn't like. I'm like. This is not for me here.

Robbie Wagner: [03:37] I was thinking we should offer people in the area near one of us could stop by and just try some whiskey, like fans of the podcast or whatever, like an experience for the listeners or something. But got to do something.

Chuck Carpenter: [03:52] Well, here we go. I'm going to throw this idea out right now, and we can discuss it towards the end and the whatnot.

Robbie Wagner: [03:58] Okay.

Chuck Carpenter: [03:59] If we have a Ship Shape NFT, part of what you get in that membership is whiskeys.

Robbie Wagner: [04:05] I like it.

Chris Thoburn: [04:07] I'm on board.

Chuck Carpenter: [04:08] I'm going to start pouring. I'm going to start pouring.

Robbie Wagner: [04:10] Yeah.

Chris Thoburn: [04:11] Take that money.

Robbie Wagner: [04:12] Yeah, so this is a single malt. Which does single malt just mean it's only malted barley? Is that what it means, Chuck?

Chuck Carpenter: [04:18] Yeah, I think it also means from the same farm strain, like, whatever, the same, like just one batch. And they're not but yeah, there's nothing else other than malted barley in a single malt whiskey. All right, here we go here. And the smell I'm getting a little kind of like Maraschino cherries from the jar kind of thing.

Chris Thoburn: [04:45] It smells a lot sweeter than most single malt whiskeys do when you open it up. Yeah. It's got to be the Texas flair.

Robbie Wagner: [04:52] Yeah. It's not as scotchy as I was thinking it could be.

Chuck Carpenter: [04:58] Yeah. Because it's not going to have those flavoring agents that they utilize for, like, peat or whatnot. So a single malt doesn't necessarily denote having traditional Scottish whiskey flavors.

Robbie Wagner: [05:11] Well, they spelled it without the E, so it is the Scottish whisky.

Chuck Carpenter: [05:17] Actually. Same as Irish or whatever. That's just how they spell it in the UK. So if you get Irish whiskey, it's also spelled that way. It's just how they spell whisky.

Robbie Wagner: [05:26] It's not what I read, but all right.

Chris Thoburn: [05:29] I was actually going to tease you about that. It was one way I knew that our whiskey palettes were different was the podcast had the E in it, and I was like, it must be more the American whiskey. Sure enough, you start talking about how you like your bourbon, and I was like, it makes sense. Makes sense.

Chuck Carpenter: [05:49] Right? But we want to be get out there in the world and try some other things and also be open to what our guests might suggest. So you get to try something and the flavor of things. I know a bunch of these, like, American single malts, don't have Scotch-like flavor. Sometimes it could, I guess, but it hasn't. I've only had a couple, but so far, it's been different.

Chris Thoburn: [06:15] I was interested in trying this, actually, because I don't know what title you would call my wife's uncle. I guess uncle-in-law. He's a big whiskey drinker, much more on the Scotch side, which I am as well. And I was mentioning how it's kind of interesting. I don't feel like the Americans had really come up with a good Scotch whiskey. And he said you have to try this distillery down in Texas. I haven't tried them, but a bunch of my friends have tried them, and they said they make an actual true-peated Scotch whiskey. So I was hoping we would get the peated one, but then we couldn't find it anywhere around here but for a non-peated whiskey. I'm a fan already. Not ready to call any tentacles, but I'm a fan.

Chuck Carpenter: [07:02] Right? Yeah. Okay. You can percolate on that a little bit. Yeah, I think it's good. I think it has getting a little bit of, like, amaretto, like a little bit of cinnamony kind of spice to me. And then I'm just getting a little bit of that leathery woodness, too, so it's pretty robust. It is also hot. Very hot. Well, yours is and going down. Mine is like very burny. A lot of hug squeeze, crushing my back going down. So there's that. This I would probably put a cube in.

Robbie Wagner: [07:39] Yeah. I would say to me, this is very drinkable. It's almost just like a somewhat bourbony, like, very sweet. Does have a little bit of Scotch finish. I would say so. Yeah. It's all around pretty good. I would give it, I think, six tentacles.

Chuck Carpenter: [07:59] Yeah. I think I'm in the same boat with it. I think it's unique. I think it's very drinkable. It's not boring. It's just different from Scotches, obviously, bourbons, and whatnot that we have tried thus far. So I find it pretty interesting. It's definitely something like I would try other things they have based on this entry.

Chris Thoburn: [08:19] I feel like to me, this tastes like if a good bourbon maker made Scotch. Like, it just has that more flavor coming into it, more sweet flavors coming into it.

Chuck Carpenter: [08:32] Yeah, it's a little more diverse than, like, a heavily peated Scotch, which is like you're coming into it to get a little whiskey flavor and a lot of peat, and you want to feel that for a while. And that's scotch enthusiasts, aficionados, or whatever that we've spoken to, that's what I hear, is what's the real draw to it. I always equate it to sort of like IPA drinkers and beer. They want so much of that hop. They want to get just sucker punched with hop. And Scotch can be that way too. I guess if you like ones that are more pedestrian. Yeah, it's my theory. I don't know. I could be debunked, possibly on Twitter.

Chris Thoburn: [09:13] I had an opinion on this that I'm glad I don't have anymore, but I'm going to tell it to you anyway. When I was younger, by younger, I mean in my mid-20s instead of now. I'm in my early 30s, so not that much younger. But when I was younger, I felt that bourbon was the gateway whiskey. It was that, oh, you're inexperienced, and so you need the sweetness because that kind of gets you in the door, and then you'll work your way onto the harder stuff. But now I'm coming back around, and I'm like. Actually, the bourbon is really good, too. So now it's just like, okay, it's the whole spectrum. I'm going to love all of it and not going to judge anybody for their drinking habit.

Chuck Carpenter: [09:57] As long as it's good stuff, otherwise we judge them.

Chris Thoburn: [10:00] Right?

Robbie Wagner: [10:02] Yeah. I think when we were talking to Robert Jackson, he was kind of similar as where he drinks ryes because scotches are harder to find, kind of right now with all the pandemic stuff and shipping issues and whatever. So it's kind of those complex flavors that you don't get as much in bourbon. Usually, the more experienced drinkers gravitate towards, I would say.

Chuck Carpenter: [10:24] Which is interesting because ryes tend to be younger, but because they have a different mash bill set up, then it just gets a different set of flavors. No corn, I guess. So that's part of it.

Robbie Wagner: [10:35] True. All right, well, no one listens to this for the whiskey. Let's keep going here.

Chuck Carpenter: [10:41] Well, I didn't know if we were going to force a tentacle or if we're going to give.

Robbie Wagner: [10:44] Oh, sure.

Chuck Carpenter: [10:45] Okay. Are you ready?

Robbie Wagner: [10:47] Do you have a rating?

Chuck Carpenter: [10:48] Are you ready for a rating? Or should we come back to you later?

Chris Thoburn: [10:51] I'm a harsh critic. I think if I was judging this as a scotch, I'd give it a four, maybe a three and a half, but just judging it as a whiskey, somewhere between that five and a six.

Chuck Carpenter: [11:04] Okay, fair enough.

Robbie Wagner: [11:05] Yeah. I don't have enough experience with scotch to really say, so it's fine.

Chuck Carpenter: [11:10] There you go. There goes our Balcones sponsorship. Jesus, Robbie, every time you poo poo something.

Chris Thoburn: [11:17] I agreed with what Charles said earlier. It's tasty enough that you get interested in what else they make.

Robbie Wagner: [11:23] Yeah, definitely.

Chuck Carpenter: [11:25] All right.

Robbie Wagner: [11:25] How long have you been in the Ember community, Chris? Long, long time. Right.

Chris Thoburn: [11:32] You got me thinking on that because I was listening to both of your origin stories over the past few days, getting caught up. I had listened to almost all of the early episodes on a road trip a few weeks back and had a few episodes that came out since then to catch up on. And you mentioned 2011 for you, Chuck. Was that right? Or 2010? That was Chris Manson. That was Chris Manson. You mentioned that.

Chuck Carpenter: [12:00] Yeah. No, I want to say more like 2014 for me or something like that. Maybe it was after I had been at National Geographic I got introduced to it, so whenever I left there, that was the beginning.

Chris Thoburn: [12:14] Chris Manson definitely has me beat. I came in after the router rewrite. It's still in still pre 1.0, but I was just barely pre-1.0. I want to say it was 2012. It might have been late 2011. It's roughly in there.

Robbie Wagner: [12:30] Got you. Yeah. I think 2012 is kind of when I got in, and that was, I think, still, it was either pre-1.0 or like 1.0 had just come out. I forget.

Chris Thoburn: [12:41] It gets hazy because I think they went through like six or eight RCs before 1.0.

Robbie Wagner: [12:48] Right.

Chris Thoburn: [12:49] The number of release candidates was really high. It just felt like it was in that we're almost 1.0, but not actually forever. That's my recollection. It's been so long. Probably was a blink of an eye, but the recollection was a long process. I got into Ember kind of similarly to some of your all takes on it. I had been trying to build a company starting in about 2009, 2008 where easiest way of describing this Google docs competitor more tailored to academic purposes, auto citations, math keyboards, auto typing, your late tech, that kind of stuff. But with the collaborative aspect. And if you wanted to do that and you wanted it to be web first, you had to build a javascript, which was this thing that nobody ever did and nobody was an expert in. And it felt like the Wild West. And yeah, there was a lot of jQuery, but you really quickly learned you couldn't write a Google docs editor in jQuery. In the process of that, I ended up building kind of the guts of my own js framework. And when I left, that when that folded, I wanted to continue to build on the web. I was really hooked on that idea. I was starting to consult, and I knew I wanted to be able to take whatever work I was working on and bring it with me project to project. I didn't want to be rebuilding the same stuff over and over again. So I wanted something open source. I barely understood what open source was, but I wanted something open source. I wanted something that I could contribute to and work with and maintain. And you started evaluating the options. You had Backbone. And you look at that, and it's just like, well, I might as well be building my own thing. And I actually heard about Ember before I heard about Angular somehow. And I looked at Ember, and I'm just like, well, the object model here is horrendous. I don't understand why I need all these views when I also have controllers. Like, why do I need to have separate things? And moved on, looked at Angular and directives and dollar scope, but I was just out, no, not doing that. So it was starting to look like I was going to be building my own framework and moving on from there. And something in me, though, that a friend of mine had said to me just kind of stuck with me, that Ember really fits my philosophy. And I just decided, this guy, he's always right in what he says. He's not a developer. He's just somebody who reads way too much Hacker News, but he's always right on what he says. So let's go give this a deeper look. And looking at the two things that were just throwing me off, even after I got past the view controller thing, I started realizing I can do container views and have more control. There is this thing called a component. No one seems to really know what it does, but I could use it. But the two things that stood out to me were, why is get and set everywhere? And what is this run loop? But then I started digging into the code, and I realized the run loop was actually literally the same run loop that I had written for the framework that it built for the startup that I've been having to solve the same order of operations problems and the same batching problems. And I was like, oh, okay, that makes a ton of sense. I know why they did that. That's very sane. I wish I didn't have this as an API, but this is the state of the web. I understand why get and set. And then I was poking around that, and I was like, oh, well, the reactivity model is kind of cool. The two-way binding is kind of cool. I knew that when I had tried to set up those sorts of things that I had tried to invest in a proxy trap. There was an experimental API in Chrome back at the time that was sort of an intercept all properties prior to the existence of proxies today. And that API had unfortunately never matured, didn't make it out to fully standards accepted, and had been removed. But in the absence of that, you always had to have a static schema for every object if you wanted to be able to intercept properties. I was really curious how they were doing the binding. And then I realized, oh, that's why we have to use get and set on everything as these no proxies. So once I accepted this unergonomic pattern because of the other very large problem it was fixing, it became a much easier pill to swallow of. Oh, this is actually maybe something to invest in. Started building with it. Early days was grunt scripts. I think it was Trek who recommended to me at least compiling all the modules with closures so that they weren't all in global scope anymore with that and started to kind of get a feel for it. I don't know that I was sold, but I was starting to build stuff and feel productive. And then Stef Penner dropped Ember CLI. And that changed everything for me because all of a sudden, it was super productive, super fast to get started with new stuff. These add-ons, which weren't called add-ons at the time that I had been helping to maintain, all of a sudden they had a place that they just fit. So I ported everything over into add-ons, and away we went, and I haven't looked back since. I've tinkered around with React. I've tinkered around with newer Angular stuff. I like Svelte, especially for those narrow, purpose things. But I've never found a reason yet to want to reevaluate Ember as my main framework. Just every time I've had a complaint, it's evolved to satisfy that complaint with time. It's been a really fun journey, and I think the not-smart developer that I was in my early 20s when I began that journey made a very intelligent decision with it because the underlying motivation was I wanted to be able to port work with me, project to project. I didn't want to be reinventing the wheel. I didn't want to be starting over every time. I wanted to be able to be more productive. And Ember has really done that for me as a consultant, which I'm not consulting now, but as a consultant, everywhere I would consult, I could slide, and I understood the project structure. I knew how to do what. Most of the time, I had zero idea of what the product did. A lot of times I didn't even see the product booted in an action. I didn't need to get the server running. I could read the code, understand what it was doing, understand how it fit in, understand what I need to do, go perform the surgery, and get out. It made it super easy to do that, which as a development model is the promise that's the promise of Ember is that that's what those conventions bring, and that has been delivered on so much more than I ever would have imagined in my early 20s.

Robbie Wagner: [19:52] Yeah, I definitely agree. I feel like other frameworks are good at certain things, but nothing kind of matches the opinions of Ember, so that everything is kind of the same. Add-ons have so much power with all the different hooks and things to just kind of do whatever. The add-on author can worry about how things work, and then you just install it, and it just works. You don't have to wire stuff up in webpack or any of that.

Chuck Carpenter: [20:18] Right. I wonder. You said you explored some other frameworks, and you've tinkered here and there and whatever else. Because in a similar paradigm, we recently were talking about RedwoodJS. And to be fair, I haven't dove into it and tried to build something, but going through the documents and just the documentation and sort of what it's trying to attack. It's the framework for startups, and it has a lot of opinionative configurations and paradigms there that could be an overlap in a way, but also provides you like a full stack thing. I was wondering if maybe you had looked into that any.

Chris Thoburn: [20:55] That podcast got me interested in looking at it. I've not found the time.

Chuck Carpenter: [21:00] Yeah.

Chris Thoburn: [21:01] My main takeaway from that podcast was, actually, here's a guy I wish I could sit down with for a couple of hours and talk him over to Ember because the philosophies were so well aligned. The direction is so well aligned, and it sounds like most of what he's setting out to do is what we have set out to do. So why reinvent the wheel?

Chuck Carpenter: [21:23] Right.

Chris Thoburn: [21:23] You have a whole community here willing to just take on your energy and keep it going.

Chuck Carpenter: [21:29] Yeah, it was interesting because the way he was speaking about things, I said, oh, some of these things sound a lot like Ember, but then you're offering some of these other bolt on things with authentication and a back end as part of it. Have you looked into that? And he hadn't because he just sort of missed the mark on where he was in his career in terms of Rails and then making his way right to React. But I definitely see what you're saying. And he mentions, I think, something about potentially having a more open-view layer at some point. So not only being part of React.

Chris Thoburn: [22:03] I would be interested to pick his brain at some point as to why he wants to build basically another API framework. You're not building another API framework because you're building these integrated levels like layers. I get that, but the reason I'd be interested in picking his brain is because he clearly sees that existing API frameworks are not mirroring well or marrying well with existing front-end frameworks. And that is a friction I still see at work. Right now. We're using Java Spring, and we literally embed our Ember app into the back end and ship it that way. Why aren't we shipping a standalone? That's stuff we have to fix. I understand, but I see that sort of thing happen more often than not because it feels like API frameworks are really more an afterthought on the back end still. It's really still. Well, we are a framework to build and render stuff, and then you can happen to build an API with us, and you can happen to not build an API with us. But I don't know. And so many of the problems that I see applications encounter later in their life cycles are problems where the API framework wasn't set up well in the first place. And if they had a better framework for building APIs and understanding how applications are maybe even mature and how that API is going to need to evolve as the application matures, they probably would have been set up for better success. Instead of getting stuck in this refactor hell about a year, two, three years into their product cycle where they're primed for big growth, they've got the money coming in, and somehow, they cannot throw enough bodies at the problem to refactor their way into something that's going to scale and grow with them. I think there's actually a space. I think it's really interesting. I think there's space for a really cool API framework right now. I'm hoping to see something come out of Rust. Personally, that is not really my area expertise. I'm going to stick here on the front end. Anyone out there listening who really wants to build me an awesome API framework, please do.

Chuck Carpenter: [23:59] Interesting one follow-up question to that. Do you think that the issue is that the teams aren't aligning in the API design early in product creation? There's not like a contract agreement necessarily, and they're just working to solve the business issue, but not working together in the technical architecture to have, like, here's the contract of operations we think we should work on and spend more time there.

Chris Thoburn: [24:27] I think that's more or less fit, and I think that also answers your question of why Orbit? So I've been wanting to answer this question because you keep asking this. It's come up like four times, like why Orbit? I don't get, you know, what is Orbit good for. Orbit, in my opinion, is the gold standard of data libraries for the front end right now because it solves every problem that you don't know you have yet. But that's also its big flaw is because it has found the end architecture that you've got to evolve to if you end up with those problems, but most people don't start there. And so if you don't start with those problems, you're not thinking about those problems, you're not caring about those problems, then it seems like way too much work and way too much effort and way too much time when you could have something like Ember Data that has nice glue code already built in, and you just ship it, and you're done. You move along. And I think this is what happens with APIs is early on. People just want to ship something, and you just added a way to get data. I have a thing in the database. I have an API endpoint that returns it voila, and they are two years in before they go. Oh, you know, probably all of our API responses should have been formatted the same, and probably our endpoints should have followed the same convention. And, you know, we have all these weird edge cases. We should clean those up and standardize those. And we didn't ever really think about whether ID should be a number or a string, but maybe we should think about that now or, hey, we're handling currencies, and we're just sending them back as numbers, and the front end has no idea how to handle them. Maybe we should come up with a standard for that. All these things that evolve over time, you want offline support, you want real-time support, you want anything like that. All these behaviors that evolve with time. You don't see those initially. And if you do see them initially, you get scared of over architecting because you have this problem. If you overtake architect initially, you don't grow fast enough. You die too early. So you just want to build. You're not spending that time to do that work, to figure out the contract, to work with your peers to figure out. This is what we're all agreeing on. This is what we should ship doesn't happen because there's no time because you've just got to ship. So by the time it matters, you've taken on a whole lot of debt that you could have avoided with those little conversations early on that you never had because you didn't have the time. So a really good API framework, I think, would take you from, hey, you're just trying to bootstrap some stuff up and get some stuff out the door to, hey, you really need your database models to be separate from your API models because you're going to be hooking up multiple services to them. You're going to be shipping different API versions to different people, all that kind of stuff. You need to be able to grow from one to the other. And I don't see an API framework that really allows you to do that naturally and quickly today. With Orbit coming back to Orbit, this is actually where Ember Data fits because Ember Data, its power is really in that glue code. It's that most people will never have to write the glue code. Now, under the hood, our aspiration is to basically be Orbit, really Orbit with a bunch of M3, because we fully realized and embraced the GraphQL future. But it's get as much of the glue code in place as we can for people and then build really nice escape hatches when we need escape hatches, and build really nice composable primitives for the areas where we can't do the glue code. But we can maybe help you get the glue code in place. And if you do it that way, then you never have to see the difficult inner workings of how A is handed off to B inside of Orbit from one source to another because you're trying to handle the transaction and do your offline support, and you've got multiple data sources we can abstract over that. So this has put me in a really interesting position, the Ember community, because I see Ember Data as a data contributor for what it is underneath the glue code, underneath the outer API layer, what we've done underneath, and what our plans are underneath. Everybody else sees the outer layer. Those are two very different libraries. I don't even know where to begin if you want to talk about that. They're just totally different. But from my perspective, we are somewhere between nice fancy glue code and Orbit, and we're trying to make that path in between very seamless.

Robbie Wagner: [28:53] Yeah, I definitely agree that Orbit does a lot of stuff, but also is hard to learn, I guess. So we've talked about it. I don't know how in-depth. We went on other podcasts. We've mentioned it a couple of times, probably, but we use it for Swatch, and we built it backwards and had a lot of trouble because we did just local storage or, I guess, IndexDB storage and then needed to add an API after the fact. And going that way hasn't really been thought about. Usually, it's like you build your API, you talk to that, and then we want it to sync locally and then sync back up. So there's a lot of stuff to think about, and we couldn't figure it all out. So we've been working with Dan a lot, trying to get it to work. But anyways, all that to say, where do you think those boundaries lie? And how can we get people to be more interested in experimenting with the more in-depth, complicated version versus just kind of using Ember Data?

Chris Thoburn: [29:57] I don't know. I think to a degree. This is where a developer evangelist would help our community because we don't really go showcase the power user. This is what you could do really awesome stuff all that often, but there's a lot of really awesome stuff you can do. I think there's an education aspect, and this is something I've been pushing on kind of hard for a few years now, and people still aren't catching on. So I'm clearly not successful in this, and I need to find out a different strategy. What I've tried so far is conference talks, and I've tried rewriting our own documentation. So I rewrote the Ember Data documentation, but that's not what people see first. They see the guides. And we haven't gone in and done anything in the guides. And I've just tried telling people what to do in Discord, and the number of times that people come back to me and they go, well, what you said in Discord, I'm just not going to do that because that's not the guide show or it's not installed by default. So I just don't want to do that. It's so high, and that frustrates me because I'm sitting. Look, I've invested more time in this project than anybody at this point, and I'm telling you, there is a much easier, pain-free way of using this library. This one weird trick and you don't want to accept the trick. I can't help you beyond this.

Chuck Carpenter: [31:22] I think everybody's afraid of not being able to upgrade things. It's the whole like, if I do anything other than what the guides say, I will get stuck on an upgrade path. Right?

Chris Thoburn: [31:30] But see, this is the thing is the most common thing that I'm recommending is actually the easier upgrade path too. So the nice example of this is adapter and serializer APIs and Ember Data. The adapters and serializers Ember Data have this reputation of having this horrendously complicated API. That's massive. But the reality is that the contract between the adapter and the store is currently five methods, and they're all pretty easy to remember. It's find record, find many, create record, update record, delete record. Query, I think to me, so maybe six. The number of methods that the store interacts with the adapter on is actually very small. Same thing with the serializer. With the serializer, it's really only one method, which is normalized response, and two methods. If you're using a specific API that is on the Ember data's version of a model, though, you don't have to use that model. So that's the serialized API. So really, the surface area there is like six, seven methods, most of which have exactly the same signature. It's just the difference is just in what operation triggered that request. So was the user asking you to find the record, or was the user asking you to delete the record? That's the difference. And if you take it from that perspective of, oh, I have this method, and it's just going to take here's the record that I'm operating on, here's what I'm supposed to do with it. I'm supposed to go do that thing, and then I need to return a JSON API formatted response. And this is an async API, and you just take that perspective on it. It's suddenly way simpler because you're not sitting here figuring out what hook do I need to convert x attribute to y attribute, what hook do I need to add in these request headers, but only when the request options match this. The things that have these huge complicated APIs are the rest adapter, the JSON API adapter, the JSON adapter, the JSON serializer, the JSON API serializer, the rest serializer. These things have been built in as glue code for a long time, and they've been there for a long time. And people just accepted that those were the base primitives. But in reality, those were reference implementations for the more abstract interface. I've been trying to unveil this abstract interface to people because unless your API perfectly matches one of those conventions, you're going to have a much easier upgrade path writing your own thing. You know how your URLs work, you know what your API responses look like, you know what your schemas are way better than we do, trying to guess at it heuristically. And even if you wanted to guess at it heuristically, you know the heuristics better than we do. We have to match multiple heuristics because we're trying to match everything. So one weird trick for performance on top of all this is simply, let's say your API is JSON an API and you're currently using the JSON API serializer, delete the serializer, put in a new one that just passes through the API response directly from the API with no additional work. If your JSON API response matches the JSON API format expected by the store, which has a couple of nuances to the flavor of JSON API, which are in the docs now as to what those are. But if it matches, then you're now doing zero work. Whereas before, you are copying over and processing every single attribute on every single object and array in that entire JSON response. You would see things that would take 15.20 30 milliseconds just to process to rebuild exactly the same object on the other side of that method. Why? So you'll be doing your application so many favors just by taking the part Ember data to honestly, is the bad part, the part that's so confusing to everybody because it has so many methods, and paring it down to what's the actual interface? And let's just build something that conforms to interface that works with the API that we have.

Chuck Carpenter: [35:38] Interesting. So here you go. You've had your forum to evangelize some of those exact points. Now you briefly touched on some GraphQL, and I'm dying to force Robbie to talk about it.

Chris Thoburn: [35:52] You haven't mentioned it on the podcast yet. I think I counted five. I was trying to do some math. I think I counted five mentions. We can make it six.

Robbie Wagner: [36:01] Yeah, I forget which podcast it was when we were kind of talking about how Ember Data kind of works best with JSON API and how GraphQL is kind of left out. I know that you pinged me after that, and we're like, hey, it's not like here's all these ways you can do stuff or whatever. So talk about that. Like you touched on M3 a minute, and I think you said LinkedIn had a lot of stuff in place for GraphQL and how, like, Ember Data is the best GraphQL or JSON's API flavor GraphQL client. Yeah, you take it away.

Chris Thoburn: [36:33] I'm going to walk all the way back to the beginning here. JSON API versus GraphQL. They're both great. They're better together. That is my probably strongest belief in programming right now is that JSON API-flavored GraphQL is the best of all worlds. And that's for a really fundamental reason. Most people think of JSON API as being URL schemes. And a lot of times when I hear these discussions comparing the two, everyone's like, oh yeah, well, JSON API, you could do the includes with your URL and all that. Forget that I don't care about the URLs that you're building. I care about what the response is formatted as because I want to know in that response data how much schema information is embedded in it by default, how much knowledge is in it by default that I can infer with a very stable heuristic. Because that information is what is going to lead to better performance and less code on the front end. And in GraphQL land, you don't really have a convention for what I would refer to as a cachable entity exists in the payload. A cachable entity means that, let's say that you have the same user object appearing four or five different places in the response. You just want to merge them together. You don't really have a great way of describing this in GraphQL. More often than not. What I see people do is they just leave the user in each individual place, and you'll use a client like apollo on the front end, and they'll just assume that the data is separate each location. And so if you're updating at one place, it's not going to reflect others until some other query is rerun or some such to fetch fully new data from the back end, which can work, that can work for a lot of people. But if you actually want the cache to merge those entities together so that they have a consistent representation throughout your application, and then if you were to retrieve it again, they have a consistent representation throughout your application, you have to have a way to find that entity in the graph and put it into your cache. If you don't hoist it to the top level, you have to walk the whole graph. So you get this big JSON response from your API, and you got to walk through every single property looking and asking is this a casual entity or not a casual entity? And if it is a cachable entity, what is its cache key, and what else do I need to merge it with, and how do I merge it? And in JSON API, there's a very simple heuristic it is casual entities are always hoisted to the top level, the response. So it's in the data member, or it's in as either the only thing that's in the data member or as one of the things in the top-level array that is the data member, or it's in the included array. If it's cachable, it's in one of those two things. Otherwise, it's not cachable. Does not matter if it has the same representation everywhere in your application or not. The other thing is around identity, which heavily relates to caching. In GraphQL, there isn't a standard for what your identity needs to look like. In JSON API, there is. JSON API it's an object with a type property and an ID property. In GraphQL, you don't have this. You can add it in if you want to, but it's not standard. And there's a lot of different ways to come up with identifying strings. And some people use UUIDs, and some people have UUIDs that have a type kind of as a part of the component of the ID. So you really don't need a separate type and ID. Even if you wanted to try to enforce schema off of that key like you could just parse the type out. But 90% of the apps I've ever been in end up at some point wanting to know I'm looking at a record of some kind, an entity of some kind. Is it a comment? Is it a post, is it a user? They end up asking that question. So why have to parse it out of your identifier? Why not just have it already separate in your identifier so that even if the ID repeats the same information, at least it's still there? And when you do that, then you have a very simple heuristic. Anywhere you encounter an object with both a type property and an ID property, you know that you have a reference to a record that it was cachable. So you know that if you don't have the full record there, you could go look for it in the cache. So all of a sudden, your graph can be self-referencing very easily, no matter where it is. And when you're exploring that graph, you recognize when it is self-referencing. So when I say JSON API flavored GraphQL, I'm not meaning that your GraphQL response comes back in JSON API format. I'm actually meaning it can still come back in GraphQL format, but I'm saying come back in GraphQL format but give yourself a top-level data property. Give yourself a top-level included property, hoist those things up that you would otherwise have to iterate and discover and use identifiers that are very clear for what they are as references to other records that could also be cachable. If you do that, it unlocks a world of potential optimization, both for libraries like Ember Data and Orbit and Apollo. But even for your own application, if you were just to, say, abandon all of those things and write your own stuff or, God knows, use Redux still, you'd have this ability to more quickly reduce across it and figure out, this is what I want to do with this data, and this is where I want to put it. So with that background in mind, here's what Ember Data actually cares about when it comes to any API response. It cares that your document has a data member that has in its top-level either an array or a single object that is going to be capable of being in the cache. And it cares that if you have an included member in that response, that each object in that is capable of being in the cache. But it doesn't actually care what the cache keys look like or what the objects look like other than that. That information is all handled by user-configured hooks at that point. Now, the default configuration is that we're expecting it to be in fully JSON API format, and we have implemented a cache that speaks JSON API and we've implemented identifier logic that speaks JSON API. But we had this RFC Ember Data a few years ago that is fundamental to working with data in a really flexible compositional way and accurate, highly reliable way. That was the identifiers RFC. And the power of the identifiers RFC is that it allows you to take any object that you received from the API and pass it into the hook and say, give me the identifier for that object. So it no longer is subject to type in ID being these keys that define, oh, this is what a record is you're no longer subjected to even single keys. Like, you could say that user email address or user Twitter handle Runspired, and user first name Chris Thoburn and user username Runspired, and user ID one. These are all the same person. We know they're all the same person. And so if we ask the cache for a record via any of these parameters in this way, we should be able to find it because we know that all of these were ways of uniquely identifying it. You can build all sorts of compound keys, secondary indexes, that kind of thing via the identifiers API because take any object. What is it an identity? How do I want to put it into cash? Once we have the identity, we're handing it off to the cache, and what we're handing it off as is, we say, hey, for this given identity, here's the blob of data, and here's what's happened. Which means that the cache implementation can be agnostic to format. It doesn't need to care about any format at all outside of that very top-level structure that we care about, of data and included. And outside of that, you got to have some way of determining identity from those objects when it gets passed to the identifiers hook. Which means that if you want your cache at that point to, say, be objects that are flat properties, not JSON API looking at all, like all properties are in rest, like single object. You could do that if you wanted each entry in the cache to actually be a full GraphQL response where the ID is maybe even the query ID for that particular GraphQL response. And all of that is cached together, and you're not really merging any entities with any other requests. You could do that. Ember Data is just, hey, for this identity, here's this blob. That's what it is now, which is not what other people see. Other people say, oh, you write these models, the models have your schema, you access attributes. Got to do some fancy magic to figure out how to whatever your API is returning to get into the format the model is going to understand doesn't have to be that at all. M3 is an alternative to Ember Data models, and it's built over an entirely public API, and it takes advantage of this big project that we took like two years to mostly finish, and we technically never quite polished off, but we mostly finished to split Ember Data into multiple packages. So Ember Data, when you import adapter from at Ember Data adapter, you import rest adapter, you import anything that you're importing from at Ember Data space that's actually a real import. We move to real imports in, I think, 312 or 316. And because there's a real import, it means that you could actually go and say, hey, remove Ember Data from my package at jSON at Ember Data adapter, add at Ember Data store, add at Ember Data model. You can reconstruct all of what's in that main Ember Data package by just installing the individual packages and then gluing them together however you see fit, which means that if you don't want the adapters that are there today at all, you don't want the serializers that are there today at all. bundle model together with store and ship that along and drop those other packages. If you don't even want model, bring just the store and M3. I believe we've gotten it down to that being the only things you need. And if you want interop with today, you would need the store, M3, the model package, and the record data package because the record data implementation is there for the model implementation. So M3 is taking advantage of the fact that you can just use less of Ember Data, and it's then building over public APIs for hey if you want to provide a model, this is how you provide a model. If you want to implement a cache, this is how you implement a cache. If you want to determine identity, this is how you determine identity.

Chuck Carpenter: [47:20] Interesting. I mean, I want to write there, Robbie, if those are some patterns to lighten Swatch up a little bit, considering, well, no, I guess we're not using any Ember Data stuff whatsoever. It's just completely Ember Orbit.

Robbie Wagner: [47:32] Yeah, we're using Orbit mainly for undo and redo, so that's much easier in Orbit. But yeah, I feel like I have a ton of follow-up questions to everything you just said.

Chris Thoburn: [47:44] Okay.

Robbie Wagner: [47:44] But we're getting close to the end of our time.

Chris Thoburn: [47:48] This rabbit hole keeps going down. So that's a jack now. Yeah.

Robbie Wagner: [47:51] So maybe we can follow up next week like we were saying.

Chris Thoburn: [47:54] Yeah.

Chuck Carpenter: [47:55] And maybe have more informed questions around some of this information you gave us.

Robbie Wagner: [48:00]Yeah. But I think in our remaining time, we should do a little bit of whatnot, keep it a little lighter.

Chris Thoburn: [48:05] I've got a whatnot question for you to start with. Oh, yeah, sure. So I hope I'm not running the end joke here, but no one has brought up yet that the podcast is the www.

Chuck Carpenter: [48:18] And it's completely intentional.

Robbie Wagner: [48:20] Oh, yeah. Yes.

Chuck Carpenter: [48:21] That's what we liked about it.

Chris Thoburn: [48:24] I'm running the end joke. Okay. Got you.

Chuck Carpenter: [48:26] Yeah, it doesn't matter. It's fine.

Chris Thoburn: [48:27] See, I really feel like the intro or the X, it's got to be, welcome back to the WWW.

Chuck Carpenter: [48:34] Yeah, we can actually do it officially. Now, here's the thing. The running end joke is that it's all a joke.

Robbie Wagner: [48:41] So it's not a joke, but.

Chuck Carpenter: [48:43] Yeah.

Robbie Wagner: [48:44] It's light-hearted.

Chris Thoburn:[48:45] Yeah.

Chuck Carpenter: [48:45] It's light-hearted and it's fun.

Robbie Wagner: [48:46] Yeah.

Chuck Carpenter: [48:47] That's all. So I heard you started running. how's that going?

Chris Thoburn: [48:54] It's a little bit of a Forest Gump situation. I started and never stopped, although I don't remember when I started. It was a long time ago.

Chuck Carpenter: [49:01] It's fair.

Chris Thoburn: [49:02] It's been going well. It's been an interesting journey. I realized about three or four years ago that I wasn't getting any younger, and I wanted to pursue professional running. So I started getting a little bit more serious about my training and somehow managed to have a major life interruption every year after that. So I think first it was I was assaulted and had to get facial reconstruction. It's not my original face here. And then it was, oh, I forget, there was another thing. And then after that, I was getting married. And then, on my wedding day, my lung collapsed. I still got married.

Chuck Carpenter: [49:45] Good for you.

Chris Thoburn: [49:46] Just sucked it up, got through the day. Yeah, I wasn't going to ruin that one. I had a blast. And I ended up getting lung surgery to correct a condition that I have, which is kind of just an effect of being a tall, skinny male is the underlying preexisting condition for this. So I ended up getting like a lung surgery operation in February right as the world was shutting down for COVID. So I had a really interesting opportunity because there weren't any races, there was nothing to blow up my fitness for. I could just hunker down, grind, focus on recovery, get really fit. And a few months after that, I left LinkedIn all the time in the world for this, and it was awesome. I think I exceeded my own expectations when it came to how far I thought I would get with certain kinds of things, came up short , and a few others. I definitely wanted to kind of put a really fast time on paper or a really key performance on paper before I ended all that, and instead, it kind of ended up in this ball of frustration where I had a race. Some stuff out of my hands kind of went amusingly wrong where the race thought I had dropped out, but I hadn't dropped out. And the miscommunication got my team off-kilter, and they went home and weren't there when I needed them. And it just kind of was a frustrating situation, and I took all that frustration, and I pounded myself into some more training that I shouldn't have done and got myself hurt. So I spent all of the last year rehabbing. It's been a really good two years despite all that because it just kind of was nice to see what I could get out of myself with dedicated effort, consistency, and time.

Robbie Wagner: [51:33]Yeah, I know you maybe didn't have a major race you placed in or anything, but for us mortals who are very out of shape and don't run fast, what kind of metrics are we talking about here?

Chris Thoburn: [51:50] So I mostly like to run ultra marathons. Technically that's anything longer than marathon. I think I've spent the most time the 50k distance. I like the 50 miles distance the most. I think that's probably where I'm best suited to perform well long term. And the race that didn't go my way in that January was 100k. I would like to get into the 100 to 200 miles effort range, but I haven't quite worked my way there yet until I realized the injury was as bad as it was. Was hoping to actually go for the fastest known time on the John Ware trail. So that's 210 miles. Technically, the effective distance for the FKT is closer to like 222. So 222 miles. I think the first half of it, you average above 10,000ft altitude. That includes you start by ascending Mount Whitney tallest point to continental US. And then you finish up in Yosemite in Happy Isles. So I had put a lot of, like, planning time towards that attempt logistically because it's almost harder to pull off logistically than it is, even from a fitness perspective. I'd really still like to go for that at some point, but right now, I'm focusing more on just as I'm getting healthy and coming back into this. I want to make a shot for a fast time at the Olympic Trials in two years, two and a half years, when that next comes around. So that I'll start by. I'll need to run a qualifier for that, which means I need to get roughly 217. I think is the time now. They just changed it. It used to be the B standard, was about 219. The A standard is about 218. I think it's now 217. There's some ambiguity still. So I have to start by running a marathon at least that fast. And then if I'm serious about trying to contend for a spot on the Olympic team, which is on the outside of my mind, like, if I'm going to go to the trials, I want to make a shot at it, take a shot at it, then I would have to be able to be in shape to run on whatever course on that day, which about a 209, which historically the trials courses are a little bit tougher than a lot of the other courses that you might run to get a fast marathon time on. So tougher than, say, a Boston or a Chicago or New York or in La or something like that. So tougher than these courses. So you're talking, like, probably an equivalent on a Chicago course, like a 207-ish time, which I have no idea if I can do that, but I'm going to try.

Chuck Carpenter: [54:44] Why not?

Chris Thoburn: [54:46] That's what's fine for me. That's a good try.

Chuck Carpenter: [54:48] Yeah, that's great. So in all the time that you're not running, what do you find yourself doing?

Chris Thoburn: [54:53] Drinking whiskey and talking on podcasts.

Chuck Carpenter: [54:55] Perfect. I'm really leaning into an excellent time on those things, those activities. I seem to be excelling quite a bit there. No Olympic representation at this time, but I am lobbying for otherwise. Also, I'd like an over 40 group. All those things.

Chris Thoburn: [55:13] Yeah.

Robbie Wagner:[55:14] Olympics light.

Chuck Carpenter: [55:17] Yes.

Chris Thoburn: [55:17] The more honest answer there is, there is no time. It's work, wife, or running.

Chuck Carpenter: [55:22] Yeah.

Chris Thoburn:[55:23] And sometimes it's not even all three. Sometimes it's kind of one of the three is taking a hit, so it's doesn't leave doesn't leave a lot of time for enjoying all the other nice things.

Chuck Carpenter: [55:34] Yeah, I feel you. Substitute running for kids, and boom.

Chris Thoburn: [55:38] Yeah.

Robbie Wagner: [55:40] All right, well, we're overtime here. As we're ending, is there anything you would like to plug? Projects you're working on? Anything you want people to know about or do or causes you're interested in?

Chris Thoburn: [55:54] Anything? I think the biggest cause I'm interested right now, Ember related, is how do we get more people into core teams in meaningful contributor positions who aren't at LinkedIn. I think that's really important for the ecosystem to do right now. So if you're interested, whether it's Ember Data or something else, obviously, my expertise is Ember Data. But if you're interested in getting more involved in one of those projects and working your way into a team, reach out. Love to work with you and see if I can help make that happen, especially for data. It basically comes down to us do a bunch of pair programming and shoot the shit and learn all the internals, and iterate our way into me not having to explain everything because, ideally, all the knowledge would not be locked away inside.

Chuck Carpenter: [56:44] Yeah. Excellent.

Chris Thoburn: [56:45] If you're interested, reach out. You can find me on Instagram or on LinkedIn, Runspired.

Robbie Wagner: [56:52] Yeah, sounds good. So thanks, everybody, for listening. If you liked it, please subscribe, and we'll catch you next time.

Chuck Carpenter: [57:02] Thanks for listening to Whiskey Web and Whatnot. This podcast is brought to you by Ship Shape and produced by Podcast Royale. If you like this episode, consider sharing it with a friend or two and leave us a rating, maybe a review. As long as it's good.

Robbie Wagner: [57:17] You can subscribe to future episodes on Apple, Spotify, or wherever you get your podcasts. For more info about Ship Shape and this show, check out our website at shipshape.io.