<?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: Oriol Moura</title>
    <description>The latest articles on DEV Community by Oriol Moura (@oriol_moura_802b96c34bd3f).</description>
    <link>https://dev.to/oriol_moura_802b96c34bd3f</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4122214%2F806e9923-fffa-4e03-998e-34fabbda3c1b.png</url>
      <title>DEV Community: Oriol Moura</title>
      <link>https://dev.to/oriol_moura_802b96c34bd3f</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oriol_moura_802b96c34bd3f"/>
    <language>en</language>
    <item>
      <title>Surviving the Chaos: Injecting Faults with the ChaosEngineeringMasterDeck</title>
      <dc:creator>Oriol Moura</dc:creator>
      <pubDate>Thu, 22 Oct 2026 13:24:57 +0000</pubDate>
      <link>https://dev.to/oriol_moura_802b96c34bd3f/surviving-the-chaos-injecting-faults-with-the-chaosengineeringmasterdeck-103d</link>
      <guid>https://dev.to/oriol_moura_802b96c34bd3f/surviving-the-chaos-injecting-faults-with-the-chaosengineeringmasterdeck-103d</guid>
      <description>&lt;p&gt;Abstract: How we turned "will it hold up?" into testable hypotheses using a deck of chaos experiments (the ChaosEngineeringMasterDeck), and what we uncovered when degrading the latency of a payment microservice in a real-world environment.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why Break Things on Purpose
