Mastering API Testing: Using Shoulda Matchers and Super Diff in Ruby - RUBY 640

Elliot Winkler is a Staff Software Engineer, Shared Libraries at MetaMask. This episode blends a diverse range of topics, from casual gaming to innovative testing approaches. They explore Elliot's transition to JavaScript and TypeScript at MetaMask while maintaining his Ruby roots through open-source projects like Shoulda Matchers. They also talk about the history and purpose of these matchers, their role in testing Ruby on Rails applications, and the intelligent diffing capabilities of Super Diff. So, sit back and get ready for a deep dive into the world of Ruby, testing methodologies, and a bit of fun along the way!

Special Guests: Elliot Winkler

Show Notes

Elliot Winkler is a Staff Software Engineer, Shared Libraries at MetaMask. This episode blends a diverse range of topics, from casual gaming to innovative testing approaches. They explore Elliot's transition to JavaScript and TypeScript at MetaMask while maintaining his Ruby roots through open-source projects like Shoulda Matchers. They also talk about the history and purpose of these matchers, their role in testing Ruby on Rails applications, and the intelligent diffing capabilities of Super Diff. So, sit back and get ready for a deep dive into the world of Ruby, testing methodologies, and a bit of fun along the way!

Socials


Picks

Transcript

Charles Max Wood [00:00:04]:
Hey, folks. Welcome to another episode of the Ruby Rogues podcast. This week, I'm your host, Charles Max Wood, and I am talking to Elliot Winkler. Elliot, now do you wanna introduce yourself real quick, let people know who you are, and why we're talking?

Elliot Winkler [00:00:20]:
Sure. I can. Yeah. Yeah. My name is Elliot. I guess I've been, I don't know, doing doing programming stuff, turned web stuff, for, gosh, I don't know, like, 15 years at least, since I was in high school, I guess, really. So, and, yeah, I worked at different consultancies and product companies, you know, doing doing writing Ruby mainly in the past, but also, like, as of, I don't know, a few years ago, kind of writing more, like, JavaScript, TypeScript, that kind of stuff. Okay.

Elliot Winkler [00:00:57]:
But, but kind of just doing full stack in general. So Uh-huh. So yeah. And then, also maintaining some open source libraries on the side as well.

Charles Max Wood [00:01:07]:
Good deal. Yeah. I think we got this lined up because, typically, what I do is I I have a virtual assistant that I'm like, hey. Projects like this. So, you know, if people are watching on the livestream, it says shoulda matchers. You know, we'll probably go into a few things here. But, Yeah. So I I probably handed off and said, hey.

Charles Max Wood [00:01:27]:
I want somebody to talk about show to match. So we'll probably go into that. But, you know, yeah, it it looks like you're maintaining a couple of other open source libraries. I think they're also interesting to get into. And so we'll just kinda see where this goes. And, anyway, it's it's always interesting to see where people are at. So Yeah. Why don't you start us off with just how you got into working on some of these projects like Shoulda or you also mentioned Super Diff?

Elliot Winkler [00:01:52]:
Yeah. Yeah. Sure. Yeah. So I can start with Shoulda. Yeah. So I I worked at Thoughtbot, I think it was between 2013 and, 2016. There we go.

Elliot Winkler [00:02:07]:
It's a little while back, but but, when I was but when I joined, you know, one of the things that they had and and they might have that they might still have this now, but they kinda have, like, a 20% time sort of similar to, like, how Google has or maybe they used to have. I don't know if they still have that now. But but, yeah, every every, I guess, every other Friday, we would, you know, get a chance to work on something that was valuable to the company. So, so I saw that we had developed shoulda, shoulda matchers, shoulda context, this kind of this this kind of Mhmm. Triumph, fire rate of, of of of gems there. So, yeah, that that was interesting to me. So and I wanted to get more involved in open source. So, I just began submitting pull requests, you know, and, yeah, at the time, I think it was maintained by by 2 or 3 people.

