<?xml version="1.0" encoding="UTF-8"?>


<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>A Java geek</title>
    <description>Nicolas Fränkel&apos;s blog</description>
    <link>https://blog.frankel.ch/</link>
    <language>en</language>
    <copyright>Copyright 2008-2026 Nicolas Fränkel</copyright>
    <atom:link href="https://blog.frankel.ch/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Mon, 08 Jun 2026 15:03:34 +0000</pubDate>
    <lastBuildDate>Mon, 08 Jun 2026 15:03:34 +0000</lastBuildDate>
    <generator>Jekyll</generator>
    <image>
      <url>https://blog.frankel.ch/assets/pages/me/me.jpg</url>
      <title>A Java geek</title>
      <link>https://blog.frankel.ch/</link>
    </image>
    
    
      <item>
        <title>Seasons time-lapse - the video</title>
        <description>In the first post of this series, I focused on the project foundations: what should I do to create a video from photos taken from the same position year after year? I dedicated the second part to aligning images. It wasn&amp;#8217;t as easy as I expected. I stumbled upon new concepts, such as ORB and RANSAC.   In this third and final post, I want to tackle the video creation itself, explain some &apos;artistic&apos; decisions, and leave the door open to future work.</description>
        <pubDate>Sun, 07 Jun 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/seasons-time-lapse/3/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/seasons-time-lapse/3/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/seasons-time-lapse/cover3.jpg" width="1280" height="853" />
        
        
        <category>python</category>
        
        <category>art</category>
        
        <category>time-lapse</category>
        
        
        <category>Development</category>
        
      </item>
    
      <item>
        <title>AI gateways: why and how</title>
        <description>Before working for 2 years on the Apache APISIX API gateway, I was mainly oblivious to API gateways. It&amp;#8217;s only by working with them that I understood their value. Decoupling the client and the server unlocks a lot of options: moving authentication to the API Gateway, securing APIs, deduplicating API requests, etc.   In this post, I want to describe how the same pattern applies to AI.   AI gateways   AI gateways work in a similar way.</description>
        <pubDate>Sun, 31 May 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/ai-gateways/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/ai-gateways/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/ai-gateways/cover.jpg" width="1536" height="1024" />
        
        
        <category>coding assistant</category>
        
        <category>ai</category>
        
        <category>gateway</category>
        
        <category>llm</category>
        
        <category>claude code</category>
        
        <category>mistral</category>
        
        <category>devstral</category>
        
        
        <category>Technical</category>
        
      </item>
    
      <item>
        <title>Seasons time-lapse - alignment</title>
        <description>In the previous post, I described the Seasons project: a time-lapse of hundreds of pictures taken from nearly the same viewpoint over the years. The hardest challenge wasn&amp;#8217;t taking the pictures or assembling them, but aligning them.   You might have noticed the nearly part about viewpoint in the above paragraph. Indeed, it&amp;#8217;s an approximation. I&amp;#8217;m a human being, not a tripod. The position changes ever so slightly, and so does the exact angle.</description>
        <pubDate>Sun, 24 May 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/seasons-time-lapse/2/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/seasons-time-lapse/2/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/seasons-time-lapse/cover2.jpg" width="1280" height="853" />
        
        
        <category>python</category>
        
        <category>art</category>
        
        <category>time-lapse</category>
        
        
        <category>Development</category>
        
      </item>
    
      <item>
        <title>Seasons time-lapse - the foundations</title>
        <description>I live close to nature. I regularly go for a run in the countryside. Over several years, during my runs, I&amp;#8217;ve taken pictures from the same position, always roughly the same angle. I had a vague idea in the back of my mind, as an &apos;artistic&apos; project. One day, I&amp;#8217;d turn those photos into a time-lapse video, one that would show the passage of seasons across a single place.   Spoiler, here&amp;#8217;s the work in progress:        However, I knew that this project would take ages.</description>
        <pubDate>Sun, 17 May 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/seasons-time-lapse/1/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/seasons-time-lapse/1/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/seasons-time-lapse/cover1.jpg" width="1280" height="853" />
        
        
        <category>python</category>
        
        <category>art</category>
        
        <category>time-lapse</category>
        
        
        <category>Development</category>
        
      </item>
    
      <item>
        <title>Tokensparsamkeit for coding assistants</title>
        <description>Good engineers make decisions based on data. Most businesses assumed that the more data, the better the decision. Then, several factors put a halt to the hoarding of ever more data. GDPR and its localized counterparts, and the cost of storage. However, before the GDPR came into effect, the Datensparsamkeit approach already existed.     Datensparsamkeit is a German word that&amp;#8217;s difficult to translate properly into English.</description>
        <pubDate>Sun, 10 May 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/tokensparsamkeit-coding-assistants/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/tokensparsamkeit-coding-assistants/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/tokensparsamkeit-coding-assistants/cover.jpg" width="1536" height="1024" />
        
        
        <category>tokens</category>
        
        <category>sparsamkeit</category>
        
        <category>agents</category>
        
        
        <category>Technical</category>
        
      </item>
    
      <item>
        <title>Designing a team of agents</title>
        <description>I continue to experiment with AI in the context of software engineering. I&amp;#8217;m fortunate that my team supports me in exploring different ways to improve our daily work. This week, I designed a team of autonomous agents to implement features, from design to implementation.   Why autonomous agents?   A long time ago, we were delighted when the IDE offered auto-completion. In the previous two years, things have changed. A lot.   Coding assistants have become our primary interfaces for coding.</description>
        <pubDate>Sun, 03 May 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/design-team-agents/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/design-team-agents/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/design-team-agents/cover.jpg" width="1536" height="1024" />
        
        
        <category>agents</category>
        
        
        <category>Technical</category>
        
      </item>
    
      <item>
        <title>Three Mastodon issues because of Cloudflare Bot protection</title>
        <description>I noticed some time ago that three Mastodon features had stopped working on my blog. Each of them seemed like a separate problem, but they had the same root cause. In this blog post, I aim to describe these issues and propose a simple solution.   Domain verification   Mastodon allows you to prove that you own a domain.</description>
        <pubDate>Sun, 26 Apr 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/mastodon-cloudflare-bot-protection/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/mastodon-cloudflare-bot-protection/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/mastodon-cloudflare-bot-protection/cover.jpg" width="1536" height="1024" />
        
        
        <category>mastodon</category>
        
        <category>cloudflare</category>
        
        <category>fediverse</category>
        
        
        <category>Technical</category>
        
      </item>
    
      <item>
        <title>Making illegal state unrepresentable</title>
        <description>A couple of years ago, I wrote that The Builder pattern is a finite state machine!. A state machine consists of states and transitions between them. As a developer, I want to make illegal states unrepresentable, i.e., users of my API can&amp;#8217;t create non-existent transitions. My hypothesis is that only a static typing system allows this at compile-time. Dynamic typing systems rely on runtime validation.   In this blog post, I will show that it holds true, with a caveat.</description>
        <pubDate>Sun, 19 Apr 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/illegal-state-unrepresentable/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/illegal-state-unrepresentable/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/illegal-state-unrepresentable/cover.jpg" width="1062" height="1332" />
        
        
        <category>software design</category>
        
        
        <category>Development</category>
        
      </item>
    
      <item>
        <title>A GitHub agentic workflow</title>
        <description>Last month, I became aware of GitHub agentic workflows. I read the site carefully, but the use cases weren&amp;#8217;t very exciting to me. I tried the continuous documentation It didn&amp;#8217;t work out initially, and because of my lack of involvement, I left it as it was. However, I succeeded in another one that I want to describe in this post.         With lessons learned here, I managed to make the documentation workflow work!</description>
        <pubDate>Sun, 12 Apr 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/agentic-github-workflows/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/agentic-github-workflows/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/agentic-github-workflows/cover.jpg" width="1536" height="1024" />
        
        
        <category>github</category>
        
        <category>github workflow</category>
        
        <category>agentic workflow</category>
        
        <category>automation</category>
        
        
        <category>Technical</category>
        
      </item>
    
      <item>
        <title>Experimenting with AI subagents</title>
        <description>I like to analyze codebases I start working on, or that I left for months. I ask my coding assistant, case in point, Copilot CLI: &apos;analyze the following codebase and report to me improvements and possible bugs.&apos; It&amp;#8217;s vague enough to leave room for crappy feedback, but also for some interesting insights.   I did it last week on a code base. Copilot returned a list of a dozen items. I asked it to create a GitHub issue for each, with the relevant labels, including priority.</description>
        <pubDate>Sun, 05 Apr 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/experimenting-ai-subagents/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/experimenting-ai-subagents/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/experimenting-ai-subagents/cover.jpg" width="1536" height="1024" />
        
        
        <category>ai</category>
        
        <category>agents</category>
        
        <category>subagents</category>
        
        
        <category>Technical</category>
        
      </item>
    
      <item>
        <title>One tip for successful OpenTelemetry projects</title>
        <description>Leading your organization to use OpenTelemetry is a challenge. In addition to all the usual project hurdles, you&amp;#8217;ll face one of these two situations: convince your teams to use OpenTelemetry, or convince them to move from the telemetry tool they are already using to OpenTelemetry. Most people don&amp;#8217;t want to change. You&amp;#8217;ll need lots of effort and baby steps. My tip is the following: the fewer the changes, the higher your chances of success.</description>
        <pubDate>Sun, 29 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/tip-opentelemetry-projects/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/tip-opentelemetry-projects/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/tip-opentelemetry-projects/cover.jpg" width="1536" height="1024" />
        
        
        <category>opentelemetry</category>
        
        <category>jvm</category>
        
        <category>jmx</category>
        
        <category>pragmatism</category>
        
        
        <category>Technical</category>
        
      </item>
    
      <item>
        <title>The Software Architect Elevator</title>
        <description>I don&amp;#8217;t think it&amp;#8217;s necessary to introduce Gregor Hohpe. I’m a big fan, having read Enterprise Integration Patterns, and I&amp;#8217;ve recommended the book ever since. When I spoke at the Software Architecture Gathering in 2024, I was fortunate enough to meet him and purchase this book. I&amp;#8217;m the happy owner of a signed copy.     Modern architects don’t try to be the smartest people in the room–they make everyone else smarter.</description>
        <pubDate>Sun, 22 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/software-architect-elevator/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/software-architect-elevator/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/software-architect-elevator/cover.jpg" width="1062" height="1332" />
        
        
        <category>api</category>
        
        <category>design pattern</category>
        
        
        <category>Book</category>
        
        <category>review</category>
        
      </item>
    
      <item>
        <title>Writing an agent skill</title>
        <description>Most developers now use coding assistants. I do too—Copilot at work, Claude Code at home. As a developer, I prefer not to repeat myself. This post explains why and how to avoid repetition as a skill.   Don&amp;#8217;t Repeat Yourself   The DRY principle has been present in the software development field for ages. The idea is that if you copy and paste code in multiple places and a bug appears, you&amp;#8217;ll need to fix the bug in all these places.</description>
        <pubDate>Sun, 15 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/writing-agent-skill/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/writing-agent-skill/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/writing-agent-skill/cover.jpg" width="1536" height="1024" />
        
        
        <category>ai</category>
        
        <category>agent</category>
        
        <category>skill</category>
        
        
        <category>Technical</category>
        
      </item>
    
      <item>
        <title>Pi-hole behind Tailscale</title>
        <description>As I age, I become increasingly cautious about my privacy. The slope the world is sliding on is also a big, unfortunate incentive. I have been eying Pi-hole for some time: in this post, I want to explain what it does, how to install it on a Raspberry Pi, and how to integrate it with Tailscale.   My take on privacy   Privacy, or more specifically digital privacy, is the ability to protect oneself from the constant data collection by legitimate companies and malicious actors alike when online.</description>
        <pubDate>Sun, 08 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/pi-hole-tailscale/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/pi-hole-tailscale/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/pi-hole-tailscale/cover.jpg" width="1536" height="1024" />
        
        
        <category>privacy</category>
        
        <category>raspberry pi</category>
        
        <category>tailscale</category>
        
        
        <category>Technical</category>
        
      </item>
    
      <item>
        <title>Ready-to-use virtual clusters</title>
        <description>vCluster is a solution for creating virtual clusters within a host Kubernetes cluster.     Virtual clusters are a Kubernetes concept that enables isolated clusters to be run within a single physical Kubernetes cluster. Each cluster has its own API server, which makes them better isolated than namespaces and more affordable than separate Kubernetes clusters.    &amp;#8212; What are virtual clusters?</description>
        <pubDate>Sun, 01 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/ready-to-use-virtual-clusters/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/ready-to-use-virtual-clusters/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/ready-to-use-virtual-clusters/cover.jpg" width="1536" height="1024" />
        
        
        <category>vcluster</category>
        
        <category>devops</category>
        
        <category>logging</category>
        
        <category>loki</category>
        
        
        <category>Technical</category>
        
      </item>
    
      <item>
        <title>JVM timing options</title>
        <description>For as long as I have been coding in Java, we have had requirements to measure the execution time of blocks of code. While the current good practice is to use OpenTelemetry&amp;#8217;s traces, not every company has reached this stage yet. Plus, some of the alternatives are OpenTelemetry-compatible. Let&amp;#8217;s see them in order.   The basic option   The basic option is what we have been doing for ages, and what the other options rely on anyway. It&amp;#8217;s based on the following API: System.</description>
        <pubDate>Sun, 22 Feb 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/jvm-timing-options/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/jvm-timing-options/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/jvm-timing-options/cover.jpg" width="1536" height="1024" />
        
        
        <category>timer</category>
        
        <category>stopwatch</category>
        
        
        <category>Java</category>
        
      </item>
    
      <item>
        <title>Migrating from Jekyll to Hugo... or not</title>
        <description>Most of my blog posts are lessons learned. I&amp;#8217;m trying to achieve something, and I document the process I used to do it. This one is one of the few where, in the end, I didn&amp;#8217;t achieve what I wanted. In this post, I aim to explain what I learned from trying to migrate from Jekyll to Hugo, and why, in the end, I didn&amp;#8217;t take the final step.   Context   I started this blog on WordPress. After several years, I decided to migrate to Jekyll. I have been happy with Jekyll so far.</description>
        <pubDate>Sun, 15 Feb 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/migrating-jekyll-hugo/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/migrating-jekyll-hugo/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/migrating-jekyll-hugo/cover.jpg" width="1536" height="1024" />
        
        
        <category>blog</category>
        
        <category>jekyll</category>
        
        <category>hugo</category>
        
        <category>static site generator</category>
        
        <category>performance</category>
        
        
        <category>Technical</category>
        
      </item>
    
      <item>
        <title>Rediscovering Java ServiceLoader: Beyond Plugins and Into Capabilities</title>
        <description>When you think of Java modularity, chances are your first thoughts land on JPMS, or perhaps on Spring’s flexible configuration model. For those who &apos;experienced&apos; like me, thought can reach OSGI specification or other stacks like Vert-X. Yet long before either, Java offered a minimal yet powerful mechanism for loose coupling: ServiceLoader.</description>
        <pubDate>Sun, 08 Feb 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/rediscovering-java-serviceloader/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/rediscovering-java-serviceloader/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/rediscovering-java-serviceloader/cover.jpg" width="1536" height="1024" />
        
        
        
        <category>Java</category>
        
      </item>
    
      <item>
        <title>Feedback on checked exceptions and lambdas</title>
        <description>I got a lot of interesting feedback on Checked exceptions and lambdas. Let&amp;#8217;s start with my own: after writing the post, I realized I had written a similar post some time ago.   Mistakes I made   I made a mistake in the code regarding Apache Commons Lang 3, where I mistakenly used the recover() function, which is actually from Vavr.   Apache Commons Lang provides a regular utility function, which mimics the custom code we wrote last week.</description>
        <pubDate>Sun, 01 Feb 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/feedback-checked-exceptions-lambdas/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/feedback-checked-exceptions-lambdas/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/feedback-checked-exceptions-lambdas/cover.jpg" width="1536" height="1024" />
        
        
        <category>exceptions</category>
        
        <category>error handling</category>
        
        <category>lambdas</category>
        
        
        <category>Java</category>
        
      </item>
    
      <item>
        <title>From a JAR to a full-fledged MacOS app</title>
        <description>A couple of years ago, I developed a small Kotlin GUI to help me rename my files in batch. I actually created it with different JVM frameworks to compare their relative merits. In any case, I didn&amp;#8217;t use it up until last week. And then, I was surprised to see that it didn&amp;#8217;t work to rename a network volume, although it had in the past. In this brief post, I aim to describe the issue and its solution.   The problem   When launching the UberJAR, I couldn&amp;#8217;t see the network volumes.</description>
        <pubDate>Sun, 25 Jan 2026 00:00:00 +0000</pubDate>
        <link>https://blog.frankel.ch/jar-to-macos-app/</link>
        <guid isPermaLink="true">https://blog.frankel.ch/jar-to-macos-app/</guid>
        



        <media:content url="https://blog.frankel.ch/assets/resources/jar-to-macos-app/cover.jpg" width="1536" height="1024" />
        
        
        <category>jar</category>
        
        <category>macos</category>
        
        <category>app</category>
        
        
        <category>Java</category>
        
      </item>
    
  </channel>
</rss>
