<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Nicolas Frankel on foojay.io - Friends of OpenJDK</title><link>https://foojayio.github.io/website/today/author/nicolas-frankel/</link><description>Articles written by Nicolas Frankel on foojay.io - Friends of OpenJDK</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Thu, 05 Feb 2026 10:15:05 +0000</lastBuildDate><atom:link href="https://foojayio.github.io/website/today/author/nicolas-frankel/index.xml" rel="self" type="application/rss+xml"/><item><title>From a JAR to a full-fledged MacOS app</title><link>https://foojayio.github.io/website/today/from-a-jar-to-a-full-fledged-macos-app/</link><pubDate>Thu, 05 Feb 2026 10:15:05 +0000</pubDate><guid>https://foojayio.github.io/website/today/from-a-jar-to-a-full-fledged-macos-app/</guid><description>&lt;p&gt;A couple of years ago, I developed a small &lt;a href="https://blog.frankel.ch/state-jvm-desktop-frameworks/2/" target="_blank" rel="noopener noreferrer"&gt;Kotlin GUI&lt;/a&gt;
 to help me rename my files in batch. I actually created it with &lt;a href="https://blog.frankel.ch/focus/state-jvm-desktop-frameworks/" target="_blank" rel="noopener noreferrer"&gt;different JVM frameworks&lt;/a&gt;
 to compare their relative merits. In any case, I didn&amp;rsquo;t use it up until last week. And then, I was surprised to see that it didn&amp;rsquo;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.&lt;/p&gt;</description></item><item><title>Transactions and ThreadLocal in Spring</title><link>https://foojayio.github.io/website/today/transactions-and-threadlocal-in-spring/</link><pubDate>Tue, 21 Oct 2025 13:27:00 +0000</pubDate><guid>https://foojayio.github.io/website/today/transactions-and-threadlocal-in-spring/</guid><description>&lt;p&gt;Two years ago, my friend José Paumard held the talk &amp;ldquo;Concurrent and Asynchronous Programming : Loom&amp;rdquo; at the Geneva Java User Group.&lt;/p&gt;
&lt;p&gt;In his talk, he mentioned that the Spring team would need to completely redesign their approach to transactions: his reasoning was that the transactions are implemented on top of &lt;code&gt;ThreadLocal&lt;/code&gt; object and Loom&amp;rsquo;s virtual threads break this approach.&lt;/p&gt;
&lt;p&gt;I was intrigued because though I used Spring transactions a lot via the &lt;code&gt;@Transactional&lt;/code&gt; annotation, I never opened thought about looking at their implementation.&lt;/p&gt;</description></item><item><title>KCDC 2025</title><link>https://foojayio.github.io/website/today/kcdc-2025/</link><pubDate>Wed, 03 Sep 2025 17:38:36 +0000</pubDate><guid>https://foojayio.github.io/website/today/kcdc-2025/</guid><description>&lt;p&gt;When I first started attending conferences, I diligently tried to write down notes and publish them. It forced me to actively listen to the talks I was attending. With the number of conferences rising, I couldn&amp;rsquo;t keep the rhythm. When I switched my career path to Developer Advocate, I drastically diminished the number of talks I attended in favor of the hallway track. As a result, the last conference &amp;ldquo;report&amp;rdquo; I wrote was &lt;a href="https://blog.frankel.ch/jprime-2022/" target="_blank" rel="noopener noreferrer"&gt;JPrime&amp;rsquo;s&lt;/a&gt;
 in 2022.&lt;/p&gt;</description></item><item><title>GitHub workflows tips and tricks</title><link>https://foojayio.github.io/website/today/github-workflows-tips-and-tricks/</link><pubDate>Tue, 26 Aug 2025 12:06:00 +0000</pubDate><guid>https://foojayio.github.io/website/today/github-workflows-tips-and-tricks/</guid><description>&lt;p&gt;I&amp;rsquo;ve quite a lengthy experience with GitHub workflows, but not up to the point where I can claim I&amp;rsquo;m an expert. However, I recently developed a new workflow, and it prompted me to write this post. Feel free to add your own.&lt;/p&gt;
&lt;h2 id="h2-0-what-are-github-workflows"&gt;What are GitHub workflows?&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;workflow&lt;/strong&gt; is a configurable automated process that will run one or more jobs. Workflows are defined by a YAML file checked in to your repository and will run when triggered by an event in your repository, or they can be triggered manually or at a defined schedule.&lt;/p&gt;</description></item><item><title>Git default options</title><link>https://foojayio.github.io/website/today/git-default-options/</link><pubDate>Tue, 26 Aug 2025 11:59:57 +0000</pubDate><guid>https://foojayio.github.io/website/today/git-default-options/</guid><description>&lt;p&gt;Git has become a fundamental part of our developers&amp;rsquo; daily routine that it&amp;rsquo;s hard to remember our lives without it. And yet, most of us use a limited set of commands &lt;strong&gt;and&lt;/strong&gt; options. Today, I want to focus on two commands most developers probably use &lt;strong&gt;every&lt;/strong&gt; day and look at the defaults behind them.&lt;/p&gt;
&lt;h2 id="h2-0-git-push"&gt;git push&lt;/h2&gt;
&lt;p&gt;After &lt;code&gt;git commit&lt;/code&gt;, &lt;code&gt;git push&lt;/code&gt; is probably the second most used command. I don&amp;rsquo;t think I&amp;rsquo;ll teach you anything with this excerpt from the documentation:&lt;/p&gt;</description></item><item><title>OpenTelemetry configuration gotchas</title><link>https://foojayio.github.io/website/today/opentelemetry-configuration-gotchas/</link><pubDate>Sun, 17 Aug 2025 08:01:26 +0000</pubDate><guid>https://foojayio.github.io/website/today/opentelemetry-configuration-gotchas/</guid><description>&lt;p&gt;Last week, I described &lt;a href="https://blog.frankel.ch/opentelemetry-tracing-jvm/" target="_blank" rel="noopener noreferrer"&gt;several approaches to OpenTelemetry on the JVM&lt;/a&gt;
, their requirements, and their different results. This week, I want to highlight several gotchas found across stacks in the zero-code instrumentation.&lt;/p&gt;
&lt;h2 id="h2-0-the-promise-of-opentelemetry"&gt;The promise of OpenTelemetry&lt;/h2&gt;
&lt;p&gt;Since its inception, OpenTelemetry has unified the 3 pillars of observability. In the distributed tracing space, it replaced proprietary protocols Zipkin and Jaeger. IMHO, it achieved such success for several reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First, a huge industry pressure to work across proprietary tools&lt;/li&gt;
&lt;li&gt;Zero-code instrumentation, allowing developers to be unconcerned by OpenTelemetry&lt;/li&gt;
&lt;li&gt;Easy and unified configuration mechanism via environment variables.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The latter is a boon for the Ops team, as they don&amp;rsquo;t have to know the underlying framework (or stack!) details. They only need to check the &lt;a href="https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/" target="_blank" rel="noopener noreferrer"&gt;Environment Variable Specification&lt;/a&gt;
 and they are done.&lt;/p&gt;</description></item><item><title>OpenTelemetry Tracing on the JVM</title><link>https://foojayio.github.io/website/today/opentelemetry-tracing-on-the-jvm/</link><pubDate>Sun, 17 Aug 2025 08:00:39 +0000</pubDate><guid>https://foojayio.github.io/website/today/opentelemetry-tracing-on-the-jvm/</guid><description>&lt;p&gt;You may know I&amp;rsquo;m a big fan of OpenTelemetry. I recently finished developing a &lt;a href="https://yowcon.com/melbourne-2025/masterclasses/560/gain-practical-in-depth-experience-with-observability-using-opentelemetry" target="_blank" rel="noopener noreferrer"&gt;master class for the YOW! conference&lt;/a&gt;
 at the end of the year. During development, I noticed massive differences in configuration and results across programming languages. Even worse, differences exist across frameworks inside the same programming language.&lt;/p&gt;
&lt;p&gt;In this post, I want to compare the different zero-code OpenTelemetry approaches on the JVM, covering the most widespread:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spring Boot with Micrometer Tracing&lt;/li&gt;
&lt;li&gt;Spring Boot with the OpenTelemetry Agent&lt;/li&gt;
&lt;li&gt;OpenTelemetry Spring Boot Starter&lt;/li&gt;
&lt;li&gt;Quarkus&lt;/li&gt;
&lt;li&gt;Quarkus with the OpenTelemetry Agent&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="h2-0-commonalities"&gt;Commonalities&lt;/h2&gt;
&lt;p&gt;I keep the architecture pretty simple:&lt;/p&gt;</description></item><item><title>Pattern-matching across different languages</title><link>https://foojayio.github.io/website/today/pattern-matching-across-different-languages/</link><pubDate>Tue, 05 Aug 2025 07:40:40 +0000</pubDate><guid>https://foojayio.github.io/website/today/pattern-matching-across-different-languages/</guid><description>&lt;p&gt;Pattern matching is a major feature in software development. While pattern matching applies in several locations, its current usage is limited to &lt;code&gt;switch case&lt;/code&gt; blocks. I want to compare the power of pattern matching across a couple of programming languages I&amp;rsquo;m familiar with in this post.&lt;/p&gt;
&lt;p&gt;I assume that every reader is familiar with the &lt;code&gt;switch case&lt;/code&gt; syntax inherited from C. In short:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;switch&lt;/code&gt; clause references a value-returning statement&lt;/li&gt;
&lt;li&gt;Each &lt;code&gt;case&lt;/code&gt; clause sets another statement; if the value matches the statement, it executes the related block&lt;/li&gt;
&lt;li&gt;&lt;code&gt;case&lt;/code&gt; clauses are evaluated in order. The first clause that matches gets its block executed&lt;/li&gt;
&lt;li&gt;In C, &lt;code&gt;case&lt;/code&gt; clauses are fall-through; you need to explicitly &lt;code&gt;break&lt;/code&gt; to escape the &lt;code&gt;switch&lt;/code&gt;, otherwise, the next &lt;code&gt;case&lt;/code&gt; is evaluated&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="h2-0-java-s-pattern-matching"&gt;Java&amp;rsquo;s pattern matching&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll start with Java, as it was the first programming language I used in a professional context.&lt;/p&gt;</description></item><item><title>Testing an OpenRewrite Recipe</title><link>https://foojayio.github.io/website/today/testing-an-openrewrite-recipe/</link><pubDate>Mon, 14 Jul 2025 09:43:52 +0000</pubDate><guid>https://foojayio.github.io/website/today/testing-an-openrewrite-recipe/</guid><description>&lt;p&gt;For the last two weeks, I&amp;rsquo;ve kicked the tires of OpenRewrite.&lt;/p&gt;
&lt;p&gt;At first, I created a &lt;a href="https://blog.frankel.ch/openrewrite-recipes/1/" target="_blank" rel="noopener noreferrer"&gt;recipe to move Kotlin source files&lt;/a&gt;
 as per the official recommendations with a set package name.&lt;/p&gt;
&lt;p&gt;I then improved the &lt;a href="https://blog.frankel.ch/openrewrite-recipes/2/" target="_blank" rel="noopener noreferrer"&gt;recipe to compute the root automatically&lt;/a&gt;
. In both versions, I thoroughly tested the recipe.&lt;/p&gt;
&lt;p&gt;However, my testing approach was wrong. In this post, I want to describe my mistakes, and how I fixed them.&lt;/p&gt;</description></item><item><title>Book Review: Writing for Developers</title><link>https://foojayio.github.io/website/today/book-review-writing-for-developers/</link><pubDate>Wed, 18 Jun 2025 10:58:31 +0000</pubDate><guid>https://foojayio.github.io/website/today/book-review-writing-for-developers/</guid><description>&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: This post includes affiliate links; I may receive compensation if you purchase the book from the different links provided in this post.&lt;/p&gt;
&lt;p&gt;This review is about &lt;a href="https://www.manning.com/books/writing-for-developers?utm_source=frankel&amp;amp;amp;utm_medium=affiliate&amp;amp;amp;utm_campaign=affiliate&amp;amp;amp;a_aid=frankel" target="_blank" rel="noopener noreferrer"&gt;Writing for Developers&lt;/a&gt;
 by Piotr Sarna and Cynthia Dunlop from Manning.&lt;/p&gt;
&lt;p&gt;I started &lt;a href="https://blog.frankel.ch/" target="_blank" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;
 as a hobby seventeen years ago, in April 2008. At the time, I had no clue about technical writing. I&amp;rsquo;m pretty sure it was not even a thing back then: the only content aimed at developers was technical documentation. Since then, the landscape has changed a lot, to the point that companies hire for technical writer positions.&lt;/p&gt;</description></item><item><title>Authoring an OpenRewrite Recipe</title><link>https://foojayio.github.io/website/today/authoring-an-openrewrite-recipe/</link><pubDate>Mon, 09 Jun 2025 17:22:13 +0000</pubDate><guid>https://foojayio.github.io/website/today/authoring-an-openrewrite-recipe/</guid><description>&lt;p&gt;I&amp;rsquo;ve been eying OpenRewrite for some time, but I haven&amp;rsquo;t had time to play with it yet. In case you never heard about OpenRewrite, OpenRewrite takes care of refactoring your codebase to newer language, framework, and paradigm versions.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;OpenRewrite is an open-source automated refactoring ecosystem for source code, enabling developers to effectively eliminate technical debt within their repositories.&lt;/p&gt;
&lt;p&gt;It consists of an auto-refactoring engine that runs prepackaged, open-source refactoring recipes for common framework migrations, security fixes, and stylistic consistency tasks &amp;ndash; reducing your coding effort from hours or days to minutes. Build tool plugins like the OpenRewrite Gradle plugin and the OpenRewrite Maven plugin help you run these recipes on one repository at a time.&lt;/p&gt;</description></item><item><title>Cloudflare Tunnel for Home Assistant</title><link>https://foojayio.github.io/website/today/cloudflare-tunnel-for-home-assistant/</link><pubDate>Tue, 03 Jun 2025 11:29:18 +0000</pubDate><guid>https://foojayio.github.io/website/today/cloudflare-tunnel-for-home-assistant/</guid><description>&lt;p&gt;I continue to take care of my Home Assistant. This week, I replaced my original setup with &lt;a href="https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/" target="_blank" rel="noopener noreferrer"&gt;Cloudflare Tunnel&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;This is the 6^th^ post in the My journey with Home Assistant focus series. Other posts include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/home-assistant/1/" target="_blank" rel="noopener noreferrer"&gt;Why Home Assistant?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/home-assistant/2/" target="_blank" rel="noopener noreferrer"&gt;The Home Assistant model&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/home-assistant/3/" target="_blank" rel="noopener noreferrer"&gt;Replace Philips Hue automation with Home Assistant&amp;rsquo;s&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/home-assistant/4/" target="_blank" rel="noopener noreferrer"&gt;An example of HACS: Adaptive Lighting&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/home-assistant/5/" target="_blank" rel="noopener noreferrer"&gt;The Home Assistant companion app&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="h2-0-the-initial-setup"&gt;The initial setup&lt;/h2&gt;
&lt;p&gt;My usage of Home Assistant required external access from the beginning.&lt;/p&gt;</description></item><item><title>Getting a single value from a device's state in Home Assistant</title><link>https://foojayio.github.io/website/today/getting-a-single-value-from-a-devices-state-in-home-assistant/</link><pubDate>Sat, 31 May 2025 09:27:38 +0000</pubDate><guid>https://foojayio.github.io/website/today/getting-a-single-value-from-a-devices-state-in-home-assistant/</guid><description>&lt;p&gt;I recently acquired &lt;a href="https://www.netatmo.com/en-eu/additional-smart-radiator-valve" target="_blank" rel="noopener noreferrer"&gt;Netatmo smart radiator valves&lt;/a&gt;
 to manage my rooms&amp;rsquo; temperature remotely. I&amp;rsquo;m not skilled at manual tasks, but I could easily replace the old thermo-static valves. I then registered the smart ones in the Netatmo app. Finally, I integrated them in my Home Assistant via the dedicated &lt;a href="https://www.home-assistant.io/integrations/netatmo/" target="_blank" rel="noopener noreferrer"&gt;Netatmo integration&lt;/a&gt;
. Everything was very straightforward.&lt;/p&gt;
&lt;p&gt;I noticed that each valve not only allows remote control but also offers a state with several attributes. I wanted to extract the room&amp;rsquo;s temperature indicator from it. It was not as easy as I thought it was, so I want to describe how I managed to achieve it.&lt;/p&gt;</description></item><item><title>Improving Maven's dependency:analyze... or not</title><link>https://foojayio.github.io/website/today/improving-mavens-dependencyanalyze-or-not/</link><pubDate>Mon, 28 Apr 2025 08:28:32 +0000</pubDate><guid>https://foojayio.github.io/website/today/improving-mavens-dependencyanalyze-or-not/</guid><description>&lt;p&gt;Recently, my good friend Richard Fichtner advised using the &lt;code&gt;mvn dependency:analyze&lt;/code&gt; command to get rid of declared but unused dependencies:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is another use case for&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mvn dependency:analyze&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;It can show you the dependencies you use in your code but have not declared in your pom.xml. This works because you have a transitive dependency on your classpath. Either don&amp;rsquo;t use the dependency or declare it.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bsky.app/profile/did:plc:cc2k5egfzqpf3nbjrs5xox4r/post/3lcxfnsc2h62m?ref_src=embed" target="_blank" rel="noopener noreferrer"&gt;&lt;img src="https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:cc2k5egfzqpf3nbjrs5xox4r/bafkreibztkdlkhrkyydfdntdkktrdw7qqr4t54mbwoazf6rkulcawhqkj4@jpeg" alt="" loading="lazy"&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&amp;mdash; &lt;a href="https://bsky.app/profile/did:plc:cc2k5egfzqpf3nbjrs5xox4r?ref_src=embed" target="_blank" rel="noopener noreferrer"&gt;Richard Fichtner 💻☕ @richard.fichtner.dev&lt;/a&gt;
&lt;br&gt;
&lt;a href="https://bsky.app/profile/did:plc:cc2k5egfzqpf3nbjrs5xox4r/post/3lcxfnsc2h62m?ref_src=embed" target="_blank" rel="noopener noreferrer"&gt;December 10, 2024 at 2:00 PM&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Mutation Testing in Rust</title><link>https://foojayio.github.io/website/today/mutation-testing-in-rust/</link><pubDate>Wed, 09 Apr 2025 12:39:50 +0000</pubDate><guid>https://foojayio.github.io/website/today/mutation-testing-in-rust/</guid><description>&lt;p&gt;I&amp;rsquo;ve been a big fan of &lt;a href="https://en.wikipedia.org/wiki/Mutation_testing" target="_blank" rel="noopener noreferrer"&gt;Mutation Testing&lt;/a&gt;
 since I discovered &lt;a href="https://pitest.org/" target="_blank" rel="noopener noreferrer"&gt;PIT&lt;/a&gt;
. As I dive deeper into Rust, I wanted to check the state of mutation testing in Rust.&lt;/p&gt;
&lt;h2 id="h2-0-starting-with-cargo-mutants"&gt;Starting with &lt;code&gt;cargo-mutants&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;I found two crates for mutation testing in Rust:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mutants.rs/" target="_blank" rel="noopener noreferrer"&gt;cargo-mutants&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;and &lt;a href="https://github.com/llogiq/mutagen" target="_blank" rel="noopener noreferrer"&gt;mutagen&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;mutagen&lt;/code&gt; hasn&amp;rsquo;t been maintained for three years, while &lt;a href="https://github.com/sourcefrog/cargo-mutants" target="_blank" rel="noopener noreferrer"&gt;cargo-mutants&lt;/a&gt;
 is still under active development.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve ported the sample code from my previous Java code to Rust:&lt;/p&gt;</description></item><item><title>The try block in Rust</title><link>https://foojayio.github.io/website/today/the-try-block-in-rust/</link><pubDate>Wed, 09 Apr 2025 12:37:58 +0000</pubDate><guid>https://foojayio.github.io/website/today/the-try-block-in-rust/</guid><description>&lt;p&gt;I wrote previously about &lt;a href="https://blog.frankel.ch/error-management-rust-libs/" target="_blank" rel="noopener noreferrer"&gt;libs for error management in Rust&lt;/a&gt;
. This week, I want to write about the &lt;code&gt;try&lt;/code&gt; block, an experimental feature.&lt;/p&gt;
&lt;h2 id="h2-0-the-limit-of-the-operator"&gt;The limit of the &lt;code&gt;?&lt;/code&gt; operator&lt;/h2&gt;
&lt;p&gt;Please check the above article for a complete refresher on error management in general and the &lt;code&gt;?&lt;/code&gt; operator in particular. In short, &lt;code&gt;?&lt;/code&gt; allows to hook into a function call that returns a &lt;code&gt;Result&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the &lt;code&gt;Result&lt;/code&gt; contains a value, it continues normally&lt;/li&gt;
&lt;li&gt;If it contains an error, it short-circuits and returns the &lt;code&gt;Result&lt;/code&gt; to the calling function.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="EnlighterJSRAW" data-enlighter-language="rust"&gt;fn add(str1: &amp;amp;str, str2: &amp;amp;str) -&amp;gt; Result&amp;lt;i8, ParseIntError&amp;gt; {
 Ok(str1.parse::&amp;lt;i8&amp;gt;()? + str2.parse::&amp;lt;i8&amp;gt;()?)
}

fn main() {
 print!("{:?}", add("1", "2"));
 print!("{:?}", add("1", "a"));
}&lt;/pre&gt;
&lt;p&gt;The output is the following:&lt;/p&gt;</description></item><item><title>One giant Kubernetes cluster for everything</title><link>https://foojayio.github.io/website/today/one-giant-kubernetes-cluster-for-everything/</link><pubDate>Tue, 25 Mar 2025 10:33:50 +0000</pubDate><guid>https://foojayio.github.io/website/today/one-giant-kubernetes-cluster-for-everything/</guid><description>&lt;p&gt;The ideal size of your Kubernetes clusters is a day 0 question and demands a definite answer.&lt;/p&gt;
&lt;p&gt;You find one giant cluster on one end of the spectrum and many small-sized ones on the other, with every combination in between. This decision will impact your organization for years to come. Worse, if you decide to change your topology, you&amp;rsquo;re in for a time-wasting and expensive ride.&lt;/p&gt;
&lt;p&gt;I want to list each approach&amp;rsquo;s pros and cons in this post. Then, I&amp;rsquo;ll settle the discussion once and for all and argue why selecting the giant cluster option is better.&lt;/p&gt;</description></item><item><title>WebAssembly on Kubernetes</title><link>https://foojayio.github.io/website/today/webassembly-on-kubernetes/</link><pubDate>Tue, 25 Mar 2025 10:32:31 +0000</pubDate><guid>https://foojayio.github.io/website/today/webassembly-on-kubernetes/</guid><description>&lt;p&gt;Like a couple of innovative technologies, different people have different viewpoints on where WebAssembly fits the technology landscape.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;WebAssembly (also called Wasm) is certainly the subject of much hype right now. But what is it? Is it the JavaScript Killer? Is it a new programming language for the web? Is it (as we like to say) the next wave of cloud compute? We&amp;rsquo;ve heard it called many things: a better eBPF, the alternative to RISC V, a competitor to Java (or Flash), a performance booster for browsers, a replacement for Docker.&lt;/p&gt;</description></item><item><title>Pull request testing on Kubernetes: testing locally and on GitHub workflows</title><link>https://foojayio.github.io/website/today/pull-request-testing-on-kubernetes-testing-locally-and-on-github-workflows/</link><pubDate>Sun, 16 Mar 2025 17:32:27 +0000</pubDate><guid>https://foojayio.github.io/website/today/pull-request-testing-on-kubernetes-testing-locally-and-on-github-workflows/</guid><description>&lt;p&gt;Imagine an organization with the following practices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Commits code on GitHub&lt;/li&gt;
&lt;li&gt;Runs its CI/CD pipelines with GitHub Actions&lt;/li&gt;
&lt;li&gt;Runs its production workload on Kubernetes&lt;/li&gt;
&lt;li&gt;Uses Google Cloud&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A new engineer manager arrives and asks for the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;On every PR, run integration tests in a Kubernetes cluster similar to the production one.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It sounds reasonable.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Engineering manager: I want #integrationtests to run on the app deployed on #Cloud infra for each #GitHub PR ✅&lt;/p&gt;</description></item><item><title>Pull Request testing on Kubernetes: Working with GitHub Actions and GKE</title><link>https://foojayio.github.io/website/today/pull-request-testing-on-kubernetes-working-with-github-actions-and-gke/</link><pubDate>Sun, 16 Mar 2025 15:44:27 +0000</pubDate><guid>https://foojayio.github.io/website/today/pull-request-testing-on-kubernetes-working-with-github-actions-and-gke/</guid><description>&lt;p&gt;I&amp;rsquo;m continuing my series on running the test suite for each Pull Request on Kubernetes. In the &lt;a href="https://blog.frankel.ch/pr-testing-kubernetes/1/" target="_blank" rel="noopener noreferrer"&gt;previous post&lt;/a&gt;
, I laid the groundwork for our learning journey: I developed a basic JVM-based CRUD app, tested it locally using Testcontainers, and tested it in a GitHub workflow with a GitHub service container.&lt;/p&gt;
&lt;p&gt;This week, I will raise the ante to run the end-to-end test in the target Kubernetes environment. For this, I&amp;rsquo;ve identified gaps that I&amp;rsquo;ll implement in this blog post:&lt;/p&gt;</description></item><item><title>Pull request testing on Kubernetes: vCluster for isolation and costs control</title><link>https://foojayio.github.io/website/today/pull-request-testing-on-kubernetes-vcluster-for-isolation-and-costs-control/</link><pubDate>Sun, 16 Mar 2025 11:47:20 +0000</pubDate><guid>https://foojayio.github.io/website/today/pull-request-testing-on-kubernetes-vcluster-for-isolation-and-costs-control/</guid><description>&lt;p&gt;This week&amp;rsquo;s article is the third and final in my series about running tests on Kubernetes for each pull request. In the &lt;a href="https://blog.frankel.ch/pr-testing-kubernetes/1/" target="_blank" rel="noopener noreferrer"&gt;first post&lt;/a&gt;
, I described the app and how to test locally using Testcontainers and in a GitHub workflow. The &lt;a href="https://blog.frankel.ch/pr-testing-kubernetes/2/" target="_blank" rel="noopener noreferrer"&gt;second post&lt;/a&gt;
 focused on setting up the target environment and running end-to-end tests on Kubernetes.&lt;/p&gt;
&lt;p&gt;I concluded the latter by mentioning a significant quandary. Creating a dedicated cluster for each workflow significantly impacts the time it takes to run. On , it took between 5 and 7 minutes to spin off a new cluster. If you create a GKE instance upstream, you face two issues:&lt;/p&gt;</description></item><item><title>Book Review: DuckDB in Action</title><link>https://foojayio.github.io/website/today/book-review-duckdb-in-action/</link><pubDate>Wed, 05 Mar 2025 13:42:59 +0000</pubDate><guid>https://foojayio.github.io/website/today/book-review-duckdb-in-action/</guid><description>&lt;p&gt;Disclaimer: this post includes affiliate links; I may receive compensation if you purchase the book from the different links provided in this post.&lt;/p&gt;
&lt;p&gt;This review is about &lt;a href="https://www.manning.com/books/duckdb-in-action?utm_source=frankel&amp;amp;amp;utm_medium=affiliate&amp;amp;amp;utm_campaign=affiliate&amp;amp;amp;a_aid=frankel" target="_blank" rel="noopener noreferrer"&gt;DuckDB in Action&lt;/a&gt;
 by JoMark Needham, Michael Hunger, and Michael Simons from Manning.&lt;/p&gt;
&lt;p&gt;The book was sent to me by &lt;a href="https://mastodon.social/@rotnroll666" target="_blank" rel="noopener noreferrer"&gt;Michael Simons&lt;/a&gt;
. He asked for my feedback: I changed my reading schedule, took a few months, and here it is.&lt;/p&gt;
&lt;h2 id="h2-0-facts"&gt;Facts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;10 chapters&lt;/li&gt;
&lt;li&gt;288 pages&lt;/li&gt;
&lt;li&gt;$33.59 (eBook)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that MotherDuck, the company behind DuckDB, offers a &lt;a href="https://motherduck.com/duckdb-book-brief/" target="_blank" rel="noopener noreferrer"&gt;free PDF copy&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Remote Development Made Simple with DevPod</title><link>https://foojayio.github.io/website/today/remote-development-made-simple-with-devpod/</link><pubDate>Thu, 13 Feb 2025 16:06:30 +0000</pubDate><guid>https://foojayio.github.io/website/today/remote-development-made-simple-with-devpod/</guid><description>&lt;p&gt;&lt;strong&gt;I come relatively late to the subject of Remote Development Environments (also known as Cloud Development Environments).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main reason is that I haven&amp;rsquo;t worked in a development team for over six years. However, I&amp;rsquo;m now working for Loft Labs, and we have a product: &lt;a href="https://devpod.sh/" target="_blank" rel="noopener noreferrer"&gt;DevPod&lt;/a&gt;
. I wanted to understand our value proposition as was on my way to &lt;a href="https://fosdem.org/" target="_blank" rel="noopener noreferrer"&gt;FOSDEM&lt;/a&gt;
 operating the &lt;a href="https://fosdem.org/2025/news/2024-11-16-stands-announced/" target="_blank" rel="noopener noreferrer"&gt;DevPod booth&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="h2-0-the-problem"&gt;The problem&lt;/h2&gt;