Elliot Winkler [00:03:09]:
And they were, you know, they were open to the to the contributions, and then, you know, they didn't really wanna take it over anymore. I think they kind of were interested in other things, so I was I volunteer, and I was like, okay. I'll take this over. And so I, you know, just began kinda making more changes, responding to people, you know, that were submitted bug reports or whatever. And yeah. And then I just kind of actually ended up maintaining that for quite a while. Like, even after I left thought bot, probably, you know, 5 or so years after that, or even longer. I'm not sure.

Elliot Winkler [00:03:44]:
I I kept maintaining it, just because it was just a fun thing to work on.

Charles Max Wood [00:03:49]:
Yep. Cool. So for those that aren't familiar with it, should a matchers just give you a convenient syntax for, asserting that things are the way you want them to be. Right? And it's usually a something should, something else. And so, anyway, that's kinda where the name comes from. Is is that a fair summary, you think? Or

Elliot Winkler [00:04:11]:
Yeah. No. I can yeah. So, trying to think about, the history a little bit of the project. So I think,

Charles Max Wood [00:04:19]:
Initially, it was just our spec only, but I think now it is both.

Elliot Winkler [00:04:22]:
It does. But well, I think I think even initially, it was it was test unit, I wanna say.

Charles Max Wood [00:04:26]:
Oh, really?

Elliot Winkler [00:04:27]:
Yeah. There was a time so when I first joined, I thought but I think they were, like, going through a transition period where they were they were transitioning or maybe they had just transitioned from test unit to tar spec.

Charles Max Wood [00:04:37]:
Okay.

Elliot Winkler [00:04:38]:
And so so these so they so it started out with with Shoulda. I think that was, like, the original gym that came out. And it was a way and so and and, you know, for for people that use test unit, you know, it's like, now they have well, now well, I see now. It's been a while. But, it's been it's been several years many years. But, you know, they have, like, test spec, and so you can write your tests just similar to how you are spec. But I mean but I but back then, I believe that isn't Texas even knew or maybe hadn't come out yet. So so, you know, people thought about it were like, what what can we do to improve test unit? So they made kind of a syntax on top of test unit, and so you could and, and so you could you could write your tests, kinda in a more expressive way.

Elliot Winkler [00:05:26]:
And then and so that is a macro. So it's like you could you could certain you know, you could have your context, you know, you could have your it, blocks, But then you can also, you could also define some macros. And so you could say, you know, should validate presence. It's been a while. I have to look at the the

Charles Max Wood [00:05:47]:
check view.

Elliot Winkler [00:05:47]:
But I believe, yeah, I believe they they were just defined as, like, class methods, within within, like, the test unit class or something like that, within within your test class, I should say. Uh-huh. And then later on, RSpec came out and they're and and so they started transitioning those to RSpec matchers. And so they kinda broke apart, like, the the context part that was adding the the the the syntax on top of our test unit, and then the should've and then the matchers, that were first, I think, designed to to work with our spec, and then I think, were added like, support was added to also use them in test suite as well. And so yeah. So the the matchers were added, I think, because they wanted to you know, they wanted a way to, you know, we wanted we wanted a way to just verify that associations work correctly, validations work correctly. You know? Because all all all the code you're adding to that, you're like you know, when you add a validation to a model, yes, you're using Rails and you like, and, you know, Rails gives you these nice way DSL of doing that, obviously. Right.

Elliot Winkler [00:06:55]:
The code you're adding to the model, like, you need to test that code. Because some people have said, oh, well, aren't you testing Rails? Like, when you when you're testing with these associations or validations, and it's like I mean, in some ways, yes, it is a layer on top of that, but also, like, you are the code you're adding is your code. That's that's code that's custom to your your application, and so you need to test that. So and so it was kind of designed to fill in this gap

Charles Max Wood [00:07:21]:
Right.

Elliot Winkler [00:07:22]:
In a way that that mimics the the syntax. So it's like, you know, if you go and add, you know, belongs to food or whatever, you know, to your, to your model or, you know, has many whatevers, then the the corresponding test looks similar so that you can kind of, it just easy it's kind of easy to translate that over.

Charles Max Wood [00:07:44]:
So Right.

Elliot Winkler [00:07:44]:
Sorry. A long description there, but, but, yeah, it's just

