Appropriate, Correct, Robust, Usable, Maintainable, and Efficient (ACRUMEN) with Dave Aronson
Should you find a burning need to share your thoughts or rants about the show, please spray them at [email protected]. While you're going to all the trouble of shipping us some bytes, please consider taking a moment to let us know what you'd like to hear on the show in the future. Despite the all-caps flaming you will receive in response, please know that we are sincerely interested in your feedback; we aim to appease. Follow us on the Twitters: @PolyglotShow.
Jonan Scheffler: Hello and welcome to Polyglot, proudly brought to you by New Relic's developer relations team, The Relicans. Polyglot is about software design. It's about looking beyond languages to the patterns and methods that we as developers use to do our best work. You can join us every week to hear from developers who have stories to share about what has worked for them and may have some opinions about how best to write quality software. We may not always agree, but we are certainly going to have fun, and we will always do our best to level up together. You can find the show notes for this episode and all of The Relicans podcasts on developer.newrelic.com/podcasts. Thank you so much for joining us. Enjoy the show.
Kirk Haines: Welcome to Polyglot. My name is Kirk Haines. You can find me @wyhaines on Twitter and pretty much anywhere else on the internet. And today I'd like to welcome my guest, Dave Aronson to our show. Dave, would you like to introduce yourself?
Dave Aronson: Hi, just one quick little correction. It's Dave Aronson, not Dave Arneson.
Dave: I'm not the co-inventor of Dungeons & Dragons though I did get a number of people making that mistake for the past several decades. Anyway, I'm Dave Aronson, the T. Rex of Codosaurus, LLC, my little one-man consultancy (which is how I can get such a cool title) in Fairfax, Virginia, a suburb of Washington, D.C.
Kirk: Well, nice to have you here, Dave. It's kind of funny because when I saw your name, I didn't actually equate it with the Dave of Dungeons & Dragons fame. But now that you mention it, I can visually see it. It's one A versus two, isn't it?
Dave: No. It's A-R-O-N versus A-R-N-Eson, Arneson, like Mr. Palmer versus Aaron, the brother of Moses.
Kirk: [laughs] Oh, that's hilarious. So why don't we just start out by having you tell the audience a little bit about yourself? You said Codosaurus, LLC T.Rex. But what do you really do? What's your background? So fill in some of those gaps for people.
Dave: Okay. Well, right now, I'm kind of, sort of retired, having just wrapped up a fairly long-term...well, I consider it very long-term, about five and a half years contract with my latest hands-on client. I'm now trying to shift more towards short engagements of basically just giving advice about processes and tools and things like that. Maybe some mentoring and whatnot and maybe some short part-time hands-on work, kind of tired of that. But I'm curious about Elixir. The camera is a little...But I'm wearing the shirt from ElixirConf 2018. I've been slowly learning it over the past several years. So I think I might make an exception for that.
But otherwise, I'm now putting much more emphasis on the life side of the work-life balance. And one of the interesting things I'm doing with that time that is still tech-related is I've been doing the speaker circuit. And one of the topics I talk on is my new definition of software quality. So when I heard Jonan speaking about your guests having opinions on how to produce quality software, okay, how are you defining that? That's the big elephant in the room. We all talk about how we make such high-quality software, but hardly anybody says what they mean by that.
And so what I've come up with is something I call ACRUMEN, A-C-R-U-M-E-N. And the acronym ACRUMEN (Try saying that ten times fast.) stands for the idea that software should be Appropriate, Correct, Robust, Usable, Maintainable, and Efficient. Now, you're probably wondering what the N stands for Nothing. I just tucked that on to make a real word.
Dave: So you're probably wondering what does ACRUMEN mean? It's not an English word. It's Latin for sour fruit. And if you look at the word for citrus in some languages, like Italian and so forth, you'll see something very close like agrumi or whatever that's derived from acrumen.
Dave: So that was the topic of my very first real conference talk as opposed to little local user groups and such. I have since branched out into other things, mainly mutation testing, which has proven much more popular. And that was actually how I met your boss, Jonan. I was at RubyConf 2019 to present about that. And he saw it, and we talked about it a bit after the conference.
Kirk: Interesting. I mean, there are several things there that you said that piqued my interest. The silliest one is, well, your comment about citrus, and the Latin, and agrumi. I speak a little bit of Dutch. And actually, in Belgium, there's this drink called agrum, which is grapefruit-flavored soda. And now it suddenly makes a lot more sense, the connection there. Very interesting.
Dave: And you even see it in languages like Croatian. There's an island I think it's off Croatia called Lokrum, which is named after the citrus trees that grow there.
Kirk: That's really interesting. So let's step back and rewind a little bit because I'm curious. So you were speaking at RubyConf in 2019. Have you had a long history with Ruby or were you there specifically for that talk? What's the context there?
Dave: Ruby has been the main language that I've used most of the time since 2009. That's when I first learned it actually as interview homework, and it was so easy to pick up. After your first few dozen or so, most of them are easy to pick up, but Ruby especially so. And I really liked how expressive it is, how it makes it very easy to understand what's going on so long as the author stays away from a lot of the deep, dark magic like excessive meta programming that would make things, as Betsy Haibel says, ungreppable.
Kirk: [laughs] You learned it as interview homework. Was there some language or some ecosystem that you lived in as your primary place of work before Ruby then?
Kirk: That's really cool.
Dave: So I've been trying to dig my way out of what I was calling the plain old C rut. So that was the job that finally got me out of there, and I didn't much like it. I won't name what company it was, but let's say I didn't like the job. And it got me to actually get out of that plain old C rut and make good use of, like I was mentioning, Perl and Python, which I had already done some of at a previous job and, of course, Ruby, which I was very happy to do.
And at one point, the boss wanted a project risk management tool, which I thought was a good fit for Ruby on Rails, which I had heard of. And at the time, I knew already it was basically the killer app of Ruby. So hey, great opportunity for what I call resume-driven development.
Kirk: [laughs] That's great.
Dave: So I whipped them up a little tool in Rails whereby you could adjust the risk of various types of risk and the particular risk that a given project faces and the intersection, and it would do various kinds of math, distributing, and all that.
Kirk: Interesting. I think that's, I guess, an unusual entrance into Ruby compared to most Ruby developers. Most folks who come to Ruby come to Ruby; I mean, some of them come to it as their first language. But people who don't come to it as their first language were usually using some other interpreted language before. And I haven't talked to a lot of people who came to Ruby from a background that was largely a compiled language, and so I think that's an interesting transition.
I myself came to it...I was actually a Perl programmer. It was my bread and butter before I came to Ruby, but I did do some C and some Java as well but still primarily a Perl programmer. So primarily in that interpreted language to interpreted language transition.
Dave: I did find some things rather jarringly different. I was so used to having compiler warnings or… well, of course, outright compiler errors alert me to when something was wrong. But it turns out that one of the ways the Ruby community likes to get around that lack of things telling you something's wrong is thorough testing, especially unit testing. And by that time, I had started to really get into test-driven development. That was really taking off, and I was finding it quite useful to improve the quality of my code, even in plain old C.
Kirk: So this leads me to a question. As you said, the main perspectives of Ruby with regard to that lack of static type checking is you have your tests catch these errors. And one of the things that I found actually converting Ruby code that I've written to Crystal, which is a statically-typed checked compiled language, is that there are cases where I've had Ruby code that has literally been running in production for more than a decade. When I converted it to Crystal, I discovered that I had some fundamental errors in a few places with regard to certain type checking things that didn't come up in any of the specs that I wrote and maybe came up in runtime errors.
But it was one of those things where the sort of belt and suspenders around the whole system if something goes down, we'll recover it. And that sort of thing automatically kept these errors from ever being found in production. And so what I'm wondering is your experience coming in the other direction from C to Ruby. Have you ever yourself experienced this as a weakness of the whole unit testing in order to find these errors paradigm?
Dave: Well, unit testing to find errors does have some inherent problems. I mentioned I speak on mutation testing. And one of the points I make is that...oh wait, no. Actually, come to think of it, that's from my ACRUMEN talk, that regular ordinary tests will always find the kinds of bugs we think to test for. So that is a huge hole and one that things like mutation testing, and property-based testing, and a strong type system will help ferret out.
I was listening to something recently about Haskell, which I don't personally know Haskell, but I know a bit about it. Apparently, it has an extremely strong type system where you have to construct types like this thing could be nil, or whatever they call it, or it could be an integer from 5 to 73 or whatever. And if you can get your types all arranged correctly, then it's apparently trivial to fill in the rest of the logic to make a program actually work.
Kirk: Yeah. [chuckles]
Dave: So that will provide a lot of the bug proofing because an entire class of bugs just disappears. You can't have a type mismatch because the compiler won't let you do that or interpreter or whatever Haskell uses, I don't know. And there are a bunch of other languages that do that.
But as for converting from something to something else and finding bugs that way, I haven't really done much porting of major programs from one language to another, but it does remind me of what's happened fairly frequently when I inherit code in plain old C and then crank up the warnings. Usually, I find the causes of some bugs that people have known about, things that, as happened to you, would be bugs if they ever actually managed to get triggered and lots of other things that were just plain sketchy, sometimes outright wrong, sometimes just rather run clean. So cranking up warnings is another thing that I find very useful.
Kirk: So in Ruby, have you ever used RPS?
Dave: No, not RPS, not Sorbet. One of these days, I might get around to playing with those. But as a more or less retired person, I’m trying to see what's the best bang for the buck if I want to keep doing hands-on stuff. Maybe I'll check into those, but I'm focusing more on Elixir. I kind of caught the Ruby wave as it crested, rode that to good profitability from about 2009 to fairly recently. If I can do the same thing with Elixir, especially if I can do that on an occasional part-time basis now that I'm retired, I think that would be a win. But I might still keep my hands in on other things.
Kirk: Let's talk about Elixir a little bit because Elixir is one of those languages that...I've never written any Elixir. I know about it. But I've never written any Elixir. So what attracts you to it? Talk to me about Elixir.
Dave: Well, I first heard of it through the Ruby community because, as you may recall, it was invented by José Valim, a big name in the Ruby community with all the gems out like Devise and so forth. And it was touted as basically combining the power of functional programming with the concurrency of Erlang with the syntax of Ruby. Now, I think that last bit is a little oversold. It's got syntax that's clearly inspired by Ruby. But the language is so different that to say it's Ruby syntax, that's a bit much. But it is certainly much easier and clearer to understand than Erlang or the other functional languages I've seen.
I took a look at some Haskell; like I said, I never actually learned it, but I have seen some. And I briefly dipped my toes in Scala awhile back, and it seemed like a good thing. And then came the Phoenix web framework drawing heavily on the general concepts of Rails but with the slightly different philosophy of making things more explicit rather than the infamous Rails magic, which is so helpful when you're doing things the Rails way. But if you try to fight it at all, no, no, no, that magic is a plus-five sword against you. [laughter]
Kirk: Yeah. Rails is one of those things where you don't fight the magic. If you're going to fight the magic, you may as well just use something else.
Dave: Yeah. I've also done a little bit of Sinatra. In fact, my last major client was doing some stuff with Sinatra and starting to get into some other interesting stuff about separating bits of this monolith out into more composable pieces. But I had to leave eventually in order to retire.
I also liked the concept of the...I'm blanking on what it stands for now, the OTP. Oh, that's right; it stands for Open Telecom Platform, which doesn't really make it obvious what it is, their whole setup with the supervision trees of processes, watching processes, and spawning processes. And when a supervised process fails, the supervisor gets notified, and it's got various policies. You can just replace that one or bring everything down and start it all back up.
You reminded me of it a bit earlier. The idea of let it crash is a common thing in the Erlang and Elixir community with a philosophy of don't waste your time on lots and lots of defensive coding. Just let it crash; bring up another one. And that fits very well with some of the ideas commonly found in functional programming of not mutating the existing thing but rather making a fresh copy with the changes in it.
And come to think of it, that reminds me of another small presentation. I do a lightning talk on Why We Prepend to lists when we're using a functional language or actually any other language but basically when we're using immutable data, which is a pretty good overlap with when we're doing functional programming. It basically boils down to how if you append, then you have to change the next pointer from the former last element to point to the new one. But you can't do that because it's immutable data. So you have to replace that. And basically, that cascades back all the way to the start of the list so that appending is basically order n instead of constant time.
Kirk: Whereas when you prepend, you set the pointer in the new object to point to the old one.
Kirk: Yep, that makes sense.
Dave: Or as I say in the presentation, you create the new one pointing at the old first one, and then we don't have to do anything. We're done. No muss, no fuss, no further allocation, no something else, no garbage creation for later collection.
Kirk: [laughs] Oh, that's good. So have you had the opportunity with Elixir to get into any real, meaty projects or anything bigger than just teaching yourself, learning yourself type-projects with it?
Dave: Only a little bit. For Hacktoberfest, a couple of years ago, I did some minor contributions to...the name was Open Pantry. It's to coordinate basically food banks. And in addition to some trivial typo fixes and such (Those make great Hacktoberfest stuffers.), there were some tests that needed fixing, some stuff that needed tests, and a few other things like that. So I had to delve in there to understand what was going on, how to test it, and the appropriate testing tools, and so forth. But other than that, I have not landed significant work in Elixir yet. Like I said, I've been learning it very slowly. I'll probably port some of my old toy Rails apps over to Phoenix one of these years.
Kirk: Yeah, that's kind of what I was getting at. I was just wondering if you had had a chance to actually do any side-to-side comparison between the two, just curious about your take on it. When I first learned Ruby, like said, I'd been a Perl programmer for years. And that was actually what I did when I approached the two is I said, oh, this looks like a really interesting language. So let me take my Perl code that I've written for several different things, and let's rewrite it in Ruby. And then let's just objectively look at the two.
And it's always an interesting exercise when you do that because the compare contrast, I don't know, there's just something interesting and insightful about it no matter what two things you're comparing, just to see how they each approach the same problem set. And so, I was just wondering if you've had a chance to do that at all with Rails and with Phoenix and Elixir.
Dave: Not to that level of scale. But I have been working my way through the Elixir track of Exercism. In fact, I had finished the V2 track entirely. Now that they've launched V3, I'm doing the rest of it. And a lot of that I had also done in Ruby. And of course, some of it is fairly standard problems. Like, they've got one called Raindrops, I think it is. It's basically a step above Fizz buzz. And, of course, there are so many, many ways to solve Fizz buzz. But then there's okay, which of these approaches might be appropriate in a functional language as opposed to an object-oriented or imperative language? Even doing it in Ruby, there's not much need for packaging something up into an object, so it may as well be imperative.
Kirk: Okay, that's interesting. So I want to circle back to something that you brought up right at the beginning, which was talking about quality software and how you assess quality in software. And I think it ties in a little bit to some of the things we've talked about, just with the general programming things, and unit testing and the class of errors that compiled stuff catches that interpreted doesn't necessarily. But how do you define quality software? If you're going to define it, give me a definition of quality software. What's your definition?
Dave: Okay. Well, like I said, to be appropriate, correct, robust, usable, maintainable, and efficient. But of course, what does all that mean?
Kirk: Yeah, exactly. Yeah.
Dave: [laughs] I'd actually intended to delve a little further into those terms in the beginning. But as tends to happen with conversations between two intelligent people, we meandered off into other topics.
Dave: So what I mean by appropriate is that it's doing what the stakeholders need it to do. And by stakeholders, you have to remember that that's not just the people sitting in front of a keyboard and screen and looking at it and typing or clicking or tapping for mobile. I prefer the definition used by the Project Management Institute. Yeah, I had a tiny little bit of PM training. And that is basically everybody involved in or affected by or in any way using the thing.
So one example I like to use is a Facebook game like FarmVille or whatever. Stakeholders would include the people who asked for this software to exist in the first place, probably some executive at whatever company it is that makes FarmVille, the developers, people at Facebook who actually deploy and run the things, the people actually playing the game, of course. And if it's like a typical Facebook app, it's probably slurping up all kinds of data about you, so whoever is dealing with that data, whether it's the actual analysis or just maintaining the data repository or whatever. Those are all stakeholders. And there's probably a whole bunch of categories totally glossing over.
The software should ideally do what all of those people need it to do, which is not quite the same as what they say they want it to do, just like two steps removed, at least. I'm sure you've seen the classical cartoon with the tire swing. The customer actually wanted the stages with the multi-level seat swing and the big roller coaster and everything, how marketing sold it, how the engineers implemented it, all kinds of different things.
The ACRUMEN is in the priority order. In the general default case, all the other stuff can move around, but appropriate is always going to be the top one. And to justify saying that, I like to use a little thought experiment. It's that you come to me asking me to write you a checkers playing program. And I go away and hack up for you the world's greatest chess-playing program. It's as correct, robust, usable, maintainable, and efficient as anybody could ever want. It will beat all the grandmasters. It will beat the programs that you already have that beat all the grandmasters. But it's not checkers. So unless you happen to have some other use for a chess program, you're not going to be terribly happy with this. It's not what you asked for. It's not what you wanted. It's not what you presumably need. In ACRUMEN terms, it's not appropriate.
So moving on, the next is Correctness. And I usually contrast these two by saying appropriate is that it's doing the right job; correct is doing the job right. And that's fairly self-explanatory, shouldn't have bugs. Of course, sometimes it can be tricky to define exactly whether some deviation from somebody's expectations is a bug. So you have to determine, okay, what was it really supposed to do here? Is that even defined? But for all the things that are nailed down, it should import with it.
Then Robust is back to being kind of fuzzy. By that, I mean it should be hard to make it malfunction or even seem to. And a lot of that is about security, which I usually explain via the CIA triad. Now, it's nothing to do with spies and gangsters. It's the three core concepts of information security: confidentiality, integrity, and availability. So, for instance, it should not reveal information when it's not supposed to, alter information when it's not supposed to, or become unavailable when it's not supposed to, in other words, crash without some automagic mechanism to bring it back up like we were talking about before.
But I also kind of shoehorn in there the concept of seeming to be fragile unless you're doing that deliberately like a security honeypot or something. And by that, I mean things like it should not give you an ugly stack trace or a vague error message like ENOENT or Error 500. It should say something like, "File not found," or, "Oops, something went wrong on our end. Please try again."
Dave: You might think that would actually go under usability, and you're right; there is a lot of overlap between these different aspects. A lot of things will violate or affirm multiple of them. But I felt that seeming to be fragile was important enough to also put under robustness.
Kirk: That makes sense.
Dave: Even if behind the scenes, the thing is coming back up after telling you 500 Server Error. That just looks so unrobust that it at least impairs the perception of quality in the user's mind.
Kirk: Yeah, that makes sense.
Dave: Next up, we have usability. And when people talk about usability, they're often talking about accessibility, making sure that people with various challenges like poor or no vision or hearing or fine motor control or whatever can use the system about as well as anyone else. That's a great goal. But I add on that it should be easy for everyone to use, not just equally difficult. And that's fairly explanatory for most of it.
But something that some people forget is that it's not just a matter of the user looking at the screen typing on the keyboard. But other kinds of software need to be usable as well, like APIs, and embedded software, and libraries, and frameworks, and so forth. Those get short shrift quite a lot.
And tying back to the mention of TDD earlier, I find that's a useful tool to help design an API that I'm currently implementing. If I TDD it and ask myself, okay, now what would make sense for a nice, easy way to call this? And then okay, can I implement that? As opposed to hmm, how should I make this actually work to implement the functionality? And then it's not easily testable and not very usable and so on.
Kirk: That's one of the things that I find when I'm writing software is often really useful is that I write the tests simply assuming that here's the way I want it to look, here's the way I want it to work. Write the code, write the tests for the code, and then come back around and make it actually work that way, rather than approaching it from the other side because you end up with patterns that are sometimes difficult to test if you don't think about testing until after you've written the code.
Dave: Yeah. As far as how things look, what I usually do is start with what some people would call a behavior-driven development test. And in my opinion, that's basically just high-level TDD. So I start with that, try and make it pass usually in such a way that it proves that whatever came out of some method call or function call or whatever, is what's shown on the screen. And then I can just test that function call and make it sort of a stack of tests. And I add some when I need to implement some smaller piece to make the current thing work and pop them off the stack when the tests pass. And then it grows and shrinks, and when the stack gets empty, everything is done.
Kirk: Yep, that makes sense. Sorry to divert you from your points. I just sort of resonated with that.
Dave: Oh, no problem. That's kind of what a good rambling conversation is like.
Dave: If we stuck to one topic, it would be so boring. And I could even divert us perhaps onto the intricacies of making mead. That's my pandemic hobby. [laughter]
Kirk: I'm afraid we'd be here way longer than we're supposed to if we went too far afield. [laughs]
Dave: All right, so moving on. We were at usability. The next step would be maintainability. For better or worse, the vast majority of software engineering advice is aimed squarely at this. So I won't ramble on too much about that. It's all the usual advice, KISS & YAGNI, and blah, blah, blah, high cohesion, low coupling, good naming. Oh, that's so easy.
And then, of course, efficiency. No doubt that's dead last despite how we developers tend to worship that, especially we older developers who grew up in the days when machine performance was measured in kilohertz. And it was a big deal when we finally got into megahertz, never mind the multiple gigahertz we have now. So that's clearly including the efficiency of using the CPU. But there are a lot of other things.
The other one that usually springs to everybody's mind is, of course, RAM. And again, [mimicking an old man's voice] back in my day...
Dave: We had machines with single-digit K, then a whole whopping 640K, and then megabytes. And now, if you don't have a bunch of gigabytes, that's a very small machine. I think we'll be seeing terabyte machines commonly very soon. Of course, they're already there for servers and whatnot, but I mean for consumer-grade.
But beyond that, there are a lot of other resources we need to be aware of. One that has become particularly irksome to me lately is screen space. There are a lot of web apps and occasionally even mobile apps that demand to use up the full width of your screen or at least much more of it than is actually necessary. There are so many that have textboxes or whatever that could be 500 pixels wide, but the designers make it not work right unless the window is at least 1200 pixels wide. That really bugs me.
Then, of course, there are various non-technical resources like the user's patience and brainpower for figuring things out. Some people would call it their spoons, the metaphor for mental and emotional energy and endurance. And the company's money, they’re paying you to actually implement this stuff. Now, of course, we all want a nice, fat paycheck. But we should have some consideration for the company's money. And I think there were a few more that I had in mind, but I'm blanking on them. So that's the explanation of ACRUMEN.
Then there's the question of how to assess it. And I don't really have a good handle on a universally applicable set of tests you can apply to this nor a good way to quantify it. So what I usually advocate...especially since number one, I don't want to put in work to come up with these universal things. And secondly, I want to keep it universal. What I generally advocate is just go on gut feel and use whatever ranking system makes sense to you, whether it's a triage into good, bad, and medium or does it meet our needs or not, or a scale of 1 to 10, 1 to 5, whatever you want to use.
Some people want to then boil it down to one number that completely represents the overall quality. And I think that would just lose too much information. One number could tell you whether the software is high or low quality, but keeping six different numbers will tell you how and help you set targets and prioritize work on making the aspects that aren't so good better.
Kirk: Well, and also, if you have one number, it misses the boat on what you said at the beginning that appropriateness trumps everything else.
Kirk: If you score highly in five of the six, but you're not appropriate, you might...if you're distilling everything down to one number, you might have a deceptively high number, but it's a deceptively high number for a chess program when you wanted checkers.
Dave: Yes. In one version of my presentation, one that I don't think I actually did anywhere but had it in the slide, I proposed using a weighted average and making sure that the weight of appropriateness is greater than the sum of all the other weights. That would take care of that. But then I decided no, no, no.
Dave: Squishing it down to one number is such a big mistake in the first place. I don't want to give advice on how.
Kirk: Yeah, that makes sense to me. So we're, believe it or not, already over 46 minutes into this thing. And I'm sure we could keep talking for a long time, but we should probably wrap it up. And so I would just like to turn it back to you and see if there are any last thoughts, any last things you want to share with people that you've been thinking about or working on, or where people can find you on the internet, whatever you want to share with people.
Dave: Okay. Well, the big thing I want to share with people these days is that whole ACRUMEN thing. That's my contribution to the state of the art of software development. And where you can find me online, I'm Dave Aronson, D-A-V-E A-R-O-N-S-O-N on Twitter and LinkedIn. Somebody beat me to that and to that backwards on Facebook. So I'm Dare2XL over there, D-A-R-E-2-X-L. But I generally don't do much of the actual technical stuff there. I save that for LinkedIn and Twitter. And apart from that, everybody, go drink some mead.
Kirk: Mead is great.
Dave: Yeah, it's been starting to make somewhat of a comeback in the U.S. And like I said, it's my pandemic hobby. And I've been finding out how many people, including former me, have a lot of misimpressions about it. It's not always sweet, for one thing.
Kirk: Oh no. Some meads can be nice and dry, yeah. Well, this has been fantastic. Thank you so much.
Dave: You're quite welcome. Thanks for having me on here. I'm honored to be here.
Kirk: Thank you. And to everybody out there, thanks for listening to Polyglot. You can find us on Twitter @PolyglotShow. This has been Kirk Haines for The Relicans. You can find The Relicans at therelicans.com. And we'll catch you again next week with another show.
Jonan: Thank you so much for joining us. We really appreciate it. You can find the show notes for this episode along with all of the rest of The Relicans podcasts on therelicans.com. In fact, most anything The Relicans get up to online will be on that site. We'll see you next week. Take care.