<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Arkadiusz Przychocki</title>
    <description>The latest articles on Forem by Arkadiusz Przychocki (@arkstack).</description>
    <link>https://forem.com/arkstack</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2387123%2Fa38712e5-6d78-4172-ac2d-e4792429f880.jpg</url>
      <title>Forem: Arkadiusz Przychocki</title>
      <link>https://forem.com/arkstack</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/arkstack"/>
    <language>en</language>
    <item>
      <title>StructuredTaskScope beyond toy examples: dependency-aware kernel bootstrap in modern Java</title>
      <dc:creator>Arkadiusz Przychocki</dc:creator>
      <pubDate>Tue, 07 Apr 2026 10:24:29 +0000</pubDate>
      <link>https://forem.com/arkstack/structuredtaskscope-beyond-toy-examples-dependency-aware-kernel-bootstrap-in-modern-java-57j0</link>
      <guid>https://forem.com/arkstack/structuredtaskscope-beyond-toy-examples-dependency-aware-kernel-bootstrap-in-modern-java-57j0</guid>
      <description>&lt;p&gt;I did not start this because I wanted to write an article about &lt;code&gt;StructuredTaskScope&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I got there from a more annoying direction: bootstrap had stopped being a startup script.&lt;/p&gt;

&lt;p&gt;Once the kernel had a real subsystem graph — config, memory, persistence, graph, events, flow, transport — the old mental model broke down. The question was no longer &lt;em&gt;"how do I start modules?"&lt;/em&gt; It became &lt;em&gt;"what is actually allowed to start now, what must already be ready, and what happens if one piece fails halfway through?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is a different problem from request fan-out.&lt;/p&gt;

&lt;p&gt;This article is a follow-up to my earlier piece on DOP, &lt;code&gt;ScopedValue&lt;/code&gt;, and Loom. There, I used &lt;code&gt;StructuredTaskScope&lt;/code&gt; as a clean example of native fail-fast execution. Here I want to show the more useful case: what happened once I tried to fit it into a real lifecycle model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Constraint upfront:&lt;/strong&gt; this only makes sense when the execution path is still under my control. If you are building a plugin surface or a highly open extension model, parts of this break down quickly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bootstrap stopped being linear
&lt;/h2&gt;

&lt;p&gt;A lot of startup code still assumes the system is basically a list:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;build some objects&lt;/li&gt;
&lt;li&gt;call &lt;code&gt;start()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;maybe wait a bit&lt;/li&gt;
&lt;li&gt;hope shutdown is the reverse&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That works until the dependency graph becomes real.&lt;/p&gt;

&lt;p&gt;In Exeris, bootstrap is constrained by subsystem relationships, not by the order I happen to like in a &lt;code&gt;main()&lt;/code&gt; method. Some subsystems are foundational. Some are optional. Some can start only after several others are already running. Some failures can degrade. Some cannot.&lt;/p&gt;

&lt;p&gt;At that point, startup becomes a graph problem whether you admit it or not.&lt;/p&gt;

&lt;p&gt;What I kept from the old model was determinism.&lt;br&gt;
What I dropped was the idea that everything meaningful should happen inside one generic &lt;em&gt;"start all modules"&lt;/em&gt; phase.&lt;/p&gt;

&lt;p&gt;The shape of the graph matters more than the urge to parallelize it.&lt;/p&gt;


    &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.arkstack.dev%2Fblog%2Fstructured-task-scope-beyond-toy-examples%2Ffig1_boot_diag.png" alt="Figure 1: Dependency-aware kernel bootstrap graph in Exeris. The point is that concurrency is legal only where the graph permits it." width="800" height="1784"&gt;


&lt;p&gt;&lt;em&gt;Figure 1: Dependency-aware kernel bootstrap graph in Exeris. The point is not that several subsystems exist. The point is that concurrency is legal only where the graph permits it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I noticed that once the graph was explicit, &lt;em&gt;"just parallelize bootstrap"&lt;/em&gt; stopped being a serious answer pretty quickly. The graph already tells you where concurrency is allowed and where it is simply too early.&lt;/p&gt;

&lt;p&gt;The bootstrap docs in Exeris describe the same thing from the subsystem side: L0 remains foundational, higher layers can move only after the substrate is ready, and shutdown keeps that structure in reverse.&lt;/p&gt;


&lt;h2&gt;
  
  
  The split that actually mattered
&lt;/h2&gt;

&lt;p&gt;The design choice that mattered most was not &lt;em&gt;using&lt;/em&gt; &lt;code&gt;StructuredTaskScope&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It was deciding &lt;strong&gt;where not to use it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At first, the obvious temptation was to parallelize more of bootstrap. If the JVM gives you virtual threads and structured concurrency, it is very easy to start looking for places to apply them.&lt;/p&gt;

&lt;p&gt;I ended up doing less than that.&lt;/p&gt;

&lt;p&gt;I kept &lt;code&gt;initialize()&lt;/code&gt; sequential and topological.&lt;br&gt;
I only allowed structured parallelism in &lt;code&gt;start()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That was not ideological. It was practical.&lt;/p&gt;

&lt;p&gt;Initialization is where the orchestrator builds structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provider bindings&lt;/li&gt;
&lt;li&gt;health registration&lt;/li&gt;
&lt;li&gt;active subsystem ordering&lt;/li&gt;
&lt;li&gt;dependency-safe lifecycle state&lt;/li&gt;
&lt;li&gt;bootstrap telemetry hooks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That phase wants determinism more than it wants speed. I did not want graph construction, provider composition, and lifecycle execution to collapse into one concurrent blur.&lt;/p&gt;

&lt;p&gt;Startup is different. Once the graph is already resolved and the active set is known, concurrency becomes useful — but only if it stays inside the same lifecycle boundaries the graph already established.&lt;/p&gt;

&lt;p&gt;That led to a much simpler rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;initialization stays ordered, startup may become parallel.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was the point where the old model stopped making sense for me. I was no longer trying to make bootstrap &lt;em&gt;faster&lt;/em&gt; in the abstract. I was trying to keep lifecycle ownership readable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BootstrapPhase&lt;/span&gt; &lt;span class="n"&gt;phase&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BootstrapPhase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Subsystem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;forPhase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orderedSubsystems&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;phase&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;phase&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forPhase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phase&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;BootstrapPhase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FOUNDATION&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;startSequential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forPhase&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;phase&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;profileName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startedNames&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;startParallel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forPhase&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;phase&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;profileName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startedNames&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In practice, &lt;code&gt;FOUNDATION&lt;/code&gt; stays sequential on purpose. That includes the parts of bootstrap that decide whether the rest of the kernel can even be interpreted correctly: configuration roots, base runtime substrate, exception boundaries, and core providers.&lt;/p&gt;