Charles Max Wood [00:07:48]:
But it makes sense. Yeah. Well and, like, on some of the code that I've been writing lately, I I wrote some code around the validations I didn't use shoulda matchers. Right? And so, when I when I pulled it in, it was, okay. Create a model with this or, you know, maybe I'm using another thought bot project factory bot.

Elliot Winkler [00:08:07]:
Mhmm.

Charles Max Wood [00:08:08]:
Right, and so maybe I use the factory to generate it. Right? And so then I'm testing the validations and, yeah, you you know, I have to set up the model and then, you know, assert, you know, model dot valid question mark. And I have to do that over and over again as I kind of, move through things. And so, yeah, it's it's a convenient way, you know, I came back to it and I was like, oh, this is kinda nice. I should be using it, but I'm not. And so that was pretty convenient. But the other thing is is especially on validations. So most most of the associations are pretty straightforward.

Charles Max Wood [00:08:42]:
Right? Right. You either has it or it doesn't or has many of them or it doesn't. Right? And so, you know, testing that that exists. Yeah. Maybe that's not super helpful. I don't know. You get into scopes and then, you know, then it starts to get a little bit more involved there with your associations.

Elliot Winkler [00:09:00]:
Right.

Charles Max Wood [00:09:00]:
But with the validation, some of the validations like presence or, you know, things like that. Yeah. You know? A name is either blank or it's not. But when you start getting into email formats or password length or password composition or, password confirmation or things like that, right, Then all of a sudden, the validation is a little bit more involved. And so, you know, having some of these matchers kind of give you a convenient way of saying, no. It should match this.

Elliot Winkler [00:09:34]:
Yeah. Yeah. Exactly. Yeah. I I think most of all I think, if anything, it just how it just gets you to start thinking about them. It's like, even if even if you have to kinda drop down to a lower level, even if you have to test the validation yourself, it gets you to think about, like, oh, I should be testing these. And even if you do have to drop down, I mean, yes, we have, you know, there are matchers for testing, you know, basic valid the the validations that are built into rails, but there's also

Charles Max Wood [00:10:02]:
Right.

Elliot Winkler [00:10:03]:
Yeah. You mentioned, you you know, email email formatting, let's say. You know? So let's say that you wanted to test that. You know? As long as there's an at sign or something in the email address, then this email address should pass validation. Right. There's a, there's a matcher called allow value that's in should it matches. And so that that kinda lets you, be a little more flexible, I guess, with how your with how your test Right.

Charles Max Wood [00:10:30]:
Yep. Absolutely. But, yeah, it it's kind of a convenient. Anyway, it's a convenient way to kinda get at least the fundamentals tested through so that you know what it's doing. Are there other things that the should a matchers do besides sort of the associations and validations?

Elliot Winkler [00:10:50]:
Yeah. So, let's see. Yeah. So there's there's also matchers that relate to controllers.

Charles Max Wood [00:10:58]:
Oh, right.

Elliot Winkler [00:10:58]:
Yep. So you can you can test if you're writing controller tests. I'm not you know, some people write them, some people don't, but, you know, if you if you do, then, you know, you can test thing you can you can verify, you know, things like like you you can you can test that the the response status is a certain thing.

Charles Max Wood [00:11:20]:
Mhmm. You can

Elliot Winkler [00:11:21]:
test that, like, maybe maybe you wanna double check that certain values get added to the session or whatever like that. You can test that. You can also test double check routes as well. So that is that's using so a lot of these, matchers use kinda built things that are built into rails anyway. So Right. So so the routes the routes is no exception there. But, yeah, that's just double checking that sort of routes are defined and that kind of thing. So yeah.

Charles Max Wood [00:11:54]:
Cool.

Elliot Winkler [00:11:55]:
Yeah. And all of this is outlined in the if you look at the read me, for sure in the

Charles Max Wood [00:11:58]:
read me. Yeah.

Elliot Winkler [00:11:59]:
Yeah. There's there's a section on on kinda what the list of all the matches that that are contained.

Charles Max Wood [00:12:07]:
Yep. So you we also mentioned Superdif, and I'm gonna ask you yeah. Let's go into Superdif for a minute, and then I kinda wanna talk about how these and maybe some of the other gems that you've used kind of inform your philosophy on what you test and what you don't and how you test it.