&lt;p&gt;As a former developer, I vividly remember the pain of setting up each developer&amp;rsquo;s development environment. At the beginning of my career, the architect had to configure my development machine painfully, so it was similar to his setup. Later on, I did the same for my team members repeatedly. The scope of possible discrepancies impacting development is virtually endless: Operating System, of course, version &lt;strong&gt;and&lt;/strong&gt; flavour of the SDKs, &lt;em&gt;e.g.&lt;/em&gt;, Java&amp;rsquo;s Eclipse Temurin vs SapMachine, git hooks, etc. It was sweat, toil, and blood on every project.&lt;/p&gt;</description></item><item><title>My first steps with Playwright</title><link>https://foojayio.github.io/website/today/my-first-steps-with-playwright/</link><pubDate>Thu, 30 Jan 2025 11:58:04 +0000</pubDate><guid>https://foojayio.github.io/website/today/my-first-steps-with-playwright/</guid><description>&lt;p&gt;&lt;strong&gt;In my previous company, I developed a batch job that tracked metrics across social media, such as Twitter, LinkedIn, Mastodon, Bluesky, Reddit, etc. Then I realized I could duplicate it for my own &amp;ldquo;persona&amp;rdquo;. The problem is that some media don&amp;rsquo;t provide an HTTP API for the metrics I want.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are &lt;a href="https://www.linkedin.com/dashboard/" target="_blank" rel="noopener noreferrer"&gt;the metrics&lt;/a&gt;
 I want on LinkedIn:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://foojayio.github.io/website/today/my-first-steps-with-playwright/linkedin-dashboard.jpg" alt="LinkedIn metrics dashboard" loading="lazy"&gt;
&lt;/p&gt;
&lt;p&gt;I searched for a long time but found no API access for the metrics above. I scraped the metrics manually every morning for a long time and finally decided to automate this tedious task. Here&amp;rsquo;s what I learned.&lt;/p&gt;</description></item><item><title>A solution to the problem of cluster-wide CRDs</title><link>https://foojayio.github.io/website/today/a-solution-to-the-problem-of-cluster-wide-crds/</link><pubDate>Thu, 30 Jan 2025 11:55:14 +0000</pubDate><guid>https://foojayio.github.io/website/today/a-solution-to-the-problem-of-cluster-wide-crds/</guid><description>&lt;p&gt;&lt;strong&gt;I&amp;rsquo;m an average Reddit user, scrolling much more than reading or interacting. Sometimes, however, a post rings a giant red bell. When I stumbled upon &lt;a href="https://www.reddit.com/r/kubernetes/comments/1ga0deo/comment/lta8itb/?context=3&amp;amp;amp;share_id=ZS15DmQexSXUjhXuqQ81z" target="_blank" rel="noopener noreferrer"&gt;If you could add one feature to K8s, what would it be?&lt;/a&gt;
, I knew the content would be worth it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The most voted answer is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Namespace scoped CRDs&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="h2-0-a-short-intro-to-crds"&gt;A short intro to CRDs&lt;/h2&gt;
&lt;p&gt;Kubernetes comes packed with existing objects, such as &lt;code&gt;Pod&lt;/code&gt;, &lt;code&gt;Service&lt;/code&gt;, &lt;code&gt;DaemonSet&lt;/code&gt;, etc., but you can create your own: the latter are called Custom Resource Definitions. Most of the time, s are paired with a custom controller called an &lt;em&gt;operator&lt;/em&gt;. An operator subscribes to the lifecycle events of CRD(s). When you act upon a CRD by creating, updating, or deleting it, Kubernetes changes its status, and the operator gets notified. What it does depends on the nature of the CRD.&lt;/p&gt;</description></item><item><title>An Example of HACS: Adaptive Lighting</title><link>https://foojayio.github.io/website/today/an-example-of-hacs-adaptive-lighting/</link><pubDate>Wed, 15 Jan 2025 08:40:46 +0000</pubDate><guid>https://foojayio.github.io/website/today/an-example-of-hacs-adaptive-lighting/</guid><description>&lt;p&gt;&lt;strong&gt;In the &lt;a href="https://blog.frankel.ch/home-assistant/3/" target="_blank" rel="noopener noreferrer"&gt;previous post&lt;/a&gt;
 of this focus, we replaced Philips Hue automation with the one from Home Assistant. One significant gap we noticed was that Home Assistant doesn&amp;rsquo;t automatically adjust the brightness according to the time of the day, a feature Philips Hue offers. In this post, we are going to address this gap.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first step when wanting to add a feature to Home Assistant is to browse through available integrations. While there was no out-of-the-box integration, I discovered an alternative: HACS.&lt;/p&gt;</description></item><item><title>2024 in Retrospective: Nicolas Frankel</title><link>https://foojayio.github.io/website/today/2024-in-retrospective-nicolas-frankel/</link><pubDate>Mon, 06 Jan 2025 08:59:26 +0000</pubDate><guid>https://foojayio.github.io/website/today/2024-in-retrospective-nicolas-frankel/</guid><description>&lt;p&gt;For the first article of 2025, I&amp;rsquo;m continuing my retrospective series!&lt;/p&gt;
&lt;p&gt;As last year, before diving in into the report proper, I&amp;rsquo;d like to remind you that Ukraine is still fighting for its survival after nearly 3 years and countless Russian war crimes. The civilized world can&amp;rsquo;t allow rewarding the invasion of a sovereign country, lest we see more invasions. Remember that in 1938, in Munich, European &amp;ldquo;leaders&amp;rdquo; acknowledged Hitler&amp;rsquo;s annexation of Czechoslovakia&amp;rsquo;s Sudetenland. It didn&amp;rsquo;t prevent Nazi Germany to invade the rest of Europe a year later; worse, it emboldened it!&lt;/p&gt;</description></item><item><title>The Home Assistant Model</title><link>https://foojayio.github.io/website/today/the-home-assistant-model/</link><pubDate>Mon, 09 Dec 2024 15:58:27 +0000</pubDate><guid>https://foojayio.github.io/website/today/the-home-assistant-model/</guid><description>&lt;p&gt;Home Assistant (&lt;a href="https://www.home-assistant.io/" target="_blank" rel="noopener noreferrer"&gt;home-assistant.io&lt;/a&gt;
) is a massive beast. It can be overwhelming for a newcomer; it was for me.&lt;/p&gt;
&lt;p&gt;In this article, I want to describe the underlying model of Home Assistant, which is a good entry point for your home automation journey.&lt;/p&gt;
&lt;p&gt;The biggest issue in describing the Home Assistant is the number of conflicting sources for this model:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;helpers&lt;/code&gt; package of the &lt;a href="https://github.com/home-assistant/core/tree/dev/homeassistant/helpers" target="_blank" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The database; disclaimer: I didn&amp;rsquo;t find the schema generation in the code, and I wasn&amp;rsquo;t bold enough to check the deployed SQLite database&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://www.home-assistant.io/getting-started/concepts-terminology/" target="_blank" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The web interface&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As far as I understand it, here&amp;rsquo;s the conceptual model.&lt;/p&gt;</description></item><item><title>Why Home Assistant</title><link>https://foojayio.github.io/website/today/why-home-assistant/</link><pubDate>Mon, 09 Dec 2024 15:54:20 +0000</pubDate><guid>https://foojayio.github.io/website/today/why-home-assistant/</guid><description>&lt;p&gt;&lt;strong&gt;Last June, I spoke at &lt;a href="https://program.berlinbuzzwords.de/bbuzz24/talk/HMQMDH/" target="_blank" rel="noopener noreferrer"&gt;Berlin Buzzwords&lt;/a&gt;
. In all honesty, I rarely attend others&amp;rsquo; talks for a variety of reasons: lack of time, lack of energy, no interest in the proposed subjects, etc. When I do, I go either for subjects I know and want to deepen my understanding of &lt;em&gt;or&lt;/em&gt; for subjects I know nothing about to get a foot in the door.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This time, I attended &lt;a href="https://program.berlinbuzzwords.de/bbuzz24/talk/BQTZHK/" target="_blank" rel="noopener noreferrer"&gt;Monitoring your home, with DevOps observability tools&lt;/a&gt;
. I thought it would be about OpenTelemetry for your home. After the speaker mentioned &lt;a href="https://www.home-assistant.io/" target="_blank" rel="noopener noreferrer"&gt;Home Assistant&lt;/a&gt;
 (&lt;a href="https://www.home-assistant.io/" target="_blank" rel="noopener noreferrer"&gt;home-assistant.io&lt;/a&gt;
), however, I didn&amp;rsquo;t pay much attention to the rest.&lt;/p&gt;</description></item><item><title>Langchain4J Musings</title><link>https://foojayio.github.io/website/today/langchain4j-musings/</link><pubDate>Sat, 23 Nov 2024 13:57:30 +0000</pubDate><guid>https://foojayio.github.io/website/today/langchain4j-musings/</guid><description>&lt;p&gt;I&amp;rsquo;m coming relatively late to the LLM party, but I rarely come very early in the hype cycle.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://upload.wikimedia.org/wikipedia/commons/9/94/Gartner_Hype_Cycle.svg" alt="Gartner hype cycle" loading="lazy"&gt;
&lt;/p&gt;
&lt;p&gt;For example, I never bought into blockchain, the solution still searching for problems to solve, nor in microservices, the latest in the cargo cult IT trends. Despite my late arrival at the LLM party, I have been a regular user of LLMs. I use OpenAI for non-controversial questions outside my cone of knowledge, &lt;em&gt;e.g&lt;/em&gt;., linguistics or legal; I use GitHub Copilot in my IDE to improve my code.&lt;/p&gt;</description></item><item><title>Summary of the AJAX Frameworks Comparison</title><link>https://foojayio.github.io/website/today/summary-of-the-ajax-frameworks-comparison/</link><pubDate>Thu, 14 Nov 2024 11:35:50 +0000</pubDate><guid>https://foojayio.github.io/website/today/summary-of-the-ajax-frameworks-comparison/</guid><description>&lt;p&gt;In previous weeks, I&amp;rsquo;ve analyzed several libraries and frameworks that augment the client with AJAX capabilities.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/ajax-ssr/3/" target="_blank" rel="noopener noreferrer"&gt;Vue.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/ajax-ssr/4/" target="_blank" rel="noopener noreferrer"&gt;Alpine.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/ajax-ssr/5/" target="_blank" rel="noopener noreferrer"&gt;HTMX&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/ajax-ssr/6/" target="_blank" rel="noopener noreferrer"&gt;Vaadin&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this post, I&amp;rsquo;ll compare them across several axes.&lt;/p&gt;
&lt;h2 id="h2-0-analysis"&gt;Analysis&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Frontend skills:Remember that I started this series from the point of view of a backend developer. In this section, I grade how much you need to know about client technologies to complete the job.&lt;/li&gt;
&lt;li&gt;Team organization:In the introduction, I hinted that the decoupling of frontend and backend teams profoundly impacted projects. Each team is fast on its own, and they can parallelize their work, but integrating the two can double the initial development time. Here, I grade how easy it is to integrate frontend and backend.&lt;/li&gt;
&lt;li&gt;Ease of setup:How easy it is to set up the tool from the backend.&lt;/li&gt;
&lt;li&gt;Ease of styling:Backend developers are not designers by default. Does the tool offer a default, at least average-looking style? How hard is it to create one?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For all intents and purposes, Vue.js and Alpine.js are similar; I&amp;rsquo;ll refer to them as JavaScript frameworks.&lt;/p&gt;</description></item><item><title>Vaadin: Battery-Included Server-Side AJAX Framework</title><link>https://foojayio.github.io/website/today/vaadin-battery-included-server-side-ajax-framework/</link><pubDate>Tue, 22 Oct 2024 09:39:11 +0000</pubDate><guid>https://foojayio.github.io/website/today/vaadin-battery-included-server-side-ajax-framework/</guid><description>&lt;p&gt;&lt;strong&gt;I&amp;rsquo;ve written a lot about &lt;a href="https://vaadin.com/" target="_blank" rel="noopener noreferrer"&gt;Vaadin&lt;/a&gt;
. I was so enthusiastic that I wrote the &lt;a href="https://www.amazon.fr/Learning-Vaadin-Nicolas-Frankel/dp/1849515220" target="_blank" rel="noopener noreferrer"&gt;first book&lt;/a&gt;
 about it (besides the Book of Vaadin), its &lt;a href="https://www.amazon.fr/Learning-Vaadin-Second-Nicolas-Frankel/dp/1782169776" target="_blank" rel="noopener noreferrer"&gt;updated edition&lt;/a&gt;
 for Vaadin 7, and a &lt;a href="https://morevaadin.com/" target="_blank" rel="noopener noreferrer"&gt;companion website&lt;/a&gt;
. Still, I&amp;rsquo;m amazed that so many people in the JVM world never heard of it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this article, I&amp;rsquo;d like to introduce Vaadin in the context of AJAX and SSR.&lt;/p&gt;
&lt;h2 id="h2-0-short-introduction-to-vaadin"&gt;Short introduction to Vaadin&lt;/h2&gt;
&lt;p&gt;The beauty of Vaadin lies in its simplicity - &lt;strong&gt;you only write backend code&lt;/strong&gt; . You read that well. A Vaadin developer only needs to know Java, or any JVM language, and the Vaadin API. At runtime, Vaadin will create the client-side code, &lt;em&gt;i.e.&lt;/em&gt;, HTML, JavaScript and CSS. This approach empowers developers to focus on the application&amp;rsquo;s core functionality, making the development process more productive.&lt;/p&gt;</description></item><item><title>Augmenting the client with HTMX</title><link>https://foojayio.github.io/website/today/augmenting-the-client-with-htmx/</link><pubDate>Mon, 14 Oct 2024 12:37:39 +0000</pubDate><guid>https://foojayio.github.io/website/today/augmenting-the-client-with-htmx/</guid><description>&lt;p&gt;This article is part of a series comparing different ways to implement asynchronous requests on the client to augment the latter. So far, I described the process with &lt;a href="https://foojayio.github.io/website/today/augmenting-the-client-with-vue-js/"&gt;Vue.js&lt;/a&gt;
 and &lt;a href="https://foojayio.github.io/website/today/augmenting-the-client-with-alpine-js/"&gt;Alpine.js&lt;/a&gt;
. Both are similar from the developers&amp;rsquo; point of view: they involve JavaScript.&lt;/p&gt;
&lt;p&gt;In this post, I&amp;rsquo;ll focus on &lt;a href="https://htmx.org/" target="_blank" rel="noopener noreferrer"&gt;HTMX&lt;/a&gt;
, whose approach is quite different.&lt;/p&gt;
&lt;h2 id="h2-0-laying-out-the-work"&gt;Laying out the work&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll follow the same structure as in the previous posts of the series. Here&amp;rsquo;s the setup, server- and client-side.&lt;/p&gt;</description></item><item><title>Augmenting the client with Alpine.js</title><link>https://foojayio.github.io/website/today/augmenting-the-client-with-alpine-js/</link><pubDate>Mon, 14 Oct 2024 10:59:44 +0000</pubDate><guid>https://foojayio.github.io/website/today/augmenting-the-client-with-alpine-js/</guid><description>&lt;p&gt;This article is part of a series comparing different ways to implement asynchronous requests on the client, which is colloquially known as AJAX. I dedicated the &lt;a href="https://foojayio.github.io/website/today/augmenting-the-client-with-vue-js/"&gt;previous post&lt;/a&gt;
 to Vue.js; I&amp;rsquo;ll dedicate this one to &lt;a href="https://alpinejs.dev/" target="_blank" rel="noopener noreferrer"&gt;Alpine.js&lt;/a&gt;
 - not to be confused with Alpine Linux.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll follow the same structure as previously.&lt;/p&gt;
&lt;h2 id="h2-0-laying-out-the-work"&gt;Laying out the work&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the setup, server- and client-side.&lt;/p&gt;
&lt;h3 id="h3-1-server-side"&gt;Server-side&lt;/h3&gt;
&lt;p&gt;Here is how I integrate Thymeleaf and Alpine.js in the POM:&lt;/p&gt;</description></item><item><title>Augmenting the client with Vue.js</title><link>https://foojayio.github.io/website/today/augmenting-the-client-with-vue-js/</link><pubDate>Mon, 14 Oct 2024 10:53:42 +0000</pubDate><guid>https://foojayio.github.io/website/today/augmenting-the-client-with-vue-js/</guid><description>&lt;p&gt;In my &lt;a href="https://foojayio.github.io/website/today/a-short-history-of-ajax-and-ssr/"&gt;previous article&lt;/a&gt;
, I laid the ground to build upon; now is the time to start &amp;ldquo;for real&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;I heard a lot of &lt;a href="https://vuejs.org/" target="_blank" rel="noopener noreferrer"&gt;Vue.js&lt;/a&gt;
. Additionally, a friend who transitioned from developer to manager told me good things about Vue, which further piqued my interest. I decided to have a look at it: it will be the first &amp;ldquo;lightweight&amp;rdquo; JavaScript framework I&amp;rsquo;ll study - from the point of view of a newbie, which I am.&lt;/p&gt;</description></item><item><title>Server-Side Rendering with Spring Boot</title><link>https://foojayio.github.io/website/today/server-side-rendering-with-spring-boot/</link><pubDate>Mon, 23 Sep 2024 06:58:41 +0000</pubDate><guid>https://foojayio.github.io/website/today/server-side-rendering-with-spring-boot/</guid><description>&lt;p&gt;Understanding the shared steps in the project setup is crucial before delving into the specifics of each client-augmenting technology. My requirements &lt;a href="https://blog.frankel.ch/ajax-ssr/1/" target="_blank" rel="noopener noreferrer"&gt;from the last post&lt;/a&gt;
 where quite straightforward:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;I&amp;rsquo;ll assume the viewpoint of a backend developer&lt;/li&gt;
&lt;li&gt;No front-end build step: no TypeScript, no minification, etc.&lt;/li&gt;
&lt;li&gt;All dependencies are managed from the backend app, &lt;em&gt;i.e.&lt;/em&gt;, Maven&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&amp;rsquo;s important to note that the technology I&amp;rsquo;ll be detailing, except Vaadin, follows a similar approach. Vaadin, with its unique paradigm, really stands out among the approaches.&lt;/p&gt;</description></item><item><title>A Short History of AJAX and SSR</title><link>https://foojayio.github.io/website/today/a-short-history-of-ajax-and-ssr/</link><pubDate>Mon, 23 Sep 2024 06:57:01 +0000</pubDate><guid>https://foojayio.github.io/website/today/a-short-history-of-ajax-and-ssr/</guid><description>&lt;p&gt;&lt;strong&gt;My journey in programming began over two decades ago, a time when JavaScript was a far cry from its current state, and developers were primarily focused on Microsoft Internet Explorer. One of my proudest achievements back then was writing a few lines of code that allowed users to add and remove table rows entirely on the client side. We called it . Many developers today have forgotten about it&amp;mdash;or never knew it existed.&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Health Check Response Format for HTTP APIs</title><link>https://foojayio.github.io/website/today/health-check-response-format-for-http-apis/</link><pubDate>Thu, 12 Sep 2024 10:02:32 +0000</pubDate><guid>https://foojayio.github.io/website/today/health-check-response-format-for-http-apis/</guid><description>&lt;p&gt;I&amp;rsquo;m continuing my journey on getting more familiar with HTTP APIs by reading related . This time, I read the &lt;a href="https://datatracker.ietf.org/doc/html/draft-inadarei-api-health-check" target="_blank" rel="noopener noreferrer"&gt;Health Check Response Format for HTTP APIs&lt;/a&gt;
 on the suggestion of &lt;a href="https://twitter.com/stefanofago/" target="_blank" rel="noopener noreferrer"&gt;Stefano Fago&lt;/a&gt;
. In this article, I&amp;rsquo;d like to summarize my reading.&lt;/p&gt;
&lt;p&gt;Note that it&amp;rsquo;s a draft. Moreover, it has been dormant for nearly two years and, thus, has been automatically expired. However, it&amp;rsquo;s the closest to a specification on health checks and thus deserves some love.&lt;/p&gt;</description></item><item><title>DRY your Apache APISIX config</title><link>https://foojayio.github.io/website/today/dry-your-apache-apisix-config/</link><pubDate>Thu, 12 Sep 2024 09:59:44 +0000</pubDate><guid>https://foojayio.github.io/website/today/dry-your-apache-apisix-config/</guid><description>&lt;p&gt;is an important principle in software development. In this article, you learn how to apply it to Apache APISIX configuration.&lt;/p&gt;
&lt;h2 id="h2-0-the-dry-principle"&gt;The DRY principle&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Don&amp;rsquo;t repeat yourself&amp;rdquo; (DRY) is a principle of software development aimed at reducing repetition of information which is likely to change, replacing it with abstractions that are less likely to change, or using data normalization which avoids redundancy in the first place.&lt;/p&gt;
&lt;p&gt;&amp;ndash; &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" target="_blank" rel="noopener noreferrer"&gt;Wikipedia - Don&amp;rsquo;t repeat yourself&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Implementing the Idempotency-Key specification on Apache APISIX</title><link>https://foojayio.github.io/website/today/implementing-the-idempotency-key-specification-on-apache-apisix/</link><pubDate>Mon, 02 Sep 2024 20:58:24 +0000</pubDate><guid>https://foojayio.github.io/website/today/implementing-the-idempotency-key-specification-on-apache-apisix/</guid><description>&lt;p&gt;&lt;strong&gt;Recently, I wrote an &lt;a href="https://blog.frankel.ch/fix-duplicate-api-requests/" target="_blank" rel="noopener noreferrer"&gt;analysis&lt;/a&gt;
 of the &lt;a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-idempotency-key-header-04" target="_blank" rel="noopener noreferrer"&gt;IETF Idempotency-Key specification&lt;/a&gt;
. The specification aims to avoid duplicated requests.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In short, the idea is for the client to send a unique key along with the request:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the server doesn&amp;rsquo;t know the key, it proceeds as usual and then stores the response&lt;/li&gt;
&lt;li&gt;If the server knows the key, it short-circuits any further processing and immediately returns the stored response&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This post shows how to implement it with &lt;a href="https://apisix.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>When (not) to write an Apache APISIX plugin</title><link>https://foojayio.github.io/website/today/when-not-to-write-an-apache-apisix-plugin/</link><pubDate>Mon, 02 Sep 2024 20:50:43 +0000</pubDate><guid>https://foojayio.github.io/website/today/when-not-to-write-an-apache-apisix-plugin/</guid><description>&lt;p&gt;&lt;strong&gt;When I introduce Apache APISIX in my talks, I mention the &lt;a href="https://apisix.apache.org/plugins/" target="_blank" rel="noopener noreferrer"&gt;massive number of existing plugins&lt;/a&gt;
, and that each of them implements a specific feature.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One of the key features of Apache APISIX is its flexibility. If a feature is missing, you can create your own plugin in Lua or a language compiled into Wasm, showcasing the platform&amp;rsquo;s adaptability to your specific needs.&lt;/p&gt;
&lt;p&gt;In this article, I aim to provide practical alternatives to writing a custom plugin, offering solutions you can quickly implement in your projects.&lt;/p&gt;</description></item><item><title>OpenTelemetry Tracing on Spring Boot, Java Agent vs. Micrometer Tracing</title><link>https://foojayio.github.io/website/today/opentelemetry-tracing-on-spring-boot-java-agent-vs-micrometer-tracing/</link><pubDate>Thu, 22 Aug 2024 08:34:57 +0000</pubDate><guid>https://foojayio.github.io/website/today/opentelemetry-tracing-on-spring-boot-java-agent-vs-micrometer-tracing/</guid><description>&lt;p&gt;&lt;strong&gt;My &lt;a href="https://github.com/nfrankel/opentelemetry-tracing" target="_blank" rel="noopener noreferrer"&gt;demo&lt;/a&gt;
 of OpenTelemetry Tracing features two Spring Boot components. One uses the Java agent, and I noticed a different behavior when I recently upgraded it from v1.x to v2.x. In the other one, I&amp;rsquo;m using Micrometer Tracing because I compile to GraalVM native, and it can&amp;rsquo;t process Java agents.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I want to compare these three different ways in this post: Java agent v1, Java agent v2, and Micrometer Tracing.&lt;/p&gt;</description></item><item><title>Free tier API with Apache APISIX</title><link>https://foojayio.github.io/website/today/free-tier-api-with-apache-apisix/</link><pubDate>Mon, 05 Aug 2024 13:50:08 +0000</pubDate><guid>https://foojayio.github.io/website/today/free-tier-api-with-apache-apisix/</guid><description>&lt;p&gt;&lt;strong&gt;Lots of service providers offer a free tier of their service. The idea is to let you kick their service&amp;rsquo;s tires freely. If you need to go above the free tier at any point, you&amp;rsquo;ll likely stay on the service and pay.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this day and age, most services are online and accessible via an API. Today, we will implement a free tier with &lt;a href="https://apisix.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="h2-0-a-naive-approach"&gt;A naive approach&lt;/h2&gt;
&lt;p&gt;I implemented a free tier in my post &lt;a href="https://blog.frankel.ch/evolve-apis/#know-your-users" target="_blank" rel="noopener noreferrer"&gt;Evolving your RESTful APIs, a step-by-step approach&lt;/a&gt;
, albeit in a very naive way. I copy-pasted the &lt;a href="https://apisix.apache.org/docs/apisix/plugins/limit-count/" target="_blank" rel="noopener noreferrer"&gt;limit-count&lt;/a&gt;
 plugin and added my required logic.&lt;/p&gt;</description></item><item><title>Differentiating rate limits in Apache APISIX</title><link>https://foojayio.github.io/website/today/differentiating-rate-limits-in-apache-apisix/</link><pubDate>Mon, 05 Aug 2024 13:37:40 +0000</pubDate><guid>https://foojayio.github.io/website/today/differentiating-rate-limits-in-apache-apisix/</guid><description>&lt;p&gt;&lt;strong&gt;In my talk Evolving your APIs, I mention that an API Gateways is a Reverse Proxy &amp;ldquo;on steroids&amp;rdquo;. One key difference between the former and the latter is that the API Gateway is not unfriendly to business logic. The poster child is rate-limiting.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Rate-limiting is an age-old Reverse Proxy feature focused on protecting against attacks. It treats all clients the same and is purely technical. In this day and age, most API providers offer different subscription tiers; the higher the tier, the higher the rate limit, and the more you pay incidentally. It&amp;rsquo;s not technical anymore and requires to differentiate between clients.&lt;/p&gt;</description></item><item><title>Random and fixed routes with Apache APISIX</title><link>https://foojayio.github.io/website/today/random-and-fixed-routes-with-apache-apisix/</link><pubDate>Mon, 05 Aug 2024 13:29:59 +0000</pubDate><guid>https://foojayio.github.io/website/today/random-and-fixed-routes-with-apache-apisix/</guid><description>&lt;p&gt;&lt;strong&gt;My ideas for blog posts inevitably start to dry up after over two years at &lt;a href="https://apisix.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;
.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hence, I did some triage on the &lt;a href="https://github.com/apache/apisix/issues" target="_blank" rel="noopener noreferrer"&gt;APISIX repo&lt;/a&gt;
. I stumbled upon this one question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We have a requirement to use a plugin, where we need to route the traffic on percentage basis. I&amp;rsquo;ll give an example for better understanding.&lt;/p&gt;
&lt;p&gt;We have an URL where ca is country (Canada) and fr is french language. Now the traffic needs to routed 10% to and the remaining 90% to. And whenever we&amp;rsquo;re routing the traffic to we need to set a cookie. So for next call, if the cookie is there, it should directly go to else it should go via a 10:90 traffic split. What is the best possible way to achieve this ??&lt;/p&gt;</description></item><item><title>Advanced URL Rewriting with Apache APISIX</title><link>https://foojayio.github.io/website/today/advanced-url-rewriting-with-apache-apisix/</link><pubDate>Thu, 25 Jul 2024 09:10:06 +0000</pubDate><guid>https://foojayio.github.io/website/today/advanced-url-rewriting-with-apache-apisix/</guid><description>&lt;p&gt;&lt;strong&gt;I spoke at &lt;a href="https://www.pgday.ch/2024/#schedule" target="_blank" rel="noopener noreferrer"&gt;Swiss PgDay&lt;/a&gt;
 in Switzerland in late June. The talk was about how to create a no-code API with the famous &lt;a href="https://www.postgresql.org/" target="_blank" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt;
 database, the related &lt;a href="https://postgrest.org/" target="_blank" rel="noopener noreferrer"&gt;PostgREST&lt;/a&gt;
