<?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>DEV Community: Sergiy Yevtushenko</title>
    <description>The latest articles on DEV Community by Sergiy Yevtushenko (@siy).</description>
    <link>https://dev.to/siy</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%2F145374%2F6e93547b-45cc-430e-9659-3adea03266b5.jpeg</url>
      <title>DEV Community: Sergiy Yevtushenko</title>
      <link>https://dev.to/siy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/siy"/>
    <language>en</language>
    <item>
      <title>We Should Write Java Code Differently: Frictionless Prod</title>
      <dc:creator>Sergiy Yevtushenko</dc:creator>
      <pubDate>Thu, 02 Apr 2026 21:51:07 +0000</pubDate>
      <link>https://dev.to/siy/we-should-write-java-code-differently-frictionless-prod-3mg8</link>
      <guid>https://dev.to/siy/we-should-write-java-code-differently-frictionless-prod-3mg8</guid>
      <description>&lt;h1&gt;
  
  
  We Should Write Java Code Differently: Frictionless Prod
&lt;/h1&gt;

&lt;p&gt;It's not a secret that modern production deployment is extremely complex. Following "best practices" and deploying in Kubernetes "for scalability" makes things even more complex. But how complex exactly? Let's look at the numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;A mid-sized e-commerce platform. Nothing exotic -- catalog, cart, checkout, orders, payments, shipping, inventory, pricing, promotions, notifications. Standard bounded contexts, standard domain decomposition.&lt;/p&gt;

&lt;p&gt;In a microservices architecture, this translates to roughly 30 services. Not because someone wanted 30 -- because the domain naturally decomposes into ~10 core services, ~10 supporting services (integrations, async processing, admin), and ~10 platform services (gateway, auth, search, analytics, event processing).&lt;/p&gt;

&lt;p&gt;30 is not a large number. It is a realistic baseline for a system that does what mid-sized e-commerce systems do.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 30 Services Actually Cost
&lt;/h2&gt;

&lt;p&gt;Each service needs to be built, deployed, configured, monitored, and kept alive -- independently. On managed Kubernetes, the standard deployment substrate for this scale, here is what the numbers look like.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production environment:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;12-18 shared platform components (ingress controller, cert manager, external DNS, metrics stack, logging pipeline, tracing collector, secrets integration, policy controller, autoscaler, GitOps controller, backup controller, image registry integration)&lt;/li&gt;
&lt;li&gt;220-280 Kubernetes workload objects (deployments, services, config maps, secrets, service accounts, network policies, autoscalers, pod disruption budgets, ingress rules, worker/consumer deployments)&lt;/li&gt;
&lt;li&gt;260-340 configuration sets (image tags, rollout strategies, replica counts, CPU/memory limits, probes, environment variables, feature flags, secret references, IAM permissions, network exposure rules, alerting configs -- per service)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Staging environment:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Topologically similar to production. You save on capacity, not on configuration complexity. 190-250 workload objects. 220-300 configuration sets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Testing environment:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;80-160 workload objects in a shared cluster with ephemeral namespaces. 100-180 configuration sets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Across all three environments: 500-700 managed runtime objects and 580-820 configuration surfaces.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is before counting databases, message brokers, CDN, object storage, and external SaaS integrations. The application itself -- the business logic that actually generates revenue -- is a small fraction of this surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Team That Manages This
&lt;/h2&gt;

&lt;p&gt;This infrastructure does not manage itself. For a 30-service system on managed Kubernetes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimum viable:&lt;/strong&gt; 3-5 platform/DevOps engineers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typical realistic:&lt;/strong&gt; 5-8 engineers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comfortable/mature:&lt;/strong&gt; 8-12 engineers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is platform and SRE combined -- not including the feature development teams that write the actual business logic. These engineers manage pipelines, rollout policies, cluster security, network configuration, secrets, observability, capacity planning, incident response, and the endless stream of version upgrades across 30 independent deployment units.&lt;/p&gt;

&lt;p&gt;The dominant complexity is not code. It is coordination: version coexistence (new service talking to old service), schema evolution (new code on old database), deployment ordering (which service goes first), and failure propagation (one bad deploy cascading through dependent services).&lt;/p&gt;

&lt;p&gt;A mid-sized organization pays for 5-8 engineers whose entire job is keeping the deployment machinery running. Not building features. Not serving customers. Managing the gap between code and production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Complexity Comes From
&lt;/h2&gt;

&lt;p&gt;This is not accidental. The complexity has three structural sources, each one a consequence of architectural decisions made so long ago that they feel like laws of nature. They are not.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Monolith Turned Inside Out
&lt;/h3&gt;

&lt;p&gt;A microservices system is a monolith turned inside out. Every internal interaction -- a method call, a shared data structure, a module boundary -- transforms into infrastructure configuration. What was a function call within a single process becomes a network call that needs discovery, routing, serialization, timeout handling, retry logic, and circuit breaking. What was an internal module boundary becomes a deployment boundary with its own pipeline, versioning, and rollout policy.&lt;/p&gt;

&lt;p&gt;The problem is not microservices as a concept. The problem is that there are no predefined patterns or limits on how services interact. The infrastructure must be infinitely flexible to accommodate every possible communication topology. Infinite flexibility means every single interaction path must be configured -- sometimes multiple times in different places. A call from the order service to the inventory service touches ingress rules, network policies, service discovery, load balancing, timeout configuration, and retry policy. Each one configured separately. Each one a potential source of misconfiguration.&lt;/p&gt;

&lt;p&gt;A 30-service system with 50-100 service-to-service interactions does not have 30 configuration problems. It has a combinatorial configuration problem that grows with the interaction graph, not with the service count.&lt;/p&gt;

&lt;p&gt;This creates an inherent contradiction. The ideal service boundary is determined by the business domain -- by cohesion, coupling, and team ownership. But the configuration and operational cost of each additional service is so high that it becomes a technical factor in the decomposition decision. Teams merge services that should be separate to avoid operational overhead, or keep services together that should be split because nobody wants to set up another pipeline. The result is almost inevitably a suboptimal split -- service boundaries driven by infrastructure cost rather than domain structure.&lt;/p&gt;

&lt;p&gt;And there is a human cost too. Every service boundary is a communication boundary. Two services owned by two teams means coordination meetings, API contracts, versioning negotiations, shared testing environments, deployment ordering discussions. Conway's Law works in reverse here -- the architecture forces organizational communication patterns that would not exist if the split were different. The more services, the more cross-team coordination. The more coordination, the slower the delivery. The very thing microservices promised to fix -- team independence -- is undermined by the infrastructure overhead of maintaining the boundaries between them.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Substrate-Application Disconnect
&lt;/h3&gt;

&lt;p&gt;Kubernetes runs containers. It starts a binary, monitors a health endpoint, restarts it if it fails. That is the extent of the relationship. Once the binary is running, it is on its own.&lt;/p&gt;

&lt;p&gt;This creates a two-way blindness. The application cannot trust the environment -- it must assume that any network call can fail, any service can be unavailable, any response can be delayed. So the application implements its own retries, its own circuit breakers, its own service discovery, its own health reporting. All of this requires configuration.&lt;/p&gt;

&lt;p&gt;The blindness goes the other direction too. The substrate knows nothing about the application. It does not know which services talk to each other, what constitutes a meaningful health check for this specific business logic, which services must be deployed before others, or whether a particular service's "healthy" status actually means it can process requests. The cluster is fault-tolerant at the container level, but the application gets no benefit from that -- it must build its own fault tolerance on top.&lt;/p&gt;

&lt;p&gt;The result: the application carries infrastructure concerns that the runtime should handle, and the runtime cannot provide services that would require understanding the application. Both sides are doing extra work because neither side can see the other.&lt;/p&gt;

&lt;p&gt;There is a particularly painful consequence of this disconnect: the application and its infrastructure share a lifecycle. Every microservice bundles its own web server, serialization library, HTTP client, connection pool, metrics agent, and retry framework. When any of these components needs a security patch -- a CVE in Netty, a vulnerability in Jackson, an update in the connection pool -- the business logic must be rebuilt, retested, repackaged, and redeployed. All 30 services. Zero changes to business logic. Pure infrastructure maintenance.&lt;/p&gt;

&lt;p&gt;This is not a deployment -- it is a tax. A Netty CVE means 30 rebuilds, 30 pipeline runs, 30 test suites, 30 rollouts. Each one risks introducing regressions in business logic that nobody touched. The operational burden scales with the service count, and the trigger has nothing to do with the business. The application and the runtime are monolithically coupled inside every single service, even as the services themselves are distributed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tool Multiplication Effect
&lt;/h3&gt;

&lt;p&gt;Because the substrate and application are disconnected, the gap between them must be filled. Each gap spawns a tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routing and mTLS between services? Service mesh.&lt;/li&gt;
&lt;li&gt;TLS certificate lifecycle? Certificate manager.&lt;/li&gt;
&lt;li&gt;Configuration across environments? Config service.&lt;/li&gt;
&lt;li&gt;Database schema evolution? Migration tool.&lt;/li&gt;
&lt;li&gt;Connection management? Connection pooler.&lt;/li&gt;
&lt;li&gt;Metrics and tracing? Observability agents.&lt;/li&gt;
&lt;li&gt;Deployment orchestration? GitOps controller.&lt;/li&gt;
&lt;li&gt;Secret management? Vault or cloud secrets integration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each tool has its own configuration language, its own upgrade cycle, its own failure modes, and its own operational surface. Each tool solves a real problem -- but the problem only exists because the substrate and application cannot communicate.&lt;/p&gt;

&lt;p&gt;A 30-service system on managed Kubernetes typically depends on 9-12 distinct operational tools beyond Kubernetes itself. Each one was added to solve a legitimate gap. Together, they are the gap. The complexity is not in any single tool -- it is in the interaction between all of them. A certificate renewal that breaks a service mesh sidecar that causes a health check failure that triggers a cascading restart -- this class of incident exists only because the tools operate independently, each with partial knowledge, none with the full picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  What If the Gap Didn't Exist?
&lt;/h2&gt;

&lt;p&gt;The three sources of complexity share a root cause: the application and the runtime are strangers. The runtime starts a binary and watches a health endpoint. The binary assumes a hostile environment and brings its own infrastructure. The gap between them fills with tools. The tools fill with configuration. The configuration fills with inconsistencies. The inconsistencies fill incident postmortems.&lt;/p&gt;

&lt;p&gt;What changes if the runtime understands the application?&lt;/p&gt;

&lt;h3&gt;
  
  
  Unification: From Multiplication to Addition
&lt;/h3&gt;

&lt;p&gt;In a Kubernetes-based system, configuration complexity is multiplicative. Each service multiplied by each environment multiplied by each configuration surface produces the 580-820 number we saw earlier. Every new service adds a full column of config. Every new environment multiplies the entire matrix.&lt;/p&gt;

&lt;p&gt;This multiplication exists because nothing is shared. Each service configures its own database connection, its own TLS, its own retries, its own health checks, its own metrics, its own log format. Even when two services use the same database, they each carry their own connection configuration -- independently managed, independently misconfigured.&lt;/p&gt;

&lt;p&gt;A unified runtime changes the math. When the runtime handles TLS, there is one TLS configuration -- not 30. When the runtime handles database connections, there is one database configuration per database -- not one per service. When the runtime handles metrics, there is one observability configuration -- not 30 agents with 30 scrape configs.&lt;/p&gt;

&lt;p&gt;The dependency structure changes from a product of factors to a sum of components. 30 slices sharing 3 databases, 1 TLS configuration, and 1 observability setup produce roughly 35 configuration surfaces -- not 340. The complexity scales with the number of distinct resources, not with the number of services that use them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integration: The Cluster Becomes Service-Aware
&lt;/h3&gt;

&lt;p&gt;When the application is embedded into the runtime -- not just started by it -- the two-way blindness disappears.&lt;/p&gt;

&lt;p&gt;The runtime knows what slices exist, what resources they need, which slices communicate with each other, and what "healthy" means for each one. It knows because the application declared it: this slice needs a database, that slice publishes to a stream, this slice depends on that one. The declarations are not configuration files scattered across repositories. They are part of the application itself -- compiled in, type-checked, deployed as a single artifact.&lt;/p&gt;

&lt;p&gt;From the application's perspective, the environment becomes trustworthy. Retries, circuit breaking, load balancing, service discovery -- these are not application concerns anymore. The runtime handles them because the runtime knows the topology. When slice A calls slice B, the runtime knows where B lives, which instances are healthy, how to route the request, and what to do if it fails. The application code is a method call. Everything between the call and the response is the runtime's responsibility.&lt;/p&gt;

&lt;p&gt;This is not a framework providing libraries. It is a managed runtime providing services -- the way an operating system provides networking and storage to applications. The application does not implement TCP. It calls an API. The same principle, applied one level up.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Communication Fabric
&lt;/h3&gt;

&lt;p&gt;The deepest integration point is inter-slice communication. In a microservices system, service-to-service calls cross process boundaries, network boundaries, and trust boundaries. Each crossing adds latency, failure modes, and configuration.&lt;/p&gt;

&lt;p&gt;When slices run inside the runtime, the communication fabric is built in. A call from one slice to another is a typed method invocation. The runtime resolves the target, handles serialization, routes the request -- potentially to the same node (microsecond latency, zero network overhead) or to a remote node (transparent, with automatic retry and failover). The slice developer writes &lt;code&gt;inventory.check(items)&lt;/code&gt; and gets back a &lt;code&gt;Promise&amp;lt;Availability&amp;gt;&lt;/code&gt;. The infrastructure between the call and the response is invisible.&lt;/p&gt;

&lt;p&gt;This is not RPC dressed up as a method call. The type system guarantees that the caller and callee agree on the contract at compile time. There are no surprise serialization failures, no version mismatches discovered in production, no "the other service changed its API and nobody told us." The contract is a Java interface. The compiler enforces it.&lt;/p&gt;

&lt;p&gt;The same fabric carries pub/sub, streaming, and scheduled task execution. All inter-slice communication -- synchronous, asynchronous, event-driven -- flows through the same runtime-managed infrastructure. One communication model, one set of guarantees, one thing to understand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resource Provisioning: Declare, Don't Configure
&lt;/h3&gt;

&lt;p&gt;In the traditional model, the application includes its dependencies and configures them. A service that needs a database brings a connection pool library, configures the URL, credentials, pool size, timeouts, and retry behavior. A service that needs messaging brings a client library, configures the broker address, topics, serialization, and consumer groups. Each dependency is another library, another config surface, another thing to upgrade.&lt;/p&gt;

&lt;p&gt;In a unified runtime, the application declares what it needs. A slice annotated with &lt;code&gt;@Sql&lt;/code&gt; gets a database connection -- provisioned, pooled, health-checked, and monitored by the runtime. A slice that declares a stream gets a stream -- partitioned, replicated, persistent. The slice does not know or care how the database connection is managed. It declares intent. The runtime delivers.&lt;/p&gt;

&lt;p&gt;This is why 30 slices do not produce 30× configuration. The resources are shared by design. Three slices using the same database share one connection pool. Ten slices publishing to the same stream share one stream configuration. The configuration count tracks resources, not consumers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Different Tradeoffs: Splitup Without Penalty
&lt;/h3&gt;

&lt;p&gt;When the operational cost of each additional slice is zero -- no pipeline, no deployment descriptor, no config set, no monitoring surface -- the decomposition decision changes fundamentally.&lt;/p&gt;

&lt;p&gt;In a microservices system, splitting a service in two is an infrastructure project: new repository, new pipeline, new deployment config, new monitoring, new network policies, new on-call surface. This cost discourages splitting, leading to oversized services that bundle unrelated logic because nobody wants to pay the operational tax of separation.&lt;/p&gt;

&lt;p&gt;When slices are the unit, splitting is a code decision. Extract an interface, annotate it with &lt;code&gt;@Slice&lt;/code&gt;, implement the business logic. The runtime handles deployment, routing, scaling, and monitoring automatically. There is no operational penalty for having 50 slices instead of 10. The only consideration is the domain: does this logic belong together, or should it be independent?&lt;/p&gt;

&lt;p&gt;This aligns perfectly with vertical slicing. Each slice is a complete vertical: an interface (the contract), an implementation (the logic), and resource declarations (what it needs). No horizontal layers spread across packages. No shared mutable state between slices. Each slice is independently deployable, independently scalable, and independently understandable.&lt;/p&gt;

&lt;p&gt;The scaling is linear -- in development, not just in production. Adding a new slice to the system does not require understanding the deployment topology, the network configuration, or the CI/CD pipeline. It requires understanding the business domain. Write the interface. Implement the logic. Deploy.&lt;/p&gt;

&lt;h3&gt;
  
  
  JBCT: Structure That Carries Across Boundaries
&lt;/h3&gt;

&lt;p&gt;This is where the code methodology meets the runtime. JBCT's six structural patterns -- Sequencer, Fork-Join, Condition, Iteration, Aspects, Leaf -- are not just coding rules. They are the structural language of business processes. A Sequencer is a sequence of dependent steps. A Fork-Join is parallel independent operations. A Condition is a routing decision. These map directly to BPMN constructs -- the same notation business analysts use to describe processes.&lt;/p&gt;

&lt;p&gt;When every slice follows the same six patterns, several things happen at once:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The code becomes the specification.&lt;/strong&gt; A business analyst who understands the process can review the code structure and verify that it matches the intended workflow. Not because the code is simple -- because the structure is familiar. The patterns are the same shapes they draw on whiteboards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI-assisted development becomes predictable.&lt;/strong&gt; The six patterns constrain the generation space. An AI that produces JBCT code generates variations of known structures, not arbitrary architectures. The mechanical rules mean less manual correction, less review overhead, less accumulated drift.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer onboarding compresses.&lt;/strong&gt; A developer who learns the six patterns can read and contribute to any slice in the system. There is no per-service learning curve, no "this team does it differently." The patterns are the same everywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The entire stack speaks the same language.&lt;/strong&gt; The business process is described in BPMN. The code implements it in JBCT patterns that mirror the BPMN structure. The runtime deploys and operates it without configuration. From business requirement to production, the structure is consistent. No translation layers. No impedance mismatches. No "we need a meeting to explain what the code does."&lt;/p&gt;

&lt;h3&gt;
  
  
  Independent Lifecycles
&lt;/h3&gt;

&lt;p&gt;Remember the Netty CVE problem -- 30 rebuilds, 30 pipelines, 30 rollouts, zero business logic changes?&lt;/p&gt;

&lt;p&gt;When the application and the runtime are separate layers, their lifecycles decouple completely. The runtime handles web serving, TLS, connection pooling, serialization, metrics, retry logic. The application handles business logic. When Netty needs a patch, the runtime updates -- once, across all nodes, without touching a single slice. When business logic changes, the slice deploys -- without rebuilding the runtime.&lt;/p&gt;

&lt;p&gt;Update the runtime: roll out new nodes, slices continue serving. Update a slice: deploy a new version, the runtime handles routing. Update the database driver: runtime concern, not application concern. Update Java itself: runtime update, slices are unaffected.&lt;/p&gt;

&lt;p&gt;Two independent update cadences. Two independent test surfaces. Two independent rollout schedules. The security patch that used to trigger 30 rebuilds is now a single runtime update that applications never see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aether: What This Looks Like in Practice
&lt;/h2&gt;