Elliot Winkler [00:12:26]:
Sure. Sure.

Charles Max Wood [00:12:27]:
So SuperDIF. So what's kind of the deal there?

Elliot Winkler [00:12:32]:
Yeah. So so this came out of, yeah, it's interesting that you mentioned testing because this kind this does relate to that for sure. So this kind of came out of, some, I guess, frustrations I had with testing, API responses, specifically. So, you know, let's say that you have some code that is that is making, yeah, making an API requests, and you just wanna double check that the response that comes back is a certain thing. So you can do that, but the response may be very large. And, you know, our spec does gives you a way like, if you use what or I guess whatever master you use, but you could use, you know, equal or whatever. It does give you a representation, I guess, a little bit of of, like, what's different between what you what you gave and and what was actually the real API response, but it's not very easy to see. I think I think they just use a a naive algorithm there to just, convert.

Elliot Winkler [00:13:38]:
If I'm not mistaken, I think they convert the the object into a string or something and just do a a simple string diff or something like that.

Charles Max Wood [00:13:46]:
Right.

Elliot Winkler [00:13:47]:
And yeah. And so I I just I just found, you know, just kind of frustrating now. So I have just had to spend some time looking through that diff to see or, you know, what's what you might do is, like, spit out the the object and and then you visually compare yourself. Just took a lot of time. So, so I actually posted a tweet, I think in 2011. I just kinda posted it on Twitter, and I was like, you know, you know, there should be a way to to do that. Oh, I wish I could actually bring up the original tweet. I didn't I didn't like to that.

Elliot Winkler [00:14:19]:
Oh, well. In the in the in the rebate. But, oh, well. But, yeah, I just kinda posted on Twitter, and then I think, David, from the from RSpec, he he he kinda posted a reply to that and or retweeted it or something like that. And so I was like, oh, that's interesting. You know, he he he noticed he noticed what I said. And so but so I kinda sat on it for a bit, and I was thinking about, like, how should I do this? And I think I made even, like, a prototype or something, and it didn't quite work well. And so so yeah.

Elliot Winkler [00:14:54]:
So I kinda didn't know what to do with it. And then I revisited it just a few years later, I think, and thought of a new design, for how for how that should work. And so yeah. So the way that it works now is it will it will compute, like, an intelligent diff of, the differences between 2 objects, 2 data structures. So they could be hashes. They could be arrays. They could be actual objects themselves, and then it gives you a diff, and it and it descends recursively into the into the data structure. So it knows like, if you're comparing 2 objects, it knows, like, okay.

Elliot Winkler [00:15:33]:
And and the keys and the keys are the same sorry. Two hashes. And the keys are the same, then, you know, it it can see that and it can tell you, okay. Well, the values are different in this way. Or if it's an array, let's say that you're comparing it, it knows, okay. You've just shifted these values around or, you know, whatever it happens to me. And there's and there's specific algorithms for for certain kinds of objects, and and then you can customize that, the diffing algorithm, you know, if you have a, you know, if you have your own object or whatever. So yeah.

Elliot Winkler [00:16:05]:
So that way, so that yeah. So that that ended up helping a lot with with with this problem that I had with the API, the with comparing the API responses because it it will it's it was able to highlight, you know, only the differences that I that I cared about in in the in in the expected versus the actual data and help me kind of narrow down what I needed to change or what was wrong with my test or whatever whatever the case may be.

Charles Max Wood [00:16:29]:
Right. Cool. So how does how does the all of this kinda come together to inform how you test stuff?

Elliot Winkler [00:16:43]:
Yeah. I mean, did you wanna just know, like, kind of how like, what's my approach to testing? Or

Charles Max Wood [00:16:48]:
Yeah. Yeah. Go ahead and start there. And then, yeah, do you actually use these in your own day to day things?

Elliot Winkler [00:16:56]:
Yeah. I mean, so I guess, yeah. I mean, when it comes to testing yeah. So, like, definitely on on every Ruby project I've worked on, like, I've I've always added this gem because, because it you know, even if it's even if even if I'm not adding working with API responses, because it just helps it just helps to know, like,