In distributed systems, partial failure is the normal state, not an exception. With dozens of services, each with 99.9% availability, the composite availability of a request traversing 10 of them in series is approximately $0.999^{10} \approx 99.0\%$. That represents roughly 87 hours of downtime per year that no one anticipated by evaluating services individually. Unit and integration tests verify what code does when everything works; they reveal nothing about system behavior when the network slows down, a node disappears, or a downstream dependency stalls.
Chaos Engineering is the discipline of experimenting on a system to build confidence in its capability to withstand turbulent conditions. Formalized in the Principles of Chaos Engineering (born out of Netflix's experience with Chaos Monkey), it follows the empirical scientific cycle:&lt;/li&gt;
&lt;li&gt; Define steady state via observable business or system metrics (not just "the server is up").&lt;/li&gt;
&lt;li&gt; Formulate a hypothesis: the steady state will persist despite fault $X$.&lt;/li&gt;
&lt;li&gt; Inject realistic faults reflecting real-world events (latency, packet loss, node or availability zone outages).&lt;/li&gt;
&lt;li&gt; Attempt to refute the hypothesis by contrasting control and experimental groups.&lt;/li&gt;
&lt;li&gt; Contain the blast radius and abort immediately if safety thresholds are breached.
The Mindset Shift
The traditional approach focuses on preventing failures (maximizing MTBF). The resilience approach assumes failures are inevitable and optimizes for recovery time and graceful degradation (minimizing MTTR and user impact). In practice, this reframes the question from "How do we prevent the payment service from going down?" to "What does the user experience when it goes down, and how quickly do we recover?"
Regarding staging versus production: mature implementations target production, as only production reflects real traffic, authentic data, and live configurations. However, the correct progression is staging first, followed by production with a minimal blast radius. An experiment should only transition environments once automated rollback and abort triggers are thoroughly validated.&lt;/li&gt;
&lt;li&gt;Dissecting the ChaosEngineeringMasterDeck
In our context, the Master Deck is a version-controlled catalog of chaos experiments modeled as playing cards, maintained in Git alongside application code. The card deck analogy serves a practical operational purpose: each card represents a self-contained unit that can be drawn during a Game Day, requiring mandatory fields. If any required field is empty, the card cannot be played.&lt;/li&gt;
&lt;/ol&gt;

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

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

&lt;p&gt;Why This Format?&lt;br&gt;
The value lies not in the novelty of the "deck" metaphor, but in enforcing explicit hypotheses and strict abort criteria. The most common pitfall in chaos experiments is executing without a hypothesis: injecting a fault, observing arbitrary behavior, and drawing unfounded conclusions. The deck enforces scientific rigor upfront. Stored in Git, each card undergoes code review just like production changes.&lt;br&gt;
Example Card in YAML&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REDE-03&lt;/span&gt;
&lt;span class="na"&gt;titulo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Latência alta no serviço de pagamento&lt;/span&gt;
&lt;span class="na"&gt;naipe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Rede&lt;/span&gt;
&lt;span class="na"&gt;hipotese&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="s"&gt;Com 2000 ms de latência adicional em payment-service para 5% do tráfego,&lt;/span&gt;
  &lt;span class="s"&gt;o checkout mantém p99 &amp;lt; 800 ms e taxa de erro &amp;lt; 1%.&lt;/span&gt;
&lt;span class="na"&gt;variaveis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;independentes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;delay_ms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;2000&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;trafego_afetado&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5%"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;duracao&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10m"&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;dependentes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;p99_checkout&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;erro_5xx&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;threads_ativas&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;estado_circuit_breaker&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;metricas_controle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;p99_checkout_ms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;800&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;erro_5xx_pct&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;1.0&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;raio_explosao&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;escopo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;namespace&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;staging-canary"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;trafego&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5%"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;duracao_max&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10m"&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;aborto&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;erro_5xx_pct&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;por&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;60s"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;conversao_checkout&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cai&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;p.p."&lt;/span&gt;
&lt;span class="na"&gt;padroes_esperados&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;circuit-breaker&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;fallback&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Case Study: Card NET-03
Architecture Under Test
An e-commerce platform running on AWS with the following checkout flow:
• API Gateway $\rightarrow$ order-service (Spring Boot 3, Java 21) $\rightarrow$ payment-service (Spring Boot) $\rightarrow$ External Payment Provider.
• order-service persists state to Amazon RDS (PostgreSQL, Multi-AZ).
• Workloads run on Amazon EKS with Horizontal Pod Autoscaler (HPA), distributed across three Availability Zones.
• Observability powered by Micrometer + Prometheus + Grafana, with distributed tracing via OpenTelemetry.
The critical failure domain is the synchronous invocation order-service $\rightarrow$ payment-service. It is a textbook candidate for cascading failure: if payment stalls, worker threads in order-service become blocked waiting for responses, starving the connection and thread pools until an otherwise healthy upstream service stops serving traffic entirely.
Hypothesis
With an additional 2000 ms of latency injected into 5% of traffic destined for payment-service, checkout maintains p99 &amp;lt; 800 ms and 5xx errors &amp;lt; 1%, because the circuit breaker will trip open and the fallback mechanism will enqueue the transaction for asynchronous processing.
Fault Injection
Using Chaos Mesh (equivalent to AWS Fault Injection Service, Litmus, or Toxiproxy):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chaos-mesh.org/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkChaos&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rede-03-latencia-pagamento&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging-canary&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;delay&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fixed-percent&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5"&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;namespaces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;staging-canary&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;labelSelectors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payment-service&lt;/span&gt;
  &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;latency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2000ms"&lt;/span&gt;
    &lt;span class="na"&gt;jitter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;200ms"&lt;/span&gt;
  &lt;span class="na"&gt;direction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;to&lt;/span&gt;
  &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10m"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Blast Radius &amp;amp; Containment&lt;br&gt;
The blast radius is strictly bound along three dimensions prior to execution:&lt;br&gt;
• Scope: Restricted exclusively to the staging-canary namespace; zero impact on other application pods or databases.&lt;br&gt;
• Traffic: 5% of requests, isolated via header-based routing at the API Gateway.&lt;br&gt;
• Duration: 10 minutes, configured natively in the resource definition so that if connection to the cluster is lost, the experiment terminates automatically.&lt;br&gt;
The emergency abort command (kubectl delete networkchaos net-03-payment-latency) was tested beforehand, complemented by automated abort webhooks triggered by Alertmanager whenever safety thresholds were violated.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Observability and Results
Telemetry Tracked&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Note: Business metrics validate technical indicators. A degraded system might maintain low latency and low error rates by prematurely returning an empty screen, all while failing 100% of revenue-generating transactions.&lt;br&gt;
Round 1: Hypothesis Refuted&lt;br&gt;
During the first run, the hypothesis failed. Illustrative experimental data:&lt;/p&gt;

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

&lt;p&gt;Distributed tracing quickly isolated root causes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; The underlying HTTP client (RestTemplate) lacked an explicit read timeout (defaulting to infinite).&lt;/li&gt;
&lt;li&gt; The Resilience4j circuit breaker was only configured to trip on explicit application exceptions, not slow calls.
Consequently, 2-second calls were never registered as failures. The circuit breaker remained closed while Tomcat's worker threads rapidly exhausted the pool. This yielded the primary architectural insight: a resilience pattern was declared in code, yet remained completely inoperative under real failure dynamics.
Remediation
We deployed three targeted fixes:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;yml&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Resilience4j&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;resilience4j:&lt;/span&gt;
  &lt;span class="nl"&gt;circuitbreaker:&lt;/span&gt;
    &lt;span class="nl"&gt;instances:&lt;/span&gt;
      &lt;span class="nl"&gt;payment:&lt;/span&gt;
        &lt;span class="nl"&gt;slidingWindowType:&lt;/span&gt; &lt;span class="no"&gt;COUNT_BASED&lt;/span&gt;
        &lt;span class="nl"&gt;slidingWindowSize:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
        &lt;span class="nl"&gt;minimumNumberOfCalls:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
        &lt;span class="nl"&gt;failureRateThreshold:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
        &lt;span class="nl"&gt;slowCallDurationThreshold:&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;   &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;chamada&lt;/span&gt; &lt;span class="n"&gt;lenta&lt;/span&gt; &lt;span class="n"&gt;passa&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;contar&lt;/span&gt;
        &lt;span class="nl"&gt;slowCallRateThreshold:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
        &lt;span class="nl"&gt;waitDurationInOpenState:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
        &lt;span class="nl"&gt;permittedNumberOfCallsInHalfOpenState:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="nl"&gt;timelimiter:&lt;/span&gt;
    &lt;span class="nl"&gt;instances:&lt;/span&gt;
      &lt;span class="nl"&gt;payment:&lt;/span&gt;
        &lt;span class="nl"&gt;timeoutDuration:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
  &lt;span class="nl"&gt;bulkhead:&lt;/span&gt;
    &lt;span class="nl"&gt;instances:&lt;/span&gt;
      &lt;span class="nl"&gt;payment:&lt;/span&gt;
        &lt;span class="nl"&gt;maxConcurrentCalls:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;             &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;isola&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;

&lt;span class="nd"&gt;@CircuitBreaker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"payment"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fallbackMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"enfileirarPagamento"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Bulkhead&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"payment"&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;PagamentoResultado&lt;/span&gt; &lt;span class="nf"&gt;cobrar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&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;paymentClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cobrar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Fallback: não perde o pedido; marca como PAGAMENTO_PENDENTE e publica em fila&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;PagamentoResultado&lt;/span&gt; &lt;span class="nf"&gt;enfileirarPagamento&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;filaPagamentos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&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="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;PagamentoResultado&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pendente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&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="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, low-level socket and connect timeouts (500 ms connect, 1000 ms read) were set on the HTTP client pool, as TimeLimiter does not guarantee cancellation of blocking I/O calls on underlying threads.&lt;br&gt;
Round 2: Hypothesis Upheld&lt;/p&gt;

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

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

&lt;p&gt;The architecture maintained resilience: the circuit opened quickly, the bulkhead prevented thread pool exhaustion, and the asynchronous fallback preserved incoming orders. The engineering tradeoff was deliberate and accepted by business stakeholders: a small fraction of customers received an immediate "payment processing" notification rather than a hard checkout failure.&lt;br&gt;
Resilience Patterns in Action&lt;br&gt;
• Timeout: Enforces a ceiling on wait times, shedding resources promptly.&lt;br&gt;
• Circuit Breaker: Fails fast against degraded dependencies, preventing backlog build-up.&lt;br&gt;
• Bulkhead: Isolates critical resources (thread pools, concurrency quotas) per dependency.&lt;br&gt;
• Queue-based Fallback (Graceful Degradation): Trades immediate strong consistency for system availability.&lt;br&gt;
• Auto Scaling (HPA): Proved ineffective during the incident. Because the bottleneck was blocked I/O rather than CPU saturation, horizontal scaling would have merely amplified concurrency pressure against the already degraded payment backend.&lt;br&gt;
Other Cards in the Deck&lt;br&gt;
The framework accommodates wider failure domains, each governed by its own blast radius constraints:&lt;br&gt;
• AZ-01 (Complete Availability Zone Outage): Verifies traffic reroutes cleanly across surviving AZs and confirms AWS Aurora / RDS Multi-AZ failover completes within SLA (typically 60–120s; actual failover time must be empirically measured rather than assumed). Executed via AWS FIS.&lt;br&gt;
• DATA-02 (Database Connectivity Loss): Validates exponential backoff with full jitter on retries, alongside HikariCP connection pool recovery mechanics when pool connections become stale.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Conclusion
Key Takeaways&lt;/li&gt;
&lt;li&gt; Unverified resilience is not resilience. The circuit breaker existed in source control, yet failed to protect the system because it had never been tested against latency-based degradation.&lt;/li&gt;
&lt;li&gt; Slowness is worse than outright failure. Downstream crashes fail fast; downstream latency silently exhausts upstream threads and memory.&lt;/li&gt;
&lt;li&gt; Hypotheses must be falsifiable and validated by business metrics. Relying solely on technical signals masks functional edge cases.&lt;/li&gt;
&lt;li&gt; Blast radiuses and automated aborts are prerequisites, not polish. They establish the safety boundary required to run experiments routinely.&lt;/li&gt;
&lt;li&gt; Every experiment must drive traceable action: a bug fix, an alert adjustment, or an updated runbook, followed by re-executing the card to validate remediation (as shown in Round 2).
Cultural Impact on DevOps
The most enduring payoff of chaos engineering is cultural. By treating failure as an objective target of empirical study rather than human error, teams shift toward proactive architectural reviews and blameless post-mortems. Engineers begin developing with failure modes in mind ("What happens when this API call hangs?"), while operations teams validate runbooks in realistic conditions. Game Days double as practical incident-response training, cutting Mean Time to Detect (MTTD) and Mean Time to Resolve (MTTR).
Next Steps: Automate low-risk cards inside CI/CD pipelines for continuous staging execution, reserve high-impact cards for scheduled Game Days, and track maturity through concrete KPIs: MTTR reduction, issues identified per experiment, and first-round card pass rates.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>devops</category>
      <category>microservices</category>
      <category>sre</category>
      <category>testing</category>
    </item>
    <item>
      <title>The Strategy Pattern in Practice</title>
      <dc:creator>Oriol Moura</dc:creator>
      <pubDate>Sat, 12 Sep 2026 14:02:10 +0000</pubDate>
      <link>https://dev.to/oriol_moura_802b96c34bd3f/the-strategy-pattern-in-practice-2c7f</link>
      <guid>https://dev.to/oriol_moura_802b96c34bd3f/the-strategy-pattern-in-practice-2c7f</guid>
      <description>&lt;p&gt;*&lt;em&gt;1. Foundations — The Problem and the Theory *&lt;/em&gt;&lt;br&gt;
_1.1 Introduction _&lt;br&gt;
Strategy is a behavioral design pattern cataloged by the Gang of Four (Gamma, Helm, Johnson &amp;amp; Vlissides, &lt;br&gt;
1994). Its purpose is to encapsulate a family of interchangeable algorithms behind a common interface, &lt;br&gt;
allowing the algorithm used by an object to vary at runtime without changing the code of the client that &lt;br&gt;
invokes it. &lt;br&gt;
Unlike creational patterns (which deal with how objects are instantiated) or structural patterns (which deal &lt;br&gt;
with how objects compose), Strategy solves a behavioral problem: which business rule should run in a given &lt;br&gt;
context, and how to swap that rule without rewriting the class that uses it. &lt;br&gt;
1.2 The Problem &lt;br&gt;
Medium- and long-lived systems tend to accumulate payment methods, notification providers, shipping-cost &lt;br&gt;
algorithms, discount policies — any rule variation that grows over time. The naive implementation &lt;br&gt;
concentrates these variations in a single class, using a chain of conditionals:&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;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CREDIT_CARD"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
&lt;span class="c1"&gt;// Stripe logic &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;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PIX"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
&lt;span class="c1"&gt;// Central Bank logic &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;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"BOLETO"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
&lt;span class="c1"&gt;// issuing bank logic &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;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PAYPAL"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
&lt;span class="c1"&gt;// PayPal logic &lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// ... and so on &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This design violates the Open/Closed Principle: adding a new payment method requires editing an existing &lt;br&gt;
class that already concentrates logic for several distinct external integrations. In practice, on a real legacy &lt;br&gt;
system, this was exactly the bottleneck faced: a PaymentService class with more than 900 lines, low test &lt;br&gt;
coverage (testing one method risked breaking another due to shared side effects), and a commit history in &lt;br&gt;
which any localized change — even to a single gateway — required recompiling, retesting, and redeploying &lt;br&gt;
the entire service, increasing the risk of regression in already-stable payment flows. &lt;br&gt;
1.3 Concept &lt;br&gt;
Strategy solves this by extracting each algorithm variation into its own class, all implementing a common &lt;br&gt;
interface. The object that originally held the logic (the "Context") now depends only on the interface and &lt;br&gt;
receives — through dependency injection or configuration — which concrete implementation to use. &lt;br&gt;
A direct analogy from software development: think of the JDBC interface. Data-access code programs against &lt;br&gt;
java.sql.Connection and java.sql.Driver — never against a specific database implementation. Switching from &lt;br&gt;
PostgreSQL to MySQL doesn't require rewriting the persistence layer, only swapping the injected driver. &lt;br&gt;
Strategy applies exactly the same idea to business rules: the Context (the consumer of the behavior) never &lt;br&gt;
knows the concrete implementation, only the contract. &lt;br&gt;
*&lt;em&gt;2. Development — Case Study, Architecture, and Code &lt;br&gt;
2.1 Real-World Scenario *&lt;/em&gt;&lt;br&gt;
Scenario: a Payment Service microservice, responsible for processing payments for an e-commerce platform, &lt;br&gt;
needs to support four payment methods — credit card (via Stripe), Pix (via the Central Bank/SPI API), boleto &lt;br&gt;
(via the issuing bank), and PayPal — with a strong likelihood that new methods will be added next quarter &lt;br&gt;
(digital wallets, crypto assets). The architectural requirement is clear: adding a new payment method must &lt;br&gt;
not require changing or retesting the existing orchestration logic, only adding a new class.&lt;br&gt;
*&lt;em&gt;2.2 UML Class Diagram *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv7lhoei3p6rrolpz7gjb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv7lhoei3p6rrolpz7gjb.png" alt=" " width="797" height="113"&gt;&lt;/a&gt;&lt;br&gt;
**&lt;br&gt;
2.3 High-Level Architecture Diagram**&lt;/p&gt;

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

&lt;p&gt;*&lt;em&gt;2.4 Java Implementation *&lt;/em&gt;&lt;br&gt;
The interface defines the contract every payment strategy must fulfill: &lt;br&gt;
public interface PaymentStrategy { &lt;br&gt;
boolean supports(String method); &lt;br&gt;
PaymentResult pay(Order order); &lt;br&gt;
} &lt;br&gt;
Each external gateway becomes a concrete implementation, isolated and independently testable:&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;@Component&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;CreditCardPaymentStrategy&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;PaymentStrategy&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;StripeClient&lt;/span&gt; &lt;span class="n"&gt;stripeClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; 
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CreditCardPaymentStrategy&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;stripeClient&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;stripeClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stripeClient&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="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;supports&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;method&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"CREDIT_CARD"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equalsIgnoreCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
    &lt;span class="o"&gt;}&lt;/span&gt; 

    &lt;span class="nd"&gt;@Override&lt;/span&gt; 
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;PaymentResult&lt;/span&gt; &lt;span class="nf"&gt;pay&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="nc"&gt;StripeCharge&lt;/span&gt; &lt;span class="n"&gt;charge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stripeClient&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;order&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="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCardToken&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;PaymentResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charge&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="nc"&gt;PaymentStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPROVED&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="nd"&gt;@Component&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;PixPaymentStrategy&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;PaymentStrategy&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;PixClient&lt;/span&gt; &lt;span class="n"&gt;pixClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; 

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PixPaymentStrategy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PixClient&lt;/span&gt; &lt;span class="n"&gt;pixClient&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;pixClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pixClient&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="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;supports&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;method&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"PIX"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equalsIgnoreCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
    &lt;span class="o"&gt;}&lt;/span&gt; 

    &lt;span class="nd"&gt;@Override&lt;/span&gt; 
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;PaymentResult&lt;/span&gt; &lt;span class="nf"&gt;pay&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="nc"&gt;PixCharge&lt;/span&gt; &lt;span class="n"&gt;charge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pixClient&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;order&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PaymentResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTxId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;PaymentStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PENDING&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;BoletoPaymentStrategy and PayPalPaymentStrategy follow exactly the same shape — each isolated in its &lt;br&gt;
own class, with no coupling between them. &lt;br&gt;
The Context handles orchestration only: it selects the correct strategy, delegates execution, persists the &lt;br&gt;
result, and publishes the domain event. It never knows any gateway-specific detail:&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;@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;PaymentProcessor&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PaymentStrategy&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;strategies&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;PaymentRepository&lt;/span&gt; &lt;span class="n"&gt;paymentRepository&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;PaymentEventPublisher&lt;/span&gt; &lt;span class="n"&gt;eventPublisher&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; 

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PaymentProcessor&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;PaymentStrategy&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;strategies&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;paymentRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                             &lt;span class="nc"&gt;PaymentEventPublisher&lt;/span&gt; &lt;span class="n"&gt;eventPublisher&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;strategies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strategies&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;paymentRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paymentRepository&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;eventPublisher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventPublisher&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;PaymentResult&lt;/span&gt; &lt;span class="nf"&gt;processPayment&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;method&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="nc"&gt;PaymentStrategy&lt;/span&gt; &lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; 
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supports&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; 
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findFirst&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; 
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&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="nc"&gt;UnsupportedPaymentMethodException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; 

        &lt;span class="nc"&gt;PaymentResult&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;strategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pay&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;paymentRepository&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;PaymentRecord&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;method&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="n"&gt;eventPublisher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; 
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PaymentProcessedEvent&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;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&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="o"&gt;}&lt;/span&gt; 
&lt;span class="nc"&gt;Note&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="nc"&gt;Spring&lt;/span&gt; &lt;span class="n"&gt;automatically&lt;/span&gt; &lt;span class="n"&gt;injects&lt;/span&gt; &lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="n"&gt;bean&lt;/span&gt; &lt;span class="n"&gt;implementing&lt;/span&gt; &lt;span class="nc"&gt;PaymentStrategy&lt;/span&gt; &lt;span class="n"&gt;into&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;s&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;PaymentStrategy&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;manual&lt;/span&gt; &lt;span class="n"&gt;registration&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nc"&gt;Adding&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;fifth&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="n"&gt;comes&lt;/span&gt; &lt;span class="n"&gt;down&lt;/span&gt; 
&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;creating&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;annotated&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="nd"&gt;@Component&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="nc"&gt;PaymentProcessor&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;touched&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; 
&lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;affected&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; 
&lt;span class="nc"&gt;The&lt;/span&gt; &lt;span class="no"&gt;REST&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="n"&gt;simply&lt;/span&gt; &lt;span class="n"&gt;delegates&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keeping&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;presentation&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt; &lt;span class="n"&gt;decoupled&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt; 
&lt;span class="n"&gt;business&lt;/span&gt; &lt;span class="nl"&gt;rule:&lt;/span&gt; 
&lt;span class="nd"&gt;@RestController&lt;/span&gt; 
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/payments"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentController&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;PaymentProcessor&lt;/span&gt; &lt;span class="n"&gt;paymentProcessor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; 
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PaymentController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentProcessor&lt;/span&gt; &lt;span class="n"&gt;paymentProcessor&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;paymentProcessor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paymentProcessor&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="nd"&gt;@PostMapping&lt;/span&gt; 
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PaymentResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;pay&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;PaymentRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
&lt;span class="nc"&gt;PaymentResult&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;paymentProcessor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processPayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; 
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toOrder&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;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&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;em&gt;2.5 Pros and Cons *&lt;/em&gt;&lt;br&gt;
Advantages &lt;br&gt;
● Open/Closed Principle compliance: new payment methods are added by extension (a new class), &lt;br&gt;
not by modifying the Context. &lt;br&gt;
● Real testability: each strategy is tested in isolation with trivial mocks of its respective HTTP &lt;br&gt;
client/SDK; the Context is tested with fake strategies, without depending on any external gateway. &lt;br&gt;
● Elimination of cyclomatic complexity: the 900-line class with multiple if/else branches was replaced &lt;br&gt;
by five small, cohesive classes, each with a single responsibility (SRP). &lt;br&gt;
● Runtime flexibility: the strategy used depends on an input value (the payment method), not on &lt;br&gt;
conditional compilation or reflection. &lt;br&gt;
Costs and trade-offs &lt;br&gt;
● More classes to manage: a small project with only two payment methods may not justify the &lt;br&gt;
indirection — the pattern pays off once the variation is expected to grow. &lt;br&gt;
● The supports(method) method decentralizes selection logic; if each strategy decides on its own &lt;br&gt;
when it applies, discipline (or contract tests) is needed to prevent two strategies from claiming the &lt;br&gt;
same method simultaneously. &lt;br&gt;
● The API client still needs to supply a correct method identifier; Strategy does not by itself solve &lt;br&gt;
routing — it solves execution once routing has already been decided. &lt;br&gt;
● The indirection overhead (one extra interface call) is technically measurable but irrelevant next to &lt;br&gt;
the network latency of any external payment gateway — it is not a real argument against the &lt;br&gt;
pattern in this scenario. &lt;br&gt;
*&lt;em&gt;3. Conclusion &lt;br&gt;
3.1 Summary *&lt;/em&gt;&lt;br&gt;
The Strategy pattern resolved the architectural bottleneck by replacing a monolithic class coupled to multiple &lt;br&gt;
payment gateways with a set of independent strategies orchestrated by a lean Context. The gain is not merely &lt;br&gt;
cosmetic: it is a direct reduction in the cost and risk of evolving the system, measurable in the amount of &lt;br&gt;
code changed and the test surface affected by each new integration. &lt;br&gt;
3.2 Personal Take &lt;br&gt;
The most valuable part of implementing this refactor was not the pattern itself — it is one of the simplest in &lt;br&gt;
the GoF catalog — but the exercise of identifying exactly where behavioral variation was genuinely, &lt;br&gt;
unnecessarily coupled to the Context. A practical warning is worth stating: Strategy should not be applied &lt;br&gt;
preemptively to every if/else. It pays off when there is concrete evidence that the family of algorithms will &lt;br&gt;
grow or has already changed more than once — applying it too early, in a still-unstable domain, only adds &lt;br&gt;
indirection without return. &lt;br&gt;
*&lt;em&gt;3.3 Over to You *&lt;/em&gt;&lt;br&gt;
Have you ever dealt with a "do-everything" class that grew until it became a risk with every deploy? What &lt;br&gt;
strategy (pun intended) did you use to decouple that logic? Share in the comments — I'd like to know whether &lt;br&gt;
you reached for Strategy, Chain of Responsibility, or another approach.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>design</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