&lt;p&gt;Everything described above is not a thought experiment. It is a working system called &lt;a href="https://pragmaticalabs.io/aether.html" rel="noopener noreferrer"&gt;Aether&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is what the 30-slice e-commerce application looks like in practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Application
&lt;/h3&gt;

&lt;p&gt;A slice is a Java interface:&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="nd"&gt;@Slice&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;placeOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PlaceOrderRequest&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;static&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="nf"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                     &lt;span class="nc"&gt;PricingService&lt;/span&gt; &lt;span class="n"&gt;pricing&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;request&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&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;items&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                                   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;pricing:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;calculate&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;OrderResult:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;placed&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 is the entire service. The interface is the contract. The factory method parameters are the dependencies. The implementation is the business logic. There is no framework, no annotations for routing or serialization or retry, no configuration file. The runtime handles all of it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Deployment
&lt;/h3&gt;

&lt;p&gt;The blueprint is a TOML file that describes the desired state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.example:commerce:1.0.0"&lt;/span&gt;

&lt;span class="nn"&gt;[[slices]]&lt;/span&gt;
&lt;span class="py"&gt;artifact&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.example:order-service:1.0.0"&lt;/span&gt;
&lt;span class="py"&gt;instances&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;

&lt;span class="nn"&gt;[[slices]]&lt;/span&gt;
&lt;span class="py"&gt;artifact&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.example:inventory-service:1.0.0"&lt;/span&gt;
&lt;span class="py"&gt;instances&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="c"&gt;# ... remaining slices&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Maven plugin packages the blueprint automatically -- along with database schema migration scripts and application configuration -- into a single deployable JAR. The entire build-to-production workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build and install to local Maven repository&lt;/span&gt;
mvn &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Push artifacts from local Maven repo to production cluster&lt;/span&gt;
aether artifact push org.example:commerce:1.0.0

&lt;span class="c"&gt;# Deploy&lt;/span&gt;
aether deploy org.example:commerce:1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three commands. The runtime resolves artifacts, runs schema migrations, distributes slice instances across nodes, registers routes, and starts serving traffic. No Docker images, no Helm charts, no deployment descriptors, no pipeline configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Cluster
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[deployment]&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"aws"&lt;/span&gt;
&lt;span class="py"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"eu-west-1"&lt;/span&gt;

&lt;span class="nn"&gt;[deployment.instances]&lt;/span&gt;
&lt;span class="py"&gt;core&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"m5.large"&lt;/span&gt;

&lt;span class="nn"&gt;[cluster]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"production"&lt;/span&gt;
&lt;span class="py"&gt;core.count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="nn"&gt;[cluster.auto_heal]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aether cluster bootstrap &lt;span class="nt"&gt;--config&lt;/span&gt; cluster.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five nodes. Auto-healing. TLS derived from a shared secret -- no external certificate authority, no cert-manager. Service discovery via consensus -- no Consul, no etcd. Metrics and tracing built in -- no Prometheus scrape configs, no observability agents. QUIC transport with mandatory TLS 1.3 between all nodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aether cluster scale &lt;span class="nt"&gt;--core&lt;/span&gt; 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two additional nodes join the cluster automatically -- same binary, same config. Worker nodes can scale independently via gossip protocol, adding capacity without touching the consensus layer. A 5-node cluster grows to 50 nodes without architecture changes. The runtime includes a reactive scaling controller that adjusts capacity based on CPU, latency, queue depth, and error rate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local Development
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build your slices&lt;/span&gt;
mvn &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Start a 5-node cluster on your laptop with your application deployed&lt;/span&gt;
aether-forge &lt;span class="nt"&gt;--blueprint&lt;/span&gt; org.example:commerce:1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A full cluster on your laptop. Real consensus, real routing, real failure scenarios. Web dashboard with live metrics. Kill a node, watch recovery. Deploy a new slice version, watch traffic shift. The same runtime that runs in production runs on your machine -- not a simulation, not a mock, the actual system. When it works in Forge, it works in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Numbers
&lt;/h3&gt;

&lt;p&gt;For the same 30-slice e-commerce application:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration sets (production):&lt;/strong&gt; 260-340 on Kubernetes. ~15 on Aether.&lt;br&gt;
&lt;strong&gt;Configuration sets (all environments):&lt;/strong&gt; 580-820 on Kubernetes. ~18 on Aether.&lt;br&gt;
&lt;strong&gt;Platform components:&lt;/strong&gt; 12-18 per environment on Kubernetes. 1 binary on Aether.&lt;br&gt;
&lt;strong&gt;Deployment:&lt;/strong&gt; 30 independent pipelines on Kubernetes. 3 commands on Aether.&lt;br&gt;
&lt;strong&gt;Runtime security patch:&lt;/strong&gt; 30 rebuilds on Kubernetes. 1 rolling update on Aether.&lt;br&gt;
&lt;strong&gt;Operational team:&lt;/strong&gt; 5-8 dedicated engineers on Kubernetes. 1 person on Aether.&lt;/p&gt;

&lt;p&gt;One person does not mean zero operational work. Monitoring the cluster, watching for bottlenecks, checking alerts, reviewing scaling behavior, planning capacity -- that is enough work for one person. But it is one person, not eight. And that person spends time on operational judgment, not on managing the configuration machinery that connects 12 tools to 30 services across 3 environments.&lt;/p&gt;




&lt;p&gt;Running Java should be as easy as writing it.&lt;/p&gt;

&lt;p&gt;With Aether, it is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pragmaticalabs.io" rel="noopener noreferrer"&gt;pragmaticalabs.io&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Previously: &lt;a href="https://dev.to/siy/introduction-to-pragmatic-functional-java-142m"&gt;Introduction to Pragmatic Functional Java&lt;/a&gt; (2019) | &lt;a href="https://dev.to/siy/we-should-write-java-code-differently-210b"&gt;We Should Write Java Code Differently&lt;/a&gt; (2021) | &lt;a href="https://dev.to/siy/we-should-write-java-code-differently-lets-get-practical-1ib2"&gt;We Should Write Java Code Differently: Let's Get Practical&lt;/a&gt; (2026)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>devops</category>
      <category>architecture</category>
      <category>distributed</category>
    </item>
    <item>
      <title>We Should Write Java Code Differently: Let's Get Practical</title>
      <dc:creator>Sergiy Yevtushenko</dc:creator>
      <pubDate>Sun, 22 Mar 2026 21:54:48 +0000</pubDate>
      <link>https://dev.to/siy/we-should-write-java-code-differently-lets-get-practical-1ib2</link>
      <guid>https://dev.to/siy/we-should-write-java-code-differently-lets-get-practical-1ib2</guid>
      <description>&lt;h1&gt;
  
  
  We Should Write Java Code Differently: Let's Get Practical
&lt;/h1&gt;

&lt;p&gt;A few years ago I wrote about &lt;a href="https://dev.to/siy/we-should-write-java-code-differently-210b"&gt;why we should write Java code differently&lt;/a&gt;. The core argument: most of what slows us down is not the amount of code — it's the amount of context we lose while writing it. Nullable variables, business exceptions, framework magic — each one eats information that should have been explicit.&lt;/p&gt;

&lt;p&gt;That article diagnosed the problem. This one delivers the tools.&lt;/p&gt;

&lt;p&gt;Three types — &lt;code&gt;Option&lt;/code&gt;, &lt;code&gt;Result&lt;/code&gt;, and &lt;code&gt;Promise&lt;/code&gt; — cover virtually every return value in a Java backend. They compose with the same &lt;code&gt;map&lt;/code&gt;/&lt;code&gt;flatMap&lt;/code&gt; vocabulary you already know from Streams. Once you internalize them, the code you write becomes shorter, safer, and — this is the part that surprised me — significantly easier to read months later.&lt;/p&gt;




&lt;h2&gt;
  
  
  Option: A Value That Might Not Be There
&lt;/h2&gt;

&lt;p&gt;If you've used Streams, you already understand the core mechanic — transform the value inside, chain transformations, extract at the end. &lt;code&gt;Option&lt;/code&gt; applies the same thinking to absent values.&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="n"&gt;findUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;findAddress&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addressId&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="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Profile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If any step returns &lt;code&gt;Option.none()&lt;/code&gt;, the whole chain short-circuits. No null checks, no early returns, no branching. The absent-value case propagates automatically.&lt;/p&gt;

&lt;p&gt;Where does &lt;code&gt;Option&lt;/code&gt; come from? At adapter boundaries — wrapping nullable external APIs:&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;Option&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;option&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;getParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside business logic, &lt;code&gt;Option&lt;/code&gt; is the container for everything genuinely optional. The type makes the absence visible in the signature, not hidden in a javadoc comment.&lt;/p&gt;

&lt;p&gt;A few things that make &lt;code&gt;Option&lt;/code&gt; practical:&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;// Pattern matching with sealed types&lt;/span&gt;
&lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;option&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;Option&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Some&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;value&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;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&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;Option&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;None&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;handleAbsence&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Convert to Result when absence is an error&lt;/span&gt;
&lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;NOT_FOUND&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Combine multiple Options — all must be present&lt;/span&gt;
&lt;span class="nc"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&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;Contact:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The conversion methods matter. &lt;code&gt;Option&lt;/code&gt; is not an island — it flows into &lt;code&gt;Result&lt;/code&gt; and &lt;code&gt;Promise&lt;/code&gt; when the context demands it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Result: Errors Without Exceptions
&lt;/h2&gt;

&lt;p&gt;This is where things change fundamentally.&lt;/p&gt;

&lt;p&gt;Consider typical Java error handling:&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="nc"&gt;User&lt;/span&gt; &lt;span class="nf"&gt;registerUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RegistrationRequest&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="k"&gt;if&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;email&lt;/span&gt;&lt;span class="o"&gt;()&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="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isBlank&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;ValidationException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Email is required"&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;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;existsByEmail&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;email&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;DuplicateEmailException&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;email&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;try&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;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;passwordHasher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&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;password&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;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&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;User&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;email&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;hash&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;HashingException&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="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RegistrationFailedException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Password hashing failed"&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="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;The method signature says it returns &lt;code&gt;User&lt;/code&gt;. It lies. It can throw three different exceptions, and the compiler won't tell you about any of them. The caller has no idea what to catch. The next developer reading this code has to trace every path to understand what can go wrong.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;Result&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="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;registerUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RegistrationRequest&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="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&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;email&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ensureUnique&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hashAndCreateUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&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;password&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;userRepository:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;save&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;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureUnique&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Email&lt;/span&gt; &lt;span class="n"&gt;email&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;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;existsByEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
           &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="no"&gt;EMAIL_ALREADY_EXISTS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
           &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&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;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;hashAndCreateUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Email&lt;/span&gt; &lt;span class="n"&gt;email&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;password&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;passwordHasher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&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="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hash&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;The return type tells the truth — this operation can fail. Every failure path is visible in the chain. No exceptions thrown, no exceptions caught. The compiler enforces that the caller handles the &lt;code&gt;Result&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Errors Work
&lt;/h3&gt;

&lt;p&gt;Errors are values, not exceptions. They implement the &lt;code&gt;Cause&lt;/code&gt; interface:&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="n"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;RegistrationError&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Cause&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;General&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;RegistrationError&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;EMAIL_ALREADY_EXISTS&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Email already registered"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="no"&gt;TOKEN_GENERATION_FAILED&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Token generation failed"&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;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="nc"&gt;General&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;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; 
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="nd"&gt;@Override&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;message&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;message&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;Fixed messages become enum constants. Dynamic messages become records. All are sealed — the compiler knows every possible failure. Pattern matching works:&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;switch&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="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Success&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;user&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;sendWelcome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&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;Result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Failure&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;cause&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;logAndRespond&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cause&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;
  
  
  Composition
&lt;/h3&gt;

&lt;p&gt;The real power shows in composition. &lt;code&gt;Result.all()&lt;/code&gt; collects independent validations:&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="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;ValidRegistration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Email&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Password&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PhoneNumber&lt;/span&gt; &lt;span class="n"&gt;phoneNumber&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;static&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ValidRegistration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;validRegistration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Registration&lt;/span&gt; &lt;span class="n"&gt;raw&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;Result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt;
                          &lt;span class="nc"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt; 
                          &lt;span class="nc"&gt;PhoneNumber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;phoneNumber&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;phone&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;ValidRegistration:&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="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;All three validations run. All failures are collected — not just the first one. The &lt;code&gt;map&lt;/code&gt; only executes if all three succeed. One line replaces the usual cascade of if-checks-and-early-returns.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interfacing with Legacy Code
&lt;/h3&gt;

&lt;p&gt;The world throws exceptions. &lt;code&gt;lift()&lt;/code&gt; catches them at the boundary:&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;Result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;DatabaseError:&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="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;legacyDao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exception goes in, &lt;code&gt;Result&lt;/code&gt; comes out. The boundary is explicit. Business logic stays clean.&lt;/p&gt;




&lt;h2&gt;
  
  
  Promise: Result, But Async
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Promise&lt;/code&gt; is &lt;code&gt;Result&lt;/code&gt; where the answer hasn't arrived yet. Same &lt;code&gt;map&lt;/code&gt;, same &lt;code&gt;flatMap&lt;/code&gt;, same mental model — just non-blocking:&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="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EnrichedUser&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;loadEnriched&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserId&lt;/span&gt; &lt;span class="n"&gt;userId&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="nf"&gt;findUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;loadUserWithOrders&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;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EnrichedUser&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;loadUserWithOrders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&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="nf"&gt;findOrders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&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="n"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EnrichedUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orders&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;If &lt;code&gt;findUser&lt;/code&gt; fails, the chain short-circuits — just like &lt;code&gt;Result&lt;/code&gt;. If &lt;code&gt;loadUserWithOrders&lt;/code&gt; fails, same thing. Errors are &lt;code&gt;Cause&lt;/code&gt; values, same as in &lt;code&gt;Result&lt;/code&gt;. The only difference: the chain executes asynchronously.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parallel Operations
&lt;/h3&gt;

&lt;p&gt;Independent operations run in parallel with &lt;code&gt;Promise.all()&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="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Profile&lt;/span&gt; &lt;span class="n"&gt;profile&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;Order&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orders&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;Notification&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;notifications&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;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;loadUserDashboard&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserId&lt;/span&gt; &lt;span class="n"&gt;userId&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;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fetchProfile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; 
                       &lt;span class="n"&gt;fetchOrders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; 
                       &lt;span class="n"&gt;fetchNotifications&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&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;Dashboard:&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three async calls, all independent, all in parallel. Result combined when all complete. If any fails, the whole thing fails — with a meaningful &lt;code&gt;Cause&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For "first success wins" semantics:&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;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Key&lt;/span&gt; &lt;span class="n"&gt;key&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;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;any&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fetchFromPrimaryCache&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; 
                       &lt;span class="n"&gt;fetchFromReplicaCache&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; 
                       &lt;span class="n"&gt;fetchFromDatabase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&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;
  
  
  Side Effects
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Promise&lt;/code&gt; distinguishes between dependent and independent actions:&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="n"&gt;findUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;validateAccess&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;// dependent — runs in sequence&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;loadProfile&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;// dependent — runs after validation&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onSuccess&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;metrics:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;recordAccess&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;// independent — runs async, doesn't block chain&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onFailure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;logger:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;warn&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;            &lt;span class="c1"&gt;// independent — runs async on failure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dependent actions (&lt;code&gt;map&lt;/code&gt;, &lt;code&gt;flatMap&lt;/code&gt;) execute in order and can fail the chain. Independent actions (&lt;code&gt;onSuccess&lt;/code&gt;, &lt;code&gt;onFailure&lt;/code&gt;) run asynchronously and never affect the chain's outcome. This distinction eliminates an entire class of bugs where logging or metrics accidentally break the business flow.&lt;br&gt;
There are also dependent side effects, for the cases when ordering matters:&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="n"&gt;findUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;validateAccess&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;// dependent — runs in sequence&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;loadProfile&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;// dependent — runs after validation&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withSuccess&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;metrics:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;recordAccess&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// dependent — runs on success, in order like map/flatMap&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withFailure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;logger:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;warn&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;          &lt;span class="c1"&gt;// dependent — runs on failure, in order like map/flatMap&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Timeouts and Recovery
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;fetchFromRemoteService&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;timeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeSpan&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                               &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;recover&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cause&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cachedFallback&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the remote call doesn't resolve in 5 seconds, it fails. &lt;code&gt;recover&lt;/code&gt; converts the failure back to success using a fallback. Clean, composable, no try-catch.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Three Types Together
&lt;/h2&gt;

&lt;p&gt;The real picture emerges when all three work together. Consider a realistic operation — processing an incoming order:&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="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderConfirmation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;processOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RawOrderRequest&lt;/span&gt; &lt;span class="n"&gt;raw&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;ValidOrder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;              &lt;span class="c1"&gt;// Result&amp;lt;ValidOrder&amp;gt; — sync validation&lt;/span&gt;
                     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;async&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;                      &lt;span class="c1"&gt;// → Promise&amp;lt;ValidOrder&amp;gt;&lt;/span&gt;
                     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;enrichOrder&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;orderRepository:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onSuccess&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;eventBus:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;publishOrderCreated&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;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EnrichedOrder&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;enrichOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ValidOrder&lt;/span&gt; &lt;span class="n"&gt;order&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;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inventoryService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt;
                       &lt;span class="n"&gt;pricingService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt;
                       &lt;span class="n"&gt;customerService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;find&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;customerId&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="n"&gt;availability&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pricing&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                           &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;EnrichedOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;availability&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pricing&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customer&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;What happens here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Validation&lt;/strong&gt; — &lt;code&gt;ValidOrder.validOrder()&lt;/code&gt; returns &lt;code&gt;Result&amp;lt;ValidOrder&amp;gt;&lt;/code&gt;. Parse, don't validate. If the input is malformed, a &lt;code&gt;Cause&lt;/code&gt; explains why. No exception.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sync to async&lt;/strong&gt; — &lt;code&gt;.async()&lt;/code&gt; lifts the &lt;code&gt;Result&lt;/code&gt; into a &lt;code&gt;Promise&lt;/code&gt;. From here, everything is non-blocking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel fetch&lt;/strong&gt; — &lt;code&gt;enrichOrder&lt;/code&gt; calls three independent services simultaneously. All must succeed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enrichment&lt;/strong&gt; — results combined into &lt;code&gt;EnrichedOrder&lt;/code&gt;. The &lt;code&gt;map&lt;/code&gt; only runs if all three calls succeed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence&lt;/strong&gt; — saved to repository. Returns &lt;code&gt;Promise&amp;lt;OrderConfirmation&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Side effect&lt;/strong&gt; — event published asynchronously. Does not affect the response.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No try-catch. No null checks. No &lt;code&gt;if (result == null) return error&lt;/code&gt;. Every failure path handled by the type system. Every step clearly visible.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Decision Tree
&lt;/h2&gt;

&lt;p&gt;Choosing the right type is mechanical:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can this operation fail?
├── NO: Can the value be absent?
│   ├── NO → return T
│   └── YES → return Option&amp;lt;T&amp;gt;
└── YES: Is it async/IO?
    ├── NO → return Result&amp;lt;T&amp;gt;
    └── YES → return Promise&amp;lt;T&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four return kinds. No judgment calls. The decision tree covers every method in a Java backend.&lt;/p&gt;

&lt;p&gt;One allowed combination: &lt;code&gt;Result&amp;lt;Option&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt; — when the value is genuinely optional but validation can still fail. Example: an optional referral code that, if provided, must match a specific format.&lt;/p&gt;