Charles Max Wood [00:17:18]:
Right.

Elliot Winkler [00:17:20]:
What it helps to kinda me help me to write tests faster, I guess, in a way because I don't I don't have to spend so much time figuring out, you know, what what the what's wrong with the test or what's wrong with the code. But, yeah, in in terms of, you know, testing in general, I mean, I I I write tests. I like tests. You know, sometimes they're a pain to write, but they are very useful. You know? It's one of those things where I don't know. Like, sometimes I'll write the test first and sometimes I won't, kinda depending on on the on the problem there. Sometimes I kind of like to do a more exploratory thing and then kinda come back and write tests later. Right.

Elliot Winkler [00:18:08]:
But but, for the most case for the most part, I I, you know, I tend to write my code and write my tests kind of at the same time. And and, also, I tend to make my pieces of code small so that writing writing the test for those pieces of code, you know, is easy as well. So I yeah. I guess I could go into more detail about, like, other other aspects, but I guess that's kind of, like, my general approach, to testing, at least at least unit testing. I mean, there's other kinds of testing as well. Of course. But but yeah.

Charles Max Wood [00:18:45]:
Cool. So you said that these days, you're kind of working more in the TypeScript front end land as opposed to the Ruby and Rails and back end land. So so yeah. So what what's kind of the story there? What's what's your history with all that?

Elliot Winkler [00:19:03]:
Yeah. I mean, I've always been interested in in JavaScript anyway and, you know, or all things front end, I should say. I never really shied away from, you know, JavaScript, CSS, all that stuff. So I I always enjoyed writing that. And, you know, with with with with JavaScript and TypeScript in general, yeah, I guess in in past jobs, I never really you know, I was, yeah, I was kind of doing mix, I guess, of of of JavaScript and and Ruby. And then, yeah, this this this job I work at now, so I work for a company called MetaMask. Okay. They're they're they're in the crypto space, but, I'm not a, you know, I'm not a crypto I'm not here to shield crypto or anything like that.

Elliot Winkler [00:19:55]:
But, Right. But,

Charles Max Wood [00:19:58]:
I think I used them at one point. I had a browser plug in for a wallet or something. I can't remember.

Elliot Winkler [00:20:04]:
Yeah. Yeah. It's a yeah. It's a it's a it's a wallet. Yeah. Exactly. That's what it is. It's a browser plug in for wallet.

Elliot Winkler [00:20:11]:
And, yeah. And so that's all written in in JavaScript. So that's been that's been interesting because it's, you know, it's it's a whole new world. Mhmm. You know, different different ecosystem there. And and, I mean, the languages are have similar enough things to where the transition from, you know, from Ruby to JavaScript isn't isn't so bad. There are some slightly different names for things, but, but for the most part, that's it's it's it's I found it pretty easy to kinda go back, you know, go go back and forth, you know, if I need to. So, yeah.

Elliot Winkler [00:20:50]:
Although, on occasion, you know, if if I work on something in Ruby on the side, I might get, you know, confused where it's like, let's say that you want to take a let's say that you want to convert something to to JSON. So in, you know, Ruby, that's JSON dot generate, but in JavaScript, that's JSON dot stringify. So sometimes I'll mix those things up

Charles Max Wood [00:21:11]:
Right.

Elliot Winkler [00:21:11]:
Myself. But yeah. So yeah. I mean I mean, these days, I I pretty much code in in TypeScript, for my job. So I don't do much Ruby, but, I mean, I still I still like writing Ruby. I still think it's a nice language. Yeah. So I and I still use some some for my side projects as well.

Elliot Winkler [00:21:32]:
So

Charles Max Wood [00:21:32]:
Gotcha. So it looks like you're still maintaining some open source in Ruby. So how how does that balance out, I guess, in your life and your career? And and what is it like, I guess, if it's not your primary language these days?

Elliot Winkler [00:21:47]:
Yeah. I mean, I guess I guess these day yeah. These days, it's just like, you know, I I work on well, I still, you know, I still want to I still wanna keep it up for sure. Right? It's like, you know, it's still a language I find useful, so I don't want to I don't want to forget how to use it. Right. Definitely not looking to, like, kind of, put it aside or anything like that. And so, yeah, I still I still, I guess, maintain side things. Mhmm.