&lt;p&gt;I could have parallelized more of that. I did not.&lt;/p&gt;

&lt;p&gt;The trade-off is deliberate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I give up some startup parallelism early&lt;/li&gt;
&lt;li&gt;in exchange for a cleaner substrate&lt;/li&gt;
&lt;li&gt;and less ambiguity when the higher layers begin to move&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not universal. If your startup graph is shallow and your layers are genuinely independent, you can be more aggressive. In my case, the real cost of a bad foundation was not a few extra milliseconds. It was a fuzzier lifecycle model and harder-to-classify failures later.&lt;/p&gt;




&lt;h2&gt;
  
  
  ScopedValue still mattered at the boundary
&lt;/h2&gt;

&lt;p&gt;This article is about &lt;code&gt;StructuredTaskScope&lt;/code&gt;, but I ended up reusing the same lesson from the previous piece: context propagation only stays clean if the boundary is explicit.&lt;/p&gt;

&lt;p&gt;In Exeris, bootstrap resolves configuration once, then binds it at the kernel boundary before the rest of the lifecycle begins. Everything spawned under that boundary inherits the same immutable context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ScopedValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KernelProviders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CURRENT_CONFIG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;runBootInsideScope&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orchestrator&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;configRegistry&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;configWatcher&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kernelMain&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SubsystemCircularDependencyException&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SubsystemOrchestrator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BootstrapException&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BootstrapException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Subsystem bootstrap failed: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That choice mattered more than another layer of constructor wiring would have.&lt;/p&gt;

&lt;p&gt;I did not want every subsystem, handler, or virtual thread to receive config through argument threading just because bootstrap needed lifecycle scope. I also did not want to fall back to &lt;code&gt;ThreadLocal&lt;/code&gt; and reintroduce the same inheritance and mutability problems I had already rejected elsewhere.&lt;/p&gt;

&lt;p&gt;So the boundary stayed strict:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;config is resolved once&lt;/li&gt;
&lt;li&gt;bound once&lt;/li&gt;
&lt;li&gt;inherited downward&lt;/li&gt;
&lt;li&gt;and torn down when boot exits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That kept the lifecycle model cleaner. It also meant that when I later opened structured startup rounds, they inherited the same immutable runtime context without extra ceremony.&lt;/p&gt;




&lt;h2&gt;
  
  
  The useful part was not STS itself
&lt;/h2&gt;

&lt;p&gt;The useful part was computing a &lt;strong&gt;safe round&lt;/strong&gt; before opening a scope.&lt;/p&gt;

&lt;p&gt;I do not want to smooth this into a generic explanation, because it is really the center of the design.&lt;/p&gt;

&lt;p&gt;The orchestrator does not just fork all pending subsystems for a phase and wait.&lt;/p&gt;

&lt;p&gt;It first computes which subsystems are actually safe to start &lt;strong&gt;now&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pendingNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pending&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Subsystem:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toCollection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;LinkedHashSet:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Subsystem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ready&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pending&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subsystem&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dependenciesReadyForRound&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subsystem&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pendingNames&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startedNames&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ready&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BootstrapException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Phase "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;phase&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" cannot make progress: unresolved dependencies among pending subsystems "&lt;/span&gt;
            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pendingNames&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That changed the role of &lt;code&gt;StructuredTaskScope&lt;/code&gt; completely.&lt;/p&gt;

&lt;p&gt;It was no longer responsible for discovering order.&lt;br&gt;
It was responsible for executing one dependency-safe round inside an order the orchestrator had already made explicit.&lt;/p&gt;

&lt;p&gt;That is why I keep saying this is a graph problem first and a concurrency problem second.&lt;/p&gt;


    &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.arkstack.dev%2Fblog%2Fstructured-task-scope-beyond-toy-examples%2Ffig2_ready_round.png" alt="Figure 2: Dependency-safe startup round. StructuredTaskScope is opened only after the orchestrator computes a ready set from the graph." width="800" height="361"&gt;


&lt;p&gt;&lt;em&gt;Figure 2: Dependency-safe startup round. The orchestrator computes eligibility first, then gives &lt;code&gt;StructuredTaskScope&lt;/code&gt; a bounded unit of work to own.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This was the point where the old &lt;em&gt;"just launch it and coordinate later"&lt;/em&gt; model stopped making sense. I did not want startup order to become an emergent property of timing, future composition, or whichever task completed first.&lt;/p&gt;

&lt;p&gt;I wanted concurrency to appear &lt;strong&gt;after&lt;/strong&gt; dependency eligibility had already been established.&lt;/p&gt;


&lt;h2&gt;
  
  
  This is where StructuredTaskScope actually earned its place
&lt;/h2&gt;

&lt;p&gt;Once the ready set exists, the role of &lt;code&gt;StructuredTaskScope&lt;/code&gt; becomes very narrow and very clean.&lt;/p&gt;

&lt;p&gt;It owns one startup round.&lt;/p&gt;

&lt;p&gt;That is it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StructuredTaskScope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StructuredTaskScope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Subtask&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ready&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StructuredTaskScope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Subtask&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;subsystem&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fork&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;doStart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subsystem&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;phase&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="o"&gt;}))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;failures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;StructuredTaskScope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Subtask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;State&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FAILED&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StructuredTaskScope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Subtask&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFirst&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BootstrapException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" subsystem(s) failed in phase "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;phase&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;". First failure: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the part I actually like.&lt;/p&gt;

&lt;p&gt;Not because it is clever. Mostly because it is boring in the right way.&lt;/p&gt;

&lt;p&gt;The round has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an owner&lt;/li&gt;
&lt;li&gt;explicit lifetime&lt;/li&gt;
&lt;li&gt;explicit completion&lt;/li&gt;
&lt;li&gt;explicit failure collection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No task belongs to some vague executor that outlives the lifecycle moment that created it. No background startup work escapes into &lt;em&gt;"maybe still running"&lt;/em&gt; territory. The concurrency boundary finally matches the lifecycle boundary.&lt;/p&gt;

&lt;p&gt;That was the point.&lt;/p&gt;

