Tales from the jar side: Mockito saved me work, Java ecosystem survey and I/O idioms, Medium doesn't pay much (shocking), and Bring me the head of Erwin Schrödinger in Tweets and Toots
Yesterday I ate a clock. It was very time consuming. Especially when I went back for seconds. (rimshot)
Quick note: For some weird reason, several of the images in last week’s newsletter didn’t come through. I have no idea why. They were all available in the editor when I was writing it. The video I posted on the YouTube channel on Monday showed them all, however. Hopefully we won’t have that problem this week.
Welcome, fellow jarheads, to Tales from the jar side, the Kousen IT newsletter, for the week of April 30 - May 7, 2023. This week I taught my Managing Your Manager course and my JUnit 5 Testing course on the O’Reilly Learning Platform.
Regular readers of (and listeners to, and now video viewers of) this newsletter are affectionately known as jarheads, and are far more intelligent, sophisticated, and attractive than the average newsletter reader (or listener, or viewer). If you wish to become a jarhead, please subscribe using this button:
As a reminder, when this message is truncated in email, click on the title to open it in a browser tab formatted properly for both the web and mobile.
Spying on loggers
My technical content this week was in service to creating this video:
The 10-minute length of this video in no way reflects the amount of time I spent on it. The whole idea was triggered by a student in my JUnit course this week, who asked about testing a class that also does some logging through a logging framework. He wanted to know to test that, and I realized it was a perfect opportunity to use a Mockito spy.
The point of spies is that they intercept calls to dependent objects, so they can keep track of what calls were made, with which arguments, in what order. The idea is that if you want to test a method that also does some logging, wrap a spy around the logger and verify that its info
(or debug
or whichever level you wish) method was called the right number of times with the right arguments.
If I’d stuck to that, however, the result would have been a two-minute video at best. But no, I also wanted to capture the logging output and check that as well. The first rabbit hole that led me down was triggered by this paragraph in the JUnit documentation:
I spent literally hours on those paragraphs. Despite all that, I couldn’t figure out any way to use the provided TestExecutionListener
(called LoggingListener
) to do anything helpful. I tried everything. I read the source code, searched at Stack Overflow (see this question I eventually asked, which, as of today, still has zero answers), and even asked on the Gitter group maintained for JUnit 5 with no results.
Then I figured out (based on an example found on a website that I now forget, sorry) that I could capture standard output and standard error in Java using this mess of byte-array output streams:
@Testvoid
testLogWithStnErr() {
Logger logger = Logger.getLogger(LoggingDemoTests.class.getName());
LoggingDemo demo = new LoggingDemo(logger);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream err = new ByteArrayOutputStream();
System.setOut(new PrintStream(out));
System.setErr(new PrintStream(err));
demo.doStuff("Hello, world!");
assertThat(out.toString())
.contains("Doing useful stuff with: Hello, world!");
assertThat(err.toString()).contains("INFO: Hello, world!")
System.setOut(System.out);
System.setErr(System.err);
}
Ugh, but it works. Alternatively, if I was willing to add the Spring Boot test dependency to my project, I could use the JUnit 5 OutputCaptureExtension
from Spring Boot this way:
@ExtendWith(OutputCaptureExtension.class)
public class LoggingWithOutputCaptureTest {
@Test
void testLogWithOutputCapture(CapturedOutput outputCapture) {
Logger logger = Logger.getLogger(
LoggingDemoTests.class.getName());
LoggingDemo demo = new LoggingDemo(logger);
demo.doStuff("Hello, world!");
assertThat(outputCapture.getOut())
.contains("Doing useful stuff with: Hello, world!");
assertThat(outputCapture.getErr())
.contains("INFO: Hello, world!");
}
}
Here’s the thing, though: If I put those tests in with the rest of my tests, they don’t work because the logger output is an empty string. The only way to get them to work is to put each of them first, and they can’t both be first.
I have no idea why they both need to be first, though there’s a metaphor for today’s world in there somewhere. I resolved that by putting each of those tests in their own class, so they could be first that way, and somewhat to my surprise, that worked.
It’s at that point I finally realized that there was no real need to do any of this. Capturing the logging output is basically testing the logging framework itself. That’s not my responsibility; it’s the job of the framework developers. It’s enough for me to just be sure that the info
method on the logger was called with the right argument, and that’s what the Mockito spy was all about in the first place. In other words, I already did what I needed to do. All that extra work wasn’t necessary.
Oh well. I now understand it better, and it gave me a story for the video, but wow did I waste a lot of time on it.
Incidentally, I tried asking both ChatGPT and Bard (the AI from Google) how to use the LoggingListener
from JUnit 5. The answers they gave were hilariously wrong, and when I questioned them about it, each tool apologized and gave me the same answer with different wording. There’s a metaphor there, too, but I’m not sure what it is. I guess there’s a reason most AI tools are referred to as mansplaining-as-a-service.
The Java Developer Ecosystem Survey
JetBrains, the company that makes the IntelliJ IDEA development environment among many other tools, released the results of their Java developer survey for 2022. The results were restricted to respondents who listed Java as one of their three primary programming languages.
This is one of the primary surveys I care about. I’ve spent pretty much my entire career in Java or related technologies (Spring, Kotlin, Groovy, Gradle, and Android). Here are my comments on a few of the results:
Asked which version of Java you regularly use, the usage of Java 17 is all the way up to 30%. That’s pretty good for this community, which is filled with large, conservative corporations that evolve slowly when the evolve at all. Java 11’s share went from 42% in 2021 to 48% in 2022, which is good, and Java 8 dropped from 72% to 60%. That’s progress. The next LTS (long-term support) version of Java, version 21, comes out in September. We’ll see how many developers are still stuck on Java 8 at that time.
Among unit testing frameworks, JUnit leads at 86% (wow), which is consistent with what I’ve seen, and explains why my JUnit courses tend to fill. Mockito is second at 46%, which is my cue to remind you I have a short, inexpensive book available on that subject called Mockito Made Clear. None of the alternatives made it out of single digits, so I think I backed the right horse.
In terms of web frameworks, Spring Boot is first (67%) and Spring MVC is second (41%), which covers pretty much everybody. No other framework has more than 5% share (whoa). I noted Micronaut at 3% and Quarkus at 4%, with poor Grails coming in at a measly 1%. To think Grails-related work funded almost my whole company for about three or four years around 2010. Oh well.
Among build systems, Maven is still at 73%, but Gradle is up to 50%, which I think is a new high for them. Now that Gradle is the default for Spring Boot builds, we’ll see if that number goes up. It will also be interesting to see what impact if any moving to the Kotlin DSL by default for Gradle will have.
The IDE story was dramatic. 78% of developers use IntelliJ IDEA, with only 8% on Eclipse or Eclipse-based tools, and VSCode users are only at 5%. That may be misleading, however, since this was a JetBrains survey, so the respondents might be a self-selecting group of IDEA users. Still, that’s consistent with what I’m seeing among attendees in my courses.
I’ll skip several categories but note finally that the question “What kind of learning content do you prefer?” split evenly between Video (49%) and Written (49%). Probably a good thing, then, that I started my Tales from the jar side YouTube channel.
I’m glad to see a survey, but given that we’re already in May and this is a pretty fast-moving ecosystem, I’m already hoping for another survey soon.
Java I/O Idioms
This week JetBrains published their May 2023 edition of the Java Annotated Monthly. I haven’t been through everything yet, but one article stood out for me: Cay Horstmann (noted author of several books, including the entire Core Java series) wrote An Incomplete Guide to Modern Java I/O Idioms.
I’m mildly embarrassed I didn’t know several of them. The problem is that if you already know how to do something, you sometimes don’t notice when a better way comes along. For example, I knew that the Files.lines(path)
method returned a Stream<String>
(which needs to be used inside a try-with-resources block to make sure the stream is closed when you’re done) and I included that in my Modern Java Recipes book, but somehow I missed that in the same class there’s a Files.readAllLines(path)
method that returns a List<String>
. Anyway, it’s a short, useful read if you’re a Java developer.
The Medium Partner Program
I’ve been publishing blog articles on Medium because my publisher has a publication there called Pragmatic Programmers. About a month ago I realized I could join the partner program myself, which supposedly pays me for people who read my articles. I knew it wouldn’t be much, but this week I got my first payment:
Cha-Ching! We’re in the money!
That was for 129 views on an article published on April 19. May is off to a good start, too, showing I’m up to 22 cents already. The sky is clearly the limit. At some point, I could be making whole entire dollars, though that’s a long way away. Still, as the saying goes, the future’s so bright, I gotta wear shades.
On a related note, this week my new Medium article called Mocking Final Classes and Methods appeared on the platform. Just thought I’d mention it, in case I wind up with another fifty cents or so at the end of the month.
Tweets and Toots
Signs from the Writer’s Strike
This isn’t a tweet or a toot, but I thought it was clever and wanted to include it anyway. As you may know, the Writers Guild of America, representing about 11,500 writers of TV and film, are on strike (gift link, so you don’t need an account to read the article). A lot of it is over compensation from streaming sources, but the move to AI tools like ChatGPT is involved as well.
As a quick aside, if I want to support the writer’s strike (and I do), should I be publishing this right now? I’m thinking yes, mostly because I’m not part of the union and nothing I do is going to affect their jobs in any way. I want to make it clear, though, that I very much support their efforts to keep the studios and executives from robbing the writers of their fair share of streaming profits, and AI tools can’t do what real writers do despite what some executives seem to think. I’m sorry but not surprised that it’s come to this, and I hope management makes a reasonable offer soon.
On the plus side, some of the picket signs have been awesome, as shown in this article from NPR. Here are a couple:
“Succession without writers is just The Apprentice.” Wow. Harsh but fair. “Wrote ChatGPT This.” Yup, I can believe that.
I’m sure replacing studio execs with AI would be much more effective than replacing writers.
Anyway, check out the article for more, and let’s hope this is all over quickly. I want my Babylon 5 re-imagining that’s definitely on the way.
Not a reboot, but more B5 on the way
Speaking of Babylon 5, J. Michael Straczynski announced this:
He emphasized that (1) animation writers are in a different union, and (2) the film is already in the can anyway. It’s just a question of broadcasting it. Warner Brothers should be making a formal announcement about that in a week or so. I’m SO ready for a return to our last, best, hope for peace.
AI Impact
I posted this during the week:
Here’s a link to that article, entitled Will A.I. Become the New McKinsey? by Ted Chiang. The McKinsey referenced in the article is the consulting firm (McKinsey & Company, also known as capital’s willing executioners) hired by many firms to layoff workers in order to improve their stock prices (among other evils, like being the company that advised Purdue Pharma to turbocharge sales of OxyContin during the opioid epidemic). The idea is that A.I. tools will be used as a cheap replacement for human workers, leading to mass layoffs once again.
It’s an excellent article, and I encourage you to read it, but it just emphasizes my point above:
The real risk of AI isn’t that it can do your job — it’s that your manager will think it can do your job.
There’s not much we can do about this, especially if you work in an area where the solutions to problems are common and routine. That’s exactly what AI tools do well.
I should note that one way to see the effect of AI tools on education (one of my primary areas) is to notice that the stock price of the education technology company Chegg dropped 48% after its CEO told investors that students are switching to ChatGPT. Of course, their response to this threat is to make their own AI tool, supported by GPT-4.
In a related post:
I’m not sure how I’m going to handle this issue in my Trinity class this Fall, but I’m already thinking about it.
Schrödinger’s Cat Is Not Happy
I would have phrased it as, “Bring me the head of Erwin Schrödinger,” but hey, the cat is angry. I get it.
Cats are dangerous
Speaking of cats (or, at least, cat pictures):
Yeah, I hate when that happens.
A use of AI that I actually need
Here’s a link to the original post, so you can go see the pictures in more detail. It’s awesome.
May the 4th
Finally, May 4th (Star Wars Day) occurred this week, which brought back this old classic:
Who knew that Luke Skywalker, as whiny a brat as ever starred in a movie, would turn out to be such a cool character? (Okay, so maybe it was Mark Hamill who was cool all along.)
Have a great week everybody!
The video version of this newsletter will be on the Tales from the jar side YouTube channel tomorrow.
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:
Managing Your Manager, on the O’Reilly Learning Platform.
Next-generation Java Testing with JUnit 5, ditto
This week:
Latest Features in Java, an NFJS Virtual Workshop