Elliot Winkler [00:22:26]:
Yeah. I don't know. It's still something that I enjoy using, I guess.

Charles Max Wood [00:22:32]:
Right. Cool. Was there anything else you wanted to go into on on the show? Or

Elliot Winkler [00:22:44]:
Yeah. I don't know. I mean, I guess nothing I guess nothing came came to mind from, myself, but, yeah, I don't know if there's any other topics that you wanted to go into.

Charles Max Wood [00:22:58]:
Not on my list. Okay. So Yeah. Yeah. The way we kinda wrap the show up is we do picks. I don't know if you're familiar with picks, but we just shout out about stuff we like. So I'm gonna throw out a few picks, and then, you can go ahead and do the same, and then we'll just wrap it up. The the first pick that I'm gonna throw out, I always do a board game pick or in this case, a card game.

Charles Max Wood [00:23:20]:
And this is a card game that I play with my kids, specifically my youngest daughter. She's 8. And, you know, and so we she's starting to get into the more involved games. But one game that we've played with her for the last few years that we got for her for Christmas when I think she was 6 It's called Sleeping Queens 2. Now there's a Sleeping Queens and then there's Sleeping Queens 2. Right? So in Sleeping Queens, you're trying to get kings, and the kings go and, you know, wake up the queens and rescue them. In sleeping queens too, it's the other way around. You're getting queens that are now rescuing the kings.

Charles Max Wood [00:23:56]:
And, you know, the the different decks have different cards that allow you to steal cards from other players or put queens back to sleep or put kings back to sleep, and things like that. So sleeping queens is a little simpler than sleeping queens too, but not terribly. You know, they're both pretty approachable for kids. I think they say they're 8 8 years plus, but we were playing it with her at, you know, 6 or whatever. She'd get this cackle every time that she'd steal a a king or whatever. But, anyway, board game geek has it rated as a 1.5. Now as I generally point out, a lot of your kind of complicated enough to be interesting, but approachable for, the general not deep gamer is about a 2 on on the board game geek weight. And so, if I had to recommend it to people, it's a little simple to play with your adult friends.

Charles Max Wood [00:24:58]:
It's about right to play with your kids. So, anyway, it's it's fun game. It's like a 20 minute game. Right? And so if you have an hour to kill, you can play 2 or 3 of them. Right? Or maybe even 4 of them. And so I'm gonna, throw that one out there. A couple of other things that I'm just gonna push, as far as picks go. So, lately, I've been on my phone.

Charles Max Wood [00:25:23]:
I picked up a new app. It's my new thing that I'm into right now. I've been wanting to learn Japanese forever. And so I picked up Duolingo on my phone, and and I'm sure everybody's going, oh, Duolingo. Right? I've I've used that. It it feels like everybody knew about it before I did. But I didn't know that there it was free. Right? You can pay to have Duolingo, Super Duolingo, or whatever they call it.

Charles Max Wood [00:25:49]:
But, anyway, I've just been using it for free, and it's been awesome. And so, initially, I picked it up and I started learning Japanese. Right? And I'm I'm still going through the ordering food the first lesson. Right? When I was a kid, they taught us in elementary school to count to 10 in Japanese. Right? So there you go, folks. I can say about 8 food words and then, like, and and please and anyway. But yeah. So I'm I'm gonna pick it up slowly, but I'm gonna pick it up.

Charles Max Wood [00:26:18]:
And I'm really enjoying it. But then I realized that, one of the places that I've always wanted to travel is to France. My grandmother was French. She immigrated to the US. She actually met my grandpa in Montreal. He's he grew up in Alberta, Canada. But yeah. So I've always wanted to go see some of these places.

Charles Max Wood [00:26:38]:
Right? I don't know that I necessarily go see anything that has a direct tie to my grandmother or my great grandmother, in France, but just kinda to have that connection. Right? And so I was like, okay. Well, I took French in high school, so I'll pick it up on Duolingo. So I added French. And so, you know, every day I do a Japanese and a French. And then I was chatting with this guy online who I I don't even remember how we got connected, but, he's he's a member of the church of Jesus Christ of Latter day Saints as am I. And we were talking about church missions. And I served my church mission in not Japan, not France, in Italy.