&lt;p&gt;And that is also why I think &lt;code&gt;StructuredTaskScope&lt;/code&gt; is more interesting here than in the usual &lt;em&gt;"fetch two things in parallel"&lt;/em&gt; examples. Those examples prove the API works. This kind of orchestrator is where it starts to fit the shape of the system.&lt;/p&gt;




&lt;h2&gt;
  
  
  I could have done this with futures. I did not want to.
&lt;/h2&gt;

&lt;p&gt;There is nothing impossible about building this with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ExecutorService&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CompletableFuture&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;latches&lt;/li&gt;
&lt;li&gt;custom worker tracking&lt;/li&gt;
&lt;li&gt;hand-rolled failure aggregation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the goal was just &lt;em&gt;"run multiple startup actions in parallel,"&lt;/em&gt; all of those would work.&lt;/p&gt;

&lt;p&gt;But the real problem was never just parallelism.&lt;/p&gt;

&lt;p&gt;What I actually cared about was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;who owns this work&lt;/li&gt;
&lt;li&gt;when exactly this round ends&lt;/li&gt;
&lt;li&gt;what belongs to this phase and what does not&lt;/li&gt;
&lt;li&gt;how failure is surfaced&lt;/li&gt;
&lt;li&gt;how shutdown reasoning stays clean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bootstrap is one of the worst places to tolerate vague concurrency ownership. When startup fails, I do not want to guess whether some task is still alive in the background or whether a future chain has already detached from the lifecycle moment that spawned it.&lt;/p&gt;

&lt;p&gt;That is the real difference here.&lt;/p&gt;

&lt;p&gt;The point is not that &lt;code&gt;StructuredTaskScope&lt;/code&gt; can run tasks. The point is that it gives this round a proper boundary.&lt;/p&gt;

&lt;p&gt;I would still use more conventional concurrency tools when the lifecycle is shallower, the ownership model is already loose, or the surrounding architecture does not benefit from such a strict boundary. This is not a universal replacement story.&lt;/p&gt;




&lt;h2&gt;
  
  
  The failure policy mattered at least as much as the concurrency primitive
&lt;/h2&gt;

&lt;p&gt;I do not think this model would feel coherent without an explicit failure policy.&lt;/p&gt;

&lt;p&gt;Exeris supports both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FAIL_FAST&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DEGRADE&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But not symmetrically.&lt;/p&gt;

&lt;p&gt;Foundational subsystems are still mandatory. They do not get to degrade just because higher layers can. That boundary matters.&lt;/p&gt;

&lt;p&gt;Inside the orchestrator, that asymmetry is explicit. Optional subsystems may be removed under &lt;code&gt;DEGRADE&lt;/code&gt;, but a mandatory failure still aborts boot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;isMandatory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subsystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;phase&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;BootstrapPhase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FOUNDATION&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;subsystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isOptional&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failurePolicy&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;FailurePolicy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DEGRADE&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isMandatory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;removeSubsystemAndTransitiveDependents&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subsystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;healthMonitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;markKernelState&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KernelHealthMonitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;KernelState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FAILED&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BootstrapException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Subsystem '"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;subsystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"' failed: "&lt;/span&gt;
            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I kept that asymmetry because not all failures mean the same thing. An optional higher-level capability failing to start can be survivable. A foundation-layer failure usually means the system no longer has a sane substrate to run on.&lt;/p&gt;

&lt;p&gt;This was another place where I resisted smoothing the model into something more uniform. Uniformity would have looked cleaner on paper, but it would have made the lifecycle semantics less truthful.&lt;/p&gt;

&lt;p&gt;So the useful question was never:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;can these tasks run in parallel?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;what does it mean for the kernel if this one fails right now?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question forces the architecture to stay honest.&lt;/p&gt;




&lt;h2&gt;
  
  
  Startup only makes sense if shutdown keeps the same shape
&lt;/h2&gt;

&lt;p&gt;One thing I did not want to lose was lifecycle symmetry.&lt;/p&gt;

&lt;p&gt;A graph-shaped startup model should not collapse into an improvised shutdown path. If startup order is derived from dependency structure, shutdown should preserve that structure in reverse.&lt;/p&gt;

&lt;p&gt;In practice, that means I care about reverse topological shutdown just as much as startup rounds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Subsystem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reversed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;orderedSubsystems&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reversed&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Subsystem&lt;/span&gt; &lt;span class="n"&gt;subsystem&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reversed&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subsystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isRunning&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;subsystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That sounds obvious, but it matters more once concurrency enters the picture. Structured startup is easier to trust when the rest of the lifecycle still behaves like one coherent model instead of a collection of unrelated hooks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4y6o5lujfaff6w8z3fd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4y6o5lujfaff6w8z3fd.png" alt="Figure 3: Lifecycle symmetry in Exeris. Startup order and shutdown order are two sides of the same dependency model." width="800" height="2914"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3: Lifecycle symmetry in Exeris. Startup derives capability from dependency order; shutdown preserves that order in reverse so the lifecycle remains one coherent model.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I would not make reverse shutdown the headline of the article, but I would not treat it as a footnote either. It is part of the same argument: structured concurrency helps most when the surrounding lifecycle is already structured.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I measured, and what I did not claim
&lt;/h2&gt;

&lt;p&gt;This article is architectural first, but I do not want to leave it floating at the level of &lt;em&gt;"this feels cleaner."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The evidence I care about here is not generic throughput. It is lifecycle evidence.&lt;/p&gt;

&lt;p&gt;For this model, the useful signals are things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sequential startup vs phase-grouped structured startup&lt;/li&gt;
&lt;li&gt;total cold boot duration until boot-ready&lt;/li&gt;
&lt;li&gt;per-phase startup timing&lt;/li&gt;
&lt;li&gt;round timing in parallel phases&lt;/li&gt;
&lt;li&gt;repeated cold-start variance&lt;/li&gt;
&lt;li&gt;degraded boot timing when optional subsystems are removed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jdk.VirtualThreadPinned&lt;/code&gt; events during startup&lt;/li&gt;
&lt;li&gt;final active subsystem count recorded at boot-ready&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why I treat JFR as part of the architecture here, not just as a performance tool. If the startup model is real, it should leave a readable lifecycle trace behind it.&lt;/p&gt;

&lt;p&gt;The bootstrap documentation in Exeris already treats startup telemetry as part of the contract: boot-ready, shutdown completion, dependency-cycle detection, and lifecycle state are all first-class signals rather than incidental logs.&lt;/p&gt;

