Weekly digest 2022-48

It’s getting bleak outside but as you might have guessed, it does not stop me from getting outside. Last week I managed to increase my Veloviewer maximum square to 40×40 tiles. That is kinda of an online game connected to Strava. I am a big fan of both services. The goal with the squad is to reach as many small tiles as possible from a location and create a square as big as possible. All running, cycling, hiking and swimming activities count and one small tile is one square mile. This is how my square looks like:

Most of it is cycling but also some hiking. Next year it’s going to get though. In the east the open coal mines start and in the south there’s a protected moor area and some tiles are… difficult to get. So I am gonna focus on the north and west.

Ongoing fires in IT world

Twitter, Meta and other big, add driven companies are dumpster fires these days, laying of workers in the thousands. While I feel sad for the people, it’s maybe for the better: Are these companies producing value or just issues? I don’t know. But the recession is reaching others as well. Others, that actually produce something tangible. Yesterday, Ash Kulkarni from Elastic published the linked letter about reducing teams by 13% of people. It feels like hitting close: Elastic is an open source company as well, with a lot of good people and many that I actually do know personally. I always assumed they are an economical wealthy company but alas, less growth than usual and not even losses are quite bad these days.

Earlier this year in June I read a book named “RCE”, by Sibylle Berg. RCE is the successor to GRM and I do recommend both of them:

The predictions in GRM about UK, social descent on the one hand and incredible wealth on the other felt like a prediction come true already and apparently, the things in RCE start happening, too. Why have we IT works thought at all that not having unions, not working together in many cases would do us any good? Why could we have thought just for a second that we aren’t expendables? Curious and frightened how things will continue.

More good reads

But more on the reading side of things. I finished “Sternkinder” by Clara Asscher-Pinkhof. A book from a Holocaust survivor writing about the Holocaust from children’s perspective. Going from Sternkinder to Sternhaus, Sternwüste and finally Sternhölle. It’s all short pieces and beautiful, but simple language, technical easy to read, but heartbreaking. I had to stop several times. But sure, let’s let idiot “musicians” like Mr. West talk about the “good things” Hitler and the Nazis did. Like my father used to say, Ich kann nicht soviel fressen, wie ich kotzen möchte.

Your weekly cup of Java

I am so happy: All PRs in Neo4j-Migrations that in one way or the other deal with JDK or dependency versions closed and dealt with: Upgrades to JDK 17, Spring Boot 3 and the latest and greatest Neo4j Java Driver done. The Quarkus Neo4j extension has just been released as 2.0 as well, including the latest upgrade and based on all of that, Gerrit released Neo4j-OGM 4.0 with support for Neo4j 5.

The last nights I did something else for a change, basically combined sports and Java and created this: Garmin Babel. It is a tool to work with your archive data from Garmin.com respectively Garmin Connect.

What? Let me show you:

I love Java and the ecosystem.

Let me point out some tech I use and the people that I know behind it:

And wow, I do love the modern HTTP Client in the JDK. Here’s the full async code to download a bunch of data:

private CompletableFuture<Optional<Path>> scheduleDownload(Activity activity, DownloadFormat format, Tokens tokens, Optional<Path> base) {
  return CompletableFuture
    .supplyAsync(() -> {
      // Randomly sleep a bit
      try {
        Thread.sleep(ThreadLocalRandom.current().nextInt(10) * 100);
      } catch (InterruptedException e) {
        throw new RuntimeException(e);
      var uri = switch (format) {
        case FIT -> "https://connect.garmin.com/download-service/files/activity/%d".formatted(activity.garminId());
        default -> "https://connect.garmin.com/download-service/export/%s/activity/%d".formatted(format.name().toLowerCase(Locale.ROOT), activity.garminId());
      return HttpRequest
        .header("Authorization", "Bearer %s".formatted(tokens.backend()))
        .header("DI-Backend", "connectapi.garmin.com")
        .header("Cookie", "JWT_FGP=%s".formatted(tokens.jwt()))
        .header("User-Agent", "garmin-babel")
    .thenCompose(request -> httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream()))
    .thenApply(res -> {
      if (res.statusCode() != 200) {
        throw new ConnectException("HTTP/2 %d for %s".formatted(res.statusCode(), res.uri()));
      try {
        var suffix = switch (format) {
          case FIT -> "zip";
          default -> format.name().toLowerCase(Locale.ROOT);
        var filename = "%d.%s".formatted(activity.garminId(), suffix);
        var targetFile = base.map(v -> v.resolveSibling(filename)).orElseGet(() -> Path.of(filename));
        Files.copy(res.body(), targetFile, StandardCopyOption.REPLACE_EXISTING);
        return Optional.of(targetFile);
      } catch (IOException e) {
        throw new RuntimeException(e);
    .thenApply(path -> {
      path.ifPresent(v -> System.err.printf("Stored data for %d %s as %s%n", activity.garminId(), activity.name() == null ? "" : "(" + activity.name() + ")", v.toAbsolutePath()));
      return path;
    .exceptionally(e -> {
      var prefix = "Error downloading activity %d ".formatted(activity.garminId());
      if (e.getCause() instanceof ConnectException connectException) {
        System.err.println(prefix + connectException.getHttpStatusAndUri());
      } else {
        System.err.println(prefix + e.getMessage());
      return Optional.empty();

From scheduleDownload.

Anyway, if you find michael-simons/garmin-babel useful, please let me know. I had a lot of fun writing it, but I realize I am not 30 anymore and hacking away 3 nights straight in a row took its tool. Super happy that my employer Neo4j continued with the 4th Neo4j Global Wellness day in 2022 today and I just can sit down with a cup of coffee and write this piece here.

Before I leave, todays featured biking picture:

Taken during the bleak and dark morning hours, accompanying my kid to school. In that sense, do something nice, not only over the weekend, but also during the week. Time is too short to waste it.

| Comments (0) »


Weekly digest 2022-47

And another week gone. Time flies. It seems that I manage to make a habit out of note taking and writing about it later. I notice a big change in my days not having the urgent need to tweet everything all at once all the time. As shown in my last digest, I put the screen-time widget onto my iPhone home screen. I’m happy seeing a big drop in daily average screen time on the thing. In the meantime I have not only removed the Twitter app from my home screen, but also deleted the app. It’s much more inconvenient to use the web page, as I logged out from it, too.

Anyway, last weekend I started with the most extreme half-marathon (13.1mi / 21.1km) in 2022. 500m of gained altitude in one run, under 2 hours. I was completely toast after that, despite the fact that I did a half-marathon each month this year. Anyway, I am aiming for the 2000m running altitude badge again this month, but that’s a though one.

So what was ongoing this week? I have binged watched season 2 of Inside Job and I am absolutely loving this to pieces:

Reagan Ridley noting on his father becoming the head of Cognito: “This is going to be the most globally damaging midlife crisis since Elon Musk.” which has been written like a year ago according to… Twitter. Continuing with that, the video I enjoyed most this week was probably done by Adam Conover and has the friendly title “Elon Musk Is An Idiot (and so are Zuck and SBF)”:

I would not call those folks dumb, which I don’t think they are, but selfish, ignorant morons and man-childs with too much power in their hands. Anyway. If your interested in more on the twitter mess, I enjoyed that article from the parted head of trust and safety at Twitter which confirms the fact that Twitter will eventually be in real trouble in Europe and hopefully that will get Musks ass. A more personal stance can be found by Matt Tait: Twitter was special. But it’s time to leave. And with the Miro-Board from Twitters code review I can jump right into tech, I guess. The Miro board gives an interesting high-level view about the services at Twitter, especially the “Mixers” that basically create the curated timeline. In that context, I totally dug this thread by Jon Bell on UX design on social network in general and comparison what’s on Mastodon vs Twitter. Brilliant stuff, worth the read and makes you think, if you are sometimes the loudest voice as well and ignoring a more silent minority.

To more positive stuff: Congratulations Spring-Boot-Team: Spring Boot 3.0 Goes GA 🎉🥳🍾🎊. Crazy, the project is now nearly 8 years old and what a ride. I was wondering the other day: Back then, the idea was part about self-contained application but also introducing better best-practices than the habit of copying and pasting various XML configs and setups from StackOverflow into Spring projects until they worked with the idea of auto configuration. These days, I find tons of (auto) configuration classes when working on tickets and issues all the time which at best are redundant but more often, dangerously wrong. At times, I feel like we have reached (another) full circle (Please note, that is *not* a negative statement about Spring Boot at all, it just seems to be the way of things these days).
Anyway, in case you are providing custom starters for Spring Boot, make sure you stop using spring.factories together with @Configuration classes for your auto configuration already in Spring Boot 2.7, as that approach will stop working in Boot 3. Here’s a commit that shows the needed changes: refactor: Migrate to @AutoConfiguration. Makes things a lot clearer, I like that.

Speaking about cool libraries: I use Picocli A LOT. And every time I think I must have found that thing that won’t work ootb, it does. This time, hidden options, parameters and subcommands. Sweet stuff.

Also, I wrote kind of a beginner post on Java Records and name clashing: While stuff like that can feel redundant to experienced developers, it isn’t in reality.

It’s about community

In terms of community and fun, this week has been brilliant. I visited Bauer + Kirch to talk about software, proper architecture and a bunch of other things and it might be that we can do an EuregJUG event there next year. They are looking for Java folks among other roles. Might be interesting for the reader.

This weeks featured biking picture was taken on my ride to Franz who really pulled of a public viewing for Karl Heinz’ talk about Maven 4 (essentially this talk). We even snatched Karl Heinz after the talk and enjoyed more French fries by the master of the industrial deep frier himself 😉

Last but not least, next week is INNOQ technology day. Fantastic opportunity to listen to excellent speakers for free. I would check this out!

Stay sane and remember to use the weekend to wind down 🙂

| Comments (0) »


Weekly digest 2022-46

Last week, I received quite a lot of really positive feedback for my first attempt at writing a digest. Thank you for that Kevin and Frederik, super kind of you! Even Payara picked it up.

One thing that I have changed this week is my iPhone home screen from which I removed the Twitter app (which I had on the first page). Instead, I put Music back into it. Also, trying to be more conscious about my time spent, I added the Apple time tracker:

Let’s see how that goes.

I started my weekend after traveling last week with… Not cycling but with this awesome video by Mary Spender:

If you didn’t watch it, it’s actually not about todays music not sucking, but against nostalgia holding things back. I liked it a lot, good stuff and actually pretty positive.

I finished reading Verschwörungsmythen by Michael Blume:

Very good read. I never thought about Platons allegory of the cave as something not that positive, but when you have a closer look, it can indeed be connected to conspiracy and the “charismatic” leaders leading the poor people out of the cave. And on the other hand, the red pill is indeed the entrance to the rabbit hole, but not in a good way.

While watching it I thought: “I should post this.” Why, actually? I am not a content / link creation machine and I just can refuse. Let thinks sink in a bit and see if they are worth sharing a week later anyway.

Before we jump a bit into Java: Of course I did cycle on the weekend and it’s madness. I was riding roughly 200km on both days in short/short. In freaking November. The map on the right: Yes, the track reassembles the temperature of one of those rides. Still, those rides give me as much serenity as the guy on the mural seems to have:

A bit related to that, my friend Markus wrote an excellent article about changing his habits at LinkedIn: Dieting vs. Nutrition vs. Rethinking my lifestyle. I’m very impressed by his achievements. I vividly remember our Devoxx 2019 conversation about that topic and role models and such: Chapeau, Markus. Well done. Wrt to nutrition: I’m still on the hard, fast and wrong side of things (apart alcohol) but that works well enough for me atm.

This week was Nodes 2022 and I worked liked crazy to get the documentation of Neo4j-Migrations into our labs pages: Neo4j Migrations Docs / Introduction. Together with Guillaume and Adam we used the existing AsciiDoctor documentation and are now building it with Antora. See the related commit. Antora makes it necessary to rethink a bunch of things, but I am totally in love with the fact that “my” build now notifies our docs repository and that in turn pulls my docs and integrates it into a bunch of other modules. Sweet stuff.

As preparation of his Nodes2022 talk, Gerrit put up a video about Testcontainers and integration testing:

I also did a presentation yesterday day and here are my slides about Neo4j-Migrations or what I call it, the lean way of refactoring Neo4j database content:

I am unsure how good my presentation was in the end: I realised with last weeks Øredev and yesterdays Nodes2022 that I am much better offline than on video. At least, this is how I perceive it.

Maciej was on fire this month with excellent posts about getting Tailwind CSS into Spring Boot proper (at some point, I will revisit my biking application and remove all that SPA Angular stuff and go back to SSR with Thymeleaf for my own sanity) and this is great stuff. He has a bunch of more things that I am using regularly, too, i.e. Activating Maven Profile by Operating System.

From Maciej and my colleague Gerrit comes 🚀 Introducing YOLO – because life is too short for running tests btw. Just click if you’re up for a laugh.

I expected this a bit later this year, but here it is: Spring Framework 6:

As a major revision of the core framework, Spring Framework 6.0 comes with a Java 17+ baseline and a move to Jakarta EE 9+ (in the jakarta namespace), with a focus on the recently released Jakarta EE 10 APIs such as Servlet 6.0 and JPA 3.1. […] Don’t be stuck on Java EE 8, make the leap to the jakarta namespace, ideally straight to the Jakarta EE 10 level! The upcoming Spring Boot 3.0.0 release includes corresponding managed dependencies for you.

IMHO this is quite big for the ecosystem. I cooperated with Heise Online a couple of weeks ago and so we did have a comment ready (in German): Spring Framework 6 verarbeitet Native Images und baut auf Jakarta EE 9 oder 10.

I did already share this article on Twitter, but it’s super interesting still. It’s about databases and query planning. Funny enough, the week before I hang out with Andres Taylor, one of the minds behind it. Andres is one of the original creators of Neo4j Cypher and was also involved in the Cypher-DSL before I took this over.

While Twitter seems indeed to be burning, I will dive into a bit of nostalgia as today, November 18th, a rerelease of Queens 1989 album “The Miracle” will happen, including a bunch of unreleased Queen demos. Looking very much forward to that: Was it all worth it?

| Comments (0) »


Weekly digest 2022-45

Tja, it had to happen at some point: Twitter is dying, I need a new old outlet. I have now this

but also this

I am not really happy about the situation and am reconsidering what to do social network wise. I never really missed my Facebook account that I deleted (at least I hope it’s deleted) more than 2 years ago. Might as well that I go a bit more silent and reluctant on those tools in total. I wish however to stay connected and do something reassembling a heartbeat. And this is my first attempt at it. Anyway, let’s go:

My week startet by participating in a 16,5km run:

I did this for the first time in 2019, then in 2021 again now this. My times went down from 1h:22min to 1h:17min and this year, 1h:15min for a light trail run with about 260 meters of altitude gain. I’m super stocked about that. Read more about the race here.

The working week I travelled to Malmö for the second time this year. I work for Neo4j (and we just released Neo4j 5, you might want to check out the release) and our engineering headquarters are in Malmö. However, I was invited to speak at Øredev there, which made me super happy and proud.

I spoke about GraalVM, Quarkus and how our driver works with it. You can see the slides here and there will be videos I heard:

Also on the conference was my friend Michael Hunger. We spent some really good quality time and also met Sebastian Daschner:

I also got some work done! Shortly before Twitter started going down in flames, I wrote one of my most successful tweets:

And in that light, I do now require Java 17 for neo4j-migrations. Java 17 provides better performance during runtime, but it is also so much nicer with text blocks, records and other smaller and bigger things. You might want have a look at this commit. Some of the big line savings come from the fact that I had a multi-release build that used some Java11/17 if available though.

I am now sitting at the Copenhagen airport after traveling the Øresund bridge by train:

More bridges, less walls I’d say. Next week, Neo4j will host Nodes2022 for free. Use this link to register and sign in if you’re interested technical talks about graph and ecosystem. Until then and please all, stay sane and healthy.

| Comments (0) »


Use Oracle Cloud Infrastructure compute instances as custom GitHub runners

I have been publishing linux-aarch64 of Neo4j-Migrations for a while now. I am unsure if there are many people using it, but one scenario is other CI/CD based on Linux ARM infrastructure in which those binaries might come in handy. Those binaries are build with GraalVM using the official setup-graalvm action from Oracle Labs.

For the above project I use the ubiquitous GitHub actions. GitHub actions supports Windows, Linux and macOS operating systems, but only on x86_64 platforms (see https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources). So far I have not seen any indication that this will change in the near future.

For Linux on Arm Oracle Cloud Infrastructure (or in short OCI) offers a solution. The “Always-Free”-Cloud-Services gives you up to 4 instances of ARM Ampere A1 with 3,000 OCPU hours and 18,000 GB hours per month at the time of writing and you can sign up here. The sign up step are typical enterprise Oracle stuff, but alas, it’s free.

I’m not gonna screenshot all the steps, as I am pretty sure they have or will change over time, but this is the compute instance I set up for my purposes:

Make sure you don’t use the Oracle Linux image but something easier to deal with, like Ubuntu Linux or CentOS. I wasn’t able to setup the GitHub runner on the Oracle ones. It is currently hidden under “platform images” when you create new instance:

During creation you can either upload your own SSH public key or generate a new pair. If you do the latter, make sure to download it and store it safely, otherwise you can’t connect to the machine.

I basically followed the process and waited until the machine is ready.

Setting up the runner is dead simple and you can follow the official GitHub instructions: Adding self-hosted runners. I did this from the repository on, not from the org. I tagged the runner with “Linux” and “ARM64” like that:

GraalVM native image needs gcc and build essentials, which is the reason I needed to install them on the runner too. This is basically everything that was necessary in my case:

sudo apt-get install gcc libz-dev build-essential
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-arm64-2.296.1.tar.gz -L https://github.com/actions/runner/releases/download/v2.296.1/actions-runner-linux-arm64-2.296.1.tar.gz
echo "ce11e5d9c1cc299bd8a197b7807f6146fbe7494abb19765fb04664afbdb3755e  actions-runner-linux-arm64-2.296.1.tar.gz" | shasum -a 256 -c
tar xzf ./actions-runner-linux-arm64-2.296.1.tar.gz
./config.sh --url https://github.com/your-org/your-repo --token your-token
sudo ./svc.sh install
sudo ./svc.sh start
sudo ./svc.sh status

Please take note that the above runner version might be outdated, you’ll find fresh instructions when setting this up from your repository or organization.

Now, how to use this? Here’s my release script: release.yml; this is the relevant part:

  name: 'Build with Graal on ${{ matrix.os }} ARM64'
    fail-fast: true
      os: [ linux ]
    - self-hosted
    - ${{ matrix.os }}
    - ARM64

Key being self-hosted in the runs-on block and the remaining, corresponding tags.

A similar approach would be feasible for macOS M1 binaries, but the only option to use them in the cloud I found was AWS with some price tag. It may or may not be worth it for your use case.

Thanks to Fabio Niephaus who brought this possibility to my attention for the first time way back in April this year.

Feature image ARMCortexA57A53.jpg.

| Comments (1) »