&lt;p&gt;One forbidden combination: &lt;code&gt;Promise&amp;lt;Result&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt; — double error channel. &lt;code&gt;Promise&lt;/code&gt; already carries failure semantics. Nesting &lt;code&gt;Result&lt;/code&gt; inside it means two places to check for errors.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Changes In Practice
&lt;/h2&gt;

&lt;p&gt;After a few weeks of writing code this way, something shifts. You stop thinking about error handling as a separate concern. It's not something you add after the happy path — it's embedded in the types. The compiler catches what used to be runtime surprises.&lt;/p&gt;

&lt;p&gt;Code reviews get faster. When every method returns one of four types, the shape of the code becomes predictable. You don't need to trace exception paths through five layers. The return type tells you everything.&lt;/p&gt;

&lt;p&gt;Testing simplifies. Each step in a chain is independently testable. Failures are values you can assert on — not exceptions you have to catch. Mock a dependency to return &lt;code&gt;EMAIL_ALREADY_EXISTS.result()&lt;/code&gt; and verify the chain handles it correctly.&lt;/p&gt;

&lt;p&gt;And the types compose. A &lt;code&gt;Result&lt;/code&gt; from validation flows into a &lt;code&gt;Promise&lt;/code&gt; for async processing, which fans out into parallel &lt;code&gt;Promise.all()&lt;/code&gt;, which combines back into a single response. Each piece connects to the next with &lt;code&gt;flatMap&lt;/code&gt;. The vocabulary is always the same.&lt;/p&gt;




&lt;h2&gt;
  
  
  Naming That Scales
&lt;/h2&gt;

&lt;p&gt;Types solve the "what can happen" question. But there's another source of friction — naming. Every code review has that moment: "should this be &lt;code&gt;fetchUser&lt;/code&gt; or &lt;code&gt;loadUser&lt;/code&gt; or &lt;code&gt;getUser&lt;/code&gt;?" The debate is real, and it wastes time because there's no shared vocabulary.&lt;/p&gt;

&lt;p&gt;Zone-based naming eliminates this. The idea, adapted from &lt;a href="https://medium.com/@brandt.a.derrick/how-to-write-clean-code-actually-5205963ec524" rel="noopener noreferrer"&gt;Derrick Brandt's systematic approach to clean code&lt;/a&gt;: verbs belong to abstraction levels. Use the wrong verb at the wrong level, and the name signals something misleading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zone 2 — orchestration steps.&lt;/strong&gt; These coordinate other operations. They don't touch databases or parse bytes. They organize.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Verb&lt;/th&gt;
&lt;th&gt;When to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Checking rules and constraints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;process&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Transforming or interpreting data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;load&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Retrieving data for use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;save&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Persisting changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;resolve&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Determining ambiguous cases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;build&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Assembling complex objects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notify&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Informing others of events&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Zone 3 — leaf operations.&lt;/strong&gt; These do the actual work. One responsibility, specific and concrete.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Verb&lt;/th&gt;
&lt;th&gt;When to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fetch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pull from external source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;parse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Break down structured input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;format&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build structured output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;calculate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Perform computation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cryptographic transformation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;send&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Transmit over network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;extract&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pull piece from larger structure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pattern:&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;// Zone 2 — step interface, orchestration verb&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;LoadUserProfile&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserProfile&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserId&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Zone 3 — leaf, implementation verb&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetchFromDatabase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserId&lt;/span&gt; &lt;span class="n"&gt;id&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;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CachedUser&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;extractFromCache&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserId&lt;/span&gt; &lt;span class="n"&gt;id&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;If you see &lt;code&gt;fetch&lt;/code&gt; on a step interface — something's wrong. If you see &lt;code&gt;process&lt;/code&gt; on a leaf — same thing. The verb tells you the abstraction level before you read the parameters.&lt;/p&gt;

&lt;p&gt;This matters for the same reason the four return types matter: it makes code predictable. A developer scanning an unfamiliar codebase can tell from the name alone whether they're looking at orchestration or implementation. No need to open the method body.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;If your codebase currently uses exceptions for business errors and null for absent values, you don't need to rewrite everything. Start at the boundaries:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick one new feature.&lt;/strong&gt; Write it with &lt;code&gt;Result&lt;/code&gt; returns instead of exceptions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrap legacy calls&lt;/strong&gt; with &lt;code&gt;Result.lift()&lt;/code&gt; and &lt;code&gt;Option.option()&lt;/code&gt; at the adapter boundary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let the types propagate.&lt;/strong&gt; Once one method returns &lt;code&gt;Result&lt;/code&gt;, its callers naturally follow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The types are available in &lt;a href="https://github.com/pragmaticalabs/pragmatica" rel="noopener noreferrer"&gt;Pragmatica Core&lt;/a&gt; — a focused library with no transitive dependencies.&lt;/p&gt;

&lt;p&gt;This is the foundation that &lt;a href="https://pragmaticalabs.io/jbct.html" rel="noopener noreferrer"&gt;JBCT&lt;/a&gt; (Java Backend Coding Technology) builds on. Six structural patterns, four return kinds, mechanical rules that make code deterministic and AI-friendly. But the types come first. Everything else follows from getting the types right.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Previously: &lt;a href="https://dev.to/siy/introduction-to-pragmatic-functional-java-142m"&gt;Introduction to Pragmatic Functional Java&lt;/a&gt; (2019) | &lt;a href="https://dev.to/siy/we-should-write-java-code-differently-210b"&gt;We Should Write Java Code Differently&lt;/a&gt; (2021)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>functional</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>No Framework, No Pain: Writing Aether Slices</title>
      <dc:creator>Sergiy Yevtushenko</dc:creator>
      <pubDate>Thu, 19 Feb 2026 10:08:28 +0000</pubDate>
      <link>https://dev.to/siy/no-framework-no-pain-writing-aether-slices-4mi6</link>
      <guid>https://dev.to/siy/no-framework-no-pain-writing-aether-slices-4mi6</guid>
      <description>&lt;h1&gt;
  
  
  No Framework, No Pain: Writing Aether Slices
&lt;/h1&gt;

&lt;p&gt;The &lt;a href="https://dev.to/siy/pragmatica-aether-let-java-be-java-4k2g"&gt;previous article&lt;/a&gt; introduced Aether's philosophy: return Java to managed runtimes, let the runtime handle infrastructure, and let developers handle business logic. This article shows what that looks like in practice -- what you actually write, how dependencies work, how testing works, and how existing code migrates in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Microservice Is Just an Interface
&lt;/h2&gt;

&lt;p&gt;Here's an entire deployable service:&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="nd"&gt;@Slice&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;placeOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PlaceOrderRequest&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;static&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="nf"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                     &lt;span class="nc"&gt;PricingEngine&lt;/span&gt; &lt;span class="n"&gt;pricing&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;request&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&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;items&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                                   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;pricing:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;calculate&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;OrderResult:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;placed&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's not a simplified example. That's the actual thing. The annotation processor sees &lt;code&gt;@Slice&lt;/code&gt;, reads the factory method signature and generates the wiring code, the proxy for remote calls, and the deployment metadata. You write one interface. You get a service that scales, fails over, and routes transparently across a distributed cluster.&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;@Autowired&lt;/code&gt;. No &lt;code&gt;application.yml&lt;/code&gt;. No &lt;code&gt;@Configuration&lt;/code&gt; class. No &lt;code&gt;@Bean&lt;/code&gt; method. No component scan. No service locator. No dependency injection container at all.&lt;/p&gt;

&lt;p&gt;The factory method &lt;em&gt;is&lt;/em&gt; dependency injection. Its parameters &lt;em&gt;are&lt;/em&gt; the declared dependencies. The compiler verifies them. The annotation processor wires them. Nothing to configure, nothing to forget, nothing to debug at 2 AM.&lt;/p&gt;

&lt;p&gt;Notice what the factory returns: a lambda. No implementation class. The interface has one method, so the factory returns a lambda that implements it directly. Business logic as a function. For slices with multiple methods, a private record captures the dependencies and implements the interface -- still no separate &lt;code&gt;Impl&lt;/code&gt; class, no file to maintain, and no indirection to trace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Rules, Zero Boilerplate
&lt;/h2&gt;

&lt;p&gt;Every slice follows two rules:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The factory method declares dependencies.&lt;/strong&gt; What the slice needs from the outside world appears in one place: the factory method signature.&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;static&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="nf"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                 &lt;span class="nc"&gt;PricingEngine&lt;/span&gt; &lt;span class="n"&gt;pricing&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;request&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&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;items&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                               &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;pricing:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;calculate&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;OrderResult:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;placed&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;Read the factory; know the dependencies. No configuration file can contradict it. No runtime surprise can introduce a dependency the compiler hasn't seen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Promise return types.&lt;/strong&gt; Every method returns &lt;code&gt;Promise&amp;lt;T&amp;gt;&lt;/code&gt;. This isn't a stylistic choice -- it's what makes transparent distribution possible. Whether the call is in-process or cross-network, the caller sees the same type.&lt;/p&gt;

&lt;p&gt;That's it. Two rules. Everything else follows from them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Magic Is in the Factory Method
&lt;/h2&gt;

&lt;p&gt;The annotation processor looks at each factory parameter and classifies it automatically:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What the processor sees&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@PrimaryDb SqlConnector db&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resource -- provisions from config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;InventoryService inventory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;External slice -- generates a network proxy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OrderValidator validator&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Local interface with factory -- calls the factory directly&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You don't configure this. You don't annotate dependencies with &lt;code&gt;@Inject&lt;/code&gt; or &lt;code&gt;@Qualifier&lt;/code&gt; (except for infrastructure resources). You just list what you need, and the processor figures out how to provide it.&lt;/p&gt;

&lt;p&gt;Consider what this means. A parameter annotated with &lt;code&gt;@ResourceQualifier&lt;/code&gt; is infrastructure -- a database connection, an HTTP client, or a message queue. The processor provisions it from configuration:&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="nd"&gt;@ResourceQualifier&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="nc"&gt;SqlConnector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&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="s"&gt;"database.primary"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nd"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;PrimaryDb&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="nd"&gt;@Slice&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;OrderRepository&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FindOrderRequest&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;static&lt;/span&gt; &lt;span class="nc"&gt;OrderRepository&lt;/span&gt; &lt;span class="nf"&gt;orderRepository&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PrimaryDb&lt;/span&gt; &lt;span class="nc"&gt;SqlConnector&lt;/span&gt; &lt;span class="n"&gt;db&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;request&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;query&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;orderId&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;OrderResult:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fromRow&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;A parameter that's a &lt;code&gt;@Slice&lt;/code&gt; interface from another package is a remote dependency. The processor generates a proxy record that delegates to the runtime's invocation fabric. Your code calls &lt;code&gt;inventory.check(request)&lt;/code&gt; as a method call. The proxy handles serialization, routing, retry, and failover.&lt;/p&gt;

&lt;p&gt;A parameter that's a plain interface with a static factory method is local. The processor calls the factory directly. No proxy, no network, no overhead.&lt;/p&gt;

&lt;p&gt;All three categories coexist in one factory:&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;static&lt;/span&gt; &lt;span class="nc"&gt;LoanService&lt;/span&gt; &lt;span class="nf"&gt;loanService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PrimaryDb&lt;/span&gt; &lt;span class="nc"&gt;SqlConnector&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                               &lt;span class="nc"&gt;CreditBureau&lt;/span&gt; &lt;span class="n"&gt;creditBureau&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                               &lt;span class="nc"&gt;RiskCalculator&lt;/span&gt; &lt;span class="n"&gt;riskCalculator&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;request&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;riskCalculator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assess&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="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;risk&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;creditBureau&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&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;applicant&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;
                                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credit&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;persistDecision&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&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="n"&gt;credit&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;Database from config. Credit bureau via network proxy. Risk calculator instantiated locally. One line declares it all. The processor handles the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Errors Without Exceptions
&lt;/h2&gt;

&lt;p&gt;Frameworks train you to throw exceptions. Spring converts them to HTTP status codes. Jackson serializes error responses. Exception handlers map types to messages. It works until someone throws an unexpected exception, and the generic 500 response tells the caller nothing.&lt;/p&gt;

&lt;p&gt;Slices use sealed Cause hierarchies:&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="n"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;OrderCause&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Cause&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;OrderCause&lt;/span&gt; &lt;span class="no"&gt;EMPTY_ORDER&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;EmptyOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Order must have items"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;OrderCause&lt;/span&gt; &lt;span class="no"&gt;INSUFFICIENT_STOCK&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;InsufficientStock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Insufficient stock"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;OrderCause&lt;/span&gt; &lt;span class="nf"&gt;insufficientStock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StockStatus&lt;/span&gt; &lt;span class="n"&gt;stock&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InsufficientStock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Insufficient stock: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;stock&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;EmptyOrder&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;message&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;OrderCause&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;InsufficientStock&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;message&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;OrderCause&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;Every failure mode is a type. The compiler knows all of them. Pattern matching handles them exhaustively. No surprise &lt;code&gt;NullPointerException&lt;/code&gt; masquerading as a business error. No &lt;code&gt;catch (Exception e)&lt;/code&gt; swallowing context.&lt;/p&gt;

&lt;p&gt;When something fails, you return a failed promise using fluent style:&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;return&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;checkStock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stockRequest&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;verifyAvailability&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;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StockStatus&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;verifyAvailability&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StockStatus&lt;/span&gt; &lt;span class="n"&gt;stock&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;stock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sufficient&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;completeOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stock&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OrderCause&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insufficientStock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stock&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;promise&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;The runtime propagates the Cause across the network. The caller gets a typed failure, not a string message. The error handling contract is part of the API, not an afterthought in a &lt;code&gt;@ControllerAdvice&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing: It's Just Java
&lt;/h2&gt;

&lt;p&gt;No test containers to spin up. No mock server to configure. No &lt;code&gt;@SpringBootTest&lt;/code&gt; annotation that loads half the universe. No mocking frameworks either -- dependencies are interfaces, so you pass lambdas that return exactly what you need:&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;class&lt;/span&gt; &lt;span class="nc"&gt;OrderServiceTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;placeOrder_succeeds_whenInventoryAvailable&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="n"&gt;inventory&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;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;success&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;StockResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"RES-123"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="nc"&gt;PricingEngine&lt;/span&gt; &lt;span class="n"&gt;pricing&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;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;success&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;PriceResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ORD-456"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;99.99&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;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pricing&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;placeOrder&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="na"&gt;await&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
               &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onFailure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Assertions:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
               &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onSuccess&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;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ORD-456"&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;orderId&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;placeOrder_fails_whenInventoryUnavailable&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="n"&gt;inventory&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;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;OrderCause&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INSUFFICIENT_STOCK&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;promise&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;PricingEngine&lt;/span&gt; &lt;span class="n"&gt;pricing&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;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;success&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;PriceResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ORD-456"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;99.99&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;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pricing&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;placeOrder&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="na"&gt;await&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
               &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onSuccess&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Assertions:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fail&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;Dependencies are interfaces. Pass lambdas that return success; pass lambdas that return failure. The factory method wires them in. No reflection, no classpath scanning, no context initialization. No Mockito, no &lt;code&gt;when(...).thenReturn(...)&lt;/code&gt;, no &lt;code&gt;verify(...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Test startup is instant because there's nothing to start. No container. No framework. No bean resolution. Just objects calling objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Slices at Any Granularity
&lt;/h2&gt;

&lt;p&gt;A single Maven module can contain as many slices as make sense:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;commerce/
  src/main/java/org/example/
    order/
      OrderService.java       # @Slice
    payment/
      PaymentService.java     # @Slice
    shipping/
      ShippingService.java    # @Slice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each &lt;code&gt;@Slice&lt;/code&gt; generates its own factory, its own API artifact, its own deployment metadata. The Maven plugin packages them separately. They deploy and scale independently. But they develop together -- shared domain types, shared build, and one repository.&lt;/p&gt;

&lt;p&gt;A slice can be as small as a single method. There's no operational overhead for small slices -- no container to configure, no load balancer to provision, and no monitoring to set up per service. This enables granular scaling that would be operationally insane with traditional microservices: one slice serving 50 instances during peak load while another idles at minimum. With Aether, it's the default.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Actually Happening
&lt;/h2&gt;

&lt;p&gt;Let's trace what the annotation processor generates for a simple slice with one external dependency:&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="nd"&gt;@Slice&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;placeOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PlaceOrderRequest&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;static&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="nf"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="n"&gt;inventory&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;request&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&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;items&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;OrderResult:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fromAvailability&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;The processor sees &lt;code&gt;InventoryService&lt;/code&gt; is from a different package and has &lt;code&gt;@Slice&lt;/code&gt; annotation -- external dependency. It generates:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A proxy record&lt;/strong&gt; that implements &lt;code&gt;InventoryService&lt;/code&gt; and delegates every method call to the runtime's &lt;code&gt;SliceInvokerFacade&lt;/code&gt;. Your code calls &lt;code&gt;inventory.check(request)&lt;/code&gt;. The proxy serializes the request, routes it to a node hosting InventoryService, deserializes the response, and returns it as a &lt;code&gt;Promise&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A factory class&lt;/strong&gt; that accepts an &lt;code&gt;Aspect&lt;/code&gt; and the &lt;code&gt;SliceInvokerFacade&lt;/code&gt;, creates the proxy, and wires everything together.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deployment metadata&lt;/strong&gt; in &lt;code&gt;META-INF/slice/&lt;/code&gt; -- the slice name, its methods, its dependencies. The runtime reads this to build the dependency graph and determine deployment order.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All generated. All verified at compile time. All invisible to your business logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Existing Code Is Already Halfway There
&lt;/h2&gt;

&lt;p&gt;You don't need to start from scratch. Any existing Java code becomes a slice with one line:&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;// Your existing Spring service&lt;/span&gt;
&lt;span class="nd"&gt;@Service&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;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;InventoryRepository&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;PricingService&lt;/span&gt; &lt;span class="n"&gt;pricing&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Transactional&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;OrderResult&lt;/span&gt; &lt;span class="nf"&gt;processOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderRequest&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;availability&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;checkAvailability&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;getItems&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;availability&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isAvailable&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;OrderResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;outOfStock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;availability&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMissingItems&lt;/span&gt;&lt;span class="o"&gt;());&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;quote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pricing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculateQuote&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;getItems&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;getCustomerId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="c1"&gt;// ... payment, order creation, notification ...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;OrderResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&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;Wrap 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="nd"&gt;@Slice&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;processOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderRequest&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;static&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessor&lt;/span&gt; &lt;span class="nf"&gt;orderProcessor&lt;/span&gt;&lt;span class="o"&gt;()&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;legacyService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;createLegacyService&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;request&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processOrder&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Promise.lift()&lt;/code&gt; wraps the synchronous call, catches any exception, and returns a proper &lt;code&gt;Promise&lt;/code&gt; with a typed failure instead of a stack trace. &lt;br&gt;
Your legacy code runs unchanged inside. The slice deploys to the Aether runtime (initially as a one-process cluster called Ember) alongside your existing application -- same JVM, no new risk. Move to a full Aether cluster when ready. That's a configuration change, not a code change.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Peeling Pattern
&lt;/h3&gt;

&lt;p&gt;The wrapped slice works, but it's a black box. The peeling pattern opens it up incrementally -- one layer at a time, working code at every step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Peel the outer structure.&lt;/strong&gt; Replace the opaque &lt;code&gt;lift()&lt;/code&gt; with a Sequencer where each step is still wrapped:&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;return&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyCheckInventory&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="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inv&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyCalculatePricing&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inv&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyProcessPayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyCreateOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the pipeline is visible. You can see the steps, test them individually, and reason about the flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Peel one step deeper.&lt;/strong&gt; Take the hottest &lt;code&gt;lift()&lt;/code&gt; and expand 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="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Availability&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;checkInventory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderRequest&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="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyCheckWarehouse&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="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyCheckSupplier&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="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;combineAvailability&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;The outer call is now clean JBCT. The inner calls are still wrapped. Tests pass at every step. Stop anywhere -- mixed JBCT and legacy code works fine. The remaining &lt;code&gt;lift()&lt;/code&gt; calls mark exactly where legacy code lives. When they're all gone, you have a clean slice. But there's no deadline. Each peeling step delivers value on its own.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://dev.to/siy/fail-safe-your-legacy-java-in-one-sprint-p5l"&gt;full migration walkthrough&lt;/a&gt; covers the complete path -- from initial wrapping through fault tolerance to clean JBCT code.&lt;/p&gt;

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

&lt;p&gt;Traditional microservice development is a negotiation with frameworks. You learn their abstractions, their lifecycle hooks, their configuration DSLs, their annotation model, their error-handling conventions, and their testing utilities. The framework becomes the center of gravity. Your business logic orbits around it.&lt;/p&gt;

&lt;p&gt;Slices invert this. Business logic is the center. The interface defines the contract. The factory method declares dependencies. The implementation is a lambda. Everything else -- serialization, routing, scaling, failover, and configuration -- is the runtime's problem.&lt;/p&gt;

&lt;p&gt;You don't learn a framework. You write Java interfaces and implement them. Two rules. The rest is just your domain.&lt;/p&gt;

&lt;p&gt;No framework. No pain.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pragmaticalabs.io/aether.html" rel="noopener noreferrer"&gt;Pragmatica Aether&lt;/a&gt; -- distributed Java runtime&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/pragmaticalabs/pragmatica" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt; -- source code&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/pragmaticalabs/pragmatica/blob/main/aether/docs/slice-developers/development-guide.md" rel="noopener noreferrer"&gt;Slice Development Guide&lt;/a&gt; -- full reference&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>microservices</category>
      <category>architecture</category>
      <category>backend</category>
    </item>
    <item>
      <title>Pragmatica Aether: Let Java Be Java</title>
      <dc:creator>Sergiy Yevtushenko</dc:creator>
      <pubDate>Fri, 13 Feb 2026 14:38:14 +0000</pubDate>
      <link>https://dev.to/siy/pragmatica-aether-let-java-be-java-4k2g</link>
      <guid>https://dev.to/siy/pragmatica-aether-let-java-be-java-4k2g</guid>
      <description>&lt;h2&gt;
  
  
  The Aberration
&lt;/h2&gt;

&lt;p&gt;We build Java applications like Go or Rust programs. Fat JARs. Docker images. Kubernetes deployments. Everyone does it, so it looks normal.&lt;/p&gt;

&lt;p&gt;It contradicts Java's design DNA.&lt;/p&gt;

&lt;p&gt;Java has always been a language for managed environments. Applets ran inside browsers. Servlets ran inside application servers. EJBs ran inside containers like JBoss and WebLogic. OSGi bundles ran inside runtime containers like Eclipse Equinox. In every generation, the pattern was the same: a managed runtime hosts the application. The application handles business logic. The runtime handles infrastructure.&lt;/p&gt;

&lt;p&gt;The fat-jar era threw that away. We stopped letting Java be Java. We started bundling web servers, serialization frameworks, service discovery clients, configuration management, health checks, metrics libraries, and logging frameworks into every application. Then we wrapped the result in a Docker container and deployed it to an orchestration platform that reimplements — poorly — the infrastructure management that Java runtimes used to provide natively.&lt;/p&gt;

&lt;p&gt;This article introduces &lt;a href="https://pragmaticalabs.io/aether.html" rel="noopener noreferrer"&gt;Pragmatica Aether&lt;/a&gt;: a distributed runtime that returns Java to its natural habitat. Application handles business logic. Runtime handles infrastructure. This isn't radical — it's returning to what Java was designed for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Infrastructure Wearing a Business Logic Mask
&lt;/h2&gt;

&lt;p&gt;Think of what a typical Java microservice carries. A web server (Tomcat, Netty, Undertow). A serialization framework (Jackson, Gson). A dependency injection container (Spring, Guice). A service discovery client (Eureka, Consul). Health check endpoints. Configuration management (Spring Cloud Config, Consul KV). A metrics library (Micrometer, Dropwizard). A logging framework (Logback, Log4j2). Retry logic (Resilience4j). Circuit breakers. HTTP client configuration. The application is wearing a heavy winter coat of infrastructure, armed to the teeth to survive in a hostile environment.&lt;/p&gt;

&lt;p&gt;Now consider the coupling this creates.&lt;/p&gt;

&lt;p&gt;Update Java version — rebuild and test every service. Change your message broker from RabbitMQ to Kafka — modify, rebuild, and redeploy every application that touches messaging. Add a new observability tool — update dependencies in every microservice. Switch cloud providers — rewrite configuration, SDK calls, and deployment manifests across the entire fleet. Each change ripples through dozens or hundreds of services because infrastructure is entangled with business logic at the dependency level.&lt;/p&gt;

&lt;p&gt;This is the coupling trap. Your application's &lt;code&gt;pom.xml&lt;/code&gt; doesn't distinguish between business dependencies and infrastructure dependencies. They compile together, deploy together, and break together. A security patch in Netty requires a new build of every service that embeds a web server — which is all of them.&lt;/p&gt;

&lt;p&gt;Framework lock-in makes this worse. It isn't a vendor problem — it's an architecture problem. Spring's dependency injection fights with Kubernetes service mesh for control over service routing and circuit breaking. The framework's configuration system overlaps with Consul KV and Kubernetes ConfigMaps. Your cloud SDK's retry logic conflicts with Resilience4j. Every layer claims authority over the same cross-cutting concerns, and the conflicts surface as subtle bugs in production — not during development.&lt;/p&gt;

&lt;p&gt;This is an architecture problem. Architecture problems have architectural solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aether: The Core Idea
&lt;/h2&gt;

&lt;p&gt;What you write: an interface annotated with &lt;code&gt;@Slice&lt;/code&gt;, plus business logic implementation.&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="nd"&gt;@Slice&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;placeOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PlaceOrderRequest&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;static&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="nf"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PricingEngine&lt;/span&gt; &lt;span class="n"&gt;pricing&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;request&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&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;items&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                                   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pricing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;available&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="n"&gt;priced&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;OrderResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;placed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;priced&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;What you don't write: everything else.&lt;/p&gt;

&lt;p&gt;No HTTP clients — inter-slice calls are direct method invocations via generated proxies. No service discovery — the runtime tracks where every slice instance lives. No retry logic — built-in retry with exponential backoff and node failover. No circuit breakers — the reliability fabric handles failure automatically. No serialization code — request/response types are serialized transparently.&lt;/p&gt;

&lt;p&gt;A method call via imported interface is the only visible contract. The only hint that the actual call might be remote is a design requirement: slice methods should be idempotent. This isn't a limitation — it's what enables retry, scaling, and fault tolerance to work transparently. The same request, processed by any available instance, producing the same result. Most read operations are naturally idempotent. For writes, standard patterns like idempotency keys and conditional writes handle it cleanly.&lt;/p&gt;

&lt;p&gt;Everything else is the environment's job: resource provisioning, scaling, transport, discovery, retries, circuit breakers, configuration, observability, logging, tracing, monitoring, security. None of these are application concerns and none should be handled at the business logic level.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://dev.to/siy/the-six-patterns-that-cover-everything-4d8a"&gt;JBCT Leaf pattern&lt;/a&gt; serves two purposes here: it documents the design ("what we expect from an external implementation") and encourages exactly one interface per dependency. Different implementations may have different technical properties — performance, latency, memory consumption — but as long as they're compatible with the interface, business logic works unchanged.&lt;/p&gt;

&lt;p&gt;You write basically pure business logic that scales from your local computer to a global multi-zone distributed deployment, transparently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Under The Hood: What Makes It Work
&lt;/h2&gt;

&lt;p&gt;Five architectural decisions make this possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consensus KV Store.&lt;/strong&gt; A single source of truth for all configuration, deployment state, and service discovery. Based on the &lt;a href="https://dl.acm.org/doi/10.1145/3477132.3483582" rel="noopener noreferrer"&gt;Rabia protocol&lt;/a&gt; — a crash-fault-tolerant, leaderless consensus algorithm published in 2021. Any node can propose; agreement is reached through a two-round voting protocol with a fast path when super-majority agrees in round one. No external config servers. No etcd. No Consul. Configuration changes propagate through consensus and take effect cluster-wide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Built-in Artifact Repository.&lt;/strong&gt; DHT-based storage with configurable replication — 3 replicas with quorum reads/writes in production, full replication in development. Artifacts are chunked into 64KB pieces, distributed across nodes via consistent hashing, and integrity-verified with MD5 and SHA-1 on every resolve. No external Nexus or Artifactory needed. During development, slices resolve from your local Maven repository. In production, the cluster is self-contained.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ClassLoader Isolation.&lt;/strong&gt; Each slice runs in its own &lt;code&gt;SliceClassLoader&lt;/code&gt; with child-first delegation. Two slices can use different versions of the same library without conflict. Shared dependencies like Pragmatica Lite core are loaded once in a parent classloader. No dependency conflicts. No classpath hell between slices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Declarative Deployment.&lt;/strong&gt; Blueprints — TOML files — describe the desired state: which slices, how many instances.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.example:commerce:1.0.0"&lt;/span&gt;

&lt;span class="nn"&gt;[[slices]]&lt;/span&gt;
&lt;span class="py"&gt;artifact&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.example:inventory-service:1.0.0"&lt;/span&gt;
&lt;span class="py"&gt;instances&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;

&lt;span class="nn"&gt;[[slices]]&lt;/span&gt;
&lt;span class="py"&gt;artifact&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.example:order-processor:1.0.0"&lt;/span&gt;
&lt;span class="py"&gt;instances&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply with one command: &lt;code&gt;aether blueprint apply commerce.toml&lt;/code&gt;. The cluster resolves artifacts, loads slices, distributes instances across nodes, registers routes, and starts serving traffic. The cluster converges to the desired state automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure Independence.&lt;/strong&gt; Aether nodes are identical — there's only one deployment artifact to manage at the infrastructure level. Node updates and application deployments run on completely independent schedules. Update Java — roll it out across nodes without touching applications. Update the Aether runtime — same. Update business logic — deploy new slice versions without touching infrastructure. Each independently, each without downtime. This is the fundamental benefit of proper separation: when layers don't share a deployment unit, they don't share a deployment schedule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fault Tolerance: The 50% Rule
&lt;/h2&gt;

&lt;p&gt;The system survives failure of less than half the nodes. Performance may degrade until replacements spin up, but functionality remains intact — actual redundancy, not just graceful degradation. A 5-node cluster tolerates 2 simultaneous failures. A 7-node cluster tolerates 3. The same request, processed by any available node, producing the same result. Quorum requires &lt;code&gt;(N/2) + 1&lt;/code&gt; nodes — as long as a majority is alive, the cluster operates normally.&lt;/p&gt;

&lt;p&gt;Leader failover is consensus-based and near-instant. Node replacement happens automatically — the Cluster Deployment Manager detects the deficit and provisions a replacement through the NodeProvider interface. The entire recovery sequence — from failure detection through state restoration to serving traffic — completes without human intervention.&lt;/p&gt;

&lt;p&gt;When a node fails, the recovery is automatic. Requests to slices on the failed node are immediately retried on healthy nodes. A replacement node is provisioned. It connects to peers, restores consensus state from a cluster snapshot, re-resolves artifacts from the DHT, and re-activates assigned slices. Dead nodes are automatically removed from routing tables. The new leader reconciles stale state. No human intervention required.&lt;/p&gt;

&lt;p&gt;Rolling updates leverage this fault tolerance for zero-downtime deployments with weighted traffic routing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aether update start org.example:order-processor 2.0.0 &lt;span class="nt"&gt;-n&lt;/span&gt; 3
aether update routing &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; 1:3    &lt;span class="c"&gt;# 25% to v2, 75% to v1&lt;/span&gt;
aether update routing &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; 1:1    &lt;span class="c"&gt;# 50/50&lt;/span&gt;
aether update &lt;span class="nb"&gt;complete&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;          &lt;span class="c"&gt;# 100% to v2, drain v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy during business hours. Shift traffic gradually — 10% canary, then 25%, 50%, 75%, 100%. Monitor health metrics at each step. If health degrades — error rate exceeds thresholds, latency spikes — instant rollback with one command: &lt;code&gt;aether update rollback &amp;lt;id&amp;gt;&lt;/code&gt;. Traffic immediately shifts back to the old version. The 3 AM pager alert becomes an audit log entry.&lt;/p&gt;

&lt;h2&gt;
  
  
  For Every Project: Legacy, Greenfield, And Everything Between
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Legacy Migration
&lt;/h3&gt;

&lt;p&gt;Your legacy Java system doesn't need a complete rewrite. It needs a path forward.&lt;/p&gt;

&lt;p&gt;Pick a relatively independent part of your system — something hitting limits, something with clear boundaries. Extract an interface. Annotate it with &lt;code&gt;@Slice&lt;/code&gt;. Wrap the legacy implementation:&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;private&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Report&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;generateReport&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReportRequest&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="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyReportService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One line to enter the Aether world. &lt;code&gt;Promise.lift()&lt;/code&gt; wraps the legacy call, catches exceptions, and returns a proper &lt;code&gt;Result&lt;/code&gt; inside a &lt;code&gt;Promise&lt;/code&gt;. Your legacy code keeps running. Call sites don't change. You haven't added risk — the initial deployment in Ember runs in the same JVM as your existing application, which means it's no worse than what you have today. You've laid the foundation for removing risk, not adding it. Moving from Ember to a full Aether cluster is a configuration change, not a code change — and that's when the 50% rule starts to apply.&lt;/p&gt;

&lt;p&gt;From there, it's the strangler fig pattern. Extract a hot path, deploy it as a slice, route traffic, repeat. Each extracted slice can be gradually refactored using the &lt;a href="https://dev.to/siy/fail-safe-your-legacy-java-in-one-sprint-p5l"&gt;peeling pattern&lt;/a&gt;: first wrap everything in &lt;code&gt;Promise.lift()&lt;/code&gt;, then decompose into a Sequencer with each step still wrapped, then peel individual steps into clean JBCT patterns. Tests pass at every step. The &lt;code&gt;lift()&lt;/code&gt; calls mark exactly where legacy code remains, making progress visible and remaining work obvious.&lt;/p&gt;

&lt;p&gt;No rewrite required. No big bang migration. One sprint to first slice in production. The &lt;a href="https://dev.to/siy/fail-safe-your-legacy-java-in-one-sprint-p5l"&gt;migration article&lt;/a&gt; covers the full path in detail — from initial wrapping through gradual peeling to clean JBCT code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Greenfield Development
&lt;/h3&gt;

&lt;p&gt;For new projects, slices enable a granularity that's impossible with traditional microservices.&lt;/p&gt;

&lt;p&gt;Each slice can be as lean as a single method — and that's the recommended approach. There are no operational or complexity tradeoffs for small slices because Aether handles all the infrastructure overhead. No container to configure, no load balancer to provision, no monitoring to set up per service. You get per-use-case scaling: one slice serving 50 instances during peak load while another idles at minimum. That kind of granularity would be operationally insane with traditional microservices — each needing its own container, load balancer, monitoring, and deployment pipeline. With Aether, it's the default.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/siy/the-six-patterns-that-cover-everything-4d8a"&gt;JBCT patterns&lt;/a&gt; — Leaf, Sequencer, Fork-Join, Condition, Iteration, Aspects — compose naturally within slices. Each slice method is a &lt;a href="https://dev.to/siy/the-underlying-process-of-request-processing-1od4"&gt;data transformation pipeline&lt;/a&gt;: parse input, gather data, process, respond. The patterns provide consistent structure within slices. &lt;a href="https://dev.to/siy/slices-the-right-size-for-microservices-5cco"&gt;Slices provide consistent boundaries&lt;/a&gt; between them.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Spectrum
&lt;/h3&gt;

&lt;p&gt;Same slice model, different granularity. A service slice wraps an entire legacy component. A lean slice implements a single method. Both coexist in the same cluster, deployed and scaled independently.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/siy/slices-the-right-size-for-microservices-5cco"&gt;Slice is the executable unit&lt;/a&gt;. It can be big or small as necessary and convenient. The architecture accommodates both monolith migration and greenfield development simultaneously. Your legacy system gains fault tolerance while new features get maximum deployment flexibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling: Two Levels, Three Tiers of Intelligence
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Two-Level Horizontal Scaling
&lt;/h3&gt;

&lt;p&gt;Aether scales in two dimensions independently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Slice scaling&lt;/strong&gt;: Spin up more instances of a specific slice on existing nodes. Classes are already loaded — scaling takes milliseconds, not seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node scaling&lt;/strong&gt;: Add more machines to the cluster. The node connects, restores state, and begins accepting work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Independent controls, combined effect. Each node hosts at most one instance of a given slice, so scaling a slice beyond the current node count requires adding nodes first. Add 2 more nodes to a 3-node cluster, then scale a hot slice to 5 instances — one per node. No coordination between the two dimensions required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three-Tier Decision System
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Tier 1 — Decision Tree (1-second intervals).&lt;/strong&gt; Instant reactive decisions based on CPU utilization, request latency, queue depth, and error rate. CPU above 70%? Add an instance. Below 30% sustained? Remove one (if above minimum). Latency exceeding P95 threshold? Scale up. Error rate above 1% due to timeouts? Scale up. Deterministic, predictable, fast. Handles routine load changes with configurable cooldown periods — 30 seconds for scale-up, 5 minutes for scale-down — to prevent oscillation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 2 — TTM Predictor (60-second intervals).&lt;/strong&gt; An ONNX-based machine learning model (Tiny Time Mixers) analyzing a 60-minute sliding window of metrics — CPU usage, request rate, P95 latency, active instances. Forecasts load and adjusts the Decision Tree's thresholds preemptively. If TTM predicts a load increase, it lowers the scale-up CPU threshold by 20% so the reactive tier responds earlier. The cluster scales before the spike arrives, not after. The key design principle: the cluster always survives on Tier 1 alone. TTM enhances; it doesn't replace. If TTM fails — model load error, insufficient data, inference failure — the Decision Tree continues with default thresholds. The error is logged and recorded in metrics. No scaling disruption.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 3 — LLM-based (planned).&lt;/strong&gt; Long-term capacity planning and cluster health monitoring. Seasonal pattern prediction, maintenance window planning, anomaly investigation. This tier is not yet implemented — the current system operates with Tiers 1 and 2.&lt;/p&gt;

&lt;p&gt;Fault tolerance makes preemptible instances viable for burst scaling. If a spot instance gets reclaimed, the cluster survives — it was designed for nodes to disappear.&lt;/p&gt;

&lt;p&gt;You don't need a PhD in distributed systems or a dedicated platform team. The scaling system manages itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Development Experience: From Laptop To Production
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Three Environments, Zero Code Changes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Ember.&lt;/strong&gt; Single-process runtime with multiple cluster nodes running in the same JVM. Fast startup, simple debugging. Deploy your slices alongside your existing application — slices call each other directly in-process. No network overhead. Standard debugger breakpoints work as expected. Perfect for local development and unit testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Forge.&lt;/strong&gt; A 5-node cluster simulator running on your laptop. Real consensus. Real routing. Real failure scenarios. Kill nodes, crash the leader, trigger rolling restarts — and watch the cluster recover in real time through a web dashboard with D3.js topology visualization, per-node metrics (CPU, heap, leader status), and event timeline. Configurable load generation with TOML-based multi-target configuration lets you stress-test realistic scenarios — set request rates, define body templates, and run duration-limited load tests. Chaos operations include node kill, leader kill, and rolling restart. Forge validates the entire dependency graph before starting anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aether.&lt;/strong&gt; Production cluster. Same slices, same code, different scale. Your code doesn't know which environment it's running in. Whether inter-slice calls are in-process or cross-network is transparent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tooling
&lt;/h3&gt;

&lt;p&gt;37 CLI commands cover deployment, scaling, updates, artifacts, observability, controller configuration, and alerts — in both single-command and interactive REPL modes. A web dashboard streams real-time metrics via WebSocket — no polling. 30+ REST management endpoints enable full programmatic control of everything the CLI can do. Prometheus-compatible metrics export (&lt;code&gt;/metrics/prometheus&lt;/code&gt;) integrates with existing monitoring stacks. Metrics are push-based at 1-second intervals, with zero consensus overhead — they bypass the consensus protocol entirely. Per-method invocation tracking with P50/P95/P99 latency and configurable slow-invocation detection strategies (fixed threshold, adaptive, per-method, composite) surfaces performance issues before users notice. Dynamic aspects let you toggle LOG/METRICS/LOG_AND_METRICS modes per method at runtime via REST API, without redeployment.&lt;/p&gt;

&lt;p&gt;Test realistic failure scenarios on your laptop. Deploy to production with a config change, not a code change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maturity
&lt;/h2&gt;

&lt;p&gt;Aether is a working system, not a concept paper.&lt;/p&gt;

&lt;p&gt;81 end-to-end tests run against real 5-node clusters in Podman containers, validating cluster formation, quorum establishment, slice deployment and scaling, blueprint application with topological ordering, multi-instance distribution, artifact upload and cross-node resolution with integrity verification, leader failure and recovery, node restart with state restoration, and orphaned state cleanup after leader changes.&lt;/p&gt;

&lt;p&gt;The recovery and fault tolerance claims come from automated tests against real clusters, not marketing slides.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let Java Be Java
&lt;/h2&gt;

&lt;p&gt;Java's lineage leads here. From applets managed by browsers, through servlets managed by application servers, through EJBs managed by enterprise containers, through OSGi managed by runtime frameworks — to Aether, managed by a distributed runtime.&lt;/p&gt;

&lt;p&gt;The fat-jar era was a detour. An understandable one — when Docker emerged, it offered a universal packaging format, and the industry standardized on it regardless of language. Java adopted the patterns of languages that were designed to produce standalone binaries. We started treating Java applications like Go programs with a heavier runtime. But it was never the destination. Java was designed for managed environments. The JVM makes it possible. The runtime manages the application. That's the lineage. Aether continues it.&lt;/p&gt;

&lt;p&gt;Two entry points exist today. Wrap your legacy monolith behind a &lt;code&gt;@Slice&lt;/code&gt; interface in one sprint and gain fault tolerance without rewriting anything. Or start fresh with maximum clarity — lean slices, explicit contracts, per-use-case scaling. Both paths converge on the same runtime, the same cluster, the same operational model. Both paths can coexist — legacy service slices and new lean slices running side by side.&lt;/p&gt;

&lt;p&gt;Fault tolerance is not an afterthought — it's the foundation. Scaling is not your problem — it's the environment's. Infrastructure is not your code — it's the runtime's. The heavy winter coat comes off. The application breathes.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pragmaticalabs.io" rel="noopener noreferrer"&gt;Pragmatica Aether&lt;/a&gt; — project site&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/pragmaticalabs/pragmatica" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt; — source code&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Let Java be Java. Let infrastructure be infrastructure. Write business logic that scales from your laptop to global deployment without changing a line of code.&lt;/p&gt;

</description>
      <category>java</category>
      <category>architecture</category>
      <category>distributedsystems</category>
      <category>backend</category>
    </item>
    <item>
      <title>Why Interface + Factory? The Java Pattern That Makes Everything Replaceable</title>
      <dc:creator>Sergiy Yevtushenko</dc:creator>
      <pubDate>Sat, 07 Feb 2026 21:39:17 +0000</pubDate>
      <link>https://dev.to/siy/why-interface-factory-the-java-pattern-that-makes-everything-replaceable-3pm4</link>
      <guid>https://dev.to/siy/why-interface-factory-the-java-pattern-that-makes-everything-replaceable-3pm4</guid>
      <description>&lt;h1&gt;
  
  
  Why Interface + Factory? The Java Pattern That Makes Everything Replaceable
&lt;/h1&gt;

&lt;h2&gt;
  
  
  The Pattern
&lt;/h2&gt;

&lt;p&gt;Every component — use case, processing step, adapter — is defined as an interface with a static factory method:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;ProcessOrder&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Request&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;orderId&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;paymentToken&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderConfirmation&lt;/span&gt; &lt;span class="n"&gt;confirmation&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

    &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Request&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;interface&lt;/span&gt; &lt;span class="nc"&gt;ValidateInput&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ValidRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ReserveInventory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Reservation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ValidRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ProcessPayment&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Payment&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Reservation&lt;/span&gt; &lt;span class="n"&gt;reservation&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ConfirmOrder&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;ProcessOrder&lt;/span&gt; &lt;span class="nf"&gt;processOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ValidateInput&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                     &lt;span class="nc"&gt;ReserveInventory&lt;/span&gt; &lt;span class="n"&gt;reserve&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                     &lt;span class="nc"&gt;ProcessPayment&lt;/span&gt; &lt;span class="n"&gt;processPayment&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                     &lt;span class="nc"&gt;ConfirmOrder&lt;/span&gt; &lt;span class="n"&gt;confirm&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;request&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apply&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="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;reserve:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;processPayment:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;confirm:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;apply&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;Four steps. Each is a single-method interface. The factory method accepts all dependencies as parameters and returns a lambda implementing the use case. The body reads exactly like the business process: validate, reserve, process payment, confirm.&lt;/p&gt;

&lt;p&gt;This isn't arbitrary convention. There are three specific reasons this structure exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reason 1: Substitutability Without Magic
&lt;/h2&gt;

&lt;p&gt;Anyone can implement the interface. No framework. No inheritance hierarchy. No annotations.&lt;/p&gt;

&lt;p&gt;Testing becomes trivial:&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="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;order_fails_when_inventory_insufficient&lt;/span&gt;&lt;span class="o"&gt;()&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;useCase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ProcessOrder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processOrder&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;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;success&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;ValidRequest&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;// always valid&lt;/span&gt;
        &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;INSUFFICIENT_INVENTORY&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;                &lt;span class="c1"&gt;// always fails&lt;/span&gt;
        &lt;span class="n"&gt;reservation&lt;/span&gt; &lt;span class="o"&gt;-&amp;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="nc"&gt;AssertionError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unreachable"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;-&amp;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="nc"&gt;AssertionError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unreachable"&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;useCase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&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;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"order-1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"tok_123"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onSuccess&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Assertions:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fail&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;No mocking framework. No &lt;code&gt;@Mock&lt;/code&gt; annotations. No &lt;code&gt;when().thenReturn()&lt;/code&gt; chains. The test constructs the exact scenario it needs with plain lambdas.&lt;/p&gt;

&lt;p&gt;Stubbing incomplete implementations during development is equally straightforward:&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;// Payment gateway isn't ready yet? Stub it.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;useCase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ProcessOrder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;realValidator&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;realInventoryService&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;reservation&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;success&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;Payment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"stub-"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;reservation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ZERO&lt;/span&gt;&lt;span class="o"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;realConfirmation&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The team working on inventory doesn't need to wait for the payment team. Each step is independently implementable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reason 2: Implementation Isolation
&lt;/h2&gt;

&lt;p&gt;Each implementation is self-contained. No shared base classes. No abstract methods to override. No coupling between implementations whatsoever.&lt;/p&gt;

&lt;p&gt;Compare with the typical abstract class approach:&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;// The abstract class trap&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AbstractOrderProcessor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoggerFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getClass&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;final&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Request&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="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Processing order: {}"&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;orderId&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doExecute&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="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Order result: {}"&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;doExecute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Request&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;protected&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ValidRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Request&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;// "Shared utility" that every subclass now depends on&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;calculateTotal&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;LineItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 47 lines of logic that one subclass needed once&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;Now every implementation is coupled to the base class. Change &lt;code&gt;calculateTotal&lt;/code&gt; and you need to understand every subclass. Add logging to &lt;code&gt;execute&lt;/code&gt; and every implementation gets it whether appropriate or not. The base class becomes a gravity well — accumulating shared code that creates invisible dependencies between implementations that should have nothing in common.&lt;/p&gt;

&lt;p&gt;With interface + factory, there is no shared implementation code. Period. Each intersection between implementations is unnecessary coupling with corresponding maintenance overhead — up to needing deep understanding of two projects instead of one, with zero benefit.&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;// Implementation A: uses database&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;ProcessPayment&lt;/span&gt; &lt;span class="nf"&gt;databasePayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentRepository&lt;/span&gt; &lt;span class="n"&gt;repo&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;reservation&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reservation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;paymentToken&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;reservation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;total&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;Payment:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fromRecord&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Implementation B: uses external API&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;ProcessPayment&lt;/span&gt; &lt;span class="nf"&gt;stripePayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StripeClient&lt;/span&gt; &lt;span class="n"&gt;client&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;reservation&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createCharge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reservation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;reservation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;paymentToken&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;Payment:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fromStripe&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;These implementations don't know about each other. They don't share code. They don't share a base class. They share a contract — the interface — and nothing else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reason 3: Disposable Implementation
&lt;/h2&gt;

&lt;p&gt;Here's the subtle one. The factory method returns a lambda or local record. It can't be referenced externally by class name.&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;static&lt;/span&gt; &lt;span class="nc"&gt;ProcessOrder&lt;/span&gt; &lt;span class="nf"&gt;processOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ValidateInput&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                 &lt;span class="nc"&gt;ReserveInventory&lt;/span&gt; &lt;span class="n"&gt;reserve&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                 &lt;span class="nc"&gt;ProcessPayment&lt;/span&gt; &lt;span class="n"&gt;processPayment&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                 &lt;span class="nc"&gt;ConfirmOrder&lt;/span&gt; &lt;span class="n"&gt;confirm&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;request&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apply&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;// this lambda IS the implementation&lt;/span&gt;
                              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;reserve:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;processPayment:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;confirm:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;apply&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;No code anywhere says &lt;code&gt;new ProcessOrderImpl()&lt;/code&gt;. No code depends on the implementation class. The implementation is replaceable by definition — because nothing can reference it.&lt;/p&gt;

&lt;p&gt;The interface is the design artifact. The implementation is incidental.&lt;/p&gt;

&lt;p&gt;This might sound academic until you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace a synchronous implementation with an async one&lt;/li&gt;
&lt;li&gt;Swap a database adapter for an API adapter&lt;/li&gt;
&lt;li&gt;Add a caching layer around an existing step&lt;/li&gt;
&lt;li&gt;Completely rewrite a step's internals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In each case, the interface stays. The factory method signature stays. The implementation — which nothing references — gets replaced. No downstream changes. No adapter layers. No "backwards compatibility."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Compound Effect
&lt;/h2&gt;

&lt;p&gt;Each reason is valuable on its own. Together, they create a system where:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing is configuration.&lt;/strong&gt; You assemble the exact combination of real and stubbed components you need. No mocking framework overhead. No "mock everything" test fragility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Refactoring is safe.&lt;/strong&gt; Replacing an implementation can't break other implementations because they don't share code. The compiler enforces the contract through the interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complexity is bounded.&lt;/strong&gt; Understanding one implementation requires understanding only that implementation and the interfaces it consumes. Not a base class hierarchy. Not shared utilities. Not other implementations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incremental development is natural.&lt;/strong&gt; Stub what's not ready. Replace stubs with real implementations one at a time. Each step can be developed, tested, and deployed independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Does This Not Apply?
&lt;/h2&gt;

&lt;p&gt;When there genuinely is one implementation and always will be. Pure utility functions, mathematical computations, simple data transformations — these don't need the interface + factory treatment. A static method is fine.&lt;/p&gt;

&lt;p&gt;The pattern pays for itself when there's any possibility of multiple implementations — including the test implementation, which almost always exists.&lt;/p&gt;

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

&lt;p&gt;Most Java codebases default to classes. Interface extraction happens later, reluctantly, when testing forces it or when the second implementation appears.&lt;/p&gt;

&lt;p&gt;Flip this. Start with the interface. Define the contract. The implementation follows naturally — and when it needs to change, nothing else does.&lt;/p&gt;

&lt;p&gt;The interface is what you design. The implementation is what you happen to write today.&lt;/p&gt;

</description>
      <category>java</category>
      <category>architecture</category>
      <category>designpatterns</category>
      <category>functional</category>
    </item>
    <item>
      <title>Fail-Safe Your Legacy Java in One Sprint</title>
      <dc:creator>Sergiy Yevtushenko</dc:creator>
      <pubDate>Tue, 27 Jan 2026 12:24:03 +0000</pubDate>
      <link>https://dev.to/siy/fail-safe-your-legacy-java-in-one-sprint-d2b</link>
      <guid>https://dev.to/siy/fail-safe-your-legacy-java-in-one-sprint-d2b</guid>
      <description>&lt;h1&gt;
  
  
  Fail-Safe Your Legacy Java in One Sprint
&lt;/h1&gt;

&lt;h2&gt;
  
  
  The Scaling Wall
&lt;/h2&gt;

&lt;p&gt;Your Java system works. It's been working for years. But lately, it's showing strain. Response times creep up during peak hours. That batch job that used to finish overnight now runs into morning operations. Users notice.&lt;/p&gt;

&lt;p&gt;The conventional answer is microservices. Decompose the monolith, deploy to Kubernetes, hire a platform team. Eighteen months, significant budget, and a team with specialized skills you don't have. Meanwhile, every deployment feels like Russian roulette. One bad release, one server failure, and the business stops.&lt;/p&gt;

&lt;p&gt;For middle-sized businesses, this isn't a technology problem. It's a survival problem. The system that runs your operations is both essential and fragile. You can't afford to replace it, and you can't afford to lose it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 50% Rule
&lt;/h2&gt;

&lt;p&gt;What if half your servers could fail and users wouldn't notice?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pragmaticalabs.io/aether.html" rel="noopener noreferrer"&gt;Aether&lt;/a&gt;, the runtime behind the slice architecture, provides exactly this guarantee. When your code runs across a cluster, failure of less than half the nodes affects only performance, not functionality. Requests automatically route to surviving nodes. No manual intervention, no pager alerts at 3 AM.&lt;/p&gt;

&lt;p&gt;This isn't eventual consistency or graceful degradation. It's actual redundancy. The same request, processed by any available node, producing the same result. Your business keeps running while you fix the failed hardware.&lt;/p&gt;

&lt;p&gt;For a C-level executive, this translates simply: business continuity without enterprise budget. The system that runs your operations becomes the system that survives failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Simplest Migration Path
&lt;/h2&gt;

&lt;p&gt;Here's how to start. Pick a relatively independent part of your system. Something that's already hitting limits. Something with clear boundaries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Extract an interface.&lt;/strong&gt; This is mechanical. Any Java developer can do it. The interface defines what the component does, not how.&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="nd"&gt;@Slice&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ReportGenerator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Report&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;generateReport&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReportRequest&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Make it idempotent.&lt;/strong&gt; The same request should produce the same result, even if processed multiple times. Pragmatica Lite provides built-in support for this pattern. For most code, it's a small change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Deploy Ember.&lt;/strong&gt; Ember runs multiple cluster nodes in the same JVM as your existing application. Your legacy code calls the interface exactly as before. No changes to call sites.&lt;/p&gt;

&lt;p&gt;That's it. Your first slice is running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important caveat:&lt;/strong&gt; This initial step is not fault-tolerant. You're still running in a single JVM, which means a single point of failure. But here's the key insight: it's no worse than what you have today. You haven't added risk. You've laid the foundation for removing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Foundation to Fault Tolerance
&lt;/h2&gt;

&lt;p&gt;The foundation is in place. Now you can build on it.&lt;/p&gt;

&lt;p&gt;Moving from Ember to full Aether deployment is a configuration change, not a code change. Your slices, your interfaces, your business logic—all unchanged. You're just telling the runtime to distribute across multiple machines instead of running in-process.&lt;/p&gt;

&lt;p&gt;Now the 50% rule applies. Your report generator runs on three nodes. One dies. The other two handle the load. You fix the failed node when convenient, not when panicked.&lt;/p&gt;

&lt;p&gt;Each step in this path delivers value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ember in-JVM&lt;/strong&gt;: Foundation laid, no new risk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ember multi-node&lt;/strong&gt;: Development and testing environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aether cluster&lt;/strong&gt;: Production fault tolerance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You control the pace. Extract another slice when ready. Expand the cluster when needed. The architecture grows with your confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Peeling Pattern
&lt;/h2&gt;

&lt;p&gt;Once your slice is running, you have a choice: leave the internals as-is, or gradually refactor them. The peeling pattern lets you do the latter without risk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1: Wrap everything.&lt;/strong&gt; Your initial slice wraps the entire legacy method:&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;private&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Report&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;generateReport&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReportRequest&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="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyReportService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Phase 2: Peel the outer layer.&lt;/strong&gt; Refactor into a Sequencer, but keep each step wrapped:&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;private&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Report&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;generateReport&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReportRequest&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;validateRequest&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="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valid&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyFetchData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyProcess&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&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;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyFormat&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Phase 3: Peel deeper.&lt;/strong&gt; Take one wrapped step and expand 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="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RawData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ValidRequest&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="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyFetchFromDb&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="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lift&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;legacyFetchFromApi&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="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;combineData&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;Each phase keeps the code working. Tests pass at every step. You can stop anywhere—the system runs fine with mixed JBCT and wrapped legacy code. The &lt;code&gt;lift()&lt;/code&gt; calls mark exactly where legacy code remains, making progress visible and the remaining work obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Don't Need
&lt;/h2&gt;

&lt;p&gt;Traditional modernization projects require capabilities most middle-sized businesses don't have. Aether is different.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Kubernetes expertise.&lt;/strong&gt; Aether manages its own clustering. You don't need to learn pod configurations, service meshes, or container orchestration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No platform team.&lt;/strong&gt; The runtime handles deployment, discovery, and failover. Your existing operations team can manage it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No new infrastructure.&lt;/strong&gt; Start with Ember in your existing JVM. Add machines only when you're ready for fault tolerance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No retraining.&lt;/strong&gt; Same Java. Same IDE. Same debugging. Your developers write slice interfaces exactly like they write any other interface. The patterns are familiar; only the deployment model changes.&lt;/p&gt;

&lt;p&gt;The migration path is designed for teams that have a business to run, not a technology transformation to execute.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Path Forward
&lt;/h2&gt;

&lt;p&gt;Once the foundation is working, possibilities open up.&lt;/p&gt;

&lt;p&gt;More slices mean more of your system becomes fault-tolerant. The relatively independent parts you migrated first are now proven. You understand the pattern. The next extraction is faster.&lt;/p&gt;

&lt;p&gt;Aether's operational model scales beyond manual management. A three-tier control system handles increasingly complex decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decision trees&lt;/strong&gt; handle routine scaling—deterministic, predictable, fast&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TTM (predictive models)&lt;/strong&gt; detect patterns and scale preemptively&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM agents&lt;/strong&gt; (planned) handle capacity planning and anomaly investigation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You're not just surviving anymore. You're building toward a system that manages itself.&lt;/p&gt;

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

&lt;p&gt;The legacy Java system running your business doesn't need a complete rewrite. It needs a path forward that doesn't bet the company on an 18-month transformation project.&lt;/p&gt;

&lt;p&gt;Start with one slice. Run it in Ember alongside your existing code. Prove it works. Then decide: add fault tolerance, extract another slice, or pause and let the system prove itself in production.&lt;/p&gt;

&lt;p&gt;The 50% rule isn't a promise for someday. It's a capability you can reach in weeks, not years. Your business deserves infrastructure that survives failures. Now there's a path to get there.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Part of &lt;a href="//../README.md"&gt;Java Backend Coding Technology&lt;/a&gt; - a methodology for writing predictable, testable backend code.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>architecture</category>
      <category>migration</category>
      <category>backend</category>
    </item>
    <item>
      <title>Slices: The Right Size for Microservices</title>
      <dc:creator>Sergiy Yevtushenko</dc:creator>
      <pubDate>Sun, 18 Jan 2026 21:49:19 +0000</pubDate>
      <link>https://dev.to/siy/slices-the-right-size-for-microservices-c4</link>
      <guid>https://dev.to/siy/slices-the-right-size-for-microservices-c4</guid>
      <description>&lt;h1&gt;
  
  
  Slices: The Right Size for Microservices
&lt;/h1&gt;

&lt;h2&gt;
  
  
  The Granularity Trap
&lt;/h2&gt;

&lt;p&gt;Every team that adopts microservices eventually hits the same wall: how big should a service be?&lt;/p&gt;

&lt;p&gt;Go too small and you drown in network calls, distributed transactions, and deployment complexity. Your simple "get user profile" operation now involves five services, three of which are just proxies for database tables. Latency compounds. Debugging becomes archaeology.&lt;/p&gt;

&lt;p&gt;Go too large and you're back to the monolith. Different teams step on each other. Deployments require coordination. The "micro" in microservices becomes ironic.&lt;/p&gt;

&lt;p&gt;The standard advice—"one service per bounded context" or "services should be independently deployable"—sounds reasonable but provides no actionable guidance. Where does one context end and another begin? What exactly makes something "independently deployable"?&lt;/p&gt;

&lt;p&gt;Teams oscillate between extremes, refactoring services that are "too small" into larger ones, then splitting services that grew "too large." The cycle repeats because the fundamental question remains unanswered: what determines the right boundary?&lt;/p&gt;

&lt;h2&gt;
  
  
  Boundaries Before Size
&lt;/h2&gt;

&lt;p&gt;The problem isn't size. It's boundaries.&lt;/p&gt;

&lt;p&gt;A well-defined boundary has specific properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clear contract&lt;/strong&gt;: callers know exactly what they can request and what they'll receive&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explicit dependencies&lt;/strong&gt;: the component declares what it needs from outside&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal freedom&lt;/strong&gt;: implementation details can change without affecting callers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Size follows from boundaries, not the other way around. A component is the right size when it fully owns its boundaries—when everything needed to fulfill its contract lives inside, and everything outside is accessed through explicit dependencies.&lt;/p&gt;

&lt;p&gt;This is where most microservice designs fail. They draw boundaries based on technical layers (API gateway, business logic, database access) or organizational structure (team ownership). Neither approach produces stable boundaries because neither focuses on the actual contracts between components.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Slice?
&lt;/h2&gt;

&lt;p&gt;A slice is a deployable unit defined by its contract. You write an interface with a single annotation:&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="nd"&gt;@Slice&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CreateOrderRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GetOrderRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;cancelOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CancelOrderRequest&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. The annotation processor generates everything else—factory methods, dependency wiring, deployment metadata. You define the contract; the tooling handles the infrastructure.&lt;/p&gt;

&lt;p&gt;This interface is the boundary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Methods define the contract&lt;/strong&gt;: each takes a request, returns a promise of response&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request/response types are explicit&lt;/strong&gt;: no hidden parameters, no ambient context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async by default&lt;/strong&gt;: &lt;code&gt;Promise&amp;lt;T&amp;gt;&lt;/code&gt; handles both success and failure paths&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The implementation lives behind this interface. It might be simple or complex. It might call other slices or be completely self-contained. The boundary doesn't care.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aether and Forge: Development Made Simple
&lt;/h2&gt;

&lt;p&gt;Slices run on Aether, a distributed runtime designed around slice contracts. You don't configure service discovery, serialization, or inter-slice communication—Aether handles it based on what the slice interfaces declare. Every inter-slice call eventually succeeds if the cluster is alive; the runtime manages retries, failover, and recovery transparently.&lt;/p&gt;

&lt;p&gt;Forge provides a development environment for testing slices under realistic conditions—load generation, chaos injection, backend simulation. Instead of deploying to staging to see how your slices behave under pressure, you run Forge locally and observe.&lt;/p&gt;

&lt;p&gt;The development experience stays simple: write &lt;code&gt;@Slice&lt;/code&gt; interfaces, implement them, test with Forge, deploy to Aether. The annotation processor generates all the boilerplate—factories, dependency wiring, routing metadata.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependencies That Don't Lie
&lt;/h2&gt;

&lt;p&gt;Traditional service architectures bury dependencies in configuration files, environment variables, or runtime discovery. You find out what a service needs by reading its code, tracing its network calls, or waiting for it to fail in production.&lt;/p&gt;

&lt;p&gt;Slices declare dependencies in the interface:&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="nd"&gt;@Slice&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CreateOrderRequest&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;// Other methods...&lt;/span&gt;

    &lt;span class="c1"&gt;// Factory method declares dependencies explicitly&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="nf"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PaymentService&lt;/span&gt; &lt;span class="n"&gt;payment&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;OrderServiceFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Aspect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&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;The annotation processor generates the factory that wires everything:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderServiceFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;OrderServiceFactory&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;static&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="nf"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;Aspect&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderService&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;aspect&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;PaymentService&lt;/span&gt; &lt;span class="n"&gt;payment&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;aspect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apply&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;OrderServiceImpl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment&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;The factory method signature declares dependencies. No service locators, no runtime discovery, no configuration files that might or might not match reality. Dependencies are visible at compile time and verified before deployment.&lt;/p&gt;

&lt;p&gt;This explicitness matters. You can trace the dependency graph by reading code. You can test with substitutes by passing different implementations. Forge validates the entire graph before starting anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Same Code, Different Environments
&lt;/h2&gt;

&lt;p&gt;The same slices run unchanged across three runtime modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ember&lt;/strong&gt;: Single-process runtime with multiple cluster nodes. Fast startup, simple debugging. Perfect for local development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forge&lt;/strong&gt;: Ember plus load generation and chaos injection. Test how slices behave under pressure without deploying anywhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aether&lt;/strong&gt;: Full distributed cluster. Production deployment with all the resilience guarantees.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your code doesn't know which mode it's running in. Slice interfaces, implementations, and dependencies stay identical. The runtime handles the difference—whether inter-slice calls are in-process or cross-network is transparent.&lt;/p&gt;

&lt;p&gt;This changes the development workflow. You write and debug in Ember. You stress-test in Forge. You deploy to Aether. At no point do you modify slice code to accommodate the environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Right-Sized by Definition
&lt;/h2&gt;

&lt;p&gt;With boundaries explicit and deployment flexible, the "right size" question dissolves.&lt;/p&gt;

&lt;p&gt;A slice is the right size when:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Its interface captures a coherent set of operations&lt;/li&gt;
&lt;li&gt;Its dependencies accurately reflect what it needs&lt;/li&gt;
&lt;li&gt;Its implementation can fulfill its contract&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There's no minimum or maximum. An authentication slice might have two methods. An order processing slice might have twenty. Size follows from the domain, not from arbitrary rules about lines of code or team structure.&lt;/p&gt;

&lt;p&gt;More importantly, getting it wrong is recoverable. Split a slice that grew too complex? The boundary changes, but callers just see a new interface. Merge slices that were artificially separated? Same story. Refactoring slices is refactoring code, not rewriting infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The JBCT Connection
&lt;/h2&gt;

&lt;p&gt;Slices are where JBCT patterns live.&lt;/p&gt;

&lt;p&gt;Each slice method is a data transformation pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parse input (validated request types)&lt;/li&gt;
&lt;li&gt;Gather data (dependencies, other slices)&lt;/li&gt;
&lt;li&gt;Process (business logic)&lt;/li&gt;
&lt;li&gt;Respond (typed response)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The six patterns—Leaf, Sequencer, Fork-Join, Condition, Iteration, Aspects—compose within and across slice methods. A slice is simply the deployment boundary around a set of related transformations.&lt;/p&gt;

&lt;p&gt;This is why the combination works. JBCT gives you consistent structure within slices. Slices give you consistent boundaries between them. Together, they eliminate the two sources of architectural entropy: inconsistent implementation patterns and unclear service boundaries.&lt;/p&gt;

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

&lt;p&gt;The microservices granularity problem persists because it asks the wrong question. "How big should a service be?" has no good answer. "What are the contracts between components?" has a precise one.&lt;/p&gt;

&lt;p&gt;Slices shift focus from size to boundaries. Define the interface. Declare dependencies explicitly. Let deployment topology adapt to operational needs rather than dictating code structure.&lt;/p&gt;

&lt;p&gt;The result: boundaries that are clear by construction, dependencies that are visible by design, and deployment flexibility that doesn't require rewriting code.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Part of &lt;a href="//../README.md"&gt;Java Backend Coding Technology&lt;/a&gt; - a methodology for writing predictable, testable backend code.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>microservices</category>
      <category>architecture</category>
      <category>backend</category>
    </item>
    <item>
      <title>The Six Patterns That Cover Everything</title>
      <dc:creator>Sergiy Yevtushenko</dc:creator>
      <pubDate>Wed, 14 Jan 2026 23:12:12 +0000</pubDate>
      <link>https://dev.to/siy/the-six-patterns-that-cover-everything-kmn</link>
      <guid>https://dev.to/siy/the-six-patterns-that-cover-everything-kmn</guid>
      <description>&lt;h1&gt;
  
  
  The Six Patterns That Cover Everything
&lt;/h1&gt;

&lt;h2&gt;
  
  
  The Complete Vocabulary
&lt;/h2&gt;

&lt;p&gt;Every data transformation you'll ever write falls into one of six patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Leaf&lt;/strong&gt; - One thing. No substeps. Atomic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sequencer&lt;/strong&gt; - This, then that. Output becomes input.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fork-Join&lt;/strong&gt; - These together, then combine. Independent operations merging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Condition&lt;/strong&gt; - Which path? Route based on value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iteration&lt;/strong&gt; - Same thing, many times. Transform a collection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aspects&lt;/strong&gt; - Wrap it. Add retry, timeout, logging around an operation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. Six patterns. They cover everything.&lt;/p&gt;

&lt;p&gt;Not "cover most cases." Not "work well for common scenarios." Everything. Every piece of request processing logic you'll ever write is one of these six, or a composition of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Only Six?
&lt;/h2&gt;

&lt;p&gt;These aren't design patterns someone invented. They're the fundamental ways data can flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Transform a value&lt;/strong&gt; (Leaf)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chain dependent transforms&lt;/strong&gt; (Sequencer)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combine independent transforms&lt;/strong&gt; (Fork-Join)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose between transforms&lt;/strong&gt; (Condition)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply transform to many values&lt;/strong&gt; (Iteration)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhance a transform&lt;/strong&gt; (Aspects)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There's no seventh option. Data either transforms, chains, combines, branches, iterates, or gets wrapped. That's the complete set of possibilities.&lt;/p&gt;

&lt;p&gt;This is why learning six patterns gives you everything. Not because JBCT is comprehensive - because reality is constrained.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Strange Coincidence
&lt;/h2&gt;

&lt;p&gt;Here's what's remarkable: these same six patterns describe every business process.&lt;/p&gt;

&lt;p&gt;Think about any workflow in your domain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Leaf&lt;/strong&gt;: "Validate the email format" - one check, atomic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sequencer&lt;/strong&gt;: "First verify identity, then check permissions, then grant access" - dependent chain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fork-Join&lt;/strong&gt;: "Get user profile, account balance, and recent transactions, then build the dashboard" - independent data gathering&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Condition&lt;/strong&gt;: "If premium user, apply discount; otherwise, standard pricing" - routing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iteration&lt;/strong&gt;: "For each item in cart, calculate tax" - collection processing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aspects&lt;/strong&gt;: "Log every payment attempt" - cross-cutting concern&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Business processes and code patterns use the same vocabulary. This isn't coincidence. It's because both describe how information flows and transforms. Business logic IS data transformation - we just use different words for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Common Language
&lt;/h2&gt;

&lt;p&gt;This equivalence creates something powerful: a shared language between developers and business stakeholders.&lt;/p&gt;

&lt;p&gt;Watch the precision gain:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt; "Get the user's stuff and show it"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt; "Fork-Join: fetch profile, preferences, and history in parallel, then combine into dashboard view"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Same requirement. One is vague. One is implementable.&lt;/p&gt;

&lt;p&gt;When a developer asks "Can these operations run in parallel?" they're really asking "Do these steps depend on each other's results?"&lt;/p&gt;

&lt;p&gt;When business says "First we verify, then we process, then we notify" - that's a Sequencer. Directly translatable to code.&lt;/p&gt;

&lt;p&gt;When business says "We need the user's profile, their preferences, and their history to show the dashboard" - that's a Fork-Join. Three independent fetches, one combined result.&lt;/p&gt;

&lt;p&gt;The translation becomes mechanical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Check if..." → &lt;strong&gt;Leaf&lt;/strong&gt; → Single validation&lt;/li&gt;
&lt;li&gt;"First... then... then..." → &lt;strong&gt;Sequencer&lt;/strong&gt; → &lt;code&gt;.flatMap()&lt;/code&gt; chain&lt;/li&gt;
&lt;li&gt;"Get X and Y and Z, then..." → &lt;strong&gt;Fork-Join&lt;/strong&gt; → &lt;code&gt;Promise.all()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;"If... otherwise..." → &lt;strong&gt;Condition&lt;/strong&gt; → Ternary/switch&lt;/li&gt;
&lt;li&gt;"For each..." → &lt;strong&gt;Iteration&lt;/strong&gt; → &lt;code&gt;.map()&lt;/code&gt; / loop&lt;/li&gt;
&lt;li&gt;"Always log/retry/timeout..." → &lt;strong&gt;Aspects&lt;/strong&gt; → Wrapper function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No translation layer. No impedance mismatch. The same six concepts, different vocabulary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gap Detection
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. When you model business processes using these patterns, gaps become visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Missing validation:&lt;/strong&gt;&lt;br&gt;
You're building a Sequencer: verify -&amp;gt; process -&amp;gt; notify. But what validates the input before "verify"? The pattern demands something produces the input for step one. If nothing does, you've found a gap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unclear dependencies:&lt;/strong&gt;&lt;br&gt;
Business describes five things that need to happen. Are they a Sequencer (dependent chain) or Fork-Join (independent operations)? If they can't tell you which outputs feed which inputs, the process isn't fully defined.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Missing error handling:&lt;/strong&gt;&lt;br&gt;
Every Leaf can fail. Every step in a Sequencer can fail. When you map business process to patterns, you naturally ask: "What happens when this fails?" If they don't know, you've found a gap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inefficient flows:&lt;/strong&gt;&lt;br&gt;
Business describes a sequential process: get A, then get B, then get C, then combine. But if A, B, and C don't depend on each other, this should be Fork-Join, not Sequencer. The pattern reveals the inefficiency.&lt;/p&gt;

&lt;p&gt;The patterns don't just implement requirements - they validate them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Right Questions
&lt;/h2&gt;

&lt;p&gt;Once you think in patterns, the right questions emerge naturally:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At the start (Leaf/Validation):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"How do we know this request is valid?"&lt;/li&gt;
&lt;li&gt;"What makes an email/phone/amount valid in your domain?"&lt;/li&gt;
&lt;li&gt;"What's the first thing we need to verify?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For sequences (Sequencer):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"What do we need from step 1 to perform step 2?"&lt;/li&gt;
&lt;li&gt;"Can step 3 ever happen if step 2 fails?"&lt;/li&gt;
&lt;li&gt;"Is this order fixed, or could steps be reordered?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For parallel work (Fork-Join):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Do these operations depend on each other?"&lt;/li&gt;
&lt;li&gt;"Can we fetch user profile while also fetching their orders?"&lt;/li&gt;
&lt;li&gt;"What do we do if one succeeds and another fails?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For branching (Condition):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"What determines which path we take?"&lt;/li&gt;
&lt;li&gt;"Are these paths mutually exclusive?"&lt;/li&gt;
&lt;li&gt;"Is there a default path?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For collections (Iteration):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Do we process all items or stop at first failure?"&lt;/li&gt;
&lt;li&gt;"Does order matter?"&lt;/li&gt;
&lt;li&gt;"Can items be processed independently (in parallel)?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For cross-cutting concerns (Aspects):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Should we retry on failure? How many times?"&lt;/li&gt;
&lt;li&gt;"Is there a timeout?"&lt;/li&gt;
&lt;li&gt;"What needs to be logged/measured?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You're not inventing questions. The patterns generate them. Each pattern has a fixed set of things that must be defined. If they're not defined, you ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Patterns to Process Design
&lt;/h2&gt;

&lt;p&gt;The flow works both ways.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Forward:&lt;/strong&gt; Business describes a process -&amp;gt; you identify patterns -&amp;gt; you implement code&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backward:&lt;/strong&gt; You see the patterns -&amp;gt; you notice gaps -&amp;gt; you ask questions -&amp;gt; business clarifies -&amp;gt; process improves&lt;/p&gt;

&lt;p&gt;This backward flow is underrated. Developers who think in patterns become process consultants. They don't just implement what they're told - they improve what they're told by making implicit assumptions explicit.&lt;/p&gt;

&lt;p&gt;"You said first A, then B, then C. But B doesn't use A's output. Can B and A happen at the same time? That would be faster."&lt;/p&gt;

&lt;p&gt;"You said validate the request. What exactly are we validating? Email format? Email exists in system? User is active? Each is a separate check."&lt;/p&gt;

&lt;p&gt;"You said handle the error. Which error? Network timeout? Invalid data? User not found? Each might need different handling."&lt;/p&gt;