&lt;p&gt;I also have some early exploratory startup measurements, although I am deliberately treating them as supporting evidence rather than a headline claim.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Exeris community h1&lt;/th&gt;
&lt;th&gt;Quarkus JVM VT tuned&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Startup → health-ready&lt;/td&gt;
&lt;td&gt;1132 ms&lt;/td&gt;
&lt;td&gt;2182 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup → first request&lt;/td&gt;
&lt;td&gt;1205 ms&lt;/td&gt;
&lt;td&gt;2432 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Health-ready → first request&lt;/td&gt;
&lt;td&gt;73 ms&lt;/td&gt;
&lt;td&gt;250 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These measurements were taken on dev hardware and remain sensitive to local runtime conditions, including machine state and GUI / no-GUI setup. So I am not using them to claim broad startup superiority yet.&lt;/p&gt;

&lt;p&gt;What they do show already is narrower, but still useful: this bootstrap model is measurable in operational terms. It is not just architecturally cleaner on paper.&lt;/p&gt;

&lt;p&gt;The smaller &lt;code&gt;health-ready → first-request&lt;/code&gt; gap is especially interesting to me, because it suggests the lifecycle boundary is not only short on paper but also closer to usable work.&lt;/p&gt;

&lt;p&gt;I have also validated the same runtime under a constrained exploratory profile with zero request errors, but that belongs to a different discussion than this article. The point here is narrower: the lifecycle model is observable and survives contact with measurement.&lt;/p&gt;

&lt;p&gt;I am also deliberately keeping the claim scope narrow. Early measurements are useful, but they are still sensitive to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;classloading state&lt;/li&gt;
&lt;li&gt;JIT state&lt;/li&gt;
&lt;li&gt;machine noise&lt;/li&gt;
&lt;li&gt;native load conditions&lt;/li&gt;
&lt;li&gt;startup environment shape&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I would rather say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;this model is measurable and operationally inspectable&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;than jump too quickly to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;this model is definitively faster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That comes later, if the data actually holds.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this does not solve
&lt;/h2&gt;

&lt;p&gt;This model does not fix bad subsystem boundaries.&lt;/p&gt;

&lt;p&gt;It does not fix circular graphs.&lt;br&gt;
It does not fix startup work that should not exist in the first place.&lt;br&gt;
It does not mean every subsystem should suddenly become parallel.&lt;br&gt;
And it definitely does not generalize to every runtime architecture.&lt;/p&gt;

&lt;p&gt;I would still use more conventional patterns when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the graph is shallow&lt;/li&gt;
&lt;li&gt;the lifecycle is simpler&lt;/li&gt;
&lt;li&gt;subsystem ownership is fuzzy by design&lt;/li&gt;
&lt;li&gt;plugin-style openness matters more than deterministic startup shape&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a universal recipe. It applies when the execution path is still under my control and the lifecycle itself is part of the architecture.&lt;/p&gt;

&lt;p&gt;That boundary matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I kept, what I dropped
&lt;/h2&gt;

&lt;p&gt;I think this is the part that usually gets lost when articles get too polished.&lt;/p&gt;

&lt;p&gt;I did not end up with a universal &lt;em&gt;"use STS for bootstrap"&lt;/em&gt; rule.&lt;/p&gt;

&lt;p&gt;What I kept:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;topological lifecycle order&lt;/li&gt;
&lt;li&gt;deterministic initialization&lt;/li&gt;
&lt;li&gt;explicit phase boundaries&lt;/li&gt;
&lt;li&gt;explicit failure policy&lt;/li&gt;
&lt;li&gt;reverse shutdown symmetry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I dropped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the idea that &lt;code&gt;initialize()&lt;/code&gt; and &lt;code&gt;start()&lt;/code&gt; should be the same phase&lt;/li&gt;
&lt;li&gt;the idea that startup parallelism should be maximal&lt;/li&gt;
&lt;li&gt;the idea that concurrency should appear before dependency safety is known&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also considered using &lt;code&gt;StructuredTaskScope&lt;/code&gt; in other places where it looked fashionable on paper. In at least one case, it simply did not buy me anything meaningful, so I left it out.&lt;/p&gt;

&lt;p&gt;That contrast was useful. It made the bootstrap use case clearer. &lt;code&gt;StructuredTaskScope&lt;/code&gt; was not valuable because it was new. It was valuable because this part of the system already had a natural owner, a natural boundary, and a natural failure model.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A few things became clearer to me while building this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bootstrap became a graph problem before it became a concurrency problem.&lt;/strong&gt;&lt;br&gt;
That changed which part of the design actually needed structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;StructuredTaskScope&lt;/code&gt; helped only after order was already explicit.&lt;/strong&gt;&lt;br&gt;
The useful move was not &lt;em&gt;"fork everything"&lt;/em&gt; but &lt;em&gt;"compute a safe round, then run it inside a bounded scope."&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The trade-off is intentional.&lt;/strong&gt;&lt;br&gt;
I kept &lt;code&gt;initialize()&lt;/code&gt; and &lt;code&gt;FOUNDATION&lt;/code&gt; sequential on purpose. I gave up some parallelism to keep lifecycle ownership and failure semantics easier to reason about.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What this unlocks next in Exeris is not just cleaner startup code. It gives me a more inspectable lifecycle model for later work around health, telemetry, subsystem isolation, and eventually more demanding cold-start contracts.&lt;/p&gt;

&lt;p&gt;If you want to see what this looks like outside a toy example, the bootstrap and lifecycle code is in the Exeris Kernel repository.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Explore the Exeris Kernel — zero-allocation architecture in running code:&lt;br&gt;
🔗 &lt;a href="https://github.com/exeris-systems/exeris-kernel" rel="noopener noreferrer"&gt;exeris-systems/exeris-kernel&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>projectloom</category>
      <category>structuredconcurrency</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Reevaluating 1990s OOP in Java: DOP, Scoped Values, and Loom in 2026</title>
      <dc:creator>Arkadiusz Przychocki</dc:creator>
      <pubDate>Sat, 21 Mar 2026 09:17:18 +0000</pubDate>
      <link>https://forem.com/arkstack/reevaluating-1990s-oop-in-java-dop-scoped-values-and-loom-in-2026-3p4g</link>
      <guid>https://forem.com/arkstack/reevaluating-1990s-oop-in-java-dop-scoped-values-and-loom-in-2026-3p4g</guid>
      <description>&lt;p&gt;For decades, the Gang of Four (GoF) design patterns were the standard for object-oriented programming. If you had conditional behavior, you built a Factory. If you had interchangeable algorithms, you built a Strategy.&lt;/p&gt;