, and &lt;a href="https://apisix.apache.org" target="_blank" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;
, of course. I already wrote about the idea in a &lt;a href="https://blog.frankel.ch/poor-man-api/" target="_blank" rel="noopener noreferrer"&gt;previous post&lt;/a&gt;
. However, I wanted to improve it, if only slightly.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PostgREST offers a powerful &lt;code&gt;SELECT&lt;/code&gt; mechanism. To list all entities with a column equal to a value, you need the following command:&lt;/p&gt;</description></item><item><title>Dynamic watermarking with imgproxy and Apache APISIX</title><link>https://foojayio.github.io/website/today/dynamic-watermarking-with-imgproxy-and-apache-apisix/</link><pubDate>Wed, 10 Jul 2024 13:38:07 +0000</pubDate><guid>https://foojayio.github.io/website/today/dynamic-watermarking-with-imgproxy-and-apache-apisix/</guid><description>&lt;p&gt;I described &lt;a href="https://foojayio.github.io/website/today/dynamic-watermarking-on-the-jvm/"&gt;how to add a dynamic watermark to your images on the JVM&lt;/a&gt;
. I didn&amp;rsquo;t find any library, so I had to develop the feature, or, more precisely, an embryo of a feature, by myself.&lt;/p&gt;
&lt;p&gt;Depending on your tech stack, you must search for an existing library or roll up your sleeves. For example, Rust offers such an out-of-the-box library. Worse, this approach might be impossible to implement if you don&amp;rsquo;t have access to the source image.&lt;/p&gt;</description></item><item><title>Dynamic watermarking on the JVM</title><link>https://foojayio.github.io/website/today/dynamic-watermarking-on-the-jvm/</link><pubDate>Tue, 09 Jul 2024 07:59:29 +0000</pubDate><guid>https://foojayio.github.io/website/today/dynamic-watermarking-on-the-jvm/</guid><description>&lt;p&gt;Displaying images on your website makes for an interesting problem: on one side, you want to make them publicly available; on the other, you want to protect them against undue use. The age-long method to achieve it is watermarking:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;digital watermark&lt;/strong&gt; is a kind of marker covertly embedded in a noise-tolerant signal such as audio, video or image data. It is typically used to identify ownership of the copyright of such signal. &amp;ldquo;Watermarking&amp;rdquo; is the process of hiding digital information in a carrier signal; the hidden information should, but does not need to, contain a relation to the carrier signal. Digital watermarks may be used to verify the authenticity or integrity of the carrier signal or to show the identity of its owners. It is prominently used for tracing copyright infringements and for banknote authentication.&lt;/p&gt;</description></item><item><title>Renovate for everything</title><link>https://foojayio.github.io/website/today/renovate-for-everything/</link><pubDate>Thu, 27 Jun 2024 08:18:20 +0000</pubDate><guid>https://foojayio.github.io/website/today/renovate-for-everything/</guid><description>&lt;p&gt;In my earlier post about moving from &lt;a href="https://blog.frankel.ch/kotlin-scripting-to-python/" target="_blank" rel="noopener noreferrer"&gt;Kotlin Scripting to Python&lt;/a&gt;
, I mentioned several reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Separating the content from the script&lt;/li&gt;
&lt;li&gt;Kotlin Scripting is an unloved child of JetBrains&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mend.io/renovate/" target="_blank" rel="noopener noreferrer"&gt;Renovate&lt;/a&gt;
 cannot update Kotlin Scripting files&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was wrong on the third point. Here&amp;rsquo;s my &lt;em&gt;mea culpa&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;First things first, Renovate does indeed &lt;a href="https://docs.renovatebot.com/modules/manager/kotlin-script/" target="_blank" rel="noopener noreferrer"&gt;manages Kotlin Scripting&lt;/a&gt;
 files - since 2022.&lt;/p&gt;
&lt;p&gt;Even better, Renovate can manage &lt;em&gt;any&lt;/em&gt; type of file. Thanks to Max Andersen for the tip:&lt;/p&gt;</description></item><item><title>Even More Opentelemetry!</title><link>https://foojayio.github.io/website/today/even-more-opentelemetry/</link><pubDate>Thu, 20 Jun 2024 06:40:47 +0000</pubDate><guid>https://foojayio.github.io/website/today/even-more-opentelemetry/</guid><description>&lt;p&gt;&lt;strong&gt;I continue to work on my &lt;a href="https://github.com/nfrankel/opentelemetry-tracing" target="_blank" rel="noopener noreferrer"&gt;Opentelemetry demo&lt;/a&gt;
. Its main idea is to showcase &lt;em&gt;traces&lt;/em&gt; across various technology stacks, including asynchronous communication via an MQTT queue. Recently, I added a couple of components and changed the architecture. Here are some noteworthy learnings; note that some of them might not be entirely connected to OpenTelemetry.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an updated diagram. New components appear in violet, and updated components appear in green.&lt;/p&gt;</description></item><item><title>Foojay Podcast #53: JCON Report, Part 5 – CQRS, JOOQ, GraphQL, API, Vaadin, OpenRewrite, ErrorProne, Gateways, Proxies,...</title><link>https://foojayio.github.io/website/today/foojay-podcast-53/</link><pubDate>Mon, 17 Jun 2024 09:24:52 +0000</pubDate><guid>https://foojayio.github.io/website/today/foojay-podcast-53/</guid><description>&lt;p&gt;This is the final part of the JCON interviews. Did I save the best for last? It&amp;rsquo;s up to you to decide&amp;hellip;&lt;/p&gt;
&lt;p&gt;In this episode you&amp;rsquo;ll hear Simon Martinelli, Nicolas Fränkel, Marcus Hellberg, Rick Ossendrijver, and Abdel Sghiouar.&lt;/p&gt;
&lt;p&gt;We talked about a bunch of topics like evolving your APIs, GraphQL, Java versus Kotlin versus Rust, Vaadin, AI and ChatGPT, OpenRewrite, ErrorProne, Infrastructure, and a lot more.&lt;/p&gt;
&lt;h2 id="h2-0-video"&gt;Video&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
			&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/6ops5sU_UiY?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
		&lt;/div&gt;

&lt;h2 id="h2-1-podcast-apps"&gt;Podcast Apps&lt;/h2&gt;
&lt;p&gt;You can listen and subscribe to the Foojay Podcast on:&lt;/p&gt;</description></item><item><title>Workflow, From Stateless To Stateful</title><link>https://foojayio.github.io/website/today/workflow-from-stateless-to-stateful/</link><pubDate>Wed, 05 Jun 2024 06:11:38 +0000</pubDate><guid>https://foojayio.github.io/website/today/workflow-from-stateless-to-stateful/</guid><description>&lt;p&gt;&lt;strong&gt;A (long) time ago, my first job consisted of implementing &lt;em&gt;workflows&lt;/em&gt; using the Staffware engine. In short, a workflow comprises &lt;em&gt;tasks&lt;/em&gt;; an automated task delegates to code, while a manual task requires somebody to do something and mark it as done. Then, it proceeds to the next task - or tasks.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a sample workflow:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://foojayio.github.io/website/today/workflow-from-stateless-to-stateful/procurement.png" alt="" loading="lazy"&gt;
&lt;/p&gt;
&lt;p&gt;The above diagram uses &lt;a href="https://en.wikipedia.org/wiki/Business_Process_Model_and_Notation" target="_blank" rel="noopener noreferrer"&gt;Business Process Model and Notation&lt;/a&gt;
. You can now design your workflow using and run it with compatible workflow engines.&lt;/p&gt;</description></item><item><title>My opinion on the Tauri framework</title><link>https://foojayio.github.io/website/today/my-opinion-on-the-tauri-framework/</link><pubDate>Thu, 30 May 2024 16:05:06 +0000</pubDate><guid>https://foojayio.github.io/website/today/my-opinion-on-the-tauri-framework/</guid><description>&lt;p&gt;&lt;strong&gt;I&amp;rsquo;ve always liked , both desktop-based and browser-based before you needed five years of training on the latter. That&amp;rsquo;s the reason I loved, and still love &lt;a href="https://vaadin.com/" target="_blank" rel="noopener noreferrer"&gt;Vaadin&lt;/a&gt;
: you can develop web UIs without writing a single line of HTML, JavaScript, and CSS. I&amp;rsquo;m still interested in the subject; a couple of years ago, I analyzed the &lt;a href="https://blog.frankel.ch/focus/state-jvm-desktop-frameworks/" target="_blank" rel="noopener noreferrer"&gt;state of JVM desktop frameworks&lt;/a&gt;
.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I also like the Rust programming language a lot.&lt;/p&gt;</description></item><item><title>The Vary HTTP Header</title><link>https://foojayio.github.io/website/today/the-vary-http-header/</link><pubDate>Wed, 15 May 2024 07:46:26 +0000</pubDate><guid>https://foojayio.github.io/website/today/the-vary-http-header/</guid><description>&lt;p&gt;&lt;strong&gt;I try to constantly to deepen my knowledge of HTTP and REST. Recently, I stumbled upon the list of all &lt;a href="https://www.iana.org/assignments/http-fields/http-fields.xhtml" target="_blank" rel="noopener noreferrer"&gt;registered HTTP Headers&lt;/a&gt;
. This post is dedicated to the &lt;code&gt;Vary&lt;/code&gt; HTTP Header.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="h2-0-the-problem"&gt;The problem&lt;/h2&gt;
&lt;p&gt;Two years ago, I wrote about &lt;a href="https://blog.frankel.ch/web-caching/server/" target="_blank" rel="noopener noreferrer"&gt;web resource caching server-side&lt;/a&gt;
. The idea is to set up a component between the client and the upstream to cache previously computed results to avoid overloading the latter. Depending on your infrastructure and requirements, this component can be a reverse proxy or an API Gateway. HTTP offers the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control" target="_blank" rel="noopener noreferrer"&gt;Cache-Control&lt;/a&gt;
 header to customize the different aspects of caching, &lt;em&gt;e.g.&lt;/em&gt; , the time the server holds the resource in cache before it considers it stale. I used plugin configuration in the above post, but you can also delegate to &lt;code&gt;Cache-Control&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Five ways to pass parameters to Apache APISIX</title><link>https://foojayio.github.io/website/today/five-ways-to-pass-parameters-to-apache-apisix/</link><pubDate>Tue, 30 Apr 2024 14:53:30 +0000</pubDate><guid>https://foojayio.github.io/website/today/five-ways-to-pass-parameters-to-apache-apisix/</guid><description>&lt;p&gt;I recently read &lt;a href="https://javabulletin.substack.com/p/6-ways-to-pass-parameters-to-spring" target="_blank" rel="noopener noreferrer"&gt;6 Ways To Pass Parameters to Spring REST API&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Though the title is a bit misleading, as it&amp;rsquo;s unrelated to REST, it does an excellent job listing all ways to send parameters to a Spring application.&lt;/p&gt;
&lt;p&gt;I want to do the same for Apache APISIX; it&amp;rsquo;s beneficial when you write a custom plugin.&lt;/p&gt;
&lt;h2 id="h2-0-general-setup"&gt;General setup&lt;/h2&gt;
&lt;p&gt;The general setup uses Docker Compose and static configuration.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll have one plugin per way to pass parameters.&lt;/p&gt;</description></item><item><title>Using my new Raspberry Pi to run an existing GitHub Action</title><link>https://foojayio.github.io/website/today/using-my-new-raspberry-pi-to-run-an-existing-github-action/</link><pubDate>Tue, 23 Apr 2024 18:45:04 +0000</pubDate><guid>https://foojayio.github.io/website/today/using-my-new-raspberry-pi-to-run-an-existing-github-action/</guid><description>&lt;p&gt;Recently, I mentioned &lt;a href="https://blog.frankel.ch/kotlin-scripting-to-python/" target="_blank" rel="noopener noreferrer"&gt;how I refactored&lt;/a&gt;
 &lt;a href="https://github.com/nfrankel/nfrankel-update/" target="_blank" rel="noopener noreferrer"&gt;the script&lt;/a&gt;
 that kept &lt;a href="https://github.com/nfrankel/" target="_blank" rel="noopener noreferrer"&gt;my GitHub profile&lt;/a&gt;
 up-to-date. Since Geecon Prague, I&amp;rsquo;m also a happy owner of a Raspberry Pi:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/nicolas_frankel/status/1715313240568197233" target="_blank" rel="noopener noreferrer"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;[&lt;/p&gt;
&lt;img fetchpriority="high" decoding="async" class="aligncenter wp-image-106305 size-medium" src="Screenshot-2024-03-10-at-17.20.56-557x510.png" alt="" width="557" height="510"&gt;
&lt;p&gt;](&lt;a href="https://twitter.com/nicolas_frankel/status/1715313240568197233" target="_blank" rel="noopener noreferrer"&gt;https://twitter.com/nicolas_frankel/status/1715313240568197233&lt;/a&gt;
)&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;Though the current setup works flawlessly - and is free, I wanted to experiment with self-hosted runners. Here are my findings.&lt;/p&gt;
&lt;h2 id="h2-0-context"&gt;Context&lt;/h2&gt;
&lt;p&gt;GitHub offers a large free usage of GitHub Actions:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;GitHub Actions usage is free for standard GitHub-hosted runners in public repositories, and for self-hosted runners. For private repositories, each GitHub account receives a certain amount of free minutes and storage for use with GitHub-hosted runners, depending on the account&amp;rsquo;s plan. Any usage beyond the included amounts is controlled by spending limits.&lt;/p&gt;</description></item><item><title>Improving upon my OpenTelemetry Tracing demo</title><link>https://foojayio.github.io/website/today/improving-upon-my-opentelemetry-tracing-demo/</link><pubDate>Wed, 03 Apr 2024 06:35:22 +0000</pubDate><guid>https://foojayio.github.io/website/today/improving-upon-my-opentelemetry-tracing-demo/</guid><description>&lt;p&gt;Last year, I wrote a &lt;a href="https://blog.frankel.ch/end-to-end-tracing-opentelemetry/" target="_blank" rel="noopener noreferrer"&gt;post&lt;/a&gt;
 on Open Telemetry Tracing to understand more about the subject. I also created a demo around it, which featured the following components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Apache APISIX API Gateway&lt;/li&gt;
&lt;li&gt;A Kotlin/Spring Boot service&lt;/li&gt;
&lt;li&gt;A Python/Flask service&lt;/li&gt;
&lt;li&gt;And a Rust/Axum service&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ve recently improved the demo to deepen my understanding and want to share my learning.&lt;/p&gt;
&lt;h2 id="h2-0-using-a-regular-database"&gt;Using a regular database&lt;/h2&gt;
&lt;p&gt;In the initial demo, I didn&amp;rsquo;t bother with a regular database. Instead:&lt;/p&gt;</description></item><item><title>Apache APISIX North America Tour</title><link>https://foojayio.github.io/website/today/apache-apisix-north-america-tour/</link><pubDate>Mon, 25 Mar 2024 15:31:08 +0000</pubDate><guid>https://foojayio.github.io/website/today/apache-apisix-north-america-tour/</guid><description>&lt;p&gt;&lt;strong&gt;Once in a while, I write non-technical blog posts when I&amp;rsquo;ve something worth sharing. Today, I&amp;rsquo;d like to write about my North America &amp;ldquo;Tour&amp;rdquo; across several conferences and user groups.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first leg of my journey started in Oakland, California, with &lt;a href="https://developerweek2024.sched.com/event/1WpId" target="_blank" rel="noopener noreferrer"&gt;Developer Week&lt;/a&gt;
. Developer Week is an established conference with different editions in several locations and online during the year. Though I&amp;rsquo;m on their advisory board, this is only the second time I&amp;rsquo;ve spoken at one of their events. Pro-tip: Avoid being on any board of a conference where you speak. It&amp;rsquo;s bad taste and casts doubt on whether you validated yourself.&lt;/p&gt;</description></item><item><title>Secure your API with these 16 Practices with Apache APISIX – part 2</title><link>https://foojayio.github.io/website/today/secure-your-api-with-these-16-practices-with-apache-apisix-part-2/</link><pubDate>Mon, 11 Mar 2024 09:39:24 +0000</pubDate><guid>https://foojayio.github.io/website/today/secure-your-api-with-these-16-practices-with-apache-apisix-part-2/</guid><description>&lt;p&gt;&lt;a href="https://foojayio.github.io/website/today/secure-your-api-with-these-16-practices-with-apache-apisix-part-1/"&gt;We&amp;rsquo;ve listed 16 practices to help secure one&amp;rsquo;s APIs&lt;/a&gt;
 and described how to implement them with Apache APISIX.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;del&gt;Authentication 🕵️️ - Verifies the identity of users accessing APIs.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Authorization 🚦 - Determines permissions of authenticated users.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;Data Redaction 🖍️ - Obscures sensitive data for protection.&lt;/li&gt;
&lt;li&gt;Encryption 🔒 - Encodes data so only authorized parties can decode it.&lt;/li&gt;
&lt;li&gt;Error Handling ❌ - Manages responses when things go wrong, avoiding revealing sensitive info.&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Input Validation &amp;amp; Data Sanitization 🧹 - Checks input data and removes harmful parts.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;Intrusion Detection Systems 👀 - Monitor networks for suspicious activities.&lt;/li&gt;
&lt;li&gt;&lt;del&gt;IP Whitelisting 📝 - Permits API access only from trusted IP addresses.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Logging and Monitoring 🖥️ - Keeps detailed logs and regularly monitors APIs.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Rate Limiting ⏱️ - Limits user requests to prevent overload.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;Secure Dependencies 📦 - Ensures third-party code is free from vulnerabilities.&lt;/li&gt;
&lt;li&gt;Security Headers 📋 - Enhances site security against types of attacks like XSS.&lt;/li&gt;
&lt;li&gt;Token Expiry ⏳ - Regularly expiring and renewing tokens prevents unauthorized access.&lt;/li&gt;
&lt;li&gt;Use of Security Standards and Frameworks 📘 - Guides your API security strategy.&lt;/li&gt;
&lt;li&gt;Web Application Firewall 🔥 - Protects your site from HTTP-specific attacks.&lt;/li&gt;
&lt;li&gt;API Versioning 🔄 - Maintains different versions of your API for seamless updates.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let&amp;rsquo;s now look at the remaining practices.&lt;/p&gt;</description></item><item><title>Secure your API with these 16 Practices with Apache APISIX - part 1</title><link>https://foojayio.github.io/website/today/secure-your-api-with-these-16-practices-with-apache-apisix-part-1/</link><pubDate>Mon, 11 Mar 2024 09:35:51 +0000</pubDate><guid>https://foojayio.github.io/website/today/secure-your-api-with-these-16-practices-with-apache-apisix-part-1/</guid><description>&lt;p&gt;A couple of months ago, I stumbled upon this list &lt;a href="https://www.linkedin.com/posts/brijpandeyji_secure-your-api-with-these-16-practices-activity-7094020647529369601-5kzQ/" target="_blank" rel="noopener noreferrer"&gt;16 practices to secure your API&lt;/a&gt;
:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Authentication 🕵️️ - Verifies the identity of users accessing APIs.&lt;/li&gt;
&lt;li&gt;Authorization 🚦 - Determines permissions of authenticated users.&lt;/li&gt;
&lt;li&gt;Data Redaction 🖍️ - Obscures sensitive data for protection.&lt;/li&gt;
&lt;li&gt;Encryption 🔒 - Encodes data so only authorized parties can decode it.&lt;/li&gt;
&lt;li&gt;Error Handling ❌ - Manages responses when things go wrong, avoiding revealing sensitive info.&lt;/li&gt;
&lt;li&gt;Input Validation &amp;amp; Data Sanitization 🧹 - Checks input data and removes harmful parts.&lt;/li&gt;
&lt;li&gt;Intrusion Detection Systems 👀 - Monitor networks for suspicious activities.&lt;/li&gt;
&lt;li&gt;IP Whitelisting 📝 - Permits API access only from trusted IP addresses.&lt;/li&gt;
&lt;li&gt;Logging and Monitoring 🖥️ - Keeps detailed logs and regularly monitors APIs.&lt;/li&gt;
&lt;li&gt;Rate Limiting ⏱️ - Limits user requests to prevent overload.&lt;/li&gt;
&lt;li&gt;Secure Dependencies 📦 - Ensures third-party code is free from vulnerabilities.&lt;/li&gt;
&lt;li&gt;Security Headers 📋 - Enhances site security against types of attacks like XSS.&lt;/li&gt;
&lt;li&gt;Token Expiry ⏳ - Regularly expiring and renewing tokens prevents unauthorized access.&lt;/li&gt;
&lt;li&gt;Use of Security Standards and Frameworks 📘 - Guides your API security strategy.&lt;/li&gt;
&lt;li&gt;Web Application Firewall 🔥 - Protects your site from HTTP-specific attacks.&lt;/li&gt;
&lt;li&gt;API Versioning 🔄 - Maintains different versions of your API for seamless updates.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;While it&amp;rsquo;s debatable whether some points relate to security, &lt;em&gt;e.g.,&lt;/em&gt;, versioning, the list is a good starting point anyway. In this two-post series, I&amp;rsquo;d like to describe how we can implement each point with Apache APISIX (or not).&lt;/p&gt;</description></item><item><title>Hardening Apache APISIX with the OWASP's Coraza and Core Ruleset</title><link>https://foojayio.github.io/website/today/hardening-apache-apisix-with-the-owasps-coraza-and-core-ruleset/</link><pubDate>Tue, 20 Feb 2024 08:01:56 +0000</pubDate><guid>https://foojayio.github.io/website/today/hardening-apache-apisix-with-the-owasps-coraza-and-core-ruleset/</guid><description>&lt;blockquote&gt;
&lt;p&gt;The Open Worldwide Application Security Project is an online community that produces freely available articles, methodologies, documentation, tools, and technologies in the fields of IoT, system software and web application security. The OWASP provides free and open resources. It is led by a non-profit called The OWASP Foundation. The OWASP Top 10 - 2021 is the published result of recent research based on comprehensive data compiled from over 40 partner organizations.&lt;/p&gt;</description></item><item><title>Kicking the Tires of Docker Scout</title><link>https://foojayio.github.io/website/today/kicking-the-tires-of-docker-scout/</link><pubDate>Thu, 08 Feb 2024 08:47:20 +0000</pubDate><guid>https://foojayio.github.io/website/today/kicking-the-tires-of-docker-scout/</guid><description>&lt;p&gt;I never moved away from Docker Desktop.&lt;/p&gt;
&lt;p&gt;For some time, after you use it to build an image, it prints a message:&lt;/p&gt;
&lt;pre class="EnlighterJSRAW" data-enlighter-language="generic"&gt;What's Next?
 View a summary of image vulnerabilities and recommendations → docker scout quickview&lt;/pre&gt;
&lt;p&gt;I decided to give it a try. I&amp;rsquo;ll use the root commit of my &lt;a href="https://github.com/nfrankel/opentelemetry-tracing" target="_blank" rel="noopener noreferrer"&gt;OpenTelemetry tracing demo&lt;/a&gt;
. Let&amp;rsquo;s execute the proposed command:&lt;/p&gt;
&lt;pre class="EnlighterJSRAW" data-enlighter-language="bash"&gt;docker scout quickview otel-catalog:1.0&lt;/pre&gt;
&lt;p&gt;Here&amp;rsquo;s the result:&lt;/p&gt;
&lt;pre class="EnlighterJSRAW" data-enlighter-language="generic"&gt; ✓ Image stored for indexing
 ✓ Indexed 272 packages
 Target │ otel-catalog:1.0 │ 0C 2H 15M 23L
 digest │ 7adfce68062e │
 Base image │ eclipse-temurin:21-jre │ 0C 0H 15M 23L
 Refreshed base image │ eclipse-temurin:21-jre │ 0C 0H 15M 23L
 │ │
What's Next?
 View vulnerabilities → docker scout cves otel-catalog:1.0
 View base image update recommendations → docker scout recommendations otel-catalog:1.0
 Include policy results in your quickview by supplying an organization → docker scout quickview otel-catalog:1.0 --org &amp;lt;organization&amp;gt;&lt;/pre&gt;
&lt;p&gt;Docker gives out exciting bits of information:&lt;/p&gt;</description></item><item><title>API Versioning</title><link>https://foojayio.github.io/website/today/api-versioning/</link><pubDate>Mon, 22 Jan 2024 09:00:23 +0000</pubDate><guid>https://foojayio.github.io/website/today/api-versioning/</guid><description>&lt;p&gt;&lt;strong&gt;In my previous article &lt;a href="https://blog.frankel.ch/evolve-apis/" target="_blank" rel="noopener noreferrer"&gt;Evolving your APIs&lt;/a&gt;
, I mention the main API versioning approaches. During the talk of the same name, I sometimes get some questions on the subject. In this article, I&amp;rsquo;ll detail each of them.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I assume readers know the reasons behind versioning, semantic versioning, and product lifecycle. If not, I encourage you to read a bit about these themes; in particular, chapter 24 of the excellent &lt;a href="https://blog.frankel.ch/api-design-patterns/" target="_blank" rel="noopener noreferrer"&gt;API Design Patterns&lt;/a&gt;
 book focuses on them.&lt;/p&gt;</description></item><item><title>2023 in Retrospective</title><link>https://foojayio.github.io/website/today/2023-in-retrospective/</link><pubDate>Tue, 16 Jan 2024 07:44:39 +0000</pubDate><guid>https://foojayio.github.io/website/today/2023-in-retrospective/</guid><description>&lt;p&gt;&lt;strong&gt;Last year, I wrote my first &lt;a href="https://blog.frankel.ch/retrospective/" target="_blank" rel="noopener noreferrer"&gt;yearly retrospective&lt;/a&gt;
. I liked the experience, so I&amp;rsquo;m trying one more time. Let the future decide if it will become a trend or not.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before diving into our safe technological world, my thoughts go to Ukraine, to my friends who had to flee their own country, to other friends who fought on the front to defend it from an imperial power, and to all victims of an old kleptocrat who clings to power despite the cost to others. The free world needs to support Ukraine more. I hope 2024 will be the year of Ukrainian victory.&lt;/p&gt;</description></item><item><title>Playing with WASM on Docker</title><link>https://foojayio.github.io/website/today/playing-with-wasm-on-docker/</link><pubDate>Wed, 03 Jan 2024 07:48:29 +0000</pubDate><guid>https://foojayio.github.io/website/today/playing-with-wasm-on-docker/</guid><description>&lt;p&gt;The idea of bytecode that can run anywhere dates back to the JVM inception (as far as I know).&lt;/p&gt;
&lt;p&gt;WebAssembly is the new implementation of an old idea. While WebAssembly is meant to run in the browser, Docker recently announced its capability to run WASM code without needing containers.&lt;/p&gt;
&lt;p&gt;In this post, I want to explore how it can work.&lt;/p&gt;
&lt;h2 id="h2-0-prerequisite"&gt;Prerequisite&lt;/h2&gt;
&lt;p&gt;Running WebAssembly is a &lt;em&gt;beta&lt;/em&gt; feature and requires using &lt;code&gt;containerd&lt;/code&gt;. To enable &lt;code&gt;containerd&lt;/code&gt;, go to the Docker Desktop dashboard, then Settings &amp;gt; Features in development &amp;gt; Beta features &amp;gt; Use containerd for storing and pulling image.&lt;/p&gt;</description></item><item><title>Five Apache Projects You Probably Haven't Heard Of (Yet)</title><link>https://foojayio.github.io/website/today/five-apache-projects-you-probably-havent-heard-of-yet/</link><pubDate>Sun, 24 Dec 2023 10:17:38 +0000</pubDate><guid>https://foojayio.github.io/website/today/five-apache-projects-you-probably-havent-heard-of-yet/</guid><description>&lt;p&gt;&lt;strong&gt;In early 2021, I started to work on the &lt;a href="https://apisix.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;
 project. I have to admit that at the time I had never heard about it before.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As a result, in this article, I&amp;rsquo;d like to introduce some Apache projects that are less well-known than HTTPD or Kafka.&lt;/p&gt;
&lt;h2 id="h2-0-apache-apisix"&gt;Apache APISIX&lt;/h2&gt;
&lt;img fetchpriority="high" decoding="async" class="alignright wp-image-103491 size-full" src="apisix.png" alt="" width="256" height="256"&gt;
&lt;p&gt;&lt;a href="https://apisix.apache.org/" target="_blank" rel="noopener noreferrer"&gt;APISIX&lt;/a&gt;
 is an &lt;a href="https://en.wikipedia.org/wiki/API_management" target="_blank" rel="noopener noreferrer"&gt;API Gateway&lt;/a&gt;
. It builds upon &lt;a href="https://openresty.org/en/" target="_blank" rel="noopener noreferrer"&gt;OpenResty&lt;/a&gt;
, a Lua layer built on top of the famous &lt;a href="https://nginx.org/" target="_blank" rel="noopener noreferrer"&gt;nginx&lt;/a&gt;
 reverse-proxy. APISIX adds abstractions to the mix, &lt;em&gt;e.g.&lt;/em&gt; , &lt;code&gt;Route&lt;/code&gt;, &lt;code&gt;Service&lt;/code&gt;, &lt;code&gt;Upstream&lt;/code&gt;, and offers a plugin-based architecture.&lt;/p&gt;</description></item><item><title>Canary Releases with Apache APISIX</title><link>https://foojayio.github.io/website/today/canary-releases-with-apache-apisix/</link><pubDate>Tue, 19 Dec 2023 08:01:55 +0000</pubDate><guid>https://foojayio.github.io/website/today/canary-releases-with-apache-apisix/</guid><description>&lt;p&gt;&lt;strong&gt;In a few words, the idea of canary releases is to deliver a new software version to only a fraction of the users, analyze the results, and decide whether to proceed further or not. If results are not aligned with expectations, roll back; if they are, increase the number of users exposed until all users benefit from the new version.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this article, I&amp;rsquo;d like to detail this introduction briefly, explain different ways to define the fraction, and show how to execute it with Apache APISIX.&lt;/p&gt;</description></item><item><title>Chopping the monolith in a smarter way</title><link>https://foojayio.github.io/website/today/chopping-the-monolith-in-a-smarter-way/</link><pubDate>Thu, 07 Dec 2023 07:40:55 +0000</pubDate><guid>https://foojayio.github.io/website/today/chopping-the-monolith-in-a-smarter-way/</guid><description>&lt;p&gt;&lt;strong&gt;In my previous post &lt;a href="https://foojayio.github.io/website/today/chopping-monolith/"&gt;Chopping the Monolith&lt;/a&gt;
, I explained that some parts of a monolith are pretty stable and only the fast-changing parts are worth being &amp;ldquo;chopped.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I turned the post into a talk and presented it at several conferences. I think it&amp;rsquo;s pretty well received; I believe it&amp;rsquo;s because most developers understand, or have direct experience, that microservices are not a good fit for traditional organizations, as per &lt;a href="https://en.wikipedia.org/wiki/Conway%27s_law" target="_blank" rel="noopener noreferrer"&gt;Conway&amp;rsquo;s Law&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Exploring the OpenTelemetry Collector</title><link>https://foojayio.github.io/website/today/exploring-the-opentelemetry-collector/</link><pubDate>Sun, 03 Dec 2023 12:57:06 +0000</pubDate><guid>https://foojayio.github.io/website/today/exploring-the-opentelemetry-collector/</guid><description>&lt;p&gt;The OpenTelemetry Collector sits at the center of the OpenTelemetry architecture but is unrelated to the W3C Trace Context.&lt;/p&gt;
&lt;p&gt;In my &lt;a href="https://github.com/nfrankel/opentelemetry-tracing" target="_blank" rel="noopener noreferrer"&gt;tracing demo&lt;/a&gt;
, I use Jaeger instead of the Collector.&lt;/p&gt;
&lt;p&gt;Yet, it&amp;rsquo;s ubiquitous, as in every OpenTelemetry-related post. I wanted to explore it further.&lt;/p&gt;
&lt;p&gt;In this post, I explore the different aspects of the Collector:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The data kind: logs, metrics, and traces&lt;/li&gt;
&lt;li&gt;Push and pull models&lt;/li&gt;
&lt;li&gt;Operations: reads, transformations, and writes&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="h2-0-first-steps"&gt;First steps&lt;/h2&gt;
&lt;p&gt;A long time ago, &lt;em&gt;observability&lt;/em&gt; as we know it didn&amp;rsquo;t exist; what we had instead was &lt;em&gt;monitoring&lt;/em&gt;. Back then, monitoring was a bunch of people looking at screens displaying dashboards. Dashboards themselves consisted of metrics and only system metrics: mainly CPU, memory, and disk usage. For this reason, we will start with metrics.&lt;/p&gt;</description></item><item><title>Feedback from calling Rust from Python</title><link>https://foojayio.github.io/website/today/feedback-from-calling-rust-from-python/</link><pubDate>Wed, 22 Nov 2023 10:32:55 +0000</pubDate><guid>https://foojayio.github.io/website/today/feedback-from-calling-rust-from-python/</guid><description>&lt;p&gt;I got plenty of feedback on my post about &lt;a href="https://blog.frankel.ch/rust-from-python/" target="_blank" rel="noopener noreferrer"&gt;Calling Rust from Python&lt;/a&gt;
:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=37811953" target="_blank" rel="noopener noreferrer"&gt;Hacker News&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/Python/comments/1733gl6/calling_rust_from_python/" target="_blank" rel="noopener noreferrer"&gt;/r/python&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/rust/comments/1733gsb/calling_rust_from_python/" target="_blank" rel="noopener noreferrer"&gt;/r/rust&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many comments mentioned &lt;code&gt;pyo3&lt;/code&gt;, and I should use it instead of cooking my own. Thanks to the authors, I checked: in this post, I explain what it is and how I migrated my code.&lt;/p&gt;
&lt;h2 id="h2-0-what-is-pyo3"&gt;What is pyo3?&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Rust bindings for Python, including tools for creating native Python extension modules. Running and interacting with Python code from a Rust binary is also supported.&lt;/p&gt;</description></item><item><title>Python "magic" methods - part 2</title><link>https://foojayio.github.io/website/today/python-magic-methods-part-2/</link><pubDate>Fri, 03 Nov 2023 09:15:44 +0000</pubDate><guid>https://foojayio.github.io/website/today/python-magic-methods-part-2/</guid><description>&lt;p&gt;Let&amp;rsquo;s continue our exploration of Python&amp;rsquo;s magic methods in this second part of the series. This part will focus on numbers and containers, &lt;em&gt;i.e.&lt;/em&gt; , collections. You can read the first part &lt;a href="https://foojayio.github.io/website/today/python-magic-methods-part-1/"&gt;here&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="h2-0-container-related-methods"&gt;Container-related methods&lt;/h2&gt;
&lt;p&gt;Python provides the usual containers, &lt;em&gt;e.g.&lt;/em&gt;, lists, sets, and dictionaries. You can use the following methods when you want to implement your own.&lt;/p&gt;
&lt;h3 id="h3-1-common-methods"&gt;Common methods&lt;/h3&gt;
&lt;p&gt;Containers have a size. Python defines two methods to implement to return the number of items in a container: &lt;code&gt;object.__len__(self)&lt;/code&gt; for the exact size and &lt;code&gt;object.__length_hint__(self)&lt;/code&gt; for an approximation. You should use the latter when getting the exact size is computationally expensive.&lt;/p&gt;</description></item><item><title>Python "magic" methods - part 1</title><link>https://foojayio.github.io/website/today/python-magic-methods-part-1/</link><pubDate>Fri, 03 Nov 2023 09:08:42 +0000</pubDate><guid>https://foojayio.github.io/website/today/python-magic-methods-part-1/</guid><description>&lt;p&gt;Java was the first language I used professionally and is the scale by which I measure other languages I learned afterward. It&amp;rsquo;s an statically-typed language. Hence, Python feels a bit weird because of its dynamic typing approach.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;Object&lt;/code&gt; offers methods &lt;code&gt;equals()&lt;/code&gt;, &lt;code&gt;hashCode()&lt;/code&gt;, and &lt;code&gt;toString()&lt;/code&gt;. Because all other classes inherit from &lt;code&gt;Object&lt;/code&gt;, directly or indirectly, all objects have these methods by definition.&lt;/p&gt;
&lt;p&gt;Conversely, Python was not initially built on OOP principles and is dynamically typed. Yet, any language needs cross-cutting features on unrelated objects. In Python, these are specially-named methods: methods that the runtime interprets in a certain way but that you need to know about. You can call them magic methods.&lt;/p&gt;</description></item><item><title>Resizing images on-the-fly</title><link>https://foojayio.github.io/website/today/resizing-images-on-the-fly/</link><pubDate>Mon, 23 Oct 2023 18:01:05 +0000</pubDate><guid>https://foojayio.github.io/website/today/resizing-images-on-the-fly/</guid><description>&lt;p&gt;As a web architect, one of the many issues is asset management. And the most significant issue in assets is images. A naive approach would be to set an image and let the browser resize the image via CSS:&lt;/p&gt;
&lt;pre class="EnlighterJSRAW" data-enlighter-language="css"&gt;img {
 height: 100%;
 width: 100%;
 object-fit: contain;
}&lt;/pre&gt;
&lt;p&gt;However, it means that you download the original image. It entails two problems: the size of the original image and the suboptimal browser-based resizing.&lt;/p&gt;</description></item><item><title>Send Your Logs To Loki</title><link>https://foojayio.github.io/website/today/send-your-logs-to-loki/</link><pubDate>Thu, 12 Oct 2023 08:00:12 +0000</pubDate><guid>https://foojayio.github.io/website/today/send-your-logs-to-loki/</guid><description>&lt;p&gt;&lt;strong&gt;One of my current talks focuses on Observability in general and Distributed Tracing in particular, with an &lt;a href="https://opentelemetry.io/" target="_blank" rel="noopener noreferrer"&gt;OpenTelemetry&lt;/a&gt;
 implementation. In the demo, I show how you can see the traces of a simple distributed system consisting of: the Apache APISIX API Gateway, a Kotlin app with Spring Boot, a Python app with Flask, and a Rust app with Axum.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Earlier this year, I spoke and attended the Observability room at FOSDEM. One of the talks demoed the Grafana stack: Mimir for metrics, Tempo for traces, and Loki for logs. I was pleasantly surprised how one could move from one to the other. Thus, I wanted to achieve the same in my demo but via OpenTelemetry to avoid coupling to the Grafana stack.&lt;/p&gt;</description></item><item><title>Down the Rabbit Hole of an Apache APISIX Plugin</title><link>https://foojayio.github.io/website/today/down-the-rabbit-hole-of-an-apache-apisix-plugin/</link><pubDate>Wed, 27 Sep 2023 08:43:49 +0000</pubDate><guid>https://foojayio.github.io/website/today/down-the-rabbit-hole-of-an-apache-apisix-plugin/</guid><description>&lt;p&gt;&lt;strong&gt;My demo, Evolving your APIs, features a custom Apache APISIX plugin. I believe that the process of &lt;a href="https://apisix.apache.org/docs/apisix/plugin-develop/" target="_blank" rel="noopener noreferrer"&gt;creating a custom plugin&lt;/a&gt;
 is relatively well-documented. However, I wanted to check the parameters of the &lt;code&gt;_M.access(conf, ctx)&lt;/code&gt; function, especially the &lt;code&gt;ctx&lt;/code&gt; one.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The documentation states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;ctx&lt;/code&gt; parameter caches data information related to the request. You can use &lt;code&gt;core.log.warn(core.json.encode(ctx, true))&lt;/code&gt; to output it to &lt;code&gt;error.log&lt;/code&gt; for viewing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Unfortunately, &lt;code&gt;core.log&lt;/code&gt; ultimately depends on nginx&amp;rsquo;s logging, and its buffer is limited in size. Thanks to my colleague &lt;a href="https://twitter.com/shreemaan_abhi" target="_blank" rel="noopener noreferrer"&gt;Abhishek&lt;/a&gt;
 for finding &lt;a href="http://nginx.org/en/docs/dev/development_guide.html#logging" target="_blank" rel="noopener noreferrer"&gt;the info&lt;/a&gt;
. For this reason, the &lt;code&gt;ctx&lt;/code&gt; display is (heavily) truncated. I had to log data bit by bit; however, it was instructive.&lt;/p&gt;</description></item><item><title>Monkey-patching in Java</title><link>https://foojayio.github.io/website/today/monkey-patching-in-java/</link><pubDate>Thu, 21 Sep 2023 07:34:22 +0000</pubDate><guid>https://foojayio.github.io/website/today/monkey-patching-in-java/</guid><description>&lt;p&gt;The JVM is an excellent platform for monkey-patching.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Monkey patching is a technique used to dynamically update the behavior of a piece of code at run-time. A monkey patch (also spelled monkey-patch, MonkeyPatch) is a way to extend or modify the runtime code of dynamic languages (&lt;em&gt;e.g.&lt;/em&gt; Smalltalk, JavaScript, Objective-C, Ruby, Perl, Python, Groovy, etc.) without altering the original source code.&lt;/p&gt;
&lt;p&gt;&amp;ndash; &lt;a href="https://en.wikipedia.org/wiki/Monkey_patch" target="_blank" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I want to demo several approaches for monkey-patching in Java in this post.&lt;/p&gt;</description></item><item><title>System Architecture: Move Authentication to the API Gateway</title><link>https://foojayio.github.io/website/today/system-architecture-move-authentication-to-the-api-gateway/</link><pubDate>Fri, 15 Sep 2023 07:47:04 +0000</pubDate><guid>https://foojayio.github.io/website/today/system-architecture-move-authentication-to-the-api-gateway/</guid><description>&lt;p&gt;&lt;strong&gt;When exposing an application to the outside world, consider a Reverse-Proxy or an API Gateway to protect it from attacks. Rate Limiting comes to mind first, but it shouldn&amp;rsquo;t stop there. We can factor many features in the API Gateway and should be bold in moving them from our apps. In this post, I&amp;rsquo;ll show how to implement authentication at the Gateway API stage.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="h2-0-overall-authentication-flow"&gt;Overall authentication flow&lt;/h2&gt;
&lt;p&gt;The API Gateway doesn&amp;rsquo;t authenticate but delegates authentication to an authentication provider. After authentication, the Gateway forwards the request to the app. The app checks authentication and gets the associated identity and permissions.&lt;/p&gt;</description></item><item><title>Ops friendly Apache APISIX</title><link>https://foojayio.github.io/website/today/ops-friendly-apache-apisix/</link><pubDate>Wed, 06 Sep 2023 06:27:42 +0000</pubDate><guid>https://foojayio.github.io/website/today/ops-friendly-apache-apisix/</guid><description>&lt;p&gt;&lt;strong&gt;Though I always worked on the Dev side of IT, I was also interested in the Ops side. I even had a short experience being a WebSphere admin: I used it several times, helping Ops deal with the Admin console while being a developer.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Providing a single package that Ops can configure and deploy in different environments is very important. As a JVM developer, I&amp;rsquo;ve been happy using Spring Boot and its wealth of configuration options: command-line parameters, JVM parameters, files, profiles, environment variables, etc.&lt;/p&gt;</description></item><item><title>Introduction to the Tower Library</title><link>https://foojayio.github.io/website/today/introduction-tower/</link><pubDate>Tue, 22 Aug 2023 08:28:33 +0000</pubDate><guid>https://foojayio.github.io/website/today/introduction-tower/</guid><description>&lt;p&gt;One of the components of my &lt;a href="https://github.com/nfrankel/opentelemetry-tracing" target="_blank" rel="noopener noreferrer"&gt;OpenTelemetry demo&lt;/a&gt;
 is a Rust application built with the Axum web framework. In its description, &lt;code&gt;axum&lt;/code&gt; mentions:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;axum&lt;/code&gt; doesn&amp;rsquo;t have its own middleware system but instead uses &lt;code&gt;tower::Service&lt;/code&gt;. This means &lt;code&gt;axum&lt;/code&gt; gets timeouts, tracing, compression, authorization, and more, for free. It also enables you to share middleware with applications written using &lt;code&gt;hyper&lt;/code&gt; or &lt;code&gt;tonic&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;ndash; &lt;a href="https://github.com/tokio-rs/axum" target="_blank" rel="noopener noreferrer"&gt;axum README&lt;/a&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;So far, I was happy to let this cryptic explanation lurk in the corner of my mind, but today is the day I want to understand what it means. Like many others, this post aims to explain to me and others how to do this.&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>My Final Take on Gradle (vs. Maven)</title><link>https://foojayio.github.io/website/today/my-final-take-on-gradle-vs-maven/</link><pubDate>Tue, 15 Aug 2023 08:37:24 +0000</pubDate><guid>https://foojayio.github.io/website/today/my-final-take-on-gradle-vs-maven/</guid><description>&lt;p&gt;&lt;strong&gt;I tweet technical content that I consider interesting, but the funny tweets are the ones that get the most engagement.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I attended the JavaLand conference in March, stumbled upon the Gradle booth, and found this gem:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/nicolas_frankel/status/1638549568957861889" target="_blank" rel="noopener noreferrer"&gt;&lt;img src="https://foojayio.github.io/website/today/my-final-take-on-gradle-vs-maven/Screenshot-2023-08-05-at-10.03.59-754x1024.png" alt="" loading="lazy"&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Of course, at some point, a fanboy hijacked the thread and claimed the so-called superiority of Gradle. In this post, I&amp;rsquo;d like to shed some light on my stance, so I can direct people to it instead of debunking the same &amp;ldquo;reasoning&amp;rdquo; repeatedly.&lt;/p&gt;</description></item><item><title>Book Review: "Designing APIs with Swagger and OpenAPI"</title><link>https://foojayio.github.io/website/today/book-review-designing-apis-with-swagger-and-openapi/</link><pubDate>Tue, 01 Aug 2023 18:21:08 +0000</pubDate><guid>https://foojayio.github.io/website/today/book-review-designing-apis-with-swagger-and-openapi/</guid><description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: this post includes affiliate links; I may receive compensation if you purchase the book from the different links provided in this post.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This review is about &lt;a href="https://www.manning.com/books/designing-apis-with-swagger-and-openapi?utm_source=frankel&amp;amp;amp;utm_medium=affiliate&amp;amp;amp;utm_campaign=affiliate&amp;amp;amp;a_aid=frankel" target="_blank" rel="noopener noreferrer"&gt;Designing APIs with Swagger and OpenAPI&lt;/a&gt;
 by Joshua S. Ponelat and Lukas L. Rosenstock from Manning.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m continuing my API journey by reading books, viewing relevant YouTube videos, and reading relevant s.&lt;/p&gt;
&lt;p&gt;Today is a book review.&lt;/p&gt;
&lt;h2 id="h2-0-facts"&gt;Facts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;21 chapters&lt;/li&gt;
&lt;li&gt;$38.39 (eBook)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="h2-1-chapters"&gt;Chapters&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Part 1: Describing APIs
&lt;ol&gt;
&lt;li&gt;Introducing APIs and OpenAPI&lt;/li&gt;
&lt;li&gt;Getting set up to make API requests&lt;/li&gt;
&lt;li&gt;Our first taste of OpenAPI definitions&lt;/li&gt;
&lt;li&gt;Using Swagger Editor to write OpenAPI definitions&lt;/li&gt;
&lt;li&gt;Describing API responses&lt;/li&gt;
&lt;li&gt;Creating resources&lt;/li&gt;
&lt;li&gt;Adding authentication and authorization&lt;/li&gt;
&lt;li&gt;Preparing and hosting API documentation&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Part 2: Design first
9. Designing a web application
10. Creating an API design using OpenAPI
11. Building a change workflow around API design&amp;ndash;first
12. Implementing frontend code and reacting to changes
13. Building a backend with Node.js and Swagger Codegen
14. Integrating and releasing the web application&lt;/li&gt;
&lt;li&gt;Part 3: Extending APIs
15. Designing the next API iteration
16. Designing schemas with composition in OpenAPI
17. Scaling collection endpoints with filters and pagination
18. Supporting the unhappy path: Error handling with problem+json
19. Improving input validation with advanced JSON Schema
20. Versioning an API and handling breaking changes
21. The API prerelease checklist&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The book goes through designing a complete API via a demo project, the &lt;a href="https://github.com/designapis/farmstall" target="_blank" rel="noopener noreferrer"&gt;Farmstall API&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Evaluating Apache APISIX vs. Spring Cloud Gateway</title><link>https://foojayio.github.io/website/today/evaluating-apache-apisix-vs-spring-cloud-gateway/</link><pubDate>Thu, 27 Jul 2023 06:29:55 +0000</pubDate><guid>https://foojayio.github.io/website/today/evaluating-apache-apisix-vs-spring-cloud-gateway/</guid><description>&lt;p&gt;&lt;strong&gt;Given the number of API Gateways available on the market, I&amp;rsquo;m regularly asked which is better. Better is a very subjective term. However, there&amp;rsquo;s no denying that if you&amp;rsquo;re advocating for a product, you should know your product and its competitors. In this article, I&amp;rsquo;d like to share my understanding of Spring Cloud Gateway and how it compares to Apache APISIX.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m cautious when comparing products because most comparisons I read are heavily biased. That&amp;rsquo;s a risk, especially when working on one of the products one is comparing. I&amp;rsquo;ll also avoid &amp;ldquo;benchmarketing&amp;rdquo; - when you benchmark products in a context that favors your own; I&amp;rsquo;ll focus on the so-called Developer Experience.&lt;/p&gt;</description></item><item><title>Reactive Database Access on the JVM</title><link>https://foojayio.github.io/website/today/reactive-database-access-on-the-jvm/</link><pubDate>Mon, 17 Jul 2023 09:18:37 +0000</pubDate><guid>https://foojayio.github.io/website/today/reactive-database-access-on-the-jvm/</guid><description>&lt;p&gt;A couple of years ago, &lt;a href="https://en.wikipedia.org/wiki/Reactive_programming" target="_blank" rel="noopener noreferrer"&gt;Reactive Programming&lt;/a&gt;
 was all the rage, but it had one big issue: reactive stopped as soon as you accessed a SQL database.&lt;/p&gt;
&lt;p&gt;You had a nice reactive chain up to the database, defeating the whole purpose. Given the prevalence of SQL databases in existing and new apps, one couldn&amp;rsquo;t enjoy the full benefits of Reactive Programming but still pay the full price of complexity.&lt;/p&gt;
&lt;p&gt;Since then, the landscape has changed tremendously. Most importantly, it offers many reactive drivers over popular databases: PostgreSQL, MariaDB and MySQL, Microsoft SQL Server, Oracle, you name it!&lt;/p&gt;</description></item><item><title>Sticky sessions with Apache APISIX - the demo</title><link>https://foojayio.github.io/website/today/sticky-sessions-with-apache-apisix-the-demo/</link><pubDate>Fri, 07 Jul 2023 16:54:25 +0000</pubDate><guid>https://foojayio.github.io/website/today/sticky-sessions-with-apache-apisix-the-demo/</guid><description>&lt;p&gt;We&amp;rsquo;ve described the concept behind &lt;a href="https://foojayio.github.io/website/today/sticky-sessions-with-apache-apisix/"&gt;sticky sessions&lt;/a&gt;
: you forward a request to the same upstream because there&amp;rsquo;s context data associated with the session on that node.&lt;/p&gt;
&lt;p&gt;However, if necessary, you should replicate the data to other upstreams because this one might go down. In this post, we are going to illustrate it with a demo.&lt;/p&gt;
&lt;h2 id="h2-0-the-overall-design"&gt;The overall design&lt;/h2&gt;
&lt;p&gt;Design options are limitless. I&amp;rsquo;ll keep myself to a familiar stack, the JVM. Also, as mentioned in the previous post, one should only implement sticky sessions with session replication.&lt;/p&gt;</description></item><item><title>Sticky sessions with Apache APISIX</title><link>https://foojayio.github.io/website/today/sticky-sessions-with-apache-apisix/</link><pubDate>Fri, 07 Jul 2023 16:51:01 +0000</pubDate><guid>https://foojayio.github.io/website/today/sticky-sessions-with-apache-apisix/</guid><description>&lt;p&gt;Sticky sessions, also known as session affinity, is a mechanism by which a routing component that acts as a facade always routes a request to the same underlying upstream node.&lt;/p&gt;
&lt;p&gt;In this article, I&amp;rsquo;ll describe the reason behind sticky sessions, available alternatives, and how to implement them via Apache APISIX.&lt;/p&gt;
&lt;h2 id="h2-0-why-sticky-sessions"&gt;Why sticky sessions?&lt;/h2&gt;
&lt;p&gt;Sticky sessions became popular when we stored the state on the upstream node, not the database. I&amp;rsquo;ll use the example of a simplified e-commerce shop to explain further.&lt;/p&gt;</description></item><item><title>Working on An Unfamiliar Codebase</title><link>https://foojayio.github.io/website/today/working-unfamiliar-codebase/</link><pubDate>Sun, 02 Jul 2023 09:00:47 +0000</pubDate><guid>https://foojayio.github.io/website/today/working-unfamiliar-codebase/</guid><description>&lt;p&gt;In our profession, it&amp;rsquo;s common to work on an unfamiliar codebase.&lt;/p&gt;
&lt;p&gt;It happens every time one joins a new project or even needs to work on a previously untouched part in big ones.&lt;/p&gt;
&lt;p&gt;This occurrence is not limited to a developer having to fix a bug; it can be a solution architect having to design a new feature or an OpenSource contributor working on a GitHub issue in their free time.&lt;/p&gt;</description></item><item><title>GitLab Pages Preview</title><link>https://foojayio.github.io/website/today/gitlab-pages-preview/</link><pubDate>Mon, 12 Jun 2023 08:55:31 +0000</pubDate><guid>https://foojayio.github.io/website/today/gitlab-pages-preview/</guid><description>&lt;p&gt;When I write Apache APISIX-related blog posts, I want my colleagues to review them first. However, it&amp;rsquo;s my blog, and since I mix personal and business posts, I want to keep them from the repository. I need a preview, accessible only to a few, something like &lt;a href="https://vercel.com/docs/concepts/deployments/preview-deployments" target="_blank" rel="noopener noreferrer"&gt;Vercel&amp;rsquo;s preview&lt;/a&gt;
. I&amp;rsquo;m using GitLab Pages, and there&amp;rsquo;s no such out-of-the-box feature.&lt;/p&gt;
&lt;p&gt;I tried two methods: GitHub gists and PDFs. Both have issues.&lt;/p&gt;</description></item><item><title>Managing Data Residency: The Demo</title><link>https://foojayio.github.io/website/today/managing-data-residency-the-demo/</link><pubDate>Mon, 29 May 2023 07:33:28 +0000</pubDate><guid>https://foojayio.github.io/website/today/managing-data-residency-the-demo/</guid><description>&lt;p&gt;I explained the concepts and theory behind Data Residency in a &lt;a href="https://foojayio.github.io/website/today/managing-data-residency-concepts-theory/"&gt;previous post&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s time to get our hands dirty and implement it in a simple demo.&lt;/p&gt;
&lt;h2 id="h2-0-the-sample-architecture"&gt;The sample architecture&lt;/h2&gt;
&lt;p&gt;In the last section of the previous post, I proposed a sample architecture where location-based routing happened at two different stages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The API Gateway checks for an existing &lt;code&gt;X-Country&lt;/code&gt; header. Depending on its value, it forwards the request to the computed upstream; If no value is found or no value matches, it forwards it to a default upstream.&lt;/li&gt;
&lt;li&gt;The application uses &lt;a href="https://shardingsphere.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Apache Shardingsphre&lt;/a&gt;
 to route again depending on the data. If the value computed by the API Gateway is correct, the flow stays &amp;ldquo;in its lane&amp;rdquo;; if not, it&amp;rsquo;s routed to the correct database, but with a performance penalty as it&amp;rsquo;s outside its lane.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I simplified some aspects:&lt;/p&gt;</description></item><item><title>Managing Data Residency: Concepts &amp; Theory</title><link>https://foojayio.github.io/website/today/managing-data-residency-concepts-theory/</link><pubDate>Tue, 16 May 2023 09:18:20 +0000</pubDate><guid>https://foojayio.github.io/website/today/managing-data-residency-concepts-theory/</guid><description>&lt;p&gt;Cloud computing has opened a Pandora&amp;rsquo;s Box of many original issues compared to sound old on-premise systems. I believe that chief among them is &lt;strong&gt;Data Residency&lt;/strong&gt;, or Data Location.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Data localization or data residency law requires data about a nation&amp;rsquo;s citizens or residents to be collected, processed, and/or stored inside the country, often before being transferred internationally. Such data is usually transferred only after meeting local privacy or data protection laws, such as giving the user notice of how the information will be used and obtaining their consent.&lt;/p&gt;</description></item><item><title>Leverage the Richness of HTTP Status Codes</title><link>https://foojayio.github.io/website/today/leverage-the-richness-of-http-status-codes/</link><pubDate>Tue, 02 May 2023 09:34:43 +0000</pubDate><guid>https://foojayio.github.io/website/today/leverage-the-richness-of-http-status-codes/</guid><description>&lt;p&gt;If you&amp;rsquo;re not a REST expert, you probably use the same HTTP codes over and over in your responses, mostly 200, 404, and 500.&lt;/p&gt;
&lt;p&gt;If using authentication, you might perhaps add 401 and 403; if using redirects 301 and 302, that might be all.&lt;/p&gt;
&lt;p&gt;But the range of possible status codes is much broader than that and can improve semantics a lot.&lt;/p&gt;
&lt;p&gt;While many discussions about REST focus on entities and methods, using the correct response status codes can make your API stand out.&lt;/p&gt;</description></item><item><title>Fearless Distroless</title><link>https://foojayio.github.io/website/today/fearless-distroless/</link><pubDate>Fri, 21 Apr 2023 08:59:50 +0000</pubDate><guid>https://foojayio.github.io/website/today/fearless-distroless/</guid><description>&lt;p&gt;With the rise of Docker came a new focus for engineers: optimizing the build to reach the smallest image size possible.&lt;/p&gt;
&lt;p&gt;A couple of options are available.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multi-stage builds.&lt;/strong&gt; A &lt;code&gt;Dockerfile&lt;/code&gt; can consist of multiple steps, each having a different Docker base image. Each step can copy files from any of the previous build steps. Only the last one will receive a tag; the others will be left untagged.This approach separates one or more build steps and a run step. On the JVM, it means that the first step includes compiling and packaging, based on a JDK, and the second step comprises running, based on a JRE.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Choosing the smallest base image size.&lt;/strong&gt; The smaller the base image, the smaller the resulting image.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this post, I&amp;rsquo;m going to focus on the second point.&lt;/p&gt;</description></item><item><title>My First Firefox Extension</title><link>https://foojayio.github.io/website/today/my-first-firefox-extension/</link><pubDate>Mon, 10 Apr 2023 18:36:13 +0000</pubDate><guid>https://foojayio.github.io/website/today/my-first-firefox-extension/</guid><description>&lt;p&gt;A couple of weeks ago, I spent the weekend creating another submission helper in the form of a Firefox extension.&lt;/p&gt;
&lt;p&gt;It was not a walk in the park.&lt;/p&gt;
&lt;p&gt;To help others who may be interested in doing the same (and my future self), here&amp;rsquo;s my journey!&lt;/p&gt;
&lt;h2 id="h2-0-context"&gt;Context&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve written multiple posts about my &lt;a href="https://blog.frankel.ch/automating-conference-submission-workflow/" target="_blank" rel="noopener noreferrer"&gt;conference submission workflow&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;To sum up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Everything is based on a Trello board&lt;/li&gt;
&lt;li&gt;I created an app that registered a webhook on the board&lt;/li&gt;
&lt;li&gt;When I move a conference from one lane to another, it starts or continues a workflow on the app side&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I source the board by looking at websites, mainly &lt;a href="https://www.papercall.io/events?cfps-scope=open&amp;amp;amp;keywords=" target="_blank" rel="noopener noreferrer"&gt;Papercall&lt;/a&gt;
 and &lt;a href="https://sessionize.com/" target="_blank" rel="noopener noreferrer"&gt;Sessionize&lt;/a&gt;
, and manually copying conference data on cards. Two automation options are available:&lt;/p&gt;</description></item><item><title>My Evaluation of the Scaleway Cloud Provider</title><link>https://foojayio.github.io/website/today/my-evaluation-of-the-scaleway-cloud-provider/</link><pubDate>Fri, 31 Mar 2023 09:54:20 +0000</pubDate><guid>https://foojayio.github.io/website/today/my-evaluation-of-the-scaleway-cloud-provider/</guid><description>&lt;p&gt;A couple of years ago, I developed an app that helped me manage my conference submission workflow.&lt;/p&gt;
&lt;p&gt;Since then, I have been a happy user of the free Heroku plan.&lt;/p&gt;
&lt;p&gt;Last summer, Heroku&amp;rsquo;s owner, Salesforce, announced that it would stop the free plan in November 2022.&lt;/p&gt;
&lt;p&gt;I searched for a new hosting provider and found &lt;a href="https://www.scaleway.com/" target="_blank" rel="noopener noreferrer"&gt;Scaleway&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;In this article, I&amp;rsquo;d like to explain my requirement, why I chose them, and my experience using them.&lt;/p&gt;</description></item><item><title>Book Review: "API Design Patterns"</title><link>https://foojayio.github.io/website/today/book-review-api-design-patterns/</link><pubDate>Sun, 19 Mar 2023 15:20:56 +0000</pubDate><guid>https://foojayio.github.io/website/today/book-review-api-design-patterns/</guid><description>&lt;p&gt;&lt;em&gt;Disclaimer: this post includes affiliate links; I may receive compensation if you purchase the book from the different links provided in this post.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This review is about &lt;a href="https://www.manning.com/books/api-design-patterns?utm_source=frankel&amp;amp;amp;utm_medium=affiliate&amp;amp;amp;utm_campaign=affiliate&amp;amp;amp;a_aid=frankel" target="_blank" rel="noopener noreferrer"&gt;API Design Patterns&lt;/a&gt;
 by JJ Geewax from Manning.&lt;/p&gt;
&lt;p&gt;I &lt;a href="https://blog.frankel.ch/structured-errors-http-apis/" target="_blank" rel="noopener noreferrer"&gt;already mentioned&lt;/a&gt;
 how I&amp;rsquo;m trying to get to speed in the API world: reading books, viewing relevant YouTube videos and reading relevant s.&lt;/p&gt;
&lt;h2 id="h2-0-facts"&gt;Facts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;30 chapters, $35.00&lt;/li&gt;
&lt;li&gt;The author is a Principal Software Engineer at Google&lt;/li&gt;
&lt;li&gt;He&amp;rsquo;s also the author behind&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="h2-1-chapters"&gt;Chapters&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Design principles
3. Naming
4. Resource scope and hierarchy
5. Data types and defaults&lt;/li&gt;
&lt;li&gt;Fundamentals
6. Resource identification: How to identify resources in an API
7. Standard methods: The set of standard methods for use in resource-oriented APIs
8. Partial updates and retrievals: How to interact with portions of resources
9. Custom methods: Using custom (non-standard) methods in resource-oriented APIs
10. Long-running operations: How to handle methods that are not instantaneous
11. Rerunnable jobs: Running repeated custom functionality in an API&lt;/li&gt;
&lt;li&gt;Resource relationships
12. Singleton sub-resources: Isolating portions of resource data
13. Cross references: How to reference other resources in an API
14. Association resources: How to manage many-to-many relationships with metadata
15. Add and remove custom methods: How to manage many-to-many relationships &lt;em&gt;without&lt;/em&gt; metadata
16. Polymorphism: Designing resources with dynamically-typed attributes&lt;/li&gt;
&lt;li&gt;Collective operations
17. Copy and move: Duplicating and relocating resources in an API
18. Batch operations: Extending methods to apply to groups of resources atomically
19. Criteria-based deletion: Deleting multiple resources based on a set of filter criteria
20. Anonymous writes: Ingesting unaddressable data into an API
21. Pagination: Consuming large amounts of data in bite-sized chunks
22. Filtering: Limiting result sets according to a user-specified filter
23. Importing and exporting: Moving data into or out of an API by interacting directly with a storage system&lt;/li&gt;
&lt;li&gt;Safety and security
24. Versioning and compatibility: Defining compatibility and strategies for versioning APIs
25. Soft deletion: Moving resources to the &amp;ldquo;API recycle bin&amp;rdquo;
26. Request deduplication: Preventing duplicate work due to network interruptions in APIs
27. Request validation: Allowing API methods to be called in &amp;ldquo;safe mode&amp;rdquo;
28. Resource revisions: Tracking resource change history
29. Request retrial: Algorithms for safely retrying API requests
30. Request authentication: Verifying that requests are authentic and untampered with&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each &lt;em&gt;design pattern&lt;/em&gt; chapter follows the same structure:&lt;/p&gt;</description></item><item><title>Authenticate with OpenID Connect and Apache APISIX</title><link>https://foojayio.github.io/website/today/authenticate-with-openid-connect-and-apache-apisix/</link><pubDate>Thu, 09 Mar 2023 07:51:47 +0000</pubDate><guid>https://foojayio.github.io/website/today/authenticate-with-openid-connect-and-apache-apisix/</guid><description>&lt;p&gt;Lots of companies are eager to provide their identity provider: Twitter, Facebook, Google, etc. For smaller businesses, not having to manage identities is a benefit. However, we want to avoid being locked into one provider.&lt;/p&gt;
&lt;p&gt;In this article, I want to demo how to use OpenID Connect using Google underneath and then switch to Azure.&lt;/p&gt;
&lt;h2 id="h2-0-openid-connect"&gt;OpenID Connect&lt;/h2&gt;
&lt;p&gt;The idea of an &lt;em&gt;authorization&lt;/em&gt; open standard started with &lt;a href="https://en.wikipedia.org/wiki/OAuth" target="_blank" rel="noopener noreferrer"&gt;OAuth&lt;/a&gt;
 around 2006. Because of a security issue, OAuth 2.0 superseded the initial version. OAuth 2.0 became an in 2012:&lt;/p&gt;</description></item><item><title>Make Your Security Policy Auditable</title><link>https://foojayio.github.io/website/today/make-your-security-policy-auditable/</link><pubDate>Tue, 28 Feb 2023 11:14:22 +0000</pubDate><guid>https://foojayio.github.io/website/today/make-your-security-policy-auditable/</guid><description>&lt;p&gt;Following from my previous article, I wrote about &lt;a href="https://foojayio.github.io/website/today/the-right-feature-at-the-right-place/"&gt;putting the right feature at the right place&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;I used rate limiting as an example, moving it from a library inside the application to the API Gateway.&lt;/p&gt;
&lt;p&gt;Today, I&amp;rsquo;ll use another example: authentication and authorization.&lt;/p&gt;
&lt;h2 id="h2-0-securing-a-spring-boot-application"&gt;Securing a Spring Boot application&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll keep using Spring Boot in the following because I&amp;rsquo;m familiar with it. The Spring Boot application offers a REST endpoint to check employees&amp;rsquo; salaries.&lt;/p&gt;</description></item><item><title>The Right Feature at the Right Place</title><link>https://foojayio.github.io/website/today/the-right-feature-at-the-right-place/</link><pubDate>Tue, 28 Feb 2023 11:08:14 +0000</pubDate><guid>https://foojayio.github.io/website/today/the-right-feature-at-the-right-place/</guid><description>&lt;p&gt;Before moving to Developer Relations, I transitioned from Software Architect to Solution Architect long ago.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a reasonably common career move.&lt;/p&gt;
&lt;p&gt;The problem in this situation is two-fold:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You know perfectly well software libraries&lt;/li&gt;
&lt;li&gt;You don&amp;rsquo;t know well infrastructure components&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It seems logical that people in this situation try to solve problems with the solutions they are most familiar with.&lt;/p&gt;
&lt;p&gt;However, it doesn&amp;rsquo;t mean it&amp;rsquo;s the best approach.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a bad one in most cases.&lt;/p&gt;</description></item><item><title>Null Safety: Kotlin vs. Java</title><link>https://foojayio.github.io/website/today/null-safety-kotlin-vs-java/</link><pubDate>Mon, 13 Feb 2023 12:12:35 +0000</pubDate><guid>https://foojayio.github.io/website/today/null-safety-kotlin-vs-java/</guid><description>&lt;p&gt;Last week, I was at the &lt;a href="https://fosdem.org/" target="_blank" rel="noopener noreferrer"&gt;FOSDEM&lt;/a&gt;
 conference. FOSDEM is specific in that it has multiple rooms, each dedicated to a different theme and organized by a team. I had two talks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fosdem.org/2023/schedule/event/tracing/" target="_blank" rel="noopener noreferrer"&gt;Practical Introduction to OpenTelemetry Tracing&lt;/a&gt;
, in the &lt;em&gt;Monitoring and Observability&lt;/em&gt; devroom&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fosdem.org/2023/schedule/event/miss/" target="_blank" rel="noopener noreferrer"&gt;What I miss in Java, the perspective of a Kotlin developer&lt;/a&gt;
, in the &lt;em&gt;Friends of OpenJDK&lt;/em&gt; devroom&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The second talk is from &lt;a href="https://blog.frankel.ch/miss-in-java-kotlin-developer/" target="_blank" rel="noopener noreferrer"&gt;an earlier post&lt;/a&gt;
. Martin Bonnin did a tweet from a single slide, and it created quite a stir, even attracting Brian Goetz.&lt;/p&gt;</description></item><item><title>Securing Admin Access to Apache APISIX</title><link>https://foojayio.github.io/website/today/securing-admin-access-to-apache-apisix/</link><pubDate>Sat, 11 Feb 2023 16:34:59 +0000</pubDate><guid>https://foojayio.github.io/website/today/securing-admin-access-to-apache-apisix/</guid><description>&lt;p&gt;API Gateways are critical components in one&amp;rsquo;s infrastructure.&lt;/p&gt;
&lt;p&gt;If an attacker could change the configuration of routes, they could direct traffic to their infrastructure.&lt;/p&gt;
&lt;p&gt;Consequences could range from data theft to financial losses.&lt;/p&gt;
&lt;p&gt;Worse, data theft could only be noticed after a long time by mirroring the load.&lt;/p&gt;
&lt;p&gt;Hence, protecting your API Gateway is of utmost importance.&lt;/p&gt;
&lt;p&gt;In this short article, I&amp;rsquo;ll list a couple of ways to secure your Apache APISIX admin access.&lt;/p&gt;</description></item><item><title>Quest for REST</title><link>https://foojayio.github.io/website/today/quest-for-rest/</link><pubDate>Fri, 27 Jan 2023 14:48:38 +0000</pubDate><guid>https://foojayio.github.io/website/today/quest-for-rest/</guid><description>&lt;p&gt;Since I started working for &lt;a href="https://apisix.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;
, I have tried to deepen my understanding of REST via various means. Did you read my review of &lt;a href="https://blog.frankel.ch/api-design-patterns" target="_blank" rel="noopener noreferrer"&gt;API Design Patterns book&lt;/a&gt;
?&lt;/p&gt;
&lt;p&gt;In the current literature, REST is generally promoted as the best thing since sliced bread. Yet, it comes with lots of challenges. In 2010(!), Martin Fowler wrote a post on the &lt;a href="https://martinfowler.com/articles/richardsonMaturityModel.html" target="_blank" rel="noopener noreferrer"&gt;glory of REST&lt;/a&gt;
. He lists three steps for an API to become &lt;em&gt;truly&lt;/em&gt; REST:&lt;/p&gt;</description></item><item><title>2022 in Retrospective</title><link>https://foojayio.github.io/website/today/2022-in-retrospective/</link><pubDate>Tue, 10 Jan 2023 08:19:43 +0000</pubDate><guid>https://foojayio.github.io/website/today/2022-in-retrospective/</guid><description>&lt;p&gt;2022 is over, and not a moment too soon. I&amp;rsquo;ll never forget it: some of my friends had to flee their own country; others are fighting for their freedom as I write this post. I hope they will be safe and that their wishes will come true in 2023.&lt;/p&gt;
&lt;p&gt;On the personal and technical side, here&amp;rsquo;s a summary of the past year from my perspective.&lt;/p&gt;
&lt;h2 id="h2-0-job-change"&gt;Job change&lt;/h2&gt;
&lt;img fetchpriority="high" decoding="async" class="alignright size-full wp-image-61589" src="apache-apisix.jpeg" alt="" width="300" height="300"&gt;
&lt;br /&gt;
&lt;p&gt;First and foremost, I changed jobs. I worked for &lt;a href="https://hazelcast.com/" target="_blank" rel="noopener noreferrer"&gt;Hazelcast&lt;/a&gt;
 for 3½ years.&lt;/p&gt;</description></item><item><title>Spring Modulith: Have We Reached Modularity Maturity?</title><link>https://foojayio.github.io/website/today/spring-modulith-modularity-maturity/</link><pubDate>Thu, 29 Dec 2022 07:07:29 +0000</pubDate><guid>https://foojayio.github.io/website/today/spring-modulith-modularity-maturity/</guid><description>&lt;p&gt;One of the main reasons to design microservices is that they enforce &lt;a href="https://martinfowler.com/articles/microservice-trade-offs.html#boundaries" target="_blank" rel="noopener noreferrer"&gt;strong module boundaries&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;However, the cons of microservices are so huge that it&amp;rsquo;s like chopping off your right hand to learn to write with the left one; there are more manageable (and less painful!) ways to achieve the same result.&lt;/p&gt;
&lt;p&gt;Even since the microservices craze started, some cooler heads have prevailed.&lt;/p&gt;
&lt;p&gt;In particular, &lt;a href="https://twitter.com/odrotbohm" target="_blank" rel="noopener noreferrer"&gt;Oliver Drotbohm&lt;/a&gt;
, a developer on the Spring framework, has been a long-time proponent of the &lt;a href="https://github.com/moduliths/moduliths" target="_blank" rel="noopener noreferrer"&gt;moduliths&lt;/a&gt;
 alternative.&lt;/p&gt;</description></item><item><title>Preparing to Move Away from Twitter</title><link>https://foojayio.github.io/website/today/preparing-to-move-away-from-twitter/</link><pubDate>Fri, 16 Dec 2022 06:42:40 +0000</pubDate><guid>https://foojayio.github.io/website/today/preparing-to-move-away-from-twitter/</guid><description>&lt;p&gt;I opened my Twitter account more than 13 years ago, in August 2009. For 12 years, I kept focusing on professional-related content: Java, the JVM, programming, etc. I built my audience, trying to promote good technical content, either my own or stuff that I enjoyed reading.&lt;/p&gt;
&lt;p&gt;Then, on February 24^th^, Russia invaded Ukraine. My first visit to Ukraine was in 2014, just after the Maidan revolution. During eight years, I returned there often and made plenty of friends.&lt;/p&gt;</description></item><item><title>Web resource caching: Server-side</title><link>https://foojayio.github.io/website/today/web-caching-server/</link><pubDate>Fri, 09 Dec 2022 15:32:42 +0000</pubDate><guid>https://foojayio.github.io/website/today/web-caching-server/</guid><description>&lt;p&gt;The subject of Web resource caching is as old as the World Wide Web itself.&lt;/p&gt;
&lt;p&gt;However, I&amp;rsquo;d like to offer an as-exhaustive-as-possible catalog of how one can improve performance by caching.&lt;/p&gt;
&lt;p&gt;Web resource caching can happen in two different places: client-side - on the browser and server side.&lt;/p&gt;
&lt;p&gt;In the &lt;a href="https://foojayio.github.io/website/today/web-caching-client/"&gt;previous post&lt;/a&gt;
, I explained the former; this post focuses on the latter.&lt;/p&gt;
&lt;p&gt;While client-side caching works well, it has one central issue: to serve the resource locally, it must first have it in the cache. Thus, each client needs its cached resource. If the requested resource is intensive to compute, it doesn&amp;rsquo;t scale.&lt;/p&gt;</description></item><item><title>Web resource caching: Client-side</title><link>https://foojayio.github.io/website/today/web-caching-client/</link><pubDate>Fri, 09 Dec 2022 15:27:44 +0000</pubDate><guid>https://foojayio.github.io/website/today/web-caching-client/</guid><description>&lt;p&gt;The subject of Web resource caching is as old as the World Wide Web itself.&lt;/p&gt;
&lt;p&gt;However, I&amp;rsquo;d like to offer an as-exhaustive-as-possible catalog of how one can improve performance by caching.&lt;/p&gt;
&lt;p&gt;Web resource caching can happen in two different places: client-side - on the browser and server-side.&lt;/p&gt;
&lt;p&gt;This article is dedicated to the former; the next article will focus on the latter.&lt;/p&gt;
&lt;h2 id="h2-0-caching-101"&gt;Caching 101&lt;/h2&gt;
&lt;p&gt;The idea behind caching is simple: if a resource is a time- or resource-consuming to compute, do it once and store the result.&lt;/p&gt;</description></item><item><title>A Poor Man's API</title><link>https://foojayio.github.io/website/today/poor-mans-api/</link><pubDate>Tue, 29 Nov 2022 09:13:38 +0000</pubDate><guid>https://foojayio.github.io/website/today/poor-mans-api/</guid><description>&lt;p&gt;Creating a full-fledged API requires resources, both time and money.&lt;/p&gt;
&lt;p&gt;You need to think about the model, the design, the REST principles, etc., without writing a single line of code.&lt;/p&gt;
&lt;p&gt;Most of the time, you don&amp;rsquo;t know whether it&amp;rsquo;s worth it: you&amp;rsquo;d like to offer a Minimum Viable Product and iterate from there.&lt;/p&gt;
&lt;p&gt;I want to show how you can achieve it without writing a single line of code.&lt;/p&gt;
&lt;h2 id="h2-0-the-solution"&gt;The solution&lt;/h2&gt;
&lt;p&gt;The main requirement of the solution is to use the &lt;a href="https://www.postgresql.org/" target="_blank" rel="noopener noreferrer"&gt;PostgreSQL database&lt;/a&gt;
. It&amp;rsquo;s a well-established Open Source SQL database.&lt;/p&gt;</description></item><item><title>Geo-routing with Apache APISIX</title><link>https://foojayio.github.io/website/today/geo-routing-with-apache-apisix/</link><pubDate>Mon, 07 Nov 2022 16:41:47 +0000</pubDate><guid>https://foojayio.github.io/website/today/geo-routing-with-apache-apisix/</guid><description>&lt;p&gt;Apache APISIX, the Apache-led API Gateway, comes out of the box with many plugins to implement your use case.&lt;/p&gt;
&lt;p&gt;Sometimes, however, the plugin you&amp;rsquo;re looking for is not available.&lt;/p&gt;
&lt;p&gt;While creating your own is always possible, it&amp;rsquo;s sometimes necessary.&lt;/p&gt;
&lt;p&gt;Today, I&amp;rsquo;ll show you how to route users according to their location without writing a single line of Lua code.&lt;/p&gt;
&lt;h2 id="h2-0-why-geo-routing"&gt;Why geo-routing?&lt;/h2&gt;
&lt;p&gt;Geo-routing is to forward HTTP requests based on a user&amp;rsquo;s physical location, inferred from their IP. There are many reasons to do that, and here is a couple of them.&lt;/p&gt;</description></item><item><title>Structured Error Messages for HTTP APIs</title><link>https://foojayio.github.io/website/today/structured-error-messages-http-apis/</link><pubDate>Tue, 01 Nov 2022 11:01:18 +0000</pubDate><guid>https://foojayio.github.io/website/today/structured-error-messages-http-apis/</guid><description>&lt;p&gt;Ever since I started to work on the &lt;a href="https://apisix.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;
 project, I&amp;rsquo;ve been trying to improve my knowledge and understanding of REST RESTful HTTP APIs.&lt;/p&gt;
&lt;p&gt;For this, I&amp;rsquo;m reading and watching the following sources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Books. At the moment, I&amp;rsquo;m finishing &lt;a href="https://www.manning.com/books/api-design-patterns" target="_blank" rel="noopener noreferrer"&gt;API Design Patterns&lt;/a&gt;
. Expect a review soon.&lt;/li&gt;
&lt;li&gt;YouTube. I&amp;rsquo;d recommend &lt;a href="https://www.youtube.com/ErikWilde" target="_blank" rel="noopener noreferrer"&gt;ErikWilde&amp;rsquo; channel&lt;/a&gt;
. While some videos are better than others, they all focus on APIs.&lt;/li&gt;
&lt;li&gt;s. Most RFCs are not about APIs, but a friendly person compiled a list of the &lt;a href="https://standards.rest/" target="_blank" rel="noopener noreferrer"&gt;ones who are&lt;/a&gt;
.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Today, I&amp;rsquo;d like to introduce the &amp;ldquo;Problem Details for HTTP APIs&amp;rdquo; RFC, &lt;em&gt;aka&lt;/em&gt; , &lt;a href="https://www.rfc-editor.org/rfc/rfc7807" target="_blank" rel="noopener noreferrer"&gt;RFC 7807&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Discuss the Problem, Not the Solution!</title><link>https://foojayio.github.io/website/today/discuss-problem-not-solution/</link><pubDate>Tue, 01 Nov 2022 10:56:17 +0000</pubDate><guid>https://foojayio.github.io/website/today/discuss-problem-not-solution/</guid><description>&lt;p&gt;As a tech guy, I love to discuss technologies. And as discussions go, it&amp;rsquo;s generally the comparison kind: JVM vs. Net, Java vs. Kotlin, Go vs. Rust, Maven vs. the unspeakable one, etc.&lt;/p&gt;
&lt;p&gt;However, it&amp;rsquo;s too easy to fall into the quagmire of the merits and flaws of our beloved toys, talk about them for hours, and not reach a satisfactory agreement.&lt;/p&gt;
&lt;p&gt;A couple of years ago, I worked as a &amp;ldquo;Solution Architect&amp;rdquo;.&lt;/p&gt;</description></item><item><title>Renovate: Dependabot Alternative</title><link>https://foojayio.github.io/website/today/renovate-alternative-dependabot/</link><pubDate>Fri, 28 Oct 2022 07:17:55 +0000</pubDate><guid>https://foojayio.github.io/website/today/renovate-alternative-dependabot/</guid><description>&lt;p&gt;I won&amp;rsquo;t introduce &lt;a href="https://github.com/dependabot" target="_blank" rel="noopener noreferrer"&gt;Dependabot&lt;/a&gt;
. Lots and lots of developers use it daily on GitHub. I do use it as well. However, it suffers from two drawbacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;While it&amp;rsquo;s perfectly integrated with GitHub, integrations with other platforms are less seamless.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s limited in the list of &lt;a href="https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem" target="_blank" rel="noopener noreferrer"&gt;ecosystems&lt;/a&gt;
 it supports For example, I generally use Docker Compose files for my demos. When necessary, I use Kubernetes. Dependabot supports none.Worse, Dependabot &lt;a href="https://github.com/dependabot/dependabot-core/blob/main/CONTRIBUTING.md#contributing-new-ecosystems" target="_blank" rel="noopener noreferrer"&gt;doesn&amp;rsquo;t accept contributions to add new ecosystems&lt;/a&gt;
.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Recently, I watched Viktor Farcic&amp;rsquo;s &lt;a href="https://www.youtube.com/watch?v=l0YH557eIiE" target="_blank" rel="noopener noreferrer"&gt;Automate Dependency Management With Renovate&lt;/a&gt;
. I found &lt;a href="https://www.mend.io/free-developer-tools/renovate/" target="_blank" rel="noopener noreferrer"&gt;Renovate&lt;/a&gt;
 super neat, thought about using it, and&amp;hellip; forgot. Then I stumbled upon another mention of it. It pushed me to implement it in two locations:&lt;/p&gt;</description></item><item><title>Handling Exceptions in Java Lambdas</title><link>https://foojayio.github.io/website/today/exceptions-lambdas/</link><pubDate>Sat, 22 Oct 2022 11:36:46 +0000</pubDate><guid>https://foojayio.github.io/website/today/exceptions-lambdas/</guid><description>&lt;p&gt;Java introduced the concept of &lt;em&gt;checked exceptions&lt;/em&gt; . The idea of forcing developers to manage exceptions was revolutionary compared to the &lt;a href="https://blog.frankel.ch/error-handling/" target="_blank" rel="noopener noreferrer"&gt;earlier approaches&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Nowadays, Java remains the only widespread language to offer checked exceptions. For example, every exception in Kotlin is unchecked.&lt;/p&gt;
&lt;p&gt;Even in Java, new features are at odds with checked exceptions:the signature of Java&amp;rsquo;s built-in functional interfaces doesn&amp;rsquo;t use exceptions.It leads to cumbersome code when one integrates legacy code in lambdas.It&amp;rsquo;s evident in Streams.&lt;/p&gt;</description></item><item><title>The Maze of Python Dependency Management</title><link>https://foojayio.github.io/website/today/the-maze-of-python-dependency-management/</link><pubDate>Mon, 03 Oct 2022 12:49:11 +0000</pubDate><guid>https://foojayio.github.io/website/today/the-maze-of-python-dependency-management/</guid><description>&lt;p&gt;For over 20 years, I&amp;rsquo;ve developed code for the JVM, first in Java, then in Kotlin.&lt;/p&gt;
&lt;p&gt;However, the JVM is not a silver bullet, &lt;em&gt;e.g.&lt;/em&gt;, in scripts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Virtual machines incur additional memory requirements.&lt;/li&gt;
&lt;li&gt;In many cases, the script doesn&amp;rsquo;t run long enough to gain any benefit performance-wise. The bytecode is interpreted and never compiles to native code.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For these reasons, I now write my scripts in Python. One of them collects social media metrics from different sources and stores them in BigQuery for analytics.&lt;/p&gt;</description></item><item><title>Apache APISIX Loves Rust! (And Me Too)</title><link>https://foojayio.github.io/website/today/apache-apisix-loves-rust/</link><pubDate>Mon, 26 Sep 2022 09:23:23 +0000</pubDate><guid>https://foojayio.github.io/website/today/apache-apisix-loves-rust/</guid><description>&lt;p&gt;Apache APISIX is built upon the shoulders of two giants:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.nginx.com/" target="_blank" rel="noopener noreferrer"&gt;NGINX&lt;/a&gt;
, a widespread Open Source reverse-proxy&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openresty.org/en/" target="_blank" rel="noopener noreferrer"&gt;OpenResty&lt;/a&gt;
, a platform that allows scripting NGINX with the &lt;a href="https://www.lua.org/" target="_blank" rel="noopener noreferrer"&gt;Lua&lt;/a&gt;
 programming language via &lt;a href="https://luajit.org/" target="_blank" rel="noopener noreferrer"&gt;LuaJIT&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach allows APISIX to provide out-of-the-box Lua plugins that should fit most business requirements. But it always comes a time when generic plugins don&amp;rsquo;t fit your requirements. In this case, you can write your own Lua plugin.&lt;/p&gt;</description></item><item><title>Introduction to Kubernetes Extensibility</title><link>https://foojayio.github.io/website/today/introduction-to-kubernetes-extensibility/</link><pubDate>Tue, 20 Sep 2022 09:44:43 +0000</pubDate><guid>https://foojayio.github.io/website/today/introduction-to-kubernetes-extensibility/</guid><description>&lt;p&gt;Kubernetes offers a lot of benefits: an enormous ecosystem with plenty of actors, self-healing capabilities, etc. There&amp;rsquo;s no free lunch, though. It also comes with downsides, chief among them its complexity and operating costs.&lt;/p&gt;
&lt;p&gt;However, the more I work with Kubernetes, the more I think its most significant asset is &lt;strong&gt;extensibility&lt;/strong&gt;. If you need something that the platform doesn&amp;rsquo;t provide by default, there&amp;rsquo;s an option to develop it yourself and integrate it. In this post, I&amp;rsquo;d like to list such extension points.&lt;/p&gt;</description></item><item><title>A Quick Glance at the Kubernetes Gateway API</title><link>https://foojayio.github.io/website/today/kubernetes-gateway-api/</link><pubDate>Mon, 12 Sep 2022 09:55:16 +0000</pubDate><guid>https://foojayio.github.io/website/today/kubernetes-gateway-api/</guid><description>&lt;p&gt;In &lt;a href="https://blog.frankel.ch/basics-access-kubernetes-pods/" target="_blank" rel="noopener noreferrer"&gt;one of my recent blog posts&lt;/a&gt;
, I described several ways to access Kubernetes pods. One can access a pod through its IP, but pods are naturally transient. The nominal way is to configure a &lt;code&gt;Service&lt;/code&gt;: its IP is stable, and Kubernetes&amp;rsquo; job is to keep the mapping between a &lt;code&gt;Service&lt;/code&gt; and its underlying pods up-to-date.&lt;/p&gt;
&lt;p&gt;Different kinds of services are available: internal only, &lt;code&gt;NodePort&lt;/code&gt; to finally allow access from outside the cluster, and &lt;code&gt;LoadBalancer&lt;/code&gt; that relies on a third-party component - in general, a cloud provider one.&lt;/p&gt;</description></item><item><title>On Cosmetics vs. Intrinsics in Programming</title><link>https://foojayio.github.io/website/today/on-cosmetics-vs-intrinsics-programming/</link><pubDate>Mon, 12 Sep 2022 09:39:56 +0000</pubDate><guid>https://foojayio.github.io/website/today/on-cosmetics-vs-intrinsics-programming/</guid><description>&lt;p&gt;A ruthless battle occurs every day on the World Wide Web. Its goal is to decide which programming flavor is the best: or ? I assume that imperative and procedural programming are not part of the contenders.&lt;/p&gt;
&lt;p&gt;Arguments range from the factual to the irrelevant to the utterly stupid. A couple of years ago, I wanted to listen to a video of Martin Odersky (of Scala fame). I remember neither the exact talk nor the subject. What I remember is the introduction, though: he explained that FP was more popular than OOP&amp;hellip; because there were many more conferences dedicated to the former than to the latter.&lt;/p&gt;</description></item><item><title>Learning by Auditing Kubernetes Manifests</title><link>https://foojayio.github.io/website/today/learning-by-auditing-kubernetes-manifests/</link><pubDate>Mon, 05 Sep 2022 08:44:17 +0000</pubDate><guid>https://foojayio.github.io/website/today/learning-by-auditing-kubernetes-manifests/</guid><description>&lt;p&gt;Last year, I spoke at the &lt;a href="https://www.devopsonline.co.uk/national-devops-conference/" target="_blank" rel="noopener noreferrer"&gt;National DevOps Conference&lt;/a&gt;
 that took place at the British Museum. I had already visited the museum before, but speaking there was a fantastic experience. Besides, we had the museum all for ourselves for a couple of hours. If you&amp;rsquo;ve ever visited the place, you know what I mean.&lt;/p&gt;
&lt;p&gt;Anyway, I also attended a talk about &lt;a href="https://www.checkov.io/" target="_blank" rel="noopener noreferrer"&gt;Checkov&lt;/a&gt;
:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Checkov scans cloud infrastructure configurations to find misconfigurations before they&amp;rsquo;re deployed.&lt;/p&gt;</description></item><item><title>End-to-End Tracing with OpenTelemetry</title><link>https://foojayio.github.io/website/today/end-to-end-tracing-opentelemetry/</link><pubDate>Mon, 29 Aug 2022 14:24:00 +0000</pubDate><guid>https://foojayio.github.io/website/today/end-to-end-tracing-opentelemetry/</guid><description>&lt;p&gt;Whether you implement microservices or not (and you probably shouldn&amp;rsquo;t), your system is most probably composed of multiple components.&lt;/p&gt;
&lt;p&gt;The most straightforward system is probably made of a reverse proxy, an app, and a database.&lt;/p&gt;
&lt;p&gt;In this case, monitoring is not only a good idea; it&amp;rsquo;s a requirement.&lt;/p&gt;
&lt;p&gt;The higher the number of components through which a request may flow, the strongest the requirement.&lt;/p&gt;
&lt;p&gt;However, monitoring is only the beginning of the journey.&lt;/p&gt;</description></item><item><title>Back to Basics: Accessing Kubernetes Pods</title><link>https://foojayio.github.io/website/today/back-to-basics-accessing-kubernetes-pods/</link><pubDate>Mon, 22 Aug 2022 13:56:58 +0000</pubDate><guid>https://foojayio.github.io/website/today/back-to-basics-accessing-kubernetes-pods/</guid><description>&lt;p&gt;Kubernetes is a colossal beast. You need to understand many different concepts before it starts being useful.&lt;/p&gt;
&lt;p&gt;When everything is set up, you&amp;rsquo;ll probably want to expose some pods to the outside of the cluster.&lt;/p&gt;
&lt;p&gt;Kubernetes provides different ways to do it: I&amp;rsquo;ll describe them in this post.&lt;/p&gt;
&lt;h2 id="h2-0-setup"&gt;Setup&lt;/h2&gt;
&lt;p&gt;For the sake of the demo, I&amp;rsquo;ll be using &lt;a href="https://kind.sigs.k8s.io/" target="_blank" rel="noopener noreferrer"&gt;Kind&lt;/a&gt;
:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;kind is a tool for running local Kubernetes clusters using Docker container &amp;ldquo;nodes&amp;rdquo;. kind was primarily designed for testing Kubernetes itself, but may be used for local development or CI.&lt;/p&gt;</description></item><item><title>Backend-for-Frontend: The Demo</title><link>https://foojayio.github.io/website/today/backend-for-frontend-the-demo/</link><pubDate>Mon, 15 Aug 2022 18:29:48 +0000</pubDate><guid>https://foojayio.github.io/website/today/backend-for-frontend-the-demo/</guid><description>&lt;p&gt;In &lt;a href="https://foojayio.github.io/website/today/backend-for-front-end/"&gt;one of my earlier posts&lt;/a&gt;
, I described the Backend-for-Frontend pattern.&lt;/p&gt;
&lt;p&gt;In short, it offers a single facade over multiple backend parts.&lt;/p&gt;
&lt;p&gt;Moreover, it provides each client type, &lt;em&gt;e.g.,&lt;/em&gt; desktop or mobile, exactly the data that it needs and not more in the format required by this client type.&lt;/p&gt;
&lt;h2 id="h2-0-the-use-case"&gt;The use-case&lt;/h2&gt;
&lt;p&gt;Imagine the following use-case.&lt;/p&gt;
&lt;p&gt;In an e-commerce shop, the home page should display multiple &lt;em&gt;unrelated&lt;/em&gt; data at once.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Products: The business could configure which items are shown on the home page. They could be generic, &amp;ldquo;hero&amp;rdquo; products, or personalized, products that the customer ordered previously.&lt;/li&gt;
&lt;li&gt;News: Again, the newsfeed could be generic or personalized.&lt;/li&gt;
&lt;li&gt;Profile-related information&lt;/li&gt;
&lt;li&gt;Cart content&lt;/li&gt;
&lt;li&gt;Non-business related information, such as build number, build timestamp, version, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Depending on the client, we want more or less data. For example, on a client with limited display size, we probably want to limit a product to its name and its image. On the other hand, on desktop, we are happy to display both the above, plus a catch phrase (or a more catchy - and longer - name) and the full description.&lt;/p&gt;</description></item><item><title>Write Your Own Service Discovery Client for Apache APISIX</title><link>https://foojayio.github.io/website/today/service-discovery-client-apache-apisix/</link><pubDate>Mon, 01 Aug 2022 10:27:42 +0000</pubDate><guid>https://foojayio.github.io/website/today/service-discovery-client-apache-apisix/</guid><description>&lt;p&gt;API Gateways in general, and &lt;a href="https://apisix.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;
 in particular, provide a single entry point into one&amp;rsquo;s information system.&lt;/p&gt;
&lt;p&gt;This architecture allows for managing load balancing and failover over similar nodes.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s how you can create a route balanced over two nodes in Apache APISIX:&lt;/p&gt;
&lt;pre class="EnlighterJSRAW" data-enlighter-language="bash"&gt;curl http://localhost:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '{
 "uri": "/*",
 "upstream": {
 "type": "roundrobin",
 "nodes": {
 "192.168.0.1:80": 1, # 1
 "192.168.0.2:80": 1 # 1
 }
 }
}'&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Every request has a 50/50 chance of being sent to either node&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It worked for a long time, but in this day and age, nodes are probably not pets but cattle: they come, and they go. Hence, it&amp;rsquo;s essential to dynamically update the nodes list when it happens.&lt;/p&gt;</description></item><item><title>Discussing Backend For Front-end</title><link>https://foojayio.github.io/website/today/backend-for-front-end/</link><pubDate>Mon, 25 Jul 2022 14:49:18 +0000</pubDate><guid>https://foojayio.github.io/website/today/backend-for-front-end/</guid><description>&lt;p&gt;In the good old days, applications were simple. A browser sent a request to a webapp endpoint; the latter fetched data from a database and returned the response.&lt;/p&gt;
&lt;p&gt;The rise of mobile clients and integrations with other apps upset this simplicity. I want to discuss one solution to handle the complexity in this post.&lt;/p&gt;
&lt;h2 id="h2-0-the-increased-complexity-of-system-architecture"&gt;The increased complexity of system architecture&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s first model the above simple architecture.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://foojayio.github.io/website/today/backend-for-front-end/webapp.png" alt="" loading="lazy"&gt;
&lt;/p&gt;
&lt;p&gt;Mobile clients changed this approach. The display area of mobile clients is smaller: just smaller for tablets and much smaller for phones.&lt;/p&gt;</description></item><item><title>How to Secure Your Web Apps With An API Gateway</title><link>https://foojayio.github.io/website/today/how-to-secure-your-web-apps-with-an-api-gateway/</link><pubDate>Mon, 18 Jul 2022 18:50:10 +0000</pubDate><guid>https://foojayio.github.io/website/today/how-to-secure-your-web-apps-with-an-api-gateway/</guid><description>&lt;p&gt;API management solutions, also known as API gateways, are a must in this day and age of APIs.&lt;/p&gt;
&lt;p&gt;However, once you&amp;rsquo;ve set up such a gateway, you can use it for different purposes unrelated to APIs.&lt;/p&gt;
&lt;p&gt;Today, I want to show you how to improve the security of web apps.&lt;/p&gt;
&lt;h2 id="h2-0-prevent-sniffing"&gt;Prevent sniffing&lt;/h2&gt;
&lt;p&gt;Browsers are fantastic pieces of technology that try to make the life of users as comfortable as possible.&lt;/p&gt;</description></item><item><title>Taking VSCodium for a Spin</title><link>https://foojayio.github.io/website/today/taking-vscodium-for-a-spin/</link><pubDate>Tue, 12 Jul 2022 08:10:30 +0000</pubDate><guid>https://foojayio.github.io/website/today/taking-vscodium-for-a-spin/</guid><description>&lt;p&gt;As part of my new job on &lt;a href="https://apisix.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;
, I write less Java and Kotlin code.&lt;/p&gt;
&lt;p&gt;And when I do, the code is &lt;a href="https://github.com/nfrankel/evolve-apis/blob/master/old-api/src/main/java/org/apisix/demo/oldapi/HelloWorldController.java" target="_blank" rel="noopener noreferrer"&gt;really&lt;/a&gt;
 &lt;a href="https://github.com/nfrankel/evolve-apis/blob/master/new-api/src/main/kotlin/org/apisix/newapi/NewApiApplication.kt" target="_blank" rel="noopener noreferrer"&gt;simple&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;My coding hours (unfortunately not days) involve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A lot of containerization, including &lt;code&gt;Dockerfile&lt;/code&gt;, &lt;code&gt;docker-compose.yml&lt;/code&gt;, and soon Kubernetes manifests&lt;/li&gt;
&lt;li&gt;Some Python for scripting jobs - I abandoned Kotlin Scripting for this&lt;/li&gt;
&lt;li&gt;A bit of Lua because I want to learn it as part of my job&lt;/li&gt;
&lt;li&gt;A bit of Rust because I want to learn it for fun&lt;/li&gt;
&lt;li&gt;A bit of Kotlin because I still love it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because of this, I didn&amp;rsquo;t renew my IntelliJ Ultimate license early this year, and I fell back on the Community one.&lt;/p&gt;</description></item><item><title>Hard Things in Computer Science</title><link>https://foojayio.github.io/website/today/hard-things-computer-science/</link><pubDate>Mon, 27 Jun 2022 08:13:01 +0000</pubDate><guid>https://foojayio.github.io/website/today/hard-things-computer-science/</guid><description>&lt;p&gt;If you&amp;rsquo;ve more than a couple of years of experience in IT, you probably have stumbled upon the following quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in computer science: cache invalidation and naming things. &amp;ndash; Phil Karlton&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then, because it&amp;rsquo;s such a great quote, it evolved:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/codinghorror/status/506010907021828096" target="_blank" rel="noopener noreferrer"&gt;&lt;img src="https://foojayio.github.io/website/today/hard-things-computer-science/Screenshot-2022-06-26-at-10.28.24.png" alt="" loading="lazy"&gt;
&lt;/a&gt;
However, I think that the initial quote is misleading. A lot of things are hard in computer science. This post aims to describe some of them.&lt;/p&gt;</description></item><item><title>What I Miss in Java, the Perspective of a Kotlin Developer</title><link>https://foojayio.github.io/website/today/miss-java-kotlin-developer/</link><pubDate>Wed, 15 Jun 2022 08:15:34 +0000</pubDate><guid>https://foojayio.github.io/website/today/miss-java-kotlin-developer/</guid><description>&lt;p&gt;Java has been my bread and butter for almost two decades.&lt;/p&gt;
&lt;p&gt;Several years ago, I started to learn Kotlin; I never regretted it.&lt;/p&gt;
&lt;p&gt;Though Kotlin compiles to JVM bytecode, I sometimes have to write Java again.&lt;/p&gt;
&lt;p&gt;Every time I do, I cannot stop pondering why my code doesn&amp;rsquo;t look as nice as in Kotlin.&lt;/p&gt;
&lt;p&gt;I miss some features that would improve my code&amp;rsquo;s readability, expressiveness, and maintainability.&lt;/p&gt;
&lt;p&gt;This article is not meant to bash Java but to list some features I&amp;rsquo;d like to find in Java.&lt;/p&gt;</description></item><item><title>My Summary of jPrime 2022</title><link>https://foojayio.github.io/website/today/my-summary-of-jprime-2022/</link><pubDate>Wed, 08 Jun 2022 18:37:55 +0000</pubDate><guid>https://foojayio.github.io/website/today/my-summary-of-jprime-2022/</guid><description>&lt;p&gt;Writing summaries of conference talks is the best way to focus on the talk and listen actively.&lt;/p&gt;
&lt;p&gt;Before conference speaking became part of my job, I was already doing it.&lt;/p&gt;
&lt;p&gt;However, I don&amp;rsquo;t attend that many talks now, and I don&amp;rsquo;t take notes when I do.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://jprime.io/" target="_blank" rel="noopener noreferrer"&gt;jPrime&lt;/a&gt;
 is a conference in Bulgaria, and after two cancellations due to Covid, they had their edition this week.&lt;/p&gt;
&lt;p&gt;Probably, for this reason, the atmosphere is quite emulating: I attended a couple of talks and here are my notes.&lt;/p&gt;</description></item><item><title>Running Jekyll on a Mac</title><link>https://foojayio.github.io/website/today/running-jekyll-on-a-mac/</link><pubDate>Mon, 06 Jun 2022 17:41:49 +0000</pubDate><guid>https://foojayio.github.io/website/today/running-jekyll-on-a-mac/</guid><description>&lt;p&gt;At the beginning of the year, I had two new Macs in a row in one month. I changed my company and had to return my previous laptop. Thus, I ordered a replacement one, but due to the current hardware shortage, the shipping took weeks: I had to rent one in the meanwhile.&lt;/p&gt;
&lt;p&gt;It means I had to install my Jekyll stack twice in a row. The first time took quite some time; the second one was much faster.&lt;/p&gt;</description></item><item><title>Chopping the Monolith: The Demo</title><link>https://foojayio.github.io/website/today/chopping-monolith-demo/</link><pubDate>Mon, 23 May 2022 12:53:49 +0000</pubDate><guid>https://foojayio.github.io/website/today/chopping-monolith-demo/</guid><description>&lt;p&gt;In my previous blog post &lt;a href="https://foojayio.github.io/website/today/chopping-monolith/"&gt;Chopping the Monolith&lt;/a&gt;
, I explained my stance on microservices and why it shouldn&amp;rsquo;t be your golden standard.&lt;/p&gt;
&lt;p&gt;However, I admitted that some parts of the codebase were less stable than others and had to change more frequently.&lt;/p&gt;
&lt;p&gt;I proposed &amp;ldquo;chopping&amp;rdquo; these few parts to cope with this requirement while keeping the monolith intact.&lt;/p&gt;
&lt;p&gt;As Linus Torvalds once wrote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Talk is cheap, show me the code!&lt;/p&gt;</description></item><item><title>Toying with Kotlin's Context Receivers</title><link>https://foojayio.github.io/website/today/kotlins-context-receivers/</link><pubDate>Mon, 16 May 2022 10:39:04 +0000</pubDate><guid>https://foojayio.github.io/website/today/kotlins-context-receivers/</guid><description>&lt;p&gt;Kotlin added the idea of Context Receivers in version 1.6.20.&lt;/p&gt;
&lt;p&gt;In this article, I&amp;rsquo;d like to toy with them to understand how useful they can be.&lt;/p&gt;
&lt;p&gt;Note that if you want to play along, you&amp;rsquo;ll need to compile with the &lt;code&gt;-Xcontext-receivers&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;The main idea behind context receivers is to pass additional parameters to a function without having to do it explicitly.&lt;/p&gt;
&lt;h2 id="h2-0-a-simplified-model-sample"&gt;A simplified model sample&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s start with a simple example to show how it works. We want to model a simple transfer operation between two bank accounts.&lt;/p&gt;</description></item><item><title>Conditional Builds on GitLab</title><link>https://foojayio.github.io/website/today/conditional-builds-on-gitlab/</link><pubDate>Mon, 09 May 2022 09:16:26 +0000</pubDate><guid>https://foojayio.github.io/website/today/conditional-builds-on-gitlab/</guid><description>&lt;p&gt;Regular readers of my articles know that I&amp;rsquo;m using &lt;a href="https://jekyllrb.com/" target="_blank" rel="noopener noreferrer"&gt;Jekyll&lt;/a&gt;
 to generate my static blog site, together with GitLab. When I push on the &lt;code&gt;master&lt;/code&gt; branch, it triggers the generation job.&lt;/p&gt;
&lt;p&gt;However, Jekyll is Ruby-based and requires a couple of Gem dependencies. I&amp;rsquo;ve also added a few plugins. For this reason, I&amp;rsquo;ve created a &lt;a href="https://blog.frankel.ch/musings-dockerfile-jekyll/" target="_blank" rel="noopener noreferrer"&gt;Docker image with all required dependencies&lt;/a&gt;
. Regularly, I update the versions in the &lt;code&gt;Gemfile.lock&lt;/code&gt; via Bundler. Afterward, I need to rebuild the Docker image.&lt;/p&gt;</description></item><item><title>Securely Authenticate to Google Cloud from GitHub</title><link>https://foojayio.github.io/website/today/securely-authenticate-google-cloud-github/</link><pubDate>Mon, 02 May 2022 08:57:00 +0000</pubDate><guid>https://foojayio.github.io/website/today/securely-authenticate-google-cloud-github/</guid><description>&lt;p&gt;Recently, I designed a simple metrics-tracking system.&lt;/p&gt;
&lt;p&gt;A Python script queries different providers&amp;rsquo; APIs for metrics, &lt;em&gt;e.g.&lt;/em&gt;, Twitter, GitHub, etc.&lt;/p&gt;
&lt;p&gt;The idea is to run this script each day, store them in Google BigQuery and provide an excellent data visualization in Google Data Studio.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m a big fan of automation, so I&amp;rsquo;m using GitHub Actions.&lt;/p&gt;
&lt;h2 id="h2-0-accessing-google-cloud-with-a-service-account"&gt;Accessing Google Cloud with a Service Account&lt;/h2&gt;
&lt;p&gt;I query the different APIs with different Python libraries. All of them allow authenticating by passing a parameter. In general, it&amp;rsquo;s a token. One can store the value in a GitHub secret, get it as an environment variable in the GitHub Action and use it in the code.&lt;/p&gt;</description></item><item><title>Chopping the Monolith: Foojay.io Today</title><link>https://foojayio.github.io/website/today/chopping-monolith/</link><pubDate>Mon, 25 Apr 2022 19:06:50 +0000</pubDate><guid>https://foojayio.github.io/website/today/chopping-monolith/</guid><description>&lt;p&gt;If you attend conferences or read technical articles, you could think that microservices are the correct and only way to build a system at the moment.&lt;/p&gt;
&lt;p&gt;Despite some pushback from cooler heads, the default architecture is microservices.&lt;/p&gt;
&lt;p&gt;In this post, I&amp;rsquo;d like to argue why it&amp;rsquo;s wrong.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll first get back to the origin of microservices and the fundamental reason to use them.&lt;/p&gt;
&lt;p&gt;Then, I&amp;rsquo;ll describe why microservices don&amp;rsquo;t fit most organizations&amp;rsquo; structures.&lt;/p&gt;</description></item><item><title>How To Beautify Your GitHub Repo</title><link>https://foojayio.github.io/website/today/how-to-beautify-your-github-repo/</link><pubDate>Tue, 19 Apr 2022 08:16:37 +0000</pubDate><guid>https://foojayio.github.io/website/today/how-to-beautify-your-github-repo/</guid><description>&lt;p&gt;Whether you like it or not, GitHub has become the primary provider to host one&amp;rsquo;s code.&lt;/p&gt;
&lt;p&gt;You or your company are probably using GitHub.&lt;/p&gt;
&lt;p&gt;In this article, I want to highlight some files that you can use to beautify your GitHub repository and make it welcoming and inspiring to those who stop by.&lt;/p&gt;
&lt;h2 id="h2-0-readme"&gt;README&lt;/h2&gt;
&lt;p&gt;I hope that by now, everybody is familiar with READMEs. If you place a README file at the root of your repo, GitHub will display its content on the repo&amp;rsquo;s homepage.&lt;/p&gt;</description></item><item><title>Handling Null: Optional and Nullable Types</title><link>https://foojayio.github.io/website/today/handling-null-optional-and-nullable-types/</link><pubDate>Mon, 04 Apr 2022 08:06:37 +0000</pubDate><guid>https://foojayio.github.io/website/today/handling-null-optional-and-nullable-types/</guid><description>&lt;p&gt;Java has long been infamous for its &lt;code&gt;NullPointerException&lt;/code&gt;. The reason for the is calling a method or accessing an attribute of an &lt;strong&gt;object that has not been initialized&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class="EnlighterJSRAW" data-enlighter-language="java"&gt;var value = foo.getBar().getBaz().toLowerCase();&lt;/pre&gt;
&lt;p&gt;Running this snippet may result in something like the following:&lt;/p&gt;
&lt;pre class="EnlighterJSRAW" data-enlighter-language="generic"&gt;Exception in thread "main" java.lang.NullPointerException
 at ch.frankel.blog.NpeSample.main(NpeSample.java:10)&lt;/pre&gt;
&lt;p&gt;At this point, you have no clue which part is &lt;code&gt;null&lt;/code&gt; in the call chain: &lt;code&gt;foo&lt;/code&gt;, or the value returned by &lt;code&gt;getBar()&lt;/code&gt; or &lt;code&gt;getBaz()&lt;/code&gt;?&lt;/p&gt;</description></item><item><title>APISIX: An API Gateway the Apache Way</title><link>https://foojayio.github.io/website/today/apisix-api-gateway/</link><pubDate>Mon, 28 Mar 2022 07:40:15 +0000</pubDate><guid>https://foojayio.github.io/website/today/apisix-api-gateway/</guid><description>&lt;p&gt;During the pioneer area of the World Wide Web, the content was static. To serve it, a group of developers created a web server, which is now known as the &lt;a href="https://httpd.apache.org/" target="_blank" rel="noopener noreferrer"&gt;Apache Web Server&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;The Apache Web Server is built around a modular architecture. Developers created a module to run CGI scripts to add dynamic content to the lot. Users wrote early CGI scripts in Perl. After a while, it became evident that generating a complete HTML page from scratch was not the best way and that templating - providing an HTML page with placeholders - was a much better approach. The PHP language started like this as a simple templating engine interpreted by a module.&lt;/p&gt;</description></item><item><title>Error Handling in Java and Across Different Languages</title><link>https://foojayio.github.io/website/today/error-handling/</link><pubDate>Mon, 21 Mar 2022 11:23:46 +0000</pubDate><guid>https://foojayio.github.io/website/today/error-handling/</guid><description>&lt;p&gt;I&amp;rsquo;ve tried Go in the past, and the least I could say is that I was not enthusiastic about it. Chief among my griefs was how the language handled errors, or more precisely, what mechanism it provided developers with to manage them.&lt;/p&gt;
&lt;p&gt;In this post, I&amp;rsquo;d like to describe how a couple of popular languages cope with errors.&lt;/p&gt;
&lt;h2 id="h2-0-a-time-before-our-time"&gt;A time before our time&lt;/h2&gt;
&lt;p&gt;I could probably go back a long time, but I needed to choose a baseline at some point. In this post, the baseline is C.&lt;/p&gt;</description></item><item><title>Lessons learned from previous projects</title><link>https://foojayio.github.io/website/today/lessons-learned-from-previous-projects/</link><pubDate>Mon, 14 Mar 2022 13:02:01 +0000</pubDate><guid>https://foojayio.github.io/website/today/lessons-learned-from-previous-projects/</guid><description>&lt;p&gt;An exciting part of software development is what was unanimously considered good practice at one point in time can be more ambiguous years later. Or even plain wrong. However, you generally need to do it multiple times over time to realize it. Here are my top learnings from my experience in Java projects.&lt;/p&gt;
&lt;h2 id="h2-0-packaging-by-layers"&gt;Packaging by layers&lt;/h2&gt;
&lt;p&gt;When I started my developer career in Java, every project organized their classes by layers - controllers, services and s (repositories). A typical project&amp;rsquo;s structure would look like this:&lt;/p&gt;</description></item><item><title>Alternatives to DTO</title><link>https://foojayio.github.io/website/today/alternatives-to-dto/</link><pubDate>Mon, 07 Mar 2022 11:03:23 +0000</pubDate><guid>https://foojayio.github.io/website/today/alternatives-to-dto/</guid><description>&lt;p&gt;More than a decade ago, I &lt;a href="https://blog.frankel.ch/dto-in-anger" target="_blank" rel="noopener noreferrer"&gt;wrote&lt;/a&gt;
 about the :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;A data transfer object is an object that carries data between processes. The motivation for its use is that communication between processes is usually done resorting to remote interfaces, where each call is an expensive operation. Because the majority of the cost of each call is related to the round-trip time between the client and the server, one way of reducing the number of calls is to use an object (the DTO) that aggregates the data that would have been transferred by the several calls, but that is served by one call only.&amp;rdquo; &amp;ndash; &lt;a href="https://en.wikipedia.org/wiki/Data_transfer_object" target="_blank" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Avoiding Stringly-typed in Kotlin</title><link>https://foojayio.github.io/website/today/avoid-stringly-typed-in-kotlin/</link><pubDate>Mon, 28 Feb 2022 16:35:28 +0000</pubDate><guid>https://foojayio.github.io/website/today/avoid-stringly-typed-in-kotlin/</guid><description>&lt;p&gt;A couple of years ago, I developed an application in Kotlin based on Camunda to help me manage my conference submission workflow. It tracks my submissions in Trello and synchronizes them on Google Calendar and in a Google Sheet. Google Calendar offers a REST API. As REST APIs go, it&amp;rsquo;s cluttered with &lt;code&gt;String&lt;/code&gt; everywhere. Here&amp;rsquo;s an excerpt of the code:&lt;/p&gt;
&lt;pre class="EnlighterJSRAW" data-enlighter-language="kotlin"&gt;fun execute(color: String, availability: String) {
 findCalendarEntry(client, google, execution.conference)?.let {
 it.colorId = color // 1
 it.transparency = availability // 2
 client.events()
 .update(google.calendarId, it.id, it).execute()
 }
}&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Set the event&amp;rsquo;s color. Valid values are &amp;ldquo;0&amp;rdquo;, &amp;ldquo;1&amp;rdquo;, &amp;hellip; to &amp;ldquo;11&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Set the event&amp;rsquo;s availability. Valid values are &lt;code&gt;&amp;quot;transparent&amp;quot;&lt;/code&gt; and &lt;code&gt;&amp;quot;opaque&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;However, my experience has taught me to favor strong typing. I also want to avoid typos. I want to list some alternatives to using &lt;code&gt;String&lt;/code&gt; in this post.&lt;/p&gt;</description></item><item><title>System Logger</title><link>https://foojayio.github.io/website/today/system-logger/</link><pubDate>Fri, 18 Feb 2022 12:34:57 +0000</pubDate><guid>https://foojayio.github.io/website/today/system-logger/</guid><description>&lt;p&gt;December was not a good time for Java developers and even less for Ops. The former had to repackage their apps with a fixed Log4J&amp;rsquo;s version, and the latter had to redeploy them - several times. Yet, every cloud has a silver lining. In my case, I learned about &lt;code&gt;System.Logger&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/OndroMih/status/1469599938782932992" target="_blank" rel="noopener noreferrer"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;[&lt;/p&gt;
&lt;img fetchpriority="high" decoding="async" class="size-medium wp-image-52382 aligncenter" src="Screenshot-2022-02-12-at-16.53.31-700x451.png" alt="" width="700" height="451"&gt;
&lt;p&gt;](&lt;a href="https://twitter.com/OndroMih/status/1469599938782932992" target="_blank" rel="noopener noreferrer"&gt;https://twitter.com/OndroMih/status/1469599938782932992&lt;/a&gt;
)
In short, &lt;code&gt;System.Logger&lt;/code&gt; is a façade over your logging engine. Instead of using, say, SFL4J&amp;rsquo;s API and the wanted implementation, you&amp;rsquo;d use &lt;code&gt;System.Logger&lt;/code&gt; instead of SLF4J. It&amp;rsquo;s available since Java 9, and it&amp;rsquo;s a bummer that I learned about it only recently.&lt;/p&gt;</description></item><item><title>Backpressure in Reactive Systems</title><link>https://foojayio.github.io/website/today/backpressure-in-reactive-systems/</link><pubDate>Fri, 11 Feb 2022 10:07:46 +0000</pubDate><guid>https://foojayio.github.io/website/today/backpressure-in-reactive-systems/</guid><description>&lt;p&gt;Mid-January, I held &lt;a href="https://www.youtube.com/watch?v=w0b4OQQmhBI" target="_blank" rel="noopener noreferrer"&gt;a talk at Kotlin.amsterdam&lt;/a&gt;
 based on my post &lt;a href="https://hazelcast.org/blog/migrating-from-imperative-to-reactive/" target="_blank" rel="noopener noreferrer"&gt;Migrating from Imperative to Reactive&lt;/a&gt;
 (a Spring Boot application).&lt;/p&gt;
&lt;p&gt;Because it was a Kotlin meetup, I demoed Kotlin code, and I added a step by migrating the codebase to coroutines.&lt;/p&gt;
&lt;p&gt;During Q&amp;amp;A, somebody asked whether coroutines implemented backpressure. I admit I was not sure of the answer, so I did a bit of research.&lt;/p&gt;
&lt;p&gt;This post provides information on backpressure in general and how &lt;a href="https://github.com/ReactiveX/RxJava" target="_blank" rel="noopener noreferrer"&gt;RxJava&lt;/a&gt;
 (v3), &lt;a href="https://projectreactor.io/" target="_blank" rel="noopener noreferrer"&gt;Project Reactor&lt;/a&gt;
 and Kotlin&amp;rsquo;s &lt;a href="https://kotlinlang.org/docs/reference/coroutines-overview.html" target="_blank" rel="noopener noreferrer"&gt;Coroutines&lt;/a&gt;
 handle it.&lt;/p&gt;</description></item><item><title>The Flatten Maven plugin - fooay.io</title><link>https://foojayio.github.io/website/today/flatten-maven-plugin/</link><pubDate>Mon, 31 Jan 2022 14:06:05 +0000</pubDate><guid>https://foojayio.github.io/website/today/flatten-maven-plugin/</guid><description>&lt;p&gt;One of the Apache Maven committers recently wrote about &lt;a href="https://www.javaadvent.com/2021/12/from-maven-3-to-maven-5.html" target="_blank" rel="noopener noreferrer"&gt;their plans for Maven 5&lt;/a&gt;
. I consider the following one of the most significant changes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In summary, we need to make a distinction between two POM types: the build POM, stored in the project source control, that uses v5 schema for build time, requiring a new Maven version able to use the new features associated with the new schema. The other one is the consumer POM, that is published to Maven Central in the good old v4 schema, so every past or future build tool can continue to consume pre-built artifacts as usual for their dependencies.&lt;/p&gt;</description></item><item><title>Treat Security as a Risk</title><link>https://foojayio.github.io/website/today/treat-security-as-risk/</link><pubDate>Thu, 27 Jan 2022 11:26:57 +0000</pubDate><guid>https://foojayio.github.io/website/today/treat-security-as-risk/</guid><description>&lt;p&gt;Security is the poster child of a Non-Functional Requirement: most people don&amp;rsquo;t care until the proverbial matter hits the rotary propeller.&lt;/p&gt;
&lt;p&gt;Consequences can range from losing reputation to legal liability to putting the business out. In my &lt;a href="https://blog.frankel.ch/running-untrusted-code/" target="_blank" rel="noopener noreferrer"&gt;post on running unsecured code&lt;/a&gt;
, I concluded that you should treat security as a risk - and left it at that. I think it warrants a dedicated post.&lt;/p&gt;
&lt;p&gt;Risk management is pretty &lt;a href="https://en.wikipedia.org/wiki/Risk_management" target="_blank" rel="noopener noreferrer"&gt;much documented&lt;/a&gt;
. You can find it in many engineering disciplines, if not every one of them. A risk management process consists of the following steps:&lt;/p&gt;</description></item><item><title>You're Running Untrusted Code!</title><link>https://foojayio.github.io/website/today/running-untrusted-code/</link><pubDate>Mon, 17 Jan 2022 08:28:24 +0000</pubDate><guid>https://foojayio.github.io/website/today/running-untrusted-code/</guid><description>&lt;p&gt;Last December, Log4Shell shortened the nights of many people in the JVM world. Worse, using the earthquake analogy caused many aftershocks after the initial quake.&lt;/p&gt;
&lt;p&gt;I immediately made the connection between Log4Shell and the Security Manager. At first, I didn&amp;rsquo;t want to write about it, but I&amp;rsquo;ve received requests to do so, and I couldn&amp;rsquo;t walk away.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/nicolas_frankel/status/1471140080366632968" target="_blank" rel="noopener noreferrer"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;[&lt;/p&gt;
&lt;img fetchpriority="high" decoding="async" class="alignnone size-medium wp-image-51338" src="johannes-rab-700x119.png" alt="" width="700" height="119"&gt;
&lt;p&gt;](&lt;a href="https://twitter.com/nicolas_frankel/status/1471140080366632968" target="_blank" rel="noopener noreferrer"&gt;https://twitter.com/nicolas_frankel/status/1471140080366632968&lt;/a&gt;
)&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;As a reminder, the Oracle team deprecated the Security Manager in Java 17. One of the arguments it based its decision on is that it was initially designed to protect against applets. Applets were downloaded from the Internet, so they had to be considered untrusted code. Hence, we had to run them in a sandbox.&lt;/p&gt;</description></item><item><title>A Tentative Comparison of Fault Tolerance Libraries on the JVM</title><link>https://foojayio.github.io/website/today/comparison-fault-tolerance-libraries/</link><pubDate>Tue, 11 Jan 2022 09:31:19 +0000</pubDate><guid>https://foojayio.github.io/website/today/comparison-fault-tolerance-libraries/</guid><description>&lt;p&gt;If you&amp;rsquo;re implementing microservices or not, chances are that you&amp;rsquo;re calling HTTP endpoints. With HTTP calls, a lot of things can go wrong.&lt;/p&gt;
&lt;p&gt;Experienced developers plan for this and design beyond just the happy path. In general, fault tolerance encompasses the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Retry&lt;/li&gt;
&lt;li&gt;Timeout&lt;/li&gt;
&lt;li&gt;Circuit Breaker&lt;/li&gt;
&lt;li&gt;Fallback&lt;/li&gt;
&lt;li&gt;Rate Limiter to avoid server-side 429 responses&lt;/li&gt;
&lt;li&gt;Bulkhead: Rate Limiter limits the number of calls in a determined timeframe, while Bulkhead limits the number of concurrent calls&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A couple of libraries implement these features on the JVM. In this post, we will look at Microprofile Fault Tolerance, &lt;a href="https://failsafe.dev/" target="_blank" rel="noopener noreferrer"&gt;Failsafe&lt;/a&gt;
 and Resilience4J.&lt;/p&gt;</description></item><item><title>Beautify Third-Party APIs with Kotlin</title><link>https://foojayio.github.io/website/today/beautify-third-party-api-kotlin/</link><pubDate>Tue, 21 Dec 2021 08:15:42 +0000</pubDate><guid>https://foojayio.github.io/website/today/beautify-third-party-api-kotlin/</guid><description>&lt;p&gt;Scala has popularized the &amp;ldquo;Pimp my library&amp;rdquo; pattern:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is just a fancy expression to refer to the ability to supplement a library using implicit conversions.&lt;/p&gt;
&lt;p&gt;&amp;ndash; &lt;a href="https://www.baeldung.com/scala/pimp-my-library-pattern" target="_blank" rel="noopener noreferrer"&gt;Pimp My Library Pattern in Scala&lt;/a&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Kotlin does provide the same capability. However, it achieves it via &lt;em&gt;extension functions&lt;/em&gt;. While the generated bytecode is similar to Java&amp;rsquo;s static methods, the developer experience is the same as adding functions to existing types.&lt;/p&gt;
&lt;p&gt;This approach has limitations, though. One cannot update the type hierarchy.&lt;/p&gt;</description></item><item><title>Native-image with Quarkus</title><link>https://foojayio.github.io/website/today/native-image-quarkus/</link><pubDate>Mon, 13 Dec 2021 17:50:08 +0000</pubDate><guid>https://foojayio.github.io/website/today/native-image-quarkus/</guid><description>&lt;p&gt;So far, we have looked at how well &lt;a href="https://foojayio.github.io/website/today/native-spring-boot/"&gt;Spring Boot&lt;/a&gt;
 and &lt;a href="https://foojayio.github.io/website/today/native-image-micronaut/"&gt;Micronaut&lt;/a&gt;
 integrate GraalVM native image extension. In this post, I&amp;rsquo;ll focus on &lt;a href="https://quarkus.io/" target="_blank" rel="noopener noreferrer"&gt;Quarkus&lt;/a&gt;
:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A Kubernetes Native Java stack tailored for OpenJDK HotSpot and GraalVM, crafted from the best of breed Java libraries and standards.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="h2-0-creating-a-new-project"&gt;Creating a new project&lt;/h2&gt;
&lt;p&gt;Just as Spring Boot and Micronaut, Quarkus provides options to create new projects:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A dedicated &lt;code&gt;quarkus&lt;/code&gt; &lt;a href="https://quarkus.io/guides/cli-tooling" target="_blank" rel="noopener noreferrer"&gt;CLI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://code.quarkus.io/" target="_blank" rel="noopener noreferrer"&gt;Web UI&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;img fetchpriority="high" decoding="async" class="aligncenter size-medium wp-image-50950" src="code-quarkus-700x477.jpg" alt="" width="700" height="477"&gt;
&lt;p&gt;Quarkus offers a definite improvement over its competitors. Every dependency has a detailed contextual menu that allows:&lt;/p&gt;</description></item><item><title>Multiple Spring Boot Applications in the Same Project</title><link>https://foojayio.github.io/website/today/multiple-spring-boot-apps-same-project/</link><pubDate>Wed, 08 Dec 2021 16:42:44 +0000</pubDate><guid>https://foojayio.github.io/website/today/multiple-spring-boot-apps-same-project/</guid><description>&lt;p&gt;I frequently use the &lt;a href="https://spring.io/projects/spring-boot" target="_blank" rel="noopener noreferrer"&gt;Spring Boot&lt;/a&gt;
 framework in my demos. The latest one is no different. It shows how to achieve using two different code paths:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the command part is implemented via &lt;a href="https://spring.io/projects/spring-data-jpa" target="_blank" rel="noopener noreferrer"&gt;Spring Data JPA&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;the query part via &lt;a href="https://www.jooq.org/" target="_blank" rel="noopener noreferrer"&gt;jOOQ&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My use case is a banking application that offers a REST layer allowing clients to call any parts. Demoing the query part is easy enough with &lt;code&gt;curl&lt;/code&gt; as the URL is not complex:&lt;/p&gt;</description></item><item><title>Port Management in Local Kubernetes Clusters</title><link>https://foojayio.github.io/website/today/port-management-in-local-kubernetes-clusters/</link><pubDate>Mon, 29 Nov 2021 08:44:25 +0000</pubDate><guid>https://foojayio.github.io/website/today/port-management-in-local-kubernetes-clusters/</guid><description>&lt;p&gt;Most of my talks contain a demo. A fair share of these demos require multiple &amp;ldquo;infrastructure&amp;rdquo; dependencies: a database (or more), Elasticsearch, you name it. To ease my setup and avoid messing up my machine, I use either Docker Compose or Kubernetes locally on my Mac. Both rely on Docker Desktop.&lt;/p&gt;
&lt;p&gt;To expose a cluster &lt;code&gt;Service&lt;/code&gt; on my host, I use &lt;code&gt;nodePort&lt;/code&gt;. Hence, I set a dedicated node port for each service. I need to remember each of them for each demo. Worse, services might be (are) declared across different manifest files.&lt;/p&gt;</description></item><item><title>Native-image with Micronaut</title><link>https://foojayio.github.io/website/today/native-image-micronaut/</link><pubDate>Mon, 22 Nov 2021 10:18:53 +0000</pubDate><guid>https://foojayio.github.io/website/today/native-image-micronaut/</guid><description>&lt;p&gt;Last week, I wrote a native web app that queried the Marvel API &lt;a href="https://foojayio.github.io/website/today/native-spring-boot/"&gt;using Spring Boot&lt;/a&gt;
. This week, I want to do the same with the Micronaut framework.&lt;/p&gt;
&lt;h2 id="h2-0-creating-a-new-project"&gt;Creating a new project&lt;/h2&gt;
&lt;p&gt;Micronaut offers two options to create a new project:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A &lt;a href="https://micronaut.io/launch" target="_blank" rel="noopener noreferrer"&gt;web UI&lt;/a&gt;
:&lt;/li&gt;
&lt;/ol&gt;
&lt;img fetchpriority="high" decoding="async" class="aligncenter wp-image-50794 size-medium" src="micronaut-launch-700x330.jpg" alt="Micronaut Launch Web UI" width="700" height="330"&gt;
&lt;p&gt;As for Spring Initializr, it provides several features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Preview the project before you download it&lt;/li&gt;
&lt;li&gt;Share the configuration&lt;/li&gt;
&lt;li&gt;An API&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I do like that you can check the impact that the added features have on the POM.
2. A &lt;a href="https://docs.micronaut.io/1.3.3/guide/index.html#buildCLI" target="_blank" rel="noopener noreferrer"&gt;Command-Line Interface&lt;/a&gt;
:In parallel to the webapp, you can install the on different systems. Then you can use the &lt;code&gt;mn&lt;/code&gt; command to create new projects.&lt;/p&gt;</description></item><item><title>Native-image with Spring Boot</title><link>https://foojayio.github.io/website/today/native-spring-boot/</link><pubDate>Fri, 19 Nov 2021 11:47:19 +0000</pubDate><guid>https://foojayio.github.io/website/today/native-spring-boot/</guid><description>&lt;p&gt;The Cloud has enabled a lot of new usages that were not possible before. Among them stands Serverless:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Serverless computing is a cloud computing execution model in which the cloud provider allocates machine resources on demand, taking care of the servers on behalf of their customers. Serverless computing does not hold resources in volatile memory; computing is rather done in short bursts with the results persisted to storage. When an app is not in use, there are no computing resources allocated to the app.&lt;/p&gt;</description></item><item><title>A List of Cache Providers</title><link>https://foojayio.github.io/website/today/a-list-of-cache-providers/</link><pubDate>Thu, 18 Nov 2021 08:01:25 +0000</pubDate><guid>https://foojayio.github.io/website/today/a-list-of-cache-providers/</guid><description>&lt;p&gt;Recently, we described &lt;a href="https://foojayio.github.io/website/today/choosing-a-cache-1/"&gt;several criteria to look at to choose a cache&lt;/a&gt;
. Now it&amp;rsquo;s time to list Java cache providers based on these criteria.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#java-caching-system"&gt;Java Caching System&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#guava"&gt;Guava&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#caffeine"&gt;Caffeine&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#ehcache"&gt;Ehcache&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#infinispan"&gt;Infinispan&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#coherence-community-edition"&gt;Coherence Community Edition&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#ignite"&gt;Ignite&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#geode"&gt;Geode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#hazelcast"&gt;Hazelcast&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="java-caching-system"&gt;Java Caching System&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;JCS is a distributed caching system written in Java. It is intended to speed up applications by providing a means to manage cached data of various dynamic natures. Like any caching system, JCS is most useful for high read, low put applications. Latency times drop sharply and bottlenecks move away from the database in an effectively cached system.&lt;/p&gt;</description></item><item><title>Extending Third-Party APIs in Different Languages</title><link>https://foojayio.github.io/website/today/extending-third-party-apis-in-different-languages/</link><pubDate>Mon, 08 Nov 2021 08:36:05 +0000</pubDate><guid>https://foojayio.github.io/website/today/extending-third-party-apis-in-different-languages/</guid><description>&lt;p&gt;The need for shorter and shorter Time-To-Market requires us to integrate more and more third-party libraries. There&amp;rsquo;s no time for the &lt;a href="https://en.wikipedia.org/wiki/Not_invented_here" target="_blank" rel="noopener noreferrer"&gt;NIH syndrom&lt;/a&gt;
 anymore, if it ever was. While most of the time the library&amp;rsquo;s API is ready to use, it may happen that one needs to &amp;ldquo;adapt&amp;rdquo; it to the codebase sometimes. How easy the adaptation is depends a lot on the language.&lt;/p&gt;
&lt;p&gt;For example, in the JVM, there are a couple of Reactive-Programming libraries: RxJava, Project Reactor, Mutiny, and coroutines. You might need a library that uses types of one library, but you based your project on another.&lt;/p&gt;</description></item><item><title>Hazelcast + Kibana: Best Buddies for Exploring &amp; Visualizing Data</title><link>https://foojayio.github.io/website/today/hazelcast-kibana-best-buddies-for-exploring-visualizing-data/</link><pubDate>Thu, 04 Nov 2021 14:22:15 +0000</pubDate><guid>https://foojayio.github.io/website/today/hazelcast-kibana-best-buddies-for-exploring-visualizing-data/</guid><description>&lt;p&gt;A lot, if not all, data science projects require some data visualization front-end to display the results for humans to analyze. Python seems to boast the most potent libraries, but do not lose hope if you&amp;rsquo;re a Java developer (or if you&amp;rsquo;re proficient in another language as well).&lt;/p&gt;
&lt;p&gt;In this article I will describe how you can benefit from such a data visualization front-end without writing a single line of code.&lt;/p&gt;</description></item><item><title>Kotlin and FaaS: An Impossible Union?</title><link>https://foojayio.github.io/website/today/kotlin-faas-impossible-union/</link><pubDate>Tue, 02 Nov 2021 08:40:48 +0000</pubDate><guid>https://foojayio.github.io/website/today/kotlin-faas-impossible-union/</guid><description>&lt;p&gt;Some time ago, I read a post describing how to run a serverless Kotlin function on &lt;a href="https://www.openfaas.com/" target="_blank" rel="noopener noreferrer"&gt;OpenFaaS&lt;/a&gt;
. While the content is technically correct, I believe the concept itself is very wrong. Such posts can lead people to make ill-advised decisions: &amp;ldquo;because we can&amp;rdquo; is hardly a winning strategy.&lt;/p&gt;
&lt;p&gt;In this article, I&amp;rsquo;d like to first explain why the JVM platform is a bad idea for . Then, I&amp;rsquo;ll proceed to propose alternatives to use Kotlin nonetheless.&lt;/p&gt;</description></item><item><title>How to Choose a Cache: Capabilities</title><link>https://foojayio.github.io/website/today/choosing-a-cache-1/</link><pubDate>Tue, 26 Oct 2021 13:20:11 +0000</pubDate><guid>https://foojayio.github.io/website/today/choosing-a-cache-1/</guid><description>&lt;p&gt;Today, I&amp;rsquo;d like to provide some help on how to choose a cache solution. I will organize it into two parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In this post, we will list what features a cache must have and which ones it can optionally provide. Most criteria are general and can be used regardless of the tech stack, while a couple is specific to the JVM.&lt;/li&gt;
&lt;li&gt;In the second part, I&amp;rsquo;ll list providers and verify their respective capabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="h2-0-why-cache"&gt;Why cache?&lt;/h2&gt;
&lt;p&gt;First, let&amp;rsquo;s bust a common myth. Using a cache is not the sign of a badly-designed system &lt;em&gt;per se&lt;/em&gt;, though it might be the case. Like in many design decisions, a cache is a trade-off.&lt;/p&gt;</description></item><item><title>On Reassessing TestNG vs. Junit</title><link>https://foojayio.github.io/website/today/reassessing-testng-vs-junit/</link><pubDate>Tue, 19 Oct 2021 08:28:48 +0000</pubDate><guid>https://foojayio.github.io/website/today/reassessing-testng-vs-junit/</guid><description>&lt;p&gt;In &lt;a href="https://foojayio.github.io/website/today/annotation-free-spring/"&gt;a recent article on Spring&lt;/a&gt;
, I advised reassessing one&amp;rsquo;s opinion now and then as the IT world changes so fast. What was true a couple of years ago could be dead wrong nowadays, and you probably don&amp;rsquo;t want to base your decisions on outdated data. This week, I&amp;rsquo;d like to follow my advice.&lt;/p&gt;
&lt;p&gt;One of &lt;a href="https://blog.frankel.ch/the-unit-test-war-junit-vs-testng" target="_blank" rel="noopener noreferrer"&gt;my first posts&lt;/a&gt;
 was advocating for TestNG vs. JUnit. In the post, I mentioned several features that JUnit lacked:&lt;/p&gt;</description></item><item><title>Faster Maven Builds (Part 2): Inside Docker</title><link>https://foojayio.github.io/website/today/faster-maven-builds-part-2/</link><pubDate>Thu, 14 Oct 2021 08:33:09 +0000</pubDate><guid>https://foojayio.github.io/website/today/faster-maven-builds-part-2/</guid><description>&lt;p&gt;Following on from &lt;a href="https://foojayio.github.io/website/today/faster-maven-builds-1/"&gt;different techniques&lt;/a&gt;
 to speed up your Maven builds, I&amp;rsquo;d like to widen the scope and do the same for Maven builds &lt;em&gt;inside Docker&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Between each run, we change the source code by adding a single blank line; between each section, we remove all built images, including the intermediate ones that are the results of the multi-stage build. The idea is to avoid reusing a previously built image.&lt;/p&gt;
&lt;h2 id="h2-0-baseline"&gt;Baseline&lt;/h2&gt;
&lt;p&gt;To compute a helpful baseline, we need a sample project. I created &lt;a href="https://github.com/nfrankel/fast-maven-builds" target="_blank" rel="noopener noreferrer"&gt;one&lt;/a&gt;
 just for this purpose: it&amp;rsquo;s a relatively small Kotlin project.&lt;/p&gt;</description></item><item><title>How to Do Faster Maven Builds (Part 1)</title><link>https://foojayio.github.io/website/today/faster-maven-builds-1/</link><pubDate>Thu, 14 Oct 2021 08:27:35 +0000</pubDate><guid>https://foojayio.github.io/website/today/faster-maven-builds-1/</guid><description>&lt;p&gt;Builds require a few properties, chief among them reproducibility. I would consider speed to be low on the order of priorities. However, it&amp;rsquo;s also one of the most limiting factors to your release cycle: if your build takes &lt;em&gt;T&lt;/em&gt; , you cannot release faster than each &lt;em&gt;T&lt;/em&gt;. Hence, you&amp;rsquo;ll probably want to speed up your builds after you&amp;rsquo;ve reached a certain maturity level to enable more frequent releases.&lt;/p&gt;
&lt;p&gt;I want to detail some techniques you can leverage to make your Maven builds faster in this article. The &lt;a href="https://foojayio.github.io/website/today/faster-maven-builds-part-2/"&gt;next article&lt;/a&gt;
 focuses on how to do the same inside of Docker.&lt;/p&gt;</description></item><item><title>Multiple Ways to Configure Spring</title><link>https://foojayio.github.io/website/today/multiple-ways-configure-spring/</link><pubDate>Wed, 06 Oct 2021 08:55:34 +0000</pubDate><guid>https://foojayio.github.io/website/today/multiple-ways-configure-spring/</guid><description>&lt;p&gt;Two weeks ago, I wrote how you could write a Spring application with no annotations.&lt;/p&gt;
&lt;p&gt;Many alternatives are available to configure your Spring app.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d like to list them in this post, leaving Spring Boot out of the picture on purpose.&lt;/p&gt;
&lt;h2 id="h2-0-core-concepts"&gt;Core concepts&lt;/h2&gt;
&lt;p&gt;A couple of concepts are central in Spring. The related documentation doesn&amp;rsquo;t describe most of them. Here is my understanding of them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bean&lt;/strong&gt; : A bean is an object managed by the Spring container&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bean Factory&lt;/strong&gt; : A bean factory is a component that manages the lifecycle of &lt;em&gt;beans&lt;/em&gt;, especially regarding the instantiation of new objects&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bean Definition&lt;/strong&gt; : A bean definition is the set of properties given to the Spring container and that the requested bean will have, &lt;em&gt;e.g.&lt;/em&gt;, class, name, scope, dependencies, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context&lt;/strong&gt;: A context is a bean factory with additional capabilities (mainly internationalization and event publishing)&lt;/li&gt;
&lt;/ul&gt;
&lt;img fetchpriority="high" decoding="async" class="aligncenter size-medium wp-image-49678" src="spring-concepts-700x492.png" alt="" width="700" height="492"&gt;
&lt;br /&gt;
&lt;p&gt;To configure a Spring application, one creates one or more contexts and registers the necessary bean definitions in the desired ones. In the following sections, we will configure the following simple model:&lt;/p&gt;</description></item><item><title>Introducing Jetpack Compose for Desktop</title><link>https://foojayio.github.io/website/today/state-jvm-desktop-frameworks-jetpack-compose-for-desktop/</link><pubDate>Mon, 27 Sep 2021 07:36:24 +0000</pubDate><guid>https://foojayio.github.io/website/today/state-jvm-desktop-frameworks-jetpack-compose-for-desktop/</guid><description>&lt;p&gt;The previous articles of this series were dedicated to frameworks that adopted the same traditional Object-Oriented-Programming approach. Components were modeled as classes. This week&amp;rsquo;s article is dedicated to Jet Compose for Desktop, the new kid on the block that offers a completely different approach.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/state-jvm-desktop-frameworks/1/" target="_blank" rel="noopener noreferrer"&gt;The state of JVM desktop frameworks: introduction&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/state-jvm-desktop-frameworks/2/" target="_blank" rel="noopener noreferrer"&gt;The state of JVM desktop frameworks: Swing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/state-jvm-desktop-frameworks/3/" target="_blank" rel="noopener noreferrer"&gt;The state of JVM desktop frameworks: SWT&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/state-jvm-desktop-frameworks/4/" target="_blank" rel="noopener noreferrer"&gt;The state of JVM desktop frameworks: TornadoFX&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="_getting_your_feet_wet"&gt;Getting your feet wet&lt;/h2&gt;
&lt;p&gt;Originally, Jetpack Compose is a framework for the Android runtime. Compose for Desktop is its port to the .&lt;/p&gt;</description></item><item><title>A Return to Annotation-Free Spring</title><link>https://foojayio.github.io/website/today/annotation-free-spring/</link><pubDate>Fri, 17 Sep 2021 12:03:24 +0000</pubDate><guid>https://foojayio.github.io/website/today/annotation-free-spring/</guid><description>&lt;p&gt;Some, if not most, of our judgments regarding technology stacks come either from third-party opinions or previous experiences. Yet, we seem to be adamant about them. For a long time (and sometimes even now), I&amp;rsquo;ve seen posts that detailed how Spring is bad because it uses XML for its configuration. Unfortunately, they blissfully ignore the fact that annotation-based configuration has been available for ages.&lt;/p&gt;
&lt;p&gt;And probably for of the same reason, I recently read that Spring is bad&amp;hellip; &lt;em&gt;because of annotations&lt;/em&gt;. If you belong to this crowd, I&amp;rsquo;ve news for you: you can get rid of most annotations and even more so if you&amp;rsquo;re using Kotlin.&lt;/p&gt;</description></item><item><title>Timely Computation of Derived Values</title><link>https://foojayio.github.io/website/today/timely-computation-derived-values/</link><pubDate>Fri, 10 Sep 2021 09:22:36 +0000</pubDate><guid>https://foojayio.github.io/website/today/timely-computation-derived-values/</guid><description>&lt;p&gt;In &lt;a href="https://foojayio.github.io/website/today/real-world-stream-collector/"&gt;a recent article here on Foojay&lt;/a&gt;
, on a real world stream collector, I described the use-case of an e-commerce shop.&lt;/p&gt;
&lt;p&gt;In general, interactions in such a shop are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can browse a catalog of items&lt;/li&gt;
&lt;li&gt;Each item has a price tag&lt;/li&gt;
&lt;li&gt;You can put x items in your cart&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is where the exciting part starts.&lt;/p&gt;
&lt;p&gt;On most pages, you want to give users a condensed view of their cart&amp;rsquo;s state.&lt;/p&gt;</description></item><item><title>Looking For Free Docker Registries</title><link>https://foojayio.github.io/website/today/looking-for-free-docker-registries/</link><pubDate>Tue, 24 Aug 2021 07:19:37 +0000</pubDate><guid>https://foojayio.github.io/website/today/looking-for-free-docker-registries/</guid><description>&lt;p&gt;Since Docker announced that it would remove unused images from Docker Hub, I&amp;rsquo;ve been interested in listing places where I could host mine.&lt;/p&gt;
&lt;p&gt;As it&amp;rsquo;s for personal purposes, I&amp;rsquo;m interested in free plans. Here&amp;rsquo;s what I found:&lt;/p&gt;
&lt;p&gt;| Provider | Private? | Monthly limit || Details |&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Provider&lt;/th&gt;
					&lt;th&gt;Private?&lt;/th&gt;
					&lt;th&gt;Storage&lt;/th&gt;
					&lt;th&gt;Transfer&lt;/th&gt;
					&lt;th&gt;Details&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a href="https://www.docker.com/pricing" target="_blank" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt;
&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;❓&lt;/td&gt;
					&lt;td&gt;* Anonymous: 100 pulls / 6 hours * Authenticated: 200 pulls / 6 hours&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a href="https://docs.gitlab.com/ee/user/packages/container_registry/" target="_blank" rel="noopener noreferrer"&gt;GitLab&lt;/a&gt;
&lt;/td&gt;
					&lt;td&gt;✅&lt;/td&gt;
					&lt;td&gt;10Gb&lt;/td&gt;
					&lt;td&gt;❓&lt;/td&gt;
					&lt;td&gt;* Storage quota is per-project * Quota includes &lt;strong&gt;all&lt;/strong&gt; artifacts, including code&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a href="https://docs.github.com/en/packages/guides/about-github-container-registry" target="_blank" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/td&gt;
					&lt;td&gt;✅&lt;/td&gt;
					&lt;td&gt;&amp;gt; GitHub Container Registry is currently in public beta and subject to change. During the beta, storage and bandwidth are free&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a href="https://aws.amazon.com/ecr/pricing/" target="_blank" rel="noopener noreferrer"&gt;AWS&lt;/a&gt;
&lt;/td&gt;
					&lt;td&gt;* First year only * 500Mb storage&lt;/td&gt;
					&lt;td&gt;50Gb&lt;/td&gt;
					&lt;td&gt;* Anonymous: 500Gb * Authenticated: 5Tb&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a href="https://cloud.ibm.com/registry/catalog" target="_blank" rel="noopener noreferrer"&gt;IBM Cloud&lt;/a&gt;
&lt;/td&gt;
					&lt;td&gt;✅&lt;/td&gt;
					&lt;td&gt;500Mb&lt;/td&gt;
					&lt;td&gt;5Gb&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Here are some additional options with their associated pricing model:&lt;/p&gt;</description></item><item><title>Updating Data Files: Commits vs. Pull Requests?</title><link>https://foojayio.github.io/website/today/updating-data-files-commits-vs-pull-requests/</link><pubDate>Wed, 18 Aug 2021 17:22:05 +0000</pubDate><guid>https://foojayio.github.io/website/today/updating-data-files-commits-vs-pull-requests/</guid><description>&lt;p&gt;For once, I&amp;rsquo;m wondering a bit if this article can be helpful to somebody else since I believe my context is pretty specific. Anyway, just in case it might be the helpful case, here it is!&lt;/p&gt;
&lt;p&gt;My &lt;a href="https://github.com/hazelcast/jet-train" target="_blank" rel="noopener noreferrer"&gt;Jet Train&lt;/a&gt;
 project makes use of &lt;a href="https://developers.google.com/transit/gtfs" target="_blank" rel="noopener noreferrer"&gt;GTFS&lt;/a&gt;
. GTFS stands for General Transit Feed Specification. It models public transportation schedules and their associated geographic information.&lt;/p&gt;
&lt;p&gt;GTFS is based on two kinds of data, static data, and dynamic data. Static data may change but do so rarely, &lt;em&gt;e.g.&lt;/em&gt;, transit agencies and bus stations. They are available as static files that you need to download now and then. Before, I had to download and overwrite them every time I run the demo.&lt;/p&gt;</description></item><item><title>GitLab: Your Continuous Deployment One-Stop Shop</title><link>https://foojayio.github.io/website/today/gitlab-continuous-deployment-one-stop-shop/</link><pubDate>Wed, 04 Aug 2021 07:44:20 +0000</pubDate><guid>https://foojayio.github.io/website/today/gitlab-continuous-deployment-one-stop-shop/</guid><description>&lt;p&gt;This week, I want to take a break from my Rust series and focus on a different subject. I&amp;rsquo;ve already written about &lt;a href="https://blog.frankel.ch/my-blogging-stack-publishing-process/" target="_blank" rel="noopener noreferrer"&gt;my blogging stack&lt;/a&gt;
 in detail.&lt;/p&gt;
&lt;p&gt;However, I didn&amp;rsquo;t touch on one facet and that facet is how I generate the static pages from Jekyll. As I describe in the blog post, I&amp;rsquo;ve included quite a couple of customizations. Some of them require external dependencies, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A for PlantUML diagrams generation&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;graphviz&lt;/em&gt; package for the same reason&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All in all, it means that I require a fully configured system. I solved this problem by using containerization, namely Docker. Within the &lt;code&gt;Dockerfile&lt;/code&gt;, I&amp;rsquo;m able to install all required dependencies. Then, in my GitLab build file, I can reference this image and benefit from all its capabilities.&lt;/p&gt;</description></item><item><title>An Introduction to Rust and the JVM</title><link>https://foojayio.github.io/website/today/rust-jvm/</link><pubDate>Tue, 27 Jul 2021 10:26:20 +0000</pubDate><guid>https://foojayio.github.io/website/today/rust-jvm/</guid><description>&lt;p&gt;So far, we have learned the basics of Rust syntax, developed a custom Kubernetes controller, and integrated with the front-end with .&lt;/p&gt;
&lt;p&gt;This is the 7^th^ post in the in the &lt;a href="https://blog.frankel.ch/focus/start-rust/" target="_blank" rel="noopener noreferrer"&gt;Start Rust&lt;/a&gt;
 series.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/start-rust/1/" target="_blank" rel="noopener noreferrer"&gt;My first cup of Rust&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/start-rust/2/" target="_blank" rel="noopener noreferrer"&gt;My second cup of Rust&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/start-rust/3/" target="_blank" rel="noopener noreferrer"&gt;The Rustlings exercises - part 1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/start-rust/4/" target="_blank" rel="noopener noreferrer"&gt;The Rustlings exercises - part 2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/start-rust/5/" target="_blank" rel="noopener noreferrer"&gt;Rust on the front-end&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.frankel.ch/start-rust/6/" target="_blank" rel="noopener noreferrer"&gt;A Rust controller for Kubernetes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Rust and the JVM (this post)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ve been using the for two decades now, mainly in Java. The JVM is a fantastic piece of technology. IMHO, its most significant benefit is its ability to adapt the native code to the current workload; if the workload changes and the native code is not optimal, it will recompile the &lt;em&gt;bytecode&lt;/em&gt; accordingly.&lt;/p&gt;</description></item><item><title>Announcement: Friends of OpenJDK Podcast #1</title><link>https://foojayio.github.io/website/today/foojay-podcast-1/</link><pubDate>Fri, 09 Jul 2021 08:39:39 +0000</pubDate><guid>https://foojayio.github.io/website/today/foojay-podcast-1/</guid><description>&lt;p&gt;Foojay community members discuss recent news:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JavaFX Skins for cross-platform apps on Android, iOS, and regular computers.&lt;/li&gt;
&lt;li&gt;BlockHound, for detecting cases of blocking in reactive (non-blocking) applications.&lt;/li&gt;
&lt;li&gt;JEP 411, the SecurityManager deprecation&lt;/li&gt;
&lt;li&gt;The recent Snyk/Azul community survey&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Sorry, this recording got &amp;ldquo;lost in cyberspace&amp;hellip;&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>BlockHound and Blocking Calls: How It Works</title><link>https://foojayio.github.io/website/today/blockhound-how-it-works/</link><pubDate>Tue, 22 Jun 2021 17:09:13 +0000</pubDate><guid>https://foojayio.github.io/website/today/blockhound-how-it-works/</guid><description>&lt;p&gt;One of the talks in my current portfolio is &lt;a href="https://www.papercall.io/speakers/nicolasfrankel/speaker_talks/194232-migrating-from-imperative-to-reactive" target="_blank" rel="noopener noreferrer"&gt;Migrating from Imperative to Reactive&lt;/a&gt;
. The talk is based on a &lt;a href="https://github.com/hazelcast-demos/imperative-to-reactive/" target="_blank" rel="noopener noreferrer"&gt;demo&lt;/a&gt;
 migrating from Spring WebMVC to Spring WebFlux in a step-by-step approach. One of the steps involves installing &lt;a href="https://github.com/reactor/BlockHound" target="_blank" rel="noopener noreferrer"&gt;BlockHound&lt;/a&gt;
: it allows to check whether a blocking call occurs in a thread it shouldn&amp;rsquo;t happen and throws an exception at runtime when it happens.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve presented this talk several times in the previous week, both in its Java version and its Kotlin one. One such presentation was at &lt;a href="https://www.javaday.istanbul/" target="_blank" rel="noopener noreferrer"&gt;Javaday Istanbul&lt;/a&gt;
. After the talk, one of the questions I received was, &amp;ldquo;How does BlockHound work?&amp;rdquo; I admit that at the time, I couldn&amp;rsquo;t remember. After the surprise had passed, but too late, I remembered it involved a Java agent. But I wanted to go down the rabbit hole.&lt;/p&gt;</description></item><item><title>Getting Started Hacking Third-Party APIs on the JVM</title><link>https://foojayio.github.io/website/today/hacking-third-party-api-jvm/</link><pubDate>Thu, 27 May 2021 06:27:58 +0000</pubDate><guid>https://foojayio.github.io/website/today/hacking-third-party-api-jvm/</guid><description>&lt;p&gt;The JVM ecosystem is mature and offers plenty of libraries, so you don&amp;rsquo;t need to reinvent the wheel. Basic - and not so basic - functionalities are just a dependency away. Sometimes, however, the dependency and your use-case are slightly misaligned.&lt;/p&gt;
&lt;p&gt;The correct way to fix this would be to create a Pull Request. But your deadline is tomorrow: you need to make it work &lt;em&gt;now&lt;/em&gt;! It&amp;rsquo;s time to hack the provided API.&lt;/p&gt;</description></item><item><title>Querying Your In-Memory-Data-Grid: Why and How?</title><link>https://foojayio.github.io/website/today/querying-your-in-memory-data-grid-why-and-how/</link><pubDate>Fri, 21 May 2021 07:11:28 +0000</pubDate><guid>https://foojayio.github.io/website/today/querying-your-in-memory-data-grid-why-and-how/</guid><description>&lt;blockquote&gt;
&lt;p&gt;An in-memory data grid (IMDG) is a set of networked/clustered computers that pool together their random access memory (RAM) to let applications share data with other applications running in the cluster. Though IMDGs are sometimes generically described as a distributed in-memory data store, IMDGs offer more than just storage. IMDGs are built for data processing at extremely high speeds. They are designed for building and running large-scale applications that need more RAM than is typically available in a single computer server. This enables the highest application performance by using RAM along with the processing power of multiple computers that run tasks in parallel. IMDGs are especially valuable for applications that do extensive parallel processing on large data sets.&lt;/p&gt;</description></item><item><title>Introducing Teeing: A Hidden Gem in the Java API</title><link>https://foojayio.github.io/website/today/teeing-java-api/</link><pubDate>Wed, 12 May 2021 07:15:07 +0000</pubDate><guid>https://foojayio.github.io/website/today/teeing-java-api/</guid><description>&lt;p&gt;Last week, I &lt;a href="https://blog.frankel.ch/real-world-stream-collector/" target="_blank" rel="noopener noreferrer"&gt;described a use-case&lt;/a&gt;
 for a custom Stream &lt;code&gt;Collector&lt;/code&gt;. I received a intriguing comment on Twitter:&lt;/p&gt;
&lt;img fetchpriority="high" decoding="async" class="aligncenter wp-image-44873 size-medium" src="Screenshot-2021-05-09-at-15.31.46-700x171.png" alt="" width="700" height="171"&gt;
&lt;br /&gt;
&lt;p&gt;Hats off to you, Miguel! Your comment revealed a method I didn&amp;rsquo;t know!&lt;/p&gt;
&lt;p&gt;So I decided to investigate what is the &lt;code&gt;teeing()&lt;/code&gt; method about.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Returns a Collector that is a composite of two downstream collectors. Every element passed to the resulting collector is processed by both downstream collectors, then their results are merged using the specified merge function into the final result.&lt;/p&gt;</description></item><item><title>A Real-World Example of a Stream Collector</title><link>https://foojayio.github.io/website/today/real-world-stream-collector/</link><pubDate>Fri, 07 May 2021 07:34:45 +0000</pubDate><guid>https://foojayio.github.io/website/today/real-world-stream-collector/</guid><description>&lt;p&gt;Java Stream&amp;rsquo;s &lt;code&gt;Collectors&lt;/code&gt; methods fit most use-cases. They allow returning either a &lt;code&gt;Collection&lt;/code&gt; or a scalar. For the former, you use one of the &lt;code&gt;toXXX()&lt;/code&gt; method, for the latter, one of the &lt;code&gt;reducing()&lt;/code&gt; one.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s imagine an e-commerce platform that implements a shopping cart. The cart is modeled as the following:&lt;/p&gt;
&lt;img fetchpriority="high" decoding="async" class="aligncenter size-medium wp-image-44825" src="cart-700x332.png" alt="" width="700" height="332"&gt;
&lt;br /&gt;
&lt;p&gt;This diagram might translate into the following (abridged) code:&lt;/p&gt;
&lt;pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-highlight="3-5, 14, 17"&gt;public class Product {

 private final Long id; // 1
 private final String label; // 1
 private final BigDecimal price; // 1

 public Product(Long id, String label, BigDecimal price) {
 this.id = id;
 this.label = label;
 this.price = price;
 }

 @Override
 public boolean equals(Object object ) { ... } // 2

 @Override
 public int hashCode() { ... } // 2
}&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Getters&lt;/li&gt;
&lt;li&gt;Only depend on &lt;code&gt;id&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="EnlighterJSRAW" data-enlighter-language="java"&gt;public class Cart {

 private final Map&amp;lt;Product, Integer&amp;gt; products = new HashMap&amp;lt;&amp;gt;(); // 1

 public void add(Product product) {
 add(product, 1);
 }

 public void add(Product product, int quantity) {
 products.merge(product, quantity, Integer::sum);
 }

 public void remove(Product product) {
 products.remove(product);
 }

 public void setQuantity(Product product, int quantity) {
 products.put(product, quantity);
 }

 public Map&amp;lt;Product, Integer&amp;gt; getProducts() {
 return Collections.unmodifiableMap(products); // 2
 }
}&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Organize products into a map. The key is the &lt;code&gt;Product&lt;/code&gt;; the value is the quantity.&lt;/li&gt;
&lt;li&gt;Remember to return a read-only copy of the collection to maintain encapsulation.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once we have defined how we store data in memory, we need to design how to display the cart on-screen. We know that the checkout screen needs to show two different bits of information:&lt;/p&gt;</description></item><item><title>Taking a Closer Look at Kotlin's Delegation</title><link>https://foojayio.github.io/website/today/kotlin-delegation/</link><pubDate>Fri, 30 Apr 2021 13:53:00 +0000</pubDate><guid>https://foojayio.github.io/website/today/kotlin-delegation/</guid><description>&lt;p&gt;Kotlin offers many exciting features. In general, developers tend to cite null safety as their favorite. For me, it&amp;rsquo;s function extensions. But delegation comes a close second.&lt;/p&gt;
&lt;h2 id="h2-0-the-delegation-pattern"&gt;The delegation pattern&lt;/h2&gt;
&lt;p&gt;The delegation pattern is described in the book:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Delegation&lt;/em&gt; is a way to make composition as powerful for reuse as inheritance [Lie86, JZ91]. In delegation, &lt;em&gt;two&lt;/em&gt; objects are involved in handling a request: a receiving object delegates operations to its &lt;em&gt;delegate&lt;/em&gt; . This is analogous to subclasses deferring requests to parent classes. But with inheritance, an inherited operation can always refer to the receiving object through the &lt;code&gt;this&lt;/code&gt; member variable in C++ and &lt;code&gt;self&lt;/code&gt; in Smalltalk. To achieve the same effect with delegation, the receiver passes itself to the delegate to let the delegated operation refer to the receiver.&lt;/p&gt;</description></item><item><title>An Example of Overengineering - Keep it WET</title><link>https://foojayio.github.io/website/today/an-example-of-overengineering-keep-it-wet/</link><pubDate>Wed, 28 Apr 2021 09:20:52 +0000</pubDate><guid>https://foojayio.github.io/website/today/an-example-of-overengineering-keep-it-wet/</guid><description>&lt;p&gt;This week&amp;rsquo;s post is pretty short. I&amp;rsquo;ve already &lt;a href="https://blog.frankel.ch/are-you-guilty-of-overengineering/" target="_blank" rel="noopener noreferrer"&gt;written about overengineering&lt;/a&gt;
, but this adds a personal touch.&lt;/p&gt;
&lt;p&gt;I had to rewrite my &lt;a href="https://github.com/hazelcast/jet-train" target="_blank" rel="noopener noreferrer"&gt;Jet Train demo&lt;/a&gt;
 to use another data provider, switching from a Swiss one to a Bay Area one. One of the main components of the demo is a streaming pipeline.&lt;/p&gt;
&lt;p&gt;The pipeline:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reads data from a web endpoint&lt;/li&gt;
&lt;li&gt;Transforms data through several steps&lt;/li&gt;
&lt;li&gt;Writes the final data into an in-memory data grid&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Most of the transform steps in #2 enrich the data. Each of them requires an implementation of a &lt;code&gt;BiFunction&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Hazelcast, from Embedded to Client-Server</title><link>https://foojayio.github.io/website/today/hazelcast-from-embedded-to-client-server/</link><pubDate>Fri, 23 Apr 2021 06:58:00 +0000</pubDate><guid>https://foojayio.github.io/website/today/hazelcast-from-embedded-to-client-server/</guid><description>&lt;p&gt;Java developers are particularly spoiled when using Hazelcast. Because Hazelcast is developed in Java, it&amp;rsquo;s available as a JAR, and we can integrate it as a library in our application. Just add it to the application&amp;rsquo;s classpath, start a node, and we&amp;rsquo;re good to go. However, I believe that once you start relying on Hazelcast as a critical infrastructure component, embedding limits your options. In this post, I&amp;rsquo;d like to dive a bit deeper into the subject.&lt;/p&gt;</description></item><item><title>How to create your own custom Spring Data repository</title><link>https://foojayio.github.io/website/today/custom-spring-data-repository/</link><pubDate>Wed, 14 Apr 2021 07:33:08 +0000</pubDate><guid>https://foojayio.github.io/website/today/custom-spring-data-repository/</guid><description>&lt;p&gt;Frameworks promise to speed up one&amp;rsquo;s development pace provided one follows the mainstream path.&lt;/p&gt;
&lt;p&gt;The path may be more or less narrow. I&amp;rsquo;m a big fan of the Spring ecosystem because its design is extensible and customizable at different abstraction levels: thus, the path is as large as you need it to be.&lt;/p&gt;
&lt;p&gt;Functional Programming is becoming more and more popular. Spring provides a couple of s for the Kotlin language. For example, the &lt;a href="https://docs.spring.io/spring-framework/docs/current/reference/html/languages.html#kotlin-bean-definition-dsl" target="_blank" rel="noopener noreferrer"&gt;Beans DSL&lt;/a&gt;
 and the &lt;a href="https://docs.spring.io/spring-framework/docs/current/reference/html/languages.html#router-dsl" target="_blank" rel="noopener noreferrer"&gt;Routes DSL&lt;/a&gt;
 allow for a more functional approach toward Spring configuration. On the &lt;em&gt;type&lt;/em&gt; side, &lt;a href="https://www.vavr.io/" target="_blank" rel="noopener noreferrer"&gt;Vavr&lt;/a&gt;
 (previously Javaslang) is pretty popular in Java, while Kotlin has &lt;a href="https://arrow-kt.io/docs/core/" target="_blank" rel="noopener noreferrer"&gt;Arrow&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>How to Change a Field's Type in Recent JDKs</title><link>https://foojayio.github.io/website/today/changing-field-type-recent-jdks/</link><pubDate>Thu, 08 Apr 2021 07:40:56 +0000</pubDate><guid>https://foojayio.github.io/website/today/changing-field-type-recent-jdks/</guid><description>&lt;p&gt;A couple of years ago, I attended a talk by my former colleague (but still friend) &lt;a href="https://twitter.com/volker_simonis" target="_blank" rel="noopener noreferrer"&gt;Volker Simonis&lt;/a&gt;
. It gave me the idea to dig a bit into the subject of how to secure the JVM. From the material, I created a &lt;a href="https://blog.frankel.ch/focus/jvm-security/" target="_blank" rel="noopener noreferrer"&gt;series of blog posts&lt;/a&gt;
 as well as &lt;a href="https://www.youtube.com/watch?v=Bgo7dcCbqV8" target="_blank" rel="noopener noreferrer"&gt;a talk&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;From that point on, I submitted the talk at meetups and conferences, where it was well-received. Because I like to explore different areas, I stopped to submit other proposals. Still, the talk is in my portfolio, and it was requested again in 2021. I have already presented it twice since the beginning of the year at the time of this writing.&lt;/p&gt;</description></item><item><title>A (Definitive?) Guide to LazyInitializationException</title><link>https://foojayio.github.io/website/today/guide-lazyinitializationexception/</link><pubDate>Mon, 29 Mar 2021 07:19:49 +0000</pubDate><guid>https://foojayio.github.io/website/today/guide-lazyinitializationexception/</guid><description>&lt;p&gt;Posts that have been written about Hibernate&amp;rsquo;s &lt;code&gt;LazyInitializationException&lt;/code&gt; could probably fill whole books.&lt;/p&gt;
&lt;p&gt;Yet, I believe each of them focuses on a particular aspect of it: some on a specific solution, some on how to solve it with Spring Boot, etc.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d like this post to be the definitive guide on the subject, even though I&amp;rsquo;m pretty sure it won&amp;rsquo;t. At least, I&amp;rsquo;ll be able to point others to it!&lt;/p&gt;</description></item><item><title>Kicking Spring Native's Tires with GraalVM</title><link>https://foojayio.github.io/website/today/kicking-spring-natives-tires/</link><pubDate>Mon, 22 Mar 2021 17:18:05 +0000</pubDate><guid>https://foojayio.github.io/website/today/kicking-spring-natives-tires/</guid><description>&lt;p&gt;I&amp;rsquo;ve been playing with GraalVM Ahead-Of-Time compilation capability since I became aware of it. As a long-time Spring &lt;em&gt;aficionado&lt;/em&gt; , I carefully monitored the efforts that the engineers at Tanzu have put into making Spring AOT-compatible. Recently, they announced &lt;a href="https://spring.io/blog/2021/03/11/announcing-spring-native-beta" target="_blank" rel="noopener noreferrer"&gt;the beta version&lt;/a&gt;
 of the integration.&lt;/p&gt;
&lt;p&gt;In this post, I want to check how easy it is to produce a (working!) Docker image from an existing Spring Boot application.&lt;/p&gt;
&lt;h3 id="h3-0-introduction"&gt;Introduction&lt;/h3&gt;
&lt;p&gt;GraalVM provides many different features. Among them, the component known as Substrate VM allows to AOT-compile regular bytecode to a native executable. The process &amp;ldquo;walks&amp;rdquo; the application starting from the &lt;code&gt;main&lt;/code&gt; method at build time. Substrate VM leaves out the code that it doesn&amp;rsquo;t follow out from the resulting binary.&lt;/p&gt;</description></item><item><title>Monitoring Across Frameworks: Spring Boot, Quarkus, Micronaut, Helidon</title><link>https://foojayio.github.io/website/today/monitoring-across-frameworks-spring-boot-micronaut-quarkus-and-helidon/</link><pubDate>Tue, 02 Mar 2021 18:44:07 +0000</pubDate><guid>https://foojayio.github.io/website/today/monitoring-across-frameworks-spring-boot-micronaut-quarkus-and-helidon/</guid><description>&lt;p&gt;Gone are the times when developers&amp;rsquo; jobs ended with the release of the application. Nowadays, developers care more and more about the operational side of IT: perhaps they operate applications themselves, but more probably, their organizations foster increased collaboration between Dev and Ops.&lt;/p&gt;
&lt;p&gt;I started to become interested in the Ops side of software when I was still a consultant. When Spring Boot released the Actuator, I became excited. Via its convention-over-configuration nature, it was possible to add monitoring endpoints with just an additional dependency.&lt;/p&gt;</description></item><item><title>Learning About Optional.stream() in OpenJDK and Java</title><link>https://foojayio.github.io/website/today/optional-stream/</link><pubDate>Mon, 22 Feb 2021 17:11:33 +0000</pubDate><guid>https://foojayio.github.io/website/today/optional-stream/</guid><description>&lt;p&gt;This week, I learned about a nifty &amp;ldquo;new&amp;rdquo; feature of &lt;code&gt;Optional&lt;/code&gt; that I want to share in this post. It&amp;rsquo;s available since Java 9, so its novelty is relative.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s start with the following sequence to compute the total price of an order:&lt;/p&gt;
&lt;pre class="EnlighterJSRAW" data-enlighter-language="java"&gt;public BigDecimal getOrderPrice(Long orderId) {
 List&amp;lt;OrderLine&amp;gt; lines = orderRepository.findByOrderId(orderId);
 BigDecimal price = BigDecimal.ZERO; // 1
 for (OrderLine line : lines) {
 price = price.add(line.getPrice()); // 2
 }
 return price;
}&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Provide an accumulator variable for the price&lt;/li&gt;
&lt;li&gt;Add each line&amp;rsquo;s price to the total price&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nowadays, it&amp;rsquo;s probably more adequate to use streams instead of iterations. The following snippet is the equivalent to the previous one:&lt;/p&gt;</description></item><item><title>How to Create Self-Contained Executable JARs</title><link>https://foojayio.github.io/website/today/creating-self-contained-executable-jars/</link><pubDate>Mon, 01 Feb 2021 08:40:08 +0000</pubDate><guid>https://foojayio.github.io/website/today/creating-self-contained-executable-jars/</guid><description>&lt;p&gt;When your application goes beyond a dozen of lines of code, you should probably split the code into multiple classes. At this point, the question is how to distribute them. In Java, the classical format is the Java ARchive, better known as the JAR. But real-world applications probably depend on other JARs.&lt;/p&gt;
&lt;p&gt;This article aims to describe ways to create self-contained executable JARs, also known as uber-JARs or fat JARs.&lt;/p&gt;</description></item></channel></rss>