&lt;p&gt;The patterns force precision. Vague requirements become concrete when you have to place them in one of six boxes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;When developers and business share this vocabulary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requirements discussions become technical design sessions&lt;/li&gt;
&lt;li&gt;Gaps surface during conversation, not during implementation&lt;/li&gt;
&lt;li&gt;Code structure mirrors business process (because they're the same thing)&lt;/li&gt;
&lt;li&gt;Changes in business process map directly to code changes&lt;/li&gt;
&lt;li&gt;New team members understand both business and code faster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Six patterns. Complete coverage. Shared language. Gap detection built in.&lt;/p&gt;

&lt;p&gt;This is why pattern-based thinking isn't just a coding technique. It's a communication framework that makes the implicit explicit and the vague precise.&lt;/p&gt;

&lt;p&gt;The irony? You'll spend an hour asking the right questions. The coding takes 30 seconds. Turns out the "coding technology" is mostly about not coding.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Part of &lt;a href="https://pragmatica.dev" rel="noopener noreferrer"&gt;Java Backend Coding Technology&lt;/a&gt; - a methodology for writing predictable, testable backend code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Previous:&lt;/strong&gt; &lt;a href="https://dev.to/siy/the-underlying-process-of-request-processing-1od4"&gt;The Underlying Process of Request Processing&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>functional</category>
      <category>architecture</category>
      <category>backend</category>
    </item>
    <item>
      <title>The Underlying Process of Request Processing</title>
      <dc:creator>Sergiy Yevtushenko</dc:creator>
      <pubDate>Mon, 12 Jan 2026 21:36:33 +0000</pubDate>
      <link>https://dev.to/siy/the-underlying-process-of-request-processing-1od4</link>
      <guid>https://dev.to/siy/the-underlying-process-of-request-processing-1od4</guid>
      <description>&lt;h1&gt;
  
  
  The Underlying Process of Request Processing
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Beyond Languages and Frameworks
&lt;/h2&gt;

&lt;p&gt;Every request your system handles follows the same fundamental process. It doesn't matter if you're writing Java, Rust, or Python. It doesn't matter if you're using Spring, Express, or raw sockets. The underlying process is universal because it mirrors how humans naturally solve problems.&lt;/p&gt;

&lt;p&gt;When you receive a question, you don't answer immediately. You gather context. You retrieve relevant knowledge. You combine pieces of information. You transform raw data into meaningful understanding. Only then do you formulate a response. This is data transformation--taking input and gradually collecting necessary pieces of knowledge to provide a correct answer.&lt;/p&gt;

&lt;p&gt;Software request processing works identically.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Universal Pattern
&lt;/h2&gt;

&lt;p&gt;Every request follows these stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Parse&lt;/strong&gt; - Transform raw input into validated domain objects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gather&lt;/strong&gt; - Collect necessary data from various sources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Process&lt;/strong&gt; - Apply business logic to produce results&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Respond&lt;/strong&gt; - Transform results into appropriate output format&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This isn't a framework pattern. It's not a design choice. It's the fundamental nature of information processing. Whether you're handling an HTTP request, processing a message from a queue, or responding to a CLI command--the process is the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input → Parse → Gather → Process → Respond → Output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each stage transforms data. Each stage may need additional data. Each stage may fail. The entire flow is a data transformation pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Async Looks Like Sync
&lt;/h2&gt;

&lt;p&gt;Here's the insight that changes everything: &lt;strong&gt;when you think in terms of data transformation, the sync/async distinction disappears&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Consider these two operations:&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;// "Synchronous"&lt;/span&gt;
&lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// "Asynchronous"&lt;/span&gt;
&lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From a data transformation perspective, these are identical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both take a user ID&lt;/li&gt;
&lt;li&gt;Both produce a User (or failure)&lt;/li&gt;
&lt;li&gt;Both are steps in a larger pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only difference is &lt;em&gt;when&lt;/em&gt; the result becomes available. But that's an execution detail, not a structural concern. Your business logic doesn't care whether the data came from local memory or crossed an ocean. It cares about what the data &lt;em&gt;is&lt;/em&gt; and what to do with it.&lt;/p&gt;

&lt;p&gt;When you structure code as data transformation pipelines, this becomes obvious:&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;// The structure is identical regardless of sync/async&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;findUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;        &lt;span class="c1"&gt;// Might be sync or async&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;loadPermissions&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Might be sync or async&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fetchPreferences&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Might be sync or async&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;buildContext&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pattern doesn't change. The composition doesn't change. Only the underlying execution strategy changes--and that's handled by the types, not by you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parallel Execution Becomes Transparent
&lt;/h2&gt;

&lt;p&gt;The same principle applies to parallelism. When operations are independent, they can run in parallel. When they depend on each other, they must run sequentially. This isn't a choice you make--it's determined by the data flow.&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;// Sequential: each step needs the previous result&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;validateInput&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="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;createUser&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Parallel: steps are independent&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;fetchUserProfile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;loadAccountSettings&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;getRecentActivity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;buildDashboard&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't decide "this should be parallel" or "this should be sequential." You express the data dependencies. The execution strategy follows from the structure. If operations share no data dependencies, they're naturally parallelizable. If one needs another's output, they're naturally sequential.&lt;/p&gt;

&lt;p&gt;This is why thinking in data transformation is so powerful. You describe &lt;em&gt;what&lt;/em&gt; needs to happen and &lt;em&gt;what data flows where&lt;/em&gt;. The &lt;em&gt;how&lt;/em&gt;--sync vs async, sequential vs parallel--emerges from the structure itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The JBCT Patterns as Universal Primitives
&lt;/h2&gt;

&lt;p&gt;Java Backend Coding Technology captures this insight in six patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Leaf&lt;/strong&gt; - Single transformation (atomic)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sequencer&lt;/strong&gt; - A → B → C, dependent chain (sequential)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fork-Join&lt;/strong&gt; - A + B + C → D, independent merge (parallel-capable)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Condition&lt;/strong&gt; - Route based on value (branching)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iteration&lt;/strong&gt; - Transform collection (map/fold)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aspects&lt;/strong&gt; - Wrap transformation (decoration)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't arbitrary design patterns. They're the fundamental ways data can flow through a system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transform a single value (Leaf)&lt;/li&gt;
&lt;li&gt;Chain dependent transformations (Sequencer)&lt;/li&gt;
&lt;li&gt;Combine independent transformations (Fork-Join)&lt;/li&gt;
&lt;li&gt;Choose between transformations (Condition)&lt;/li&gt;
&lt;li&gt;Apply transformation to many values (Iteration)&lt;/li&gt;
&lt;li&gt;Enhance a transformation (Aspects)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every request processing task--regardless of domain, language, or framework--decomposes into these six primitives. Once you internalize this, implementation becomes mechanical. You're not inventing structure; you're recognizing the inherent structure of the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimal Implementation as Routine
&lt;/h2&gt;

&lt;p&gt;When you see request processing as data transformation, optimization becomes straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identify independent operations&lt;/strong&gt; → They can parallelize (Fork-Join)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identify dependent chains&lt;/strong&gt; → They must sequence (Sequencer)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identify decision points&lt;/strong&gt; → They become conditions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identify collection processing&lt;/strong&gt; → They become iterations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identify cross-cutting concerns&lt;/strong&gt; → They become aspects&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You're not making architectural decisions. You're reading the inherent structure of the problem and translating it directly into code.&lt;/p&gt;

&lt;p&gt;This is why JBCT produces consistent code across developers and AI assistants. There's essentially one correct structure for any given data flow. Different people analyzing the same problem arrive at the same solution--not because they memorized patterns, but because the patterns are the natural expression of data transformation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shift in Thinking
&lt;/h2&gt;

&lt;p&gt;Traditional programming asks: "What sequence of instructions produces the desired effect?"&lt;/p&gt;

&lt;p&gt;Data transformation thinking asks: "What shape does the data take at each stage, and what transformations connect them?"&lt;/p&gt;

&lt;p&gt;The first approach leads to imperative code where control flow dominates. The second leads to declarative pipelines where data flow dominates.&lt;/p&gt;

&lt;p&gt;When you make this shift:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Async stops being "harder" than sync&lt;/li&gt;
&lt;li&gt;Parallel stops being "risky"&lt;/li&gt;
&lt;li&gt;Error handling stops being an afterthought&lt;/li&gt;
&lt;li&gt;Testing becomes straightforward (pure transformations are trivially testable)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You're no longer fighting the machine to do what you want. You're describing transformations and letting the runtime figure out the optimal execution strategy.&lt;/p&gt;

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

&lt;p&gt;Request processing is data transformation. This isn't a paradigm or a methodology--it's the underlying reality that every paradigm and methodology is trying to express.&lt;/p&gt;

&lt;p&gt;Languages and frameworks provide different syntax. Some make data transformation easier to express than others. But the fundamental process doesn't change. Input arrives. Data transforms through stages. Output emerges.&lt;/p&gt;

&lt;p&gt;JBCT patterns aren't rules to memorize. They're the vocabulary for describing data transformation in Java. Once you see the underlying process clearly, using these patterns becomes as natural as describing what you see.&lt;/p&gt;

&lt;p&gt;The result: any processing task, implemented in close to optimal form, as a matter of routine.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Part of &lt;a href="//../README.md"&gt;Java Backend Coding Technology&lt;/a&gt; - a methodology for writing predictable, testable backend code.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>functional</category>
      <category>architecture</category>
      <category>backend</category>
    </item>
    <item>
      <title>From Subjective Opinions to Systematic Analysis: Pattern-Based Code Review</title>
      <dc:creator>Sergiy Yevtushenko</dc:creator>
      <pubDate>Sun, 21 Dec 2025 14:38:34 +0000</pubDate>
      <link>https://dev.to/siy/from-subjective-opinions-to-systematic-analysis-pattern-based-code-review-1obm</link>
      <guid>https://dev.to/siy/from-subjective-opinions-to-systematic-analysis-pattern-based-code-review-1obm</guid>
      <description>&lt;h1&gt;
  
  
  From Subjective Opinions to Systematic Analysis: Pattern-Based Code Review
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;How structural patterns transform code review from art into engineering&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem with Traditional Code Review
&lt;/h2&gt;

&lt;p&gt;Code review discussions often devolve into debates about style, naming preferences, and subjective "readability." Two experienced developers can look at the same function and have completely opposite opinions about whether it's "clean" or "messy."&lt;/p&gt;

&lt;p&gt;This subjectivity creates real problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Review quality depends on reviewer mood and experience&lt;/li&gt;
&lt;li&gt;Feedback is inconsistent across team members&lt;/li&gt;
&lt;li&gt;Discussions become defensive rather than constructive&lt;/li&gt;
&lt;li&gt;Junior developers struggle to internalize vague guidance like "make it more readable"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What if code review could be as systematic as running a test suite?&lt;/p&gt;




&lt;h2&gt;
  
  
  The Key Insight: Patterns Enable Decomposition
&lt;/h2&gt;

&lt;p&gt;When code follows well-defined structural patterns, something remarkable happens: &lt;strong&gt;functions become decomposable into discrete, analyzable parts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Consider a function that follows no particular pattern. To review it, you must:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hold the entire function in your head&lt;/li&gt;
&lt;li&gt;Trace all possible execution paths&lt;/li&gt;
&lt;li&gt;Infer the author's intent from implementation details&lt;/li&gt;
&lt;li&gt;Make subjective judgments about "complexity"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now consider a function that implements exactly one pattern from a known catalog. Suddenly you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Immediately recognize the structure&lt;/li&gt;
&lt;li&gt;Apply pattern-specific review criteria&lt;/li&gt;
&lt;li&gt;Verify each component independently&lt;/li&gt;
&lt;li&gt;Make objective assessments against clear standards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Patterns transform code review from holistic judgment into component analysis.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Pattern Catalog: A Reviewer's Toolkit
&lt;/h2&gt;

&lt;p&gt;Every function implements exactly one of these patterns:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Leaf
&lt;/h3&gt;

&lt;p&gt;The atomic unit -- a function that does one thing with no internal steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Business Leaf:&lt;/strong&gt; Pure computation, no I/O&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="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;calculateDiscount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;discountRate&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;price&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discountRate&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;strong&gt;Adapter Leaf:&lt;/strong&gt; I/O operation that bridges to external systems&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="nc"&gt;User&lt;/span&gt; &lt;span class="nf"&gt;findByEmail&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;email&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;DatabaseException&lt;/span&gt; &lt;span class="o"&gt;{&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;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&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;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prepareStatement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FIND_BY_EMAIL_SQL&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&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;rs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeQuery&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;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;mapToUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;)&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="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLException&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="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DatabaseException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to find user by email"&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="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;
  
  
  2. Sequencer
&lt;/h3&gt;

&lt;p&gt;A chain of 2-5 dependent steps where each step's output feeds the next.&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="nc"&gt;OrderConfirmation&lt;/span&gt; &lt;span class="nf"&gt;processOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderRequest&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;ValidatedOrder&lt;/span&gt; &lt;span class="n"&gt;validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validateOrder&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="nc"&gt;InventoryReservation&lt;/span&gt; &lt;span class="n"&gt;reservation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reserveInventory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validated&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;PaymentResult&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;processPayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reservation&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;confirmOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&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;
  
  
  3. Fork-Join
&lt;/h3&gt;

&lt;p&gt;Parallel independent operations combined into a single result.&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="nc"&gt;Dashboard&lt;/span&gt; &lt;span class="nf"&gt;loadDashboard&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserProfile&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;profileFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&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;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProfile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;Order&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ordersFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&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;orderService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRecentOrders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;Notification&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;notificationsFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&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;notificationService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUnread&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profileFuture&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ordersFuture&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;notificationsFuture&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;profileFuture&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="n"&gt;ordersFuture&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="n"&gt;notificationsFuture&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="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;
  
  
  4. Condition
&lt;/h3&gt;

&lt;p&gt;Branching based on a discriminator -- if/else or switch.&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="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;calculateShippingRate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&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;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPremiumCustomer&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="nf"&gt;calculatePremiumRate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&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="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getWeight&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;HEAVY_THRESHOLD&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="nf"&gt;calculateHeavyItemRate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;calculateStandardRate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&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;
  
  
  5. Iteration
&lt;/h3&gt;

&lt;p&gt;Collection processing via loops or streams.&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="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderSummary&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getPendingOrderSummaries&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;Order&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orders&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;orders&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="nl"&gt;Order:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;isPending&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;toSummary&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="nc"&gt;Collectors&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Pattern-Based Review: The Checklist Approach
&lt;/h2&gt;

&lt;p&gt;Once you recognize a function's pattern, you apply pattern-specific review criteria. This replaces vague "is it readable?" with concrete checklists.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reviewing a Leaf
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Single Responsibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does it do exactly one thing?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Purity (Business)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No side effects? Same inputs -&amp;gt; same output?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Error Handling (Adapter)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are low-level exceptions wrapped in domain exceptions?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Naming&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does the name describe the transformation?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Small enough to understand at a glance?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Reviewing a Sequencer
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Step Count&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2-5 steps? (More suggests extraction needed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dependency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does each step genuinely depend on the previous?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Single Pattern&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No hidden Fork-Join or Condition inside steps?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Abstraction Level&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are all steps at the same abstraction level?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Error Flow&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Is it clear what happens when each step fails?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Reviewing a Fork-Join
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Independence&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are branches truly independent? No shared mutable state?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Thread Safety&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are all inputs immutable or thread-safe?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Completeness&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does the combiner handle all branch results?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;What happens if one branch fails?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Infrastructure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Any hidden dependencies (DB locks, rate limits, connection pools)?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Reviewing a Condition
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Exhaustiveness&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are all cases covered? Is there a sensible default?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Balance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are branches roughly equal in complexity?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Extraction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Should complex branches be extracted to named methods?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Nesting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are conditions nested too deeply? (Max 2 levels)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Reviewing an Iteration
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transformation Clarity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Is the mapping operation obvious?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Filter Predicate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Is the filter condition clear or should it be a named method?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Side Effects&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No side effects inside map/filter/forEach?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Null Safety&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are null elements handled?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  The Meta-Review: Pattern Violations
&lt;/h2&gt;

&lt;p&gt;Beyond pattern-specific checks, reviewers should watch for structural violations:&lt;/p&gt;

&lt;h3&gt;
  
  
  Mixed Patterns
&lt;/h3&gt;

&lt;p&gt;A function that starts as a Sequencer but contains an inline Fork-Join:&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;// BAD: Mixed patterns -- Sequencer contains inline Fork-Join&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;OrderResult&lt;/span&gt; &lt;span class="nf"&gt;processOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderRequest&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;ValidatedOrder&lt;/span&gt; &lt;span class="n"&gt;validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validateOrder&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;// Suddenly doing parallel work inline&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;userFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&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;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserId&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;productFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&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;productService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProduct&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProductId&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userFuture&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;productFuture&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;OrderContext&lt;/span&gt; &lt;span class="n"&gt;context&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;OrderContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userFuture&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="n"&gt;productFuture&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;finalizeOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&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;strong&gt;Review feedback:&lt;/strong&gt; "Extract the parallel fetch into a separate method like &lt;code&gt;fetchOrderContext()&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="c1"&gt;// GOOD: Clean -- Sequencer with extracted Fork-Join&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;OrderResult&lt;/span&gt; &lt;span class="nf"&gt;processOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderRequest&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;ValidatedOrder&lt;/span&gt; &lt;span class="n"&gt;validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validateOrder&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="nc"&gt;OrderContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetchOrderContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validated&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Fork-Join hidden here&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;finalizeOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&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;OrderContext&lt;/span&gt; &lt;span class="nf"&gt;fetchOrderContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ValidatedOrder&lt;/span&gt; &lt;span class="n"&gt;validated&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Fork-Join pattern in its own method&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;userFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&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;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserId&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;productFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&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;productService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProduct&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProductId&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userFuture&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;productFuture&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OrderContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userFuture&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="n"&gt;productFuture&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Violated Abstraction Levels
&lt;/h3&gt;

&lt;p&gt;Mixing high-level orchestration with low-level details:&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;// BAD: Mixed abstraction levels&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;processUserRegistration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RegistrationRequest&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;// High-level step&lt;/span&gt;
    &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;createUser&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;// Suddenly low-level details&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;welcomeHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Welcome "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"!&amp;lt;/h1&amp;gt;"&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;p&amp;gt;Your account has been created.&amp;lt;/p&amp;gt;"&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;a href='"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;baseUrl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/verify?token="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVerificationToken&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"'&amp;gt;Verify&amp;lt;/a&amp;gt;"&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Welcome!"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;welcomeHtml&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Back to high-level&lt;/span&gt;
    &lt;span class="n"&gt;auditService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logRegistration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&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;strong&gt;Review feedback:&lt;/strong&gt; "Extract email content generation to a separate method or template."&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;// GOOD: Clean -- consistent abstraction level&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;processUserRegistration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RegistrationRequest&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;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;createUser&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="n"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;auditService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logRegistration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&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;sendWelcomeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emailTemplates&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;renderWelcome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Welcome!"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&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;
  
  
  Incorrect Pattern Choice
&lt;/h3&gt;

&lt;p&gt;Using Sequencer when Fork-Join is appropriate (sequential operations that are actually independent):&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;// BAD: Sequential when parallel is possible&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ReportData&lt;/span&gt; &lt;span class="nf"&gt;gatherReportData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;UserProfile&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProfile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;// 200ms&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;Order&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOrders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// 300ms  &lt;/span&gt;
    &lt;span class="nc"&gt;AccountBalance&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;accountService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBalance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 150ms&lt;/span&gt;
    &lt;span class="c1"&gt;// Total: 650ms sequential&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ReportData&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="n"&gt;orders&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;balance&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;strong&gt;Review feedback:&lt;/strong&gt; "These fetches are independent -- use parallel execution to reduce latency."&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;// GOOD: Parallel execution for independent operations&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ReportData&lt;/span&gt; &lt;span class="nf"&gt;gatherReportData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserProfile&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;profileFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&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;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProfile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;Order&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ordersFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&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;orderService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOrders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AccountBalance&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;balanceFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&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;accountService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBalance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profileFuture&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ordersFuture&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;balanceFuture&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="c1"&gt;// Total: ~300ms parallel&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ReportData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;profileFuture&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="n"&gt;ordersFuture&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="n"&gt;balanceFuture&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="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 "God Method" -- Multiple Patterns Jumbled Together
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BAD: Multiple patterns mixed together&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Invoice&lt;/span&gt; &lt;span class="nf"&gt;generateInvoice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orderRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Leaf&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;order&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="c1"&gt;// Condition starts&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;OrderNotFoundException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&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;InvoiceLine&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lines&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="c1"&gt;// Iteration starts&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;LineItem&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getItems&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;productService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProduct&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProductId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;  &lt;span class="c1"&gt;// Another Leaf&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;product&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isTaxable&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;                    &lt;span class="c1"&gt;// Nested Condition&lt;/span&gt;
            &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;createTaxableLine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;product&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;lines&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;createNonTaxableLine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;product&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="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;subtotal&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="c1"&gt;// Another Iteration&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;InvoiceLine&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAmount&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;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasDiscount&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;                        &lt;span class="c1"&gt;// Another Condition&lt;/span&gt;
        &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;applyDiscount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subtotal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDiscount&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Invoice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subtotal&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;strong&gt;Review feedback:&lt;/strong&gt; "This method mixes at least 4 patterns. Extract: &lt;code&gt;fetchOrder()&lt;/code&gt;, &lt;code&gt;buildInvoiceLines()&lt;/code&gt;, &lt;code&gt;calculateSubtotal()&lt;/code&gt;, &lt;code&gt;applyDiscountIfPresent()&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="c1"&gt;// GOOD: Clean -- one pattern per method, composed as Sequencer&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Invoice&lt;/span&gt; &lt;span class="nf"&gt;generateInvoice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetchOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&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;InvoiceLine&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buildInvoiceLines&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculateSubtotal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;finalAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;applyDiscountIfPresent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subtotal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Invoice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;finalAmount&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;Order&lt;/span&gt; &lt;span class="nf"&gt;fetchOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* Leaf */&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InvoiceLine&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;buildInvoiceLines&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* Iteration */&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;double&lt;/span&gt; &lt;span class="nf"&gt;calculateSubtotal&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;InvoiceLine&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* Iteration */&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;double&lt;/span&gt; &lt;span class="nf"&gt;applyDiscountIfPresent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;subtotal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* Condition */&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Practical Review Workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Pattern Recognition
&lt;/h3&gt;

&lt;p&gt;Before reading implementation details, identify the pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;See sequential method calls with data passing between them? -&amp;gt; &lt;strong&gt;Sequencer&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;See &lt;code&gt;CompletableFuture.allOf()&lt;/code&gt; or parallel streams? -&amp;gt; &lt;strong&gt;Fork-Join&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;See &lt;code&gt;if/else&lt;/code&gt; or &lt;code&gt;switch&lt;/code&gt; as the main structure? -&amp;gt; &lt;strong&gt;Condition&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;See loops or stream operations? -&amp;gt; &lt;strong&gt;Iteration&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;None of the above, just one operation? -&amp;gt; &lt;strong&gt;Leaf&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Count the Patterns
&lt;/h3&gt;

&lt;p&gt;If you identify more than one pattern in a single method, that's already a finding. Flag it for extraction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Apply Pattern Checklist
&lt;/h3&gt;

&lt;p&gt;Use the appropriate checklist. Check each criterion mechanically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Verify Abstraction Consistency
&lt;/h3&gt;

&lt;p&gt;Read through the method body. Are all statements at the same level of abstraction? High-level orchestration shouldn't mix with low-level implementation details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Check Error Handling Consistency
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Are exceptions handled at the right level?&lt;/li&gt;
&lt;li&gt;Is null checking consistent?&lt;/li&gt;
&lt;li&gt;Are edge cases covered?&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Review Comments by Pattern
&lt;/h2&gt;

&lt;p&gt;Having a vocabulary of pattern-based feedback makes reviews faster and more actionable:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Common Issue&lt;/th&gt;
&lt;th&gt;Review Comment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Leaf&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does too much&lt;/td&gt;
&lt;td&gt;"This leaf has multiple responsibilities. Extract X into a separate method."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Leaf&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Side effects in business logic&lt;/td&gt;
&lt;td&gt;"This calculation method logs/saves data. Extract side effects."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sequencer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Too many steps&lt;/td&gt;
&lt;td&gt;"This has 8 steps. Group related steps into higher-level methods."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sequencer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Independent steps&lt;/td&gt;
&lt;td&gt;"Steps 2 and 3 don't depend on each other. Consider parallel execution."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fork-Join&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shared mutable state&lt;/td&gt;
&lt;td&gt;"These parallel branches share mutable state. Make inputs immutable."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fork-Join&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Missing error handling&lt;/td&gt;
&lt;td&gt;"What happens if one future fails? Add error handling strategy."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Condition&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deep nesting&lt;/td&gt;
&lt;td&gt;"3+ levels of nesting. Extract inner conditions to named methods."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Condition&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Unbalanced branches&lt;/td&gt;
&lt;td&gt;"The else branch is 50 lines. Extract to a method."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Iteration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Side effects in loop&lt;/td&gt;
&lt;td&gt;"This forEach modifies external state. Consider using reduce or extract the mutation."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mixed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multiple patterns&lt;/td&gt;
&lt;td&gt;"This method contains Sequencer + Condition + Iteration. Extract each pattern."&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Benefits of Pattern-Based Review
&lt;/h2&gt;

&lt;h3&gt;
  
  
  For Reviewers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Faster reviews:&lt;/strong&gt; Pattern recognition is instant; checklists are mechanical&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent feedback:&lt;/strong&gt; Same criteria applied every time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Objective discussions:&lt;/strong&gt; "This violates single-pattern rule" vs. "I don't like this"&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  For Authors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clear expectations:&lt;/strong&gt; Know what reviewers will check before submitting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actionable feedback:&lt;/strong&gt; "Extract this Fork-Join" vs. "make it cleaner"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster iteration:&lt;/strong&gt; Fix specific issues, not vague concerns&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  For Teams
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shared vocabulary:&lt;/strong&gt; "That's a Sequencer with a mixed-pattern violation"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Onboarding acceleration:&lt;/strong&gt; New developers learn patterns, not tribal knowledge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced conflict:&lt;/strong&gt; Debates about style become discussions about patterns&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Implementing Pattern-Based Review
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Start Small
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Introduce the five patterns in a team meeting&lt;/li&gt;
&lt;li&gt;Start identifying patterns in PR descriptions: "This method is a Sequencer with 4 steps"&lt;/li&gt;
&lt;li&gt;Use pattern vocabulary in review comments&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Create Team Standards
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Document your pattern catalog with examples from your codebase&lt;/li&gt;
&lt;li&gt;Agree on step count limits (e.g., Sequencers have 2-5 steps)&lt;/li&gt;
&lt;li&gt;Define what "same abstraction level" means for your domain&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Build Into Process
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add pattern checklist to PR template&lt;/li&gt;
&lt;li&gt;Include pattern identification in code review training&lt;/li&gt;
&lt;li&gt;Create IDE snippets/templates for each pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Evolve and Refine
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Collect common violations and create team-specific guidelines&lt;/li&gt;
&lt;li&gt;Build a library of "before/after" examples from real PRs&lt;/li&gt;
&lt;li&gt;Consider tooling: static analysis rules for obvious violations&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Traditional code review asks: "Is this code good?" -- a question with infinite subjective answers.&lt;/p&gt;

&lt;p&gt;Pattern-based code review asks: "Is this a valid Sequencer? Does this Fork-Join have independent branches? Is this Leaf truly atomic?" -- questions with objective, verifiable answers.&lt;/p&gt;

&lt;p&gt;When you recognize structural patterns, review transforms from art appreciation into engineering inspection. Every function has a recognizable shape. Every shape has specific criteria. Every criterion has a clear pass/fail answer.&lt;/p&gt;

&lt;p&gt;The result: faster reviews, better feedback, and code that improves systematically rather than accidentally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The patterns aren't new -- you've been writing Sequencers, Fork-Joins, and Iterations your whole career. What's new is naming them, recognizing them explicitly, and using that recognition to make code review objective and systematic.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Want to dive deeper into pattern-based code structure? Check out &lt;a href="https://pragmatica.dev" rel="noopener noreferrer"&gt;Java Backend Coding Technology&lt;/a&gt; for a complete methodology built on these principles.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>codereview</category>
      <category>java</category>
      <category>patterns</category>
      <category>bestpractices</category>
    </item>
    <item>
      <title>Java Should Stop Trying To Be Like Everybody Else</title>
      <dc:creator>Sergiy Yevtushenko</dc:creator>
      <pubDate>Thu, 18 Dec 2025 23:12:26 +0000</pubDate>
      <link>https://dev.to/siy/java-should-stop-trying-to-be-like-everybody-else-5c78</link>
      <guid>https://dev.to/siy/java-should-stop-trying-to-be-like-everybody-else-5c78</guid>
      <description>&lt;h1&gt;
  
  
  Java Should Stop Trying To Be Like Everybody Else
&lt;/h1&gt;

&lt;h2&gt;
  
  
  The Wrong Competition
&lt;/h2&gt;

&lt;p&gt;Java is losing the container wars. A typical Spring Boot microservice ships as a 70-200 MB fat JAR, stuffed into a container image that easily crosses 300 MB. Go produces a 10-15 MB static binary. Rust often beats that. The industry response has been predictable: GraalVM native images, Alpine base images, multi-stage Docker builds, endless optimization of the wrong thing.&lt;/p&gt;

&lt;p&gt;Here's what nobody talks about: the actual business logic in that 200 MB artifact - the code your developers write - typically weighs &lt;strong&gt;2 to 500 kilobytes&lt;/strong&gt;. The rest is framework code, an embedded web server, a JSON library, logging infrastructure, and a bundled JVM. All of it duplicated across every single service in your fleet.&lt;/p&gt;

&lt;p&gt;One team using WildFly Swarm's skinny packaging took their application from 45 megabytes down to 2,243 bytes. That's not a typo. Two kilobytes. A 20,000x reduction by removing everything that wasn't their code.&lt;/p&gt;

&lt;p&gt;The question isn't how to make Java containers smaller. The question is: why are we packaging this way at all?&lt;/p&gt;




&lt;h2&gt;
  
  
  Java's Forgotten DNA
&lt;/h2&gt;

&lt;p&gt;Java was never designed to produce self-contained binaries. This is not a weakness - it's a fundamental design decision that the industry has been fighting against for a decade.&lt;/p&gt;

&lt;p&gt;The original target platform wasn't servers. It was set-top boxes and web consoles - &lt;em&gt;managed environments&lt;/em&gt; where a runtime handled lifecycle, security, and resource allocation. This heritage shows everywhere in the language:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic class loading&lt;/strong&gt; - classes can be loaded, unloaded, and replaced at runtime&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The module system&lt;/strong&gt; (JPMS) - explicit dependency boundaries and encapsulation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hot-swapping&lt;/strong&gt; - update code without restarting the process&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OSGi&lt;/strong&gt; - an entire ecosystem built around dynamic module deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't accidents or legacy baggage. They're capabilities that most languages would kill for. And we've abandoned all of them to stuff JVMs into containers like it's 2014 and we just discovered Docker.&lt;/p&gt;

&lt;p&gt;The current deployment model actively fights Java's strengths. We take a language optimized for dynamic, managed execution and freeze it into static artifacts. We take a runtime designed to host multiple applications efficiently and spin up one instance per service. We pay the JVM's startup cost - optimized for long-running processes - on every container spawn.&lt;/p&gt;




&lt;h2&gt;
  
  
  Turn the Model Inside-Out
&lt;/h2&gt;

&lt;p&gt;What if we stopped packaging the JVM with every service? What if we deployed just the business logic and let the environment handle everything else?&lt;/p&gt;

&lt;p&gt;This isn't a hypothetical. It's how Java EE worked for two decades. The application server provided HTTP handling, connection pooling, transaction management, security. Your WAR file contained your code and nothing else. We called it "heavyweight" and ran away to microservices - but we replaced one 200 MB application server with forty 200 MB fat JARs, and called it progress.&lt;/p&gt;

&lt;p&gt;The insight isn't "go back to Java EE." It's to recognize what Java EE got right: &lt;strong&gt;separation of application logic from infrastructure concerns&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A modern realization of this principle:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What moves to the environment:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP request handling and routing&lt;/li&gt;
&lt;li&gt;Authentication and authorization&lt;/li&gt;
&lt;li&gt;Logging, metrics, and tracing&lt;/li&gt;
&lt;li&gt;Service discovery and load balancing&lt;/li&gt;
&lt;li&gt;Connection management for databases and external APIs&lt;/li&gt;
&lt;li&gt;Lifecycle management and health checking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What stays in the artifact:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Business logic&lt;/li&gt;
&lt;li&gt;Domain models&lt;/li&gt;
&lt;li&gt;That's it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your deployment artifact becomes a thin module - kilobytes, not megabytes. The runtime environment provides everything else, configured once, updated independently, consistent across all services.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Payoff: Instant Scaling
&lt;/h2&gt;

&lt;p&gt;When your deployment unit drops from 200 MB to 200 KB, everything changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sub-millisecond startup.&lt;/strong&gt; A thin module loads in microseconds. No framework initialization, no classpath scanning, no connection pool warmup - the environment already has all that running. With some pre-warming tricks, startup becomes virtually instant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Effortless horizontal scaling.&lt;/strong&gt; The environment can spin up new instances as fast as it can allocate memory. Scaling from 1 to 100 instances isn't a capacity planning exercise - it's a configuration value. Scale-to-zero becomes practical because cold start doesn't exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource efficiency at fleet scale.&lt;/strong&gt; Instead of running 40 JVMs (one per service) each consuming 200-500 MB of heap, you run a handful of environment instances that host all your modules. The shared runtime, shared libraries, and shared connection pools dramatically reduce total memory footprint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplified operations.&lt;/strong&gt; No more "works on my machine." The environment is the same everywhere - dev, staging, production. Infrastructure upgrades (JVM version, security patches, library updates) happen once, at the environment level, not per-service.&lt;/p&gt;




&lt;h2&gt;
  
  
  Transparent Distribution (Almost)
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. When the environment controls service lifecycle and inter-service communication, it can provide guarantees that are impossible in conventional deployments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Calls between modules become environment-managed.&lt;/strong&gt; If your module instance is alive, calls to other modules succeed - the environment handles routing, retries, and failover transparently. No more debugging whether the circuit breaker configuration matches the load balancer timeout matches the container health check interval.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Location transparency.&lt;/strong&gt; Modules don't know or care where other modules run. The environment distributes them across available resources and handles all the networking. Moving a module to a different node requires zero code changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lifecycle notifications.&lt;/strong&gt; When the environment needs to drain a node or rebalance load, it notifies affected modules. Graceful shutdown becomes a first-class concept, not something you bolt on with preStop hooks and SIGTERM handlers.&lt;/p&gt;

&lt;p&gt;There's one constraint: &lt;strong&gt;externally visible entry points must be idempotent.&lt;/strong&gt; Without this property, the environment can't safely retry operations during network hiccups or instance migration. But this isn't really a new constraint - it's already a best practice for any distributed system. You're just making it explicit.&lt;/p&gt;




&lt;h2&gt;
  
  
  Native CI/CD
&lt;/h2&gt;

&lt;p&gt;The deployment model collapses to something surprisingly simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You publish.&lt;/strong&gt; Your artifact goes to a Maven repository - local, organization-wide, or public. This is already your artifact format. No container registry, no Dockerfile, no image layers to optimize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment deploys.&lt;/strong&gt; It watches the repository (or receives a webhook), pulls the new artifact, and rolls it out according to your configured strategy - canary, blue-green, rolling, whatever you need. The deployment strategy is configuration, not pipeline code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's it.&lt;/strong&gt; No docker build. No image push. No kubectl apply. No Helm chart templating. No ArgoCD sync. Just publish to Maven and watch it deploy.&lt;/p&gt;

&lt;p&gt;The environment itself can run containerized if you need to deploy to existing Kubernetes infrastructure or cloud container services. But your applications don't know or care. They're just modules in a repository.&lt;/p&gt;

&lt;p&gt;I've been exploring what this would look like in practice. The results are promising enough to be worth sharing - but that's a topic for another post.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Strategic Question
&lt;/h2&gt;

&lt;p&gt;Java's current trajectory is clear: keep chasing Go and Rust on their terms. Smaller native images. Faster startup through ahead-of-time compilation. More aggressive dead code elimination. Each step is a partial solution that fights the language's design.&lt;/p&gt;

&lt;p&gt;There's another path: stop competing on binary size and cold start, and instead leverage what Java actually does well. Dynamic runtime. Hot deployment. Mature module systems. The most sophisticated JIT compiler in existence, which needs long-running processes to reach peak performance.&lt;/p&gt;

&lt;p&gt;This isn't about nostalgia for application servers. It's about recognizing that the current model - every service is an isolated container with its own JVM - creates massive operational overhead while abandoning Java's genuine advantages.&lt;/p&gt;

&lt;p&gt;The infrastructure to do this properly is starting to emerge. The pieces exist: Java's module system is mature, the JVM's dynamic capabilities never went away, and the operational pain of container-per-service is now obvious enough that people are looking for alternatives.&lt;/p&gt;

&lt;p&gt;Whether this comes from a new runtime, a framework evolution, or a rethinking of how we use existing tools - the direction is clear. Java shouldn't try to be a better Go. It should be a better Java.&lt;/p&gt;

</description>
      <category>java</category>
      <category>kubernetes</category>
      <category>runtime</category>
      <category>deployment</category>
    </item>
    <item>
      <title>Pragmatica Lite</title>
      <dc:creator>Sergiy Yevtushenko</dc:creator>
      <pubDate>Wed, 08 Oct 2025 16:56:30 +0000</pubDate>
      <link>https://dev.to/siy/pragmatica-lite-143i</link>
      <guid>https://dev.to/siy/pragmatica-lite-143i</guid>
      <description>&lt;p&gt;Functional style library for Java&lt;br&gt;
&lt;a href="https://github.com/siy/pragmatica-lite" rel="noopener noreferrer"&gt;https://github.com/siy/pragmatica-lite&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This library is a core part of Java Backend Coding Technology: &lt;a href="https://pragmatica.dev/" rel="noopener noreferrer"&gt;https://pragmatica.dev/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest2025"&gt;2025 Hacktoberfest Writing Challenge&lt;/a&gt;: Maintainer Spotlight&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hacktoberfest</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