&lt;p&gt;While these patterns remain foundational, applying them blindly in modern Java (21 through 26) often introduces an unnecessary &lt;strong&gt;Abstraction Tax&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When engineering the &lt;strong&gt;Exeris Kernel&lt;/strong&gt;, my goal was "No Waste Compute." This didn't mean chasing micro-optimizations, but rather rethinking control flow, context propagation, and concurrency using modern JVM primitives.&lt;/p&gt;

&lt;p&gt;Here is a pragmatic look at where the JVM is heading, and how Data-Oriented Programming (DOP) combined with Project Loom changes the architectural calculus for closed-domain systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Enterprise Reality Check &amp;amp; Disclaimers
&lt;/h2&gt;

&lt;p&gt;Before diving in, let's ground this in reality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Migration Path:&lt;/strong&gt; You don't rewrite systems overnight.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java 21 gives you Records, Sealed Interfaces, Pattern Matching, and Virtual Threads (GA). You can adopt DOP today.&lt;/li&gt;
&lt;li&gt;Java 25 brings &lt;code&gt;ScopedValue&lt;/code&gt; to GA, fixing context propagation.&lt;/li&gt;
&lt;li&gt;Java 26+ further stabilizes &lt;code&gt;StructuredTaskScope&lt;/code&gt; (STS). &lt;strong&gt;Disclaimer:&lt;/strong&gt; As of JDK 26, STS is in its 6th preview (JEP 525). Running it in production requires &lt;code&gt;--enable-preview&lt;/code&gt; and organizational buy-in. It is highly stable, but it is &lt;em&gt;not&lt;/em&gt; a final standard yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. The "Closed World" Constraint:&lt;/strong&gt; The DOP approaches shown below are designed for &lt;strong&gt;Closed-World domains&lt;/strong&gt; (e.g., the core business logic of a specific microservice). If you are building an Open-World system (a plugin architecture, an extensible framework, or an SPI), you &lt;em&gt;must&lt;/em&gt; respect the Open/Closed Principle. In those cases, &lt;code&gt;sealed&lt;/code&gt; interfaces are the wrong tool, and traditional polymorphism with Service Registries remains the correct choice.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: The Legacy Approach (Understanding the Tax)
&lt;/h2&gt;

&lt;p&gt;Historically, to process different payment methods, we relied on polymorphic Strategy classes managed by a Factory. If we needed to pass context (like a Transaction ID), we relied on &lt;code&gt;ThreadLocal&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;PaymentStrategy&lt;/span&gt; &lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PaymentFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;strategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;process&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's be clear: &lt;strong&gt;allocating a single 24-byte Strategy object per request will not kill your heap.&lt;/strong&gt; The true "Abstraction Tax" at scale comes from the combination of indirection: cognitive overhead, polymorphic dispatch costs on extreme hot-paths, deep object graph complexity, and crucially, the severe memory overhead of copying &lt;code&gt;InheritableThreadLocal&lt;/code&gt; maps when spawning thousands of Virtual Threads.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Data-Oriented Programming
&lt;/h2&gt;

&lt;p&gt;In modern Java, we can separate &lt;em&gt;data&lt;/em&gt; from &lt;em&gt;behavior&lt;/em&gt;. Instead of a polymorphic Factory returning Strategy objects, we use &lt;strong&gt;Sealed Interfaces&lt;/strong&gt; and &lt;strong&gt;Records&lt;/strong&gt; to model our domain, and &lt;strong&gt;Pattern Matching&lt;/strong&gt; for dispatch.&lt;/p&gt;

&lt;p&gt;In DOP, records must guarantee the validity of their state at creation using Compact Constructors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.math.BigDecimal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 1. A closed hierarchy. The compiler ensures exhaustiveness.&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PaymentMethod&lt;/span&gt; &lt;span class="n"&gt;permits&lt;/span&gt; &lt;span class="nc"&gt;CreditCard&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Blik&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Compact Constructors prevent invalid state&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;CreditCard&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cardNumber&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;PaymentMethod&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;CreditCard&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cardNumber&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;cardNumber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\\d{16}"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid card format"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getLastFourDigits&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cardNumber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;substring&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Blik&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;PaymentMethod&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Blik&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\\d{6}"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid BLIK code"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For closed-domain dispatch, this eliminates the Factory entirely. You get compile-time exhaustiveness, guaranteed data validity, and more predictable control flow.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Memory Footprint Shift
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxk8zhrdpzpzi68tpiggf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxk8zhrdpzpzi68tpiggf.png" alt=" " width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Scoped Values (Context Without the Leak)
&lt;/h2&gt;

&lt;p&gt;If nested logic needs a Transaction ID for logging, &lt;code&gt;InheritableThreadLocal&lt;/code&gt; becomes a massive bottleneck. Copying state across millions of Virtual Threads destroys the lightweight nature of Project Loom.&lt;/p&gt;

&lt;p&gt;In JDK 25, &lt;strong&gt;Scoped Values&lt;/strong&gt; are GA. &lt;code&gt;ScopedValue&lt;/code&gt; provides immutable, downward-only data flow. It drastically reduces inheritance overhead and automatically vanishes when the execution scope exits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentContext&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ScopedValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;TX_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ScopedValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newInstance&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Binding the context&lt;/span&gt;
&lt;span class="nc"&gt;ScopedValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TX_ID&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"TX-9981"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Processing ID: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;PaymentContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TX_ID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Caveat: Because ScopedValues are strictly downward, patterns like updating MDC context deep in the call stack require architectural adjustments).&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Execution (Pure DOP + Structured Concurrency)
&lt;/h2&gt;

&lt;p&gt;We have fixed data modeling (DOP) and state propagation (&lt;code&gt;ScopedValue&lt;/code&gt;). Now we need execution.&lt;/p&gt;

&lt;p&gt;If we execute a payment while simultaneously calling a fraud service, and the fraud service fails, the payment must abort instantly (Fail-Fast).&lt;/p&gt;