Charles Max Wood [00:27:22]:
And so I speak Italian fluently, especially if you wanna talk about church. But, my vocabulary is kind of thin in some other important areas. Right? I could go to the grocery store and buy food and not think about what I was trying to say. Right? And I could go out and I could talk to people about kinda lifestyle stuff in general. Right? And then I had the vocabulary for that. But, I mean, there were some words that I just never learned. Right? And so, I was I was chatting with this guy and and I was like, I wonder if I could put this into Duolingo and and make that work. And so I put it in and I basically said, yeah, because let's just say how how good are you at it.

Charles Max Wood [00:28:06]:
Right? So I dragged it all the way to, I speak this fluently. Right? And I'll have to admit that the lessons are still pretty rudimentary, but my vocabulary has been expanding, which has been fun. And so, I learned words for, like, exercise, which was something that I had never, right, I'd never had to say on my mission. And so, anyway, that's been a ton of fun. So I've really, really been liking Duolingo. And like I said, you can get it on I I have it on my iPhone, and you can use it for free. And it looks like you can use it for free forever. Now I keep getting ads in the app saying and and that's part of the deal.

Charles Max Wood [00:28:43]:
So I'll get the ads in the app for, like, hey. Play this pirate game or whatever. Right? After I finish a lesson. And then and as soon as the I click out of that. Right? It's like, nope. Nope. Nope. Nope.

Charles Max Wood [00:28:53]:
Then it plays the, hey. Get super duolingo and make the ads go away, and I you know? Nope. Nope. Nope. Nope. But, so far, it's been awesome. So, I've been enjoying that. I try not to do the lessons back to back to back because I don't want to cross the streams with any of the languages, if that makes sense.

Charles Max Wood [00:29:10]:
And French and Italian are close enough. Like, the a lot of the words are different, but the structure is very similar. What I'm finding in Japanese is they they structure their language different very differently, and so that's less of a thing. But, anyway, so I'm gonna pick Duolingo. And since I talked about it for so long, I'm just gonna plug go check out Ruby Geniuses at rubygeniuses.com. If you want to be on a regular basis talking to people about Ruby and Rails and that kind of a stuff. You know, Elliot mentioned that he's doing, JavaScript and TypeScript. I'm also starting up JavaScript geniuses here pretty quick.

Charles Max Wood [00:29:52]:
So, anyway, what are your picks?

Elliot Winkler [00:29:56]:
That's awesome. That's cool. Yeah. I guess I don't have many picks, but I just so I recently went to a concert. So it was by this artist named Jacob Collier. And he's just an artist I've been following for a while. If you you may know him already if you're, like, in the music scene, but if you're not, kind of a a kind of interesting I don't know. He's a pretty I don't know.

Elliot Winkler [00:30:24]:
He's just a genius when it comes to when it comes to music and, you know, he has you can look up his, like, early YouTube videos, and then it's interesting how he can just combine his, like, different melodic ideas and, different, just lay kinda layers vocals on top of each other and things like that. That was kind of his signature, I guess, earlier on, and now he's kind of expanded into into different musical genres and things like that. He's collaborated, like, all kinds of artists across different different things. And so and he's and he puts on a pretty great show as well. So, you know, if he comes to your city, definitely definitely check him out. And you're and you're and you're into music, of course, check them out. Yeah. So I don't know.

Elliot Winkler [00:31:10]:
That's that's that's my pick, I guess, based on Good stuff. Yeah.

Charles Max Wood [00:31:14]:
Alright. Well, I'm gonna go ahead and wrap it up here. I know this is a little shorter episode than people used to, but that's totally fine. Thanks for coming, Elliot.

Elliot Winkler [00:31:21]:
Yeah. Thanks for having me.

Charles Max Wood [00:31:22]:
Alright, folks. We're gonna wrap it up. Till next time. Max out.
Album Art
Mastering API Testing: Using Shoulda Matchers and Super Diff in Ruby - RUBY 640
0:00
31:30
Playback Speed: