Tales from the jar side: Audiobook available, GORM event listeners, testcontainers, and COVID hits home
Dad joke of the week: What happens to an illegally parked frog? It gets toad.
Welcome, jarheads, to Tales from the jar side, the Kousen IT newsletter, for the week of November 14 - 21, 2021. This week I taught week 2 of my Spring in 3 Weeks course on the O’Reilly Learning Platform and the Introduction to the Gradle Build Tool online course for Gradle, Inc.
If you wish to become a jarhead by subscribing to this (free!) newsletter, use this button:
New Header for Tales from the jar side
Like most developers, I learn how to do things by watching how others do them. One of the newsletters I subscribe to on Substack is called Cup of Coffee by Craig Calcaterra. He’s a former lawyer turned baseball writer who lives in the Columbus, Ohio area. His newsletter is mostly about baseball, but he also talks about what’s going on the world in an entertaining way. I find it entertaining, though I must admit that if you disagree with his politics, you might not be as much of a fan as I am.
I noticed that Craig recently added a header to his newsletter, which talked about his latest book and included a nice graphical banner. That sounded like a really good idea, so I did the same.
If you’re reading this in email, you can see the new header and the new banner. If you’re reading this some other way (I post a link every week on Twitter, Facebook, and LinkedIn), you probably don’t. For the people who aren’t seeing the new banner, here it is:
I made it as a Google Drawing, since that’s part of my Google Docs subscription and was easy enough to use.
The newsletter header also includes a line about my book HELP YOUR BOSS HELP YOU, along with the coupon code kkmanage35, which gets you a 35% discount. You can do better than that, however, during the Pragmatic Programmers Pre-Black Friday sale going on right now. Use the code turkeysale2021 to get 40% off everything at Pragmatic Programmers, including my book.
(BTW, my book currently sells for $18.95. Round that up to $20, and 10% is therefore $2, so 5% is $1, 40% is $8, and 35% is $7. In other words, if you use the coupon code turkeysale2021 instead of kkmanage35, you save a whole extra dollar. Woo!)
Finally, the new newsletter header contains a link to the new audiobook edition.
Wait, what? Audiobook? What audiobook?
Audiobook Finally Available
Yes, it’s finally here, just in time for your holiday shopping, and at least for this you don’t have to worry about late shipping. The audiobook version of HELP YOUR BOSS HELP YOU is now available on both Amazon and Audible.
The Audible people suggest I share this link with you, which involves some kind of bounty bonus for new subscribers to Audible. Yeah, okay. Honestly, use whatever link you like, assuming you’re interested. I did the narration, which meant I had to fix things when they went wrong. I used Audacity to do the recordings, with the ACX Check plugin to verify that all the files satisfied all the submission requirements (RMS volume range must be between -23dB and -18dB, peak values can be no higher than -3dB, and noise floor must be no higher than -60dB RMS).
In order to include an excerpt here, I added the one-minute “retail sample” to my SoundCloud account:
The sample was taken from the beginning of Chapter 3: Creating Constructive Loyalty. I must admit I let SoundCloud charge me $5 to master the track, so it may sound better than the actual book.
According to the ACX dashboard, I haven’t sold any audiobooks yet, but I know that’s not true. My friend, occasional Groovy Podcast co-host, and frequent gadfly on Twitter sent this:
I’m sure he knew better, but I replied (nicely) with a link and he sent this:
So I felt obligated to reply:
Truth is, he was going to give me a hard time about late podcasts anyway, and I was probably going to leave him alone (for a while at least) when he fell behind, but I figured I might as well formally acknowledge those facts.
Two final notes:
It took nearly two weeks for ACX to approve my submission. I have no idea what they were doing during that process, but at least my book got through eventually.
As you can see, Substack lets you embed images, audio files, and YouTube videos into a newsletter. As a new feature, Substack now lets you embed NFTs registered on OpenSea as well. Shudder. Let me be clear about this: I will never, ever, ever do that to you. NOT EVER. See Why NFTs are bad: the long version, among many other articles, for all the reasons that NFTs are trash and an elaborate scam.
Grails GORM Listeners
Speaking of Sergio, you may recall that in the last Groovy Podcast, I talked to both him and Puneet Behl, the head of the Grails project. After we were finished, I admitted them that in the teaching app I’ve been using for years, I had a feeling I’m doing it wrong.
I’ve always relied on the layered architecture that’s been used by Java (and Java-related) apps forever (at least since Struts 1 came out, about 20 years ago). I have a domain class called Castle, which is a named location on a map. I use a service called GeocoderService to take a castle and use Google’s geocoder to fill in its latitude and longitude based on its city and state. The issue is, I want to fill in its geographical coordinates before I save the castle into a database, and to update those values if the city or state changes.
The way I’ve always done it is to inject a GeocoderService into the CastleController, and call the service.fillInLatLng(Castle) method right before saving the castle. I do that in the controller and in the BootStrap file, which allows me to start with some pre-saved castles. That’s always worked for me, but still felt awkward.
The GORM (Grails Object Oriented Mapping) layer in Grails has what they call event listeners, which are documented here. I asked Sergio and Puneet whether I should be using those instead. The idea is that whenever a castle is about to saved or updated, you a listener class would be triggered by a PreInsertEvent or a PreUpdateEvent and I could use those to update the castle. The problem was, I couldn’t get it to work.
I sent an email to Sergio about it, and he gave me a pull request on my holygrails500 GitHub repository (in the listeners branch) to make it work. I had to make a couple of modifications, but it seems to be doing the job now. The only problem is that this approach really isn’t any simpler than my original one. I don’t know if I’ll be able to incorporate it into future classes or not. We’ll see.
Testcontainers FTW
On Friday I sat in on a class on the O’Reilly Learning Platform. I don’t attend one very often, and it’s a good idea to see things from the other side. The class was called Integration Testing with Docker and Testcontainers, taught by Benjamin Muschko, who I’ve known for several years.
I’ve been hearing a lot about the Testcontainers project, which is a way to add, for example, a database to your tests without having to install and configure one yourself. The documentation is rather thin, as is true about many open source projects, so I was very interested to see what Ben did with it.
He did a great job:
His examples are all in his GitHub repository, which is quite helpful and even includes the slides.
I have an upcoming course (December 6) on Spring Data on the O’Reilly Learning Platform. I have a demo where I use Spring Data to work with an existing database, which I’ve mapped to my own domain model. For the example database, I normally use the Sakila sample database from MySQL.
Because you know I collect such things: the word Sakila is actually just the letters SQL with some vowels thrown in to make it pronounceable. It’s also the name of the dolphin in the MySQL logo, probably for the same reason.
With a Spring Boot project and JUnit 5 for testing, it was easy enough to add the testcontainers project and get a Docker image for MySQL working. The problem was that I couldn’t initialize the database with the provided SQL scripts, no matter what I did. Here’s the code, with the problematic parts commented out:
The resulting database works and is accessible, but it’s also empty. When I try to initialize it with the scripts, I get an exception. I don’t know what to do about this, since all the examples I see online work just fine.
Probably the easiest option would be to switch sample databases, but I’d like to know what’s wrong here. I sent an email to Ben (in the unlikely event he’s reading this: Hi Ben!), but we’ll see what happens.
COVID Hits Home
According to the New England Journal of Medicine, the protection from the Pfizer/BioNTech COVID-19 vaccine lowers by about 20% against infection (though not against hospitalization or death) after five to seven months. That’s why the booster shot was created and is now available.
Still, 80% protection is pretty high. Normally I’d like those odds. Unfortunately, a 1 in 5 chance still comes in roughly 20% of the time (I can do that math in my head). Twenty percent, sad to say, isn’t zero.
That mattered this week when my fully-vaccinated son (who moved back home a couple months ago — as he said, “I’m a millennial. That’s what we do”) came home from work on Wednesday night feeling sick. Thursday he was too ill to go to work. Late in the day he got a text from his manager saying another employee had tested positive, so he should get a test as well. We got him one on Friday, and yup, he’s got the virus.
He’s sick, but not dangerously so. It’s like he’s got a bad case of the flu, and three days later he’s starting to feel a bit better. My wife and I were vaccinated back in March and April, and we both got the booster shot about a month ago. We’re fine so far. My boy wasn’t eligible until January, and it looks like it cost him.
Grr. I hate it when you do everything right and lose anyway. Yes, I know the vaccine doesn’t prevent you from getting infected; it just makes the resulting case milder, and almost certainly keeps you out of the hospital. It did that. But grr anyway.
We’re in (quasi-)lockdown all over again, at least until we can get tested too, but all signs so far are that we’ll be fine. The boy is really annoyed, partly because he’s sick and partly because he works retail and he’s going to miss Black Friday and all the holiday sales. I get that.
I know the intelligent, sophisticated, almost-too-good-looking readers of this newsletter (affectionately known as jarheads) don’t need to be told this, but get your booster shot as soon as you can. It matters.
As a reminder, you can see all my upcoming training courses on the O’Reilly Learning Platform here and all the upcoming NFJS Virtual Workshops here.
Last week:
Week 2 of Spring in 3 Weeks, on the O’Reilly Learning Platform
Introduction to the Gradle Build Tool, for Gradle, Inc.
This week:
Week 3 of Spring in 3 Weeks, on the O’Reilly Learning Platform
Booster scheduled for next week. In the past 8 months I've been vaxxed for Covid (twice; Moderna), the flu, and shingles. I never got chicken pox as a kid, and my dad didn't either - he got it AND shingles in his late 80's(!). Having watched him go through it, I'll take the jab every damned time.