&lt;p&gt;In 2026, many still use libraries like Resilience4j for this. &lt;strong&gt;To be clear: &lt;code&gt;StructuredTaskScope&lt;/code&gt; does not replace retries or circuit breakers (which belong in your Service Mesh/Envoy layer).&lt;/strong&gt; However, STS natively replaces application-layer &lt;em&gt;bulkheads and timeouts&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here is the implementation using JDK 26 Preview API. We fork virtual threads and pass validated data records directly to a function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.math.BigDecimal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.UUID&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.concurrent.StructuredTaskScope&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.concurrent.StructuredTaskScope.Subtask&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;PaymentRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PaymentMethod&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentOrchestrator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;txId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomUUID&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;substring&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;ScopedValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TX_ID&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;txId&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;executeConcurrentWorkflow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;executeConcurrentWorkflow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Enforces a strict concurrency model with ownership constraints&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StructuredTaskScope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

            &lt;span class="nc"&gt;Subtask&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;paymentTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fork&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;executePayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
            &lt;span class="nc"&gt;Subtask&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fraudTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fork&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;performFraudCheck&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

            &lt;span class="c1"&gt;// Automatically interrupts sibling tasks if one fails&lt;/span&gt;
            &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Payment: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;paymentTask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fraud Check: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fraudTask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"Clear"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Suspicious"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StructuredTaskScope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FailedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Transaction aborted: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCause&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentThread&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;interrupt&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;executePayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentMethod&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[Tx: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;PaymentContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TX_ID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"] Executing..."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Simulate I/O&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;CreditCard&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Processing card ending in "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLastFourDigits&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;Blik&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;       &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Authorizing BLIK code: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;};&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;performFraudCheck&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Native Fail-Fast Architecture
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wtgvsvc40jji80c1xqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wtgvsvc40jji80c1xqs.png" alt=" " width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pragmatic Verdict
&lt;/h2&gt;

&lt;p&gt;What replaces traditional GoF patterns in closed-domain systems is not a new pattern, but a shift in native JVM primitives: &lt;strong&gt;data (Records), context (ScopedValue), and execution (StructuredTaskScope).&lt;/strong&gt; By combining these primitives, we achieve:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Indirection:&lt;/strong&gt; We pass strictly validated records to functions running on virtual threads, bypassing proxy layers and improving predictability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Safety:&lt;/strong&gt; Compact Constructors ensure invalid state never enters the pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native Fail-Fast:&lt;/strong&gt; &lt;code&gt;StructuredTaskScope&lt;/code&gt; natively handles cancellation propagation across thread boundaries.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;System design in 2026 isn't about entirely removing OOP or chasing zero-allocation myths. It is about understanding which infrastructure problems are now solved natively by the JVM and your Service Mesh—and pragmatically removing the workarounds we used to rely on.&lt;/p&gt;

&lt;p&gt;If you want to see how this model scales beyond simple request handling into a durable, off-heap runtime, take a look at the &lt;a href="https://github.com/exeris-systems/exeris-kernel" rel="noopener noreferrer"&gt;Exeris Kernel repository on GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>architecture</category>
      <category>projectloom</category>
      <category>performance</category>
    </item>
    <item>
      <title>Why I Banned ThreadLocal from the Exeris Kernel (And What Replaced It)</title>
      <dc:creator>Arkadiusz Przychocki</dc:creator>
      <pubDate>Fri, 06 Mar 2026 18:43:10 +0000</pubDate>
      <link>https://forem.com/arkstack/why-i-banned-threadlocal-from-the-exeris-kernel-and-what-replaced-it-5aa</link>
      <guid>https://forem.com/arkstack/why-i-banned-threadlocal-from-the-exeris-kernel-and-what-replaced-it-5aa</guid>
      <description>&lt;p&gt;When I started designing the &lt;strong&gt;Exeris Kernel&lt;/strong&gt; — a next-generation, zero-copy runtime built for Java 26+ — I established one non-negotiable architectural law: &lt;strong&gt;"No Waste Compute."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a system designed to handle extreme density by mapping exactly one Virtual Thread to every network stream (1-VT-per-Stream), every byte of memory and every CPU cycle must be intentional.&lt;/p&gt;

&lt;p&gt;But very quickly, I hit a &lt;strong&gt;legacy wall&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the standard Enterprise Java ecosystem, when you need to pass a &lt;code&gt;SecurityContext&lt;/code&gt;, a &lt;code&gt;TenantId&lt;/code&gt;, or a &lt;code&gt;TransactionID&lt;/code&gt; down to the database layer without polluting dozens of method signatures, you reach for a trusted tool: &lt;code&gt;ThreadLocal&lt;/code&gt;. For over two decades, &lt;code&gt;ThreadLocal&lt;/code&gt; was the backbone of Java framework magic. But in the era of Project Loom (JEP 444) and Structured Concurrency, this old friend becomes a &lt;strong&gt;performance serial killer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is why I enforced a strict, kernel-wide ban on &lt;code&gt;ThreadLocal&lt;/code&gt; in Exeris, and how adopting &lt;strong&gt;JEP 506 (Scoped Values)&lt;/strong&gt; completely changed the game for high-performance architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Forensic Analysis: The 3 Sins of ThreadLocal
&lt;/h2&gt;

&lt;p&gt;Treating Virtual Threads like OS threads discards most of their scalability advantages — especially around context propagation and allocation behavior. When you combine &lt;code&gt;ThreadLocal&lt;/code&gt; with a highly concurrent, thread-per-request architecture, you introduce three critical flaws:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Spaghetti State (Unconstrained Mutability)
&lt;/h3&gt;

&lt;p&gt;Any code deep in the call stack that can read a &lt;code&gt;ThreadLocal&lt;/code&gt; can also call &lt;code&gt;.set()&lt;/code&gt; on it. If a nested library mutates the &lt;code&gt;SecurityContext&lt;/code&gt; mid-flight, tracking down who changed it and when is a debugging nightmare. Data flow becomes completely unpredictable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.arkstack.dev%2Fblog%2Fscopedvalue%2Ffig1_spaghetti_state.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.arkstack.dev%2Fblog%2Fscopedvalue%2Ffig1_spaghetti_state.png" alt="Figure 1: The uncontrolled mutability of ThreadLocal versus the strict, read-only data flow guarantees of a lexically bounded ScopedValue." width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1: The uncontrolled mutability of ThreadLocal versus the strict, read-only data flow guarantees of a lexically bounded ScopedValue.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Memory Leak Trap (Unbounded Lifetime)
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;ThreadLocal&lt;/code&gt; survives until the thread dies or someone explicitly calls &lt;code&gt;.remove()&lt;/code&gt;. In legacy thread pools, forgetting to clean up means a security context bleeds into the next user's request.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Inheritance Tax (The RAM Killer)
&lt;/h3&gt;

&lt;p&gt;This is the fatal blow. To share context with child threads, frameworks use &lt;code&gt;InheritableThreadLocal&lt;/code&gt;. When a parent thread creates a child, the JVM must &lt;strong&gt;eagerly clone&lt;/strong&gt; the parent's &lt;code&gt;ThreadLocalMap&lt;/code&gt;. This typically allocates between &lt;strong&gt;32 and 128 bytes&lt;/strong&gt; per entry on the heap, depending on the load factor and key distribution.&lt;/p&gt;

&lt;p&gt;Now, imagine a single HTTP request where your logic forks &lt;strong&gt;50 concurrent sub-tasks&lt;/strong&gt; (Virtual Threads) to fetch data. You just triggered &lt;strong&gt;50 expensive map allocations&lt;/strong&gt;. Multiply that by 10,000 concurrent requests, and your Garbage Collector stalls your application just to clean up useless context clones. This becomes a &lt;strong&gt;pure GC tax with no business value&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.arkstack.dev%2Fblog%2Fscopedvalue%2Ffig2_inheritance_tax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.arkstack.dev%2Fblog%2Fscopedvalue%2Ffig2_inheritance_tax.png" alt="Figure 2: The O(N) memory copy penalty of InheritableThreadLocal compared to the O(1) constant-time pointer inheritance introduced in JEP 506." width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2: The O(N) memory copy penalty of InheritableThreadLocal compared to the O(1) constant-time pointer inheritance introduced in JEP 506.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Missing Link: Structured Concurrency Incompatibility
&lt;/h2&gt;

&lt;p&gt;Beyond performance, &lt;code&gt;ThreadLocal&lt;/code&gt; is fundamentally incompatible with Structured Concurrency. &lt;code&gt;StructuredTaskScope&lt;/code&gt; relies on deterministic, tree-like execution where child tasks are strictly bound to the lifetime of their parent. &lt;code&gt;ThreadLocal&lt;/code&gt;, being non-deterministic and fully mutable at any level of the tree, completely breaks this model.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You cannot build a reliable, fail-fast concurrent tree if any leaf node can secretly mutate the global state of the branch.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Exhibit A: The Zero-Waste Solution (JEP 506)
&lt;/h2&gt;

&lt;p&gt;To survive millions of Virtual Threads, we need a mechanism that is &lt;strong&gt;immutable&lt;/strong&gt;, &lt;strong&gt;temporally bounded&lt;/strong&gt;, and &lt;strong&gt;virtually free to inherit&lt;/strong&gt;. Enter &lt;strong&gt;Scoped Values&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of a globally mutable variable, a &lt;code&gt;ScopedValue&lt;/code&gt; defines a &lt;strong&gt;Dynamic Scope&lt;/strong&gt;. It binds a value to a specific block of code (and all methods called within it). Once the block finishes, the binding vanishes.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Scoreboard
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ThreadLocal&lt;/th&gt;
&lt;th&gt;ScopedValue&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Immutability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mutable (Anyone can overwrite)&lt;/td&gt;
&lt;td&gt;Immutable (Read-only for callees)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lifetime&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Unbounded (Requires manual cleanup)&lt;/td&gt;
&lt;td&gt;Lexically bounded (tied to the &lt;code&gt;.run()&lt;/code&gt; block)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inheritance Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;O(N) memory copy&lt;/td&gt;
&lt;td&gt;O(1) constant-time inheritance with negligible allocation cost&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Exhibit B: "Show, Don't Tell" — The Exeris Implementation
&lt;/h2&gt;

&lt;p&gt;In the Exeris Kernel, context propagation is strictly separated. The Security module authenticates, and the Persistence module applies Row-Level Security. They never talk directly. They communicate purely through an &lt;strong&gt;"Invisible Wall"&lt;/strong&gt; using &lt;code&gt;ScopedValue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.arkstack.dev%2Fblog%2Fscopedvalue%2Ffig3_context_scope.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.arkstack.dev%2Fblog%2Fscopedvalue%2Ffig3_context_scope.png" alt="Figure 3: Context propagation in the Exeris Kernel. Security and Persistence modules remain completely decoupled, sharing identity strictly through an immutable dynamic scope." width="302" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3: Context propagation in the Exeris Kernel. Security and Persistence modules remain completely decoupled, sharing identity strictly through an immutable dynamic scope.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here is how identity is injected at the gateway. Notice the complete absence of &lt;code&gt;.set()&lt;/code&gt; methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Decode token directly from off-heap memory (Zero-Alloc)&lt;/span&gt;
&lt;span class="nc"&gt;AuthenticationResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;securityProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authenticate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenBuffer&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Open a lexically bounded, immutable Dynamic Scope&lt;/span&gt;
&lt;span class="c1"&gt;// Note: Chained .where() calls create efficient nested scopes.&lt;/span&gt;
&lt;span class="nc"&gt;ScopedValue&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KernelProviders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PRINCIPAL_CONTEXT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;principal&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KernelProviders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;STORAGE_CONTEXT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;   &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Inside this block, the context is safe.&lt;/span&gt;
        &lt;span class="c1"&gt;// It will be inherited by any Virtual Thread spawned via StructuredTaskScope.&lt;/span&gt;
        &lt;span class="n"&gt;dispatchRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 3. Scope closes automatically. No .remove() needed. Zero leaks.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later, deep in the Persistence module, the &lt;code&gt;TransactionOrchestrator&lt;/code&gt; needs to know the Tenant ID to append it to the SQL query. It simply queries the active scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TransactionOrchestrator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;StorageContext&lt;/span&gt; &lt;span class="nf"&gt;resolveStorageContext&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Zero ThreadLocal, fully Virtual-Thread safe (JEP 506)&lt;/span&gt;
        &lt;span class="c1"&gt;// isBound() is an O(1) check&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KernelProviders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;STORAGE_CONTEXT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isBound&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;KernelProviders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;STORAGE_CONTEXT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// Fallback to system context without allocating objects&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ImmutableStorageContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ... transaction execution logic&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;ScopedValue&lt;/code&gt; is immutable, the &lt;code&gt;TransactionOrchestrator&lt;/code&gt; is &lt;strong&gt;guaranteed by lexical scoping and immutability&lt;/strong&gt; that the &lt;code&gt;StorageContext&lt;/code&gt; it reads is exactly the one set by the gateway, untampered by any interceptor along the way.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Paradigm Shift
&lt;/h2&gt;

&lt;p&gt;By ripping &lt;code&gt;ThreadLocal&lt;/code&gt; out of the kernel, we eliminated an entire category of memory leaks and GC pressure. When a system spawns 1,000,000 Virtual Threads, the difference between &lt;em&gt;"copying a map 1 million times"&lt;/em&gt; and &lt;em&gt;"sharing a pointer in constant time"&lt;/em&gt; is the difference between a crashed server and a stable infrastructure.&lt;/p&gt;

&lt;p&gt;Java 26 is not just &lt;em&gt;"Java 8 with &lt;code&gt;var&lt;/code&gt;"&lt;/em&gt;. Features like Project Loom, Panama (FFM), and Scoped Values require a &lt;strong&gt;fundamental shift&lt;/strong&gt; in how we architect systems. If we keep building frameworks using patterns from 2014, we will never unlock the true performance of modern hardware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Would you be willing to refactor your application to drop &lt;code&gt;ThreadLocal&lt;/code&gt; and embrace &lt;code&gt;ScopedValue&lt;/code&gt;?&lt;/strong&gt; Let me know in the comments.&lt;/p&gt;




&lt;h2&gt;
  
  
  Explore the Exeris Kernel
&lt;/h2&gt;

&lt;p&gt;The zero-allocation architecture described in this article isn't just theory — it's running code. Exeris is an open-core, post-container cloud kernel built for extreme density. If you're tired of GC pauses and want to see how native I/O, Panama FFM, and Virtual Thread orchestration look in practice, explore the Exeris Kernel:&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/exeris-systems/exeris-kernel" rel="noopener noreferrer"&gt;exeris-systems/exeris-kernel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>virtualthreads</category>
      <category>projectloom</category>
      <category>exeris</category>
    </item>
    <item>
      <title>Welcome to Arkstack — JVM Performance, Off-heap Memory &amp; Low-Latency Architecture</title>
      <dc:creator>Arkadiusz Przychocki</dc:creator>
      <pubDate>Fri, 06 Mar 2026 18:36:07 +0000</pubDate>
      <link>https://forem.com/arkstack/welcome-to-arkstack-jvm-performance-off-heap-memory-low-latency-architecture-2ege</link>
      <guid>https://forem.com/arkstack/welcome-to-arkstack-jvm-performance-off-heap-memory-low-latency-architecture-2ege</guid>
      <description>&lt;p&gt;Welcome to &lt;strong&gt;Arkstack.dev&lt;/strong&gt; — a minimalistic, developer-focused blog with zero unnecessary fluff.&lt;/p&gt;

&lt;p&gt;This is the digital home of &lt;strong&gt;Arkadiusz Przychocki&lt;/strong&gt;, Lead Cloud Architect &amp;amp; Full-Stack Engineer. If you care about clean systems, modern JVM engineering, and cloud-native architecture done right, you're in the right place.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Expect
&lt;/h2&gt;

&lt;p&gt;This blog covers the intersection of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Architecture&lt;/strong&gt; — designing resilient, cost-efficient systems on AWS, GCP, and Azure. Infrastructure as code, distributed systems, and the hard lessons learned in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern Java&lt;/strong&gt; — the language is evolving faster than ever. Virtual threads (Project Loom), sealed classes, pattern matching, and the growing ecosystem around GraalVM native image compilation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-Waste Engineering&lt;/strong&gt; — every abstraction has a cost. We care deeply about what actually runs on the metal.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Exeris Kernel
&lt;/h2&gt;

&lt;p&gt;One of the flagship projects I'm working on is &lt;strong&gt;Exeris Kernel&lt;/strong&gt; — a zero-allocation runtime designed for ultra-low-latency workloads. The core philosophy:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every allocation is a liability. Every system call is a negotiation. We opt out of both wherever possible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Exeris Kernel is built on top of the JVM's Foreign Function &amp;amp; Memory API, leveraging off-heap memory management to achieve predictable, GC-pause-free execution. It's designed for financial systems, real-time data pipelines, and anywhere nanoseconds matter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example: off-heap buffer allocation in Exeris Kernel&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;arena&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arena&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofConfined&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;segment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arena&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allocate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ValueLayout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;JAVA_LONG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;segment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAtIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ValueLayout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;JAVA_LONG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nanoTime&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Calendar vs. Competence
&lt;/h2&gt;

&lt;p&gt;I don't measure my career in calendar years. I measure it in the depth of the stack I've had to dismantle.&lt;/p&gt;

&lt;p&gt;While many spend a decade inside the comfort zone of a framework, I spent the last 6 months fighting the JVM Garbage Collector and manual memory management — off-heap arenas, direct &lt;code&gt;MemorySegment&lt;/code&gt; access via Project Panama, and the hard lessons of building a zero-allocation runtime from scratch.&lt;/p&gt;

&lt;p&gt;That's where real engineering begins. Not in CRUD scaffolding. In the moments when the GC log is your only clue, and latency spikes are measured in microseconds, not seconds.&lt;/p&gt;

&lt;p&gt;This blog is the audit trail of that journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Philosophy
&lt;/h2&gt;

&lt;p&gt;The philosophy of this blog mirrors the philosophy of Exeris: &lt;strong&gt;No Waste&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No unnecessary client-side JavaScript on this site&lt;/li&gt;
&lt;li&gt;No bloated frameworks where a pure function suffices&lt;/li&gt;
&lt;li&gt;No ceremony when simplicity delivers the same result&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built with &lt;a href="https://astro.build" rel="noopener noreferrer"&gt;Astro&lt;/a&gt; — the framework that ships zero JS by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stay Tuned
&lt;/h2&gt;

&lt;p&gt;Upcoming content includes deep dives into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GraalVM native image compilation for Spring Boot services&lt;/li&gt;
&lt;li&gt;Designing multi-region active-active architectures&lt;/li&gt;
&lt;li&gt;The Exeris Kernel internals: lock-free queues and off-heap buffers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's build things that last.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>java</category>
      <category>architecture</category>
      <category>exeris</category>
    </item>
  </channel>
</rss>
