<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Software-Architecture on Corebaseit — Design System Engineering · POS · Payments · Security</title><link>https://corebaseit.com/tags/software-architecture/</link><description>Recent content in Software-Architecture on Corebaseit — Design System Engineering · POS · Payments · Security</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><managingEditor>contact@corebaseit.com (Vincent Bevia)</managingEditor><webMaster>contact@corebaseit.com (Vincent Bevia)</webMaster><lastBuildDate>Thu, 27 Aug 2026 00:00:00 +0200</lastBuildDate><atom:link href="https://corebaseit.com/tags/software-architecture/index.xml" rel="self" type="application/rss+xml"/><item><title>From Monolith to Microservices: Architecture Is the Destination, Migration Is the Plan</title><link>https://corebaseit.com/corebaseit_posts/monolith-to-microservices-migration/</link><pubDate>Thu, 27 Aug 2026 00:00:00 +0200</pubDate><author>contact@corebaseit.com (Vincent Bevia)</author><guid>https://corebaseit.com/corebaseit_posts/monolith-to-microservices-migration/</guid><description>&lt;img src="https://corebaseit.com/diagrams/monolith-to-microservices-migration.png" alt="Featured image of post From Monolith to Microservices: Architecture Is the Destination, Migration Is the Plan" />&lt;p>A monolith can become difficult to change long before it becomes impossible to run.&lt;/p>
&lt;p>Deployments start affecting unrelated areas. A change in refunds requires regression testing checkout. One database becomes the integration layer between half the system. Teams wait for each other. Releases grow larger, rollback becomes scarier, and nobody is completely sure where one business capability ends and another begins.&lt;/p>
&lt;p>At that point, somebody usually draws this:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic1.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic1.png" alt="From monolithic to microservices 1" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>The destination looks simple.&lt;/p>
&lt;p>The migration is not.&lt;/p>
&lt;p>Moving from a monolithic architecture to microservices is not primarily a matter of creating smaller applications. It is a &lt;strong>controlled transfer of responsibility&lt;/strong> across boundaries while the existing system continues serving production traffic.&lt;/p>
&lt;p>That makes it both an architectural problem and a project-management problem.&lt;/p>
&lt;p>A useful migration therefore needs more than a target architecture.&lt;/p>
&lt;p>It needs a path.&lt;/p>
&lt;h2 id="start-with-the-reason-not-microservices">Start with the reason, not microservices
&lt;/h2>&lt;p>Before decomposing anything, ask a more uncomfortable question:&lt;/p>
&lt;blockquote>
&lt;p>What problem are we actually trying to solve?&lt;/p>&lt;/blockquote>
&lt;p>Microservices introduce their own costs: network failures, distributed tracing, eventual consistency, deployment coordination, infrastructure overhead, data ownership problems, versioned contracts, retries, duplicate messages, and substantially more operational surface area.&lt;/p>
&lt;p>If the real problem is simply poor module boundaries inside the codebase, a modular monolith may be the better answer.&lt;/p>
&lt;p>A migration should therefore start with measurable architectural drivers:&lt;/p>
&lt;ul>
&lt;li>independent deployment of high-change capabilities;&lt;/li>
&lt;li>different scaling characteristics;&lt;/li>
&lt;li>clearer team ownership;&lt;/li>
&lt;li>fault isolation;&lt;/li>
&lt;li>regulatory or security boundaries;&lt;/li>
&lt;li>independent technology evolution;&lt;/li>
&lt;li>reducing coupling around specific business capabilities.&lt;/li>
&lt;/ul>
&lt;p>This is where the previous discussion about &lt;a class="link" href="https://corebaseit.com/corebaseit_posts/spike-first-adr-second/" >Spikes and ADRs&lt;/a> becomes useful.&lt;/p>
&lt;p>A Spike can investigate whether extracting a capability actually improves the characteristics we care about.&lt;/p>
&lt;p>An ADR can record why that boundary was selected and which consequences were knowingly accepted.&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic2.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic2.png" alt="From monolithic to microservices 2" style="max-width: 40%; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>The ADR tells us &lt;strong>why&lt;/strong>.&lt;/p>
&lt;p>The migration plan tells us &lt;strong>how and when&lt;/strong>.&lt;/p>
&lt;p>Those are different artifacts.&lt;/p>
&lt;h2 id="do-not-migrate-the-monolith-migrate-a-capability">Do not migrate the monolith. Migrate a capability.
&lt;/h2>&lt;p>Imagine a payment platform containing:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic3.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic3.png" alt="From monolithic to microservices 3" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>A dangerous project starts with:&lt;/p>
&lt;blockquote>
&lt;p>We are migrating the monolith to microservices.&lt;/p>&lt;/blockquote>
&lt;p>That scope is enormous and gives the programme very few meaningful intermediate success states.&lt;/p>
&lt;p>A better question is:&lt;/p>
&lt;blockquote>
&lt;p>Which capability should we extract first?&lt;/p>&lt;/blockquote>
&lt;p>Suppose Refunds is selected because it has clear business semantics, changes frequently, integrates with unreliable external providers, and has different scaling and failure characteristics from checkout.&lt;/p>
&lt;p>Now the project becomes much more concrete:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic4.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic4.png" alt="From monolithic to microservices 4" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>That is something architecture and delivery teams can actually manage.&lt;/p>
&lt;h2 id="the-target-architecture-is-not-the-migration-architecture">The target architecture is not the migration architecture
&lt;/h2>&lt;p>This distinction is easy to miss.&lt;/p>
&lt;p>The desired end state might be:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic5.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic5.png" alt="From monolithic to microservices 5" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>But production cannot teleport from the current state to that diagram.&lt;/p>
&lt;p>For some period of time, the real architecture will look more like this:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic6.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic6.png" alt="From monolithic to microservices 6" style="max-width: 60%; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>That intermediate state may live for weeks or months.&lt;/p>
&lt;p>It is not temporary clutter to ignore.&lt;/p>
&lt;p>It &lt;strong>is the production architecture&lt;/strong> during the migration.&lt;/p>
&lt;p>And it needs to be designed.&lt;/p>
&lt;h2 id="the-strangler-fig-pattern">The Strangler Fig pattern
&lt;/h2>&lt;p>One of the best-known approaches to incremental replacement is Martin Fowler&amp;rsquo;s &lt;strong>Strangler Fig Application&lt;/strong> pattern.&lt;/p>
&lt;p>Instead of rewriting the entire system and switching everything at once, new functionality gradually grows around the old system.&lt;/p>
&lt;p>Conceptually:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic7.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic7.png" alt="From monolithic to microservices 7" style="max-width: 50%; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>But the percentages are less important than the principle:&lt;/p>
&lt;blockquote>
&lt;p>Replace capabilities incrementally while keeping the system operational.&lt;/p>&lt;/blockquote>
&lt;p>This creates something extremely valuable in architecture programmes:&lt;/p>
&lt;p>&lt;strong>reversibility.&lt;/strong>&lt;/p>
&lt;p>If the first extraction performs badly, creates unexpected coupling, or proves operationally expensive, the organisation has learned something without betting the entire platform.&lt;/p>
&lt;p>That is architecture behaving like risk management.&lt;/p>
&lt;h2 id="migration-needs-phases">Migration needs phases
&lt;/h2>&lt;p>Large architectural initiatives become much easier to reason about when separated into explicit phases.&lt;/p>
&lt;p>A practical structure might look like this:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic8.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic8.png" alt="From monolithic to microservices 8" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;h3 id="phase-1--discovery">Phase 1 — Discovery
&lt;/h3>&lt;p>Understand why the capability is being extracted.&lt;/p>
&lt;p>Map dependencies.&lt;/p>
&lt;p>Identify database tables, APIs, scheduled jobs, events, operational dashboards, external integrations, and other modules that depend on it.&lt;/p>
&lt;p>Run Spikes where uncertainty is material.&lt;/p>
&lt;p>Produce ADRs for significant decisions.&lt;/p>
&lt;p>The output is not yet a microservice.&lt;/p>
&lt;p>It is &lt;strong>reduced uncertainty&lt;/strong>.&lt;/p>
&lt;h3 id="phase-2--establish-the-boundary">Phase 2 — Establish the boundary
&lt;/h3>&lt;p>Define what the new service owns.&lt;/p>
&lt;p>For Refunds, that might mean:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Refund Service owns:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- refund lifecycle
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- refund state machine
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- idempotency
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- provider interaction
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- retry policy
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- refund persistence
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- refund events
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The boundary matters more than the framework.&lt;/p>
&lt;p>A Spring Boot service with the wrong business boundary is still the wrong architecture.&lt;/p>
&lt;h3 id="phase-3--build-alongside-the-monolith">Phase 3 — Build alongside the monolith
&lt;/h3>&lt;p>Do not immediately remove the existing path.&lt;/p>
&lt;p>Create the new service while production continues through the monolith.&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic9.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic9.png" alt="From monolithic to microservices 9" style="max-width: 60%; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>This gives the team somewhere to migrate traffic gradually.&lt;/p>
&lt;h3 id="phase-4--validate-in-parallel">Phase 4 — Validate in parallel
&lt;/h3>&lt;p>Before trusting the new path with all production traffic, compare behaviour.&lt;/p>
&lt;p>Depending on the capability, techniques can include:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic10.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic10.png" alt="From monolithic to microservices 10" style="max-width: 60%; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>The second path does not necessarily execute external side effects. For payments and refunds, blindly duplicating a production command would obviously be dangerous.&lt;/p>
&lt;p>But calculations, transformations, routing decisions, or state transitions can often be compared safely.&lt;/p>
&lt;p>This turns migration from:&lt;/p>
&lt;blockquote>
&lt;p>We think the new service works.&lt;/p>&lt;/blockquote>
&lt;p>into:&lt;/p>
&lt;blockquote>
&lt;p>Across 1.8 million representative operations, the old and new implementations agreed in 99.99% of the cases, and we understand the remaining differences.&lt;/p>&lt;/blockquote>
&lt;p>That is a much stronger basis for moving traffic.&lt;/p>
&lt;h2 id="move-traffic-not-hope">Move traffic, not hope
&lt;/h2>&lt;p>Eventually the new service must become authoritative.&lt;/p>
&lt;p>Do not think only in terms of deployment.&lt;/p>
&lt;p>Think in terms of &lt;strong>traffic migration&lt;/strong>.&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic11.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic1.png" alt="From monolithic to microservices 11" style="max-width: 90%; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>A migration might progress through controlled stages:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Stage 1 100% old 0% new
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Stage 2 95% old 5% new
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Stage 3 75% old 25% new
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Stage 4 25% old 75% new
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Stage 5 0% old 100% new
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The exact percentages are implementation details.&lt;/p>
&lt;p>The important part is that each stage has &lt;strong>entry criteria, observations, and rollback conditions&lt;/strong>.&lt;/p>
&lt;p>For example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Proceed if:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>error rate &amp;lt; threshold
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p95 latency &amp;lt; threshold
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>duplicate rate = expected
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>reconciliation = clean
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>DLQ growth = normal
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>provider errors = understood
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Architecture has now become measurable.&lt;/p>
&lt;h2 id="data-is-usually-the-hard-part">Data is usually the hard part
&lt;/h2>&lt;p>Extracting Java or TypeScript code into another repository is rarely the hardest part.&lt;/p>
&lt;p>Data ownership is.&lt;/p>
&lt;p>The monolith may currently do this:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic12.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic12.png" alt="From monolithic to microservices 12" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>Creating four services that all continue directly accessing those same tables gives us:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic13.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic13.png" alt="From monolithic to microservices 13" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>We have distributed the applications while preserving much of the original coupling.&lt;/p>
&lt;p>This is sometimes a valid &lt;strong>transitional state&lt;/strong>.&lt;/p>
&lt;p>It is a poor place to stop accidentally.&lt;/p>
&lt;p>A stronger destination is explicit ownership:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic14.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic14.png" alt="From monolithic to microservices 14" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>Now another problem appears.&lt;/p>
&lt;p>A database transaction can no longer quietly coordinate everything.&lt;/p>
&lt;p>Distributed boundaries force previously hidden architectural questions into the open:&lt;/p>
&lt;ul>
&lt;li>What is the source of truth?&lt;/li>
&lt;li>Which service owns the state transition?&lt;/li>
&lt;li>What happens when a downstream call fails?&lt;/li>
&lt;li>Do we need eventual consistency?&lt;/li>
&lt;li>What is retried?&lt;/li>
&lt;li>What must be idempotent?&lt;/li>
&lt;li>What happens if an event is delivered twice?&lt;/li>
&lt;li>How do we reconcile inconsistent states?&lt;/li>
&lt;/ul>
&lt;p>Microservices do not eliminate complexity.&lt;/p>
&lt;p>They &lt;strong>move complexity across boundaries&lt;/strong>.&lt;/p>
&lt;h2 id="project-management-has-to-follow-the-architecture">Project management has to follow the architecture
&lt;/h2>&lt;p>Traditional project plans often describe migration in technical tasks:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Create repository
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Create service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Create database
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Implement endpoints
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Deploy service
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>All of those tasks can be completed while the migration itself remains nowhere near finished.&lt;/p>
&lt;p>A more meaningful plan tracks &lt;strong>capability ownership&lt;/strong>.&lt;/p>
&lt;p>For example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Refund Extraction
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[✓] Boundary agreed
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[✓] ADRs accepted
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[✓] Service operational
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[✓] Observability available
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[✓] Data ownership established
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[✓] Shadow validation passed
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[✓] 5% production traffic
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[✓] 25% production traffic
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ ] 100% production traffic
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ ] Old refund path disabled
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ ] Old database access removed
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ ] Dead code removed
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This changes what &amp;ldquo;done&amp;rdquo; means.&lt;/p>
&lt;p>The service existing is not the milestone.&lt;/p>
&lt;p>The responsibility having moved is.&lt;/p>
&lt;h2 id="every-migration-step-needs-an-exit-condition">Every migration step needs an exit condition
&lt;/h2>&lt;p>One of the most useful disciplines in architecture programmes is defining what allows the team to move to the next phase.&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic15.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic15.png" alt="From monolithic to microservices 15" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>Without exit criteria, migrations tend to move according to calendar pressure:&lt;/p>
&lt;blockquote>
&lt;p>We planned to switch on Thursday.&lt;/p>&lt;/blockquote>
&lt;p>With exit criteria, the decision becomes evidence-based:&lt;/p>
&lt;blockquote>
&lt;p>Error rate, latency and reconciliation are inside the agreed thresholds, so we can increase traffic.&lt;/p>&lt;/blockquote>
&lt;p>That is a very different engineering culture.&lt;/p>
&lt;h2 id="observability-is-part-of-the-migration-architecture">Observability is part of the migration architecture
&lt;/h2>&lt;p>A migration without observability is extremely difficult to control.&lt;/p>
&lt;p>Before moving production traffic, the new boundary should expose enough information to answer:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Is it working?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Is it slower?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Is it failing differently?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Are retries increasing?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Are duplicate requests appearing?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Where is time being spent?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Can we correlate the request across systems?
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That means metrics, logs, and distributed traces are not something to &amp;ldquo;add later.&amp;rdquo;&lt;/p>
&lt;p>They are part of the migration mechanism.&lt;/p>
&lt;p>During the transition, a trace may cross both worlds:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic16.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic16.png" alt="From monolithic to microservices 16" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>Without correlation across that boundary, operational complexity increases precisely when the architecture is already at its most complicated.&lt;/p>
&lt;h2 id="decommissioning-is-part-of-the-project">Decommissioning is part of the project
&lt;/h2>&lt;p>Migration projects have a dangerous moment:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>New service works.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Production uses it.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Everyone celebrates.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>But the old implementation remains.&lt;/p>
&lt;p>Six months later:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Refund Service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> +
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Old Refund Module
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> +
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Old Tables
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> +
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Old Jobs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> +
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Compatibility Code
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> +
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Temporary Routing
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The organisation now owns more architecture than before the migration.&lt;/p>
&lt;p>Decommissioning therefore belongs in the original plan.&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic17.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic17.png" alt="From monolithic to microservices 17" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>Deleting the old architecture is not cleanup.&lt;/p>
&lt;p>It is the final migration phase.&lt;/p>
&lt;h2 id="architecture-and-project-management-meet-in-the-middle">Architecture and project management meet in the middle
&lt;/h2>&lt;p>A system architect can draw an excellent target:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic18.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic18.png" alt="From monolithic to microservices 18" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>A project manager can build an excellent roadmap:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Q1 → Q2 → Q3 → Q4
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Neither is sufficient alone.&lt;/p>
&lt;p>The useful artifact connects them:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic19.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic19.png" alt="From monolithic to microservices 19" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>This is where architecture stops being a picture of the future and becomes an executable strategy.&lt;/p>
&lt;h2 id="the-migration-itself-is-architecture">The migration itself is architecture
&lt;/h2>&lt;p>There are really three architectures involved:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>CURRENT STATE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> │
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ▼
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>TRANSITION ARCHITECTURE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> │
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ▼
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>TARGET STATE
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Teams naturally spend most of their design effort on the first and third.&lt;/p>
&lt;p>The middle deserves just as much attention.&lt;/p>
&lt;p>During migration, the organisation may temporarily operate duplicate paths, compatibility APIs, routing rules, event bridges, shared databases, shadow traffic, feature flags, and synchronization mechanisms.&lt;/p>
&lt;p>Those components may never appear in the final diagram.&lt;/p>
&lt;p>They still need architecture decisions, ownership, observability, security, testing, and explicit retirement plans.&lt;/p>
&lt;p>That is why a large architectural migration is not simply a refactoring exercise.&lt;/p>
&lt;p>It is the controlled evolution of a running system.&lt;/p>
&lt;h2 id="a-useful-mental-model">A useful mental model
&lt;/h2>&lt;p>The entire approach can be reduced to:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/monolithic20.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/monolithic20.png" alt="From monolithic to microservices 20" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>Or even more compactly:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Architecture defines the destination. Migration architecture defines the safe path. Project management makes that path executable.&lt;/strong>&lt;/p>&lt;/blockquote>
&lt;p>A monolith does not become a healthy microservice architecture because enough services were created.&lt;/p>
&lt;p>The migration succeeds when responsibilities, data ownership, traffic, operational ownership, and failure handling have moved deliberately — and the old architecture can finally be deleted.&lt;/p>
&lt;p>That is a much more meaningful definition of done.&lt;/p>
&lt;h2 id="references">References
&lt;/h2>&lt;ol>
&lt;li>Fowler, M. — &lt;em>Strangler Fig Application&lt;/em>. MartinFowler.com.&lt;/li>
&lt;li>Newman, S. — &lt;em>Monolith to Microservices: Evolutionary Patterns to Transform Your Monolith&lt;/em>. O&amp;rsquo;Reilly Media.&lt;/li>
&lt;li>Newman, S. — &lt;em>Building Microservices&lt;/em>, 2nd Edition. O&amp;rsquo;Reilly Media.&lt;/li>
&lt;li>Ford, N., Richards, M., Sadalage, P. &amp;amp; Dehghani, Z. — &lt;em>Software Architecture: The Hard Parts&lt;/em>. O&amp;rsquo;Reilly Media.&lt;/li>
&lt;li>Richards, M. &amp;amp; Ford, N. — &lt;em>Fundamentals of Software Architecture: An Engineering Approach&lt;/em>. O&amp;rsquo;Reilly Media.&lt;/li>
&lt;li>Nygard, M. — &amp;ldquo;Documenting Architecture Decisions.&amp;rdquo;&lt;/li>
&lt;li>Fowler, M. — &lt;em>Feature Toggles (aka Feature Flags)&lt;/em>.&lt;/li>
&lt;li>Corebaseit — &lt;a class="link" href="https://corebaseit.com/corebaseit_posts/spike-first-adr-second/" >Spike First, ADR Second: Evidence and Rationale in System Design&lt;/a>.&lt;/li>
&lt;/ol></description></item><item><title>Spike First, ADR Second: Evidence and Rationale in System Design</title><link>https://corebaseit.com/corebaseit_posts/spike-first-adr-second/</link><pubDate>Mon, 24 Aug 2026 00:00:00 +0200</pubDate><author>contact@corebaseit.com (Vincent Bevia)</author><guid>https://corebaseit.com/corebaseit_posts/spike-first-adr-second/</guid><description>&lt;img src="https://corebaseit.com/diagrams/Spike_and_ADR_Decision_Loop.png" alt="Featured image of post Spike First, ADR Second: Evidence and Rationale in System Design" />&lt;p>System design discussions often collapse into technology comparisons: Kafka or SQS, PostgreSQL or DynamoDB, synchronous or asynchronous, monolith or microservices. Those choices matter. They are not the whole problem.&lt;/p>
&lt;p>Architectural work has two other obligations that diagrams do not carry by themselves:&lt;/p>
&lt;ol>
&lt;li>How did the team gather enough evidence to decide?&lt;/li>
&lt;li>Why was this option chosen over the alternatives that were still on the table?&lt;/li>
&lt;/ol>
&lt;p>Two lightweight practices address those obligations: &lt;strong>Spikes&lt;/strong> and &lt;strong>Architecture Decision Records (ADRs)&lt;/strong>. They solve different problems. Used together under uncertainty, they form a simple decision loop — investigate, decide, document — that keeps future teams from treating intentional trade-offs as accidents.&lt;/p>
&lt;p>This post defines each practice, shows how they connect, and grounds the pattern in a payment-system example: asynchronous refund processing with external partner latency, retries, and idempotency. The POS framing draws on &lt;a class="link" href="https://corebaseit.com/my-books/" target="_blank" rel="noopener"
>&lt;em>POINT OF SALE ARCHITECTURE&lt;/em>&lt;/a> (&lt;em>the book&lt;/em>), especially Chapter 6 (architectural principles and separation of concerns), Chapter 14 (offline / store-and-forward queues, retries, idempotency), and Chapter 15 (backend timeouts, safe retries, STAN/RRN correlation).&lt;/p>
&lt;p>Related reading: &lt;a class="link" href="https://corebaseit.com/corebaseit_posts/double-charging/" >double charging and idempotency&lt;/a>, &lt;a class="link" href="https://corebaseit.com/corebaseit_posts/offline-emv-vs-store-and-forward/" >offline EMV vs store-and-forward&lt;/a>.&lt;/p>
&lt;h2 id="claims-to-keep-separate">Claims to keep separate
&lt;/h2>&lt;p>&lt;strong>Confirmed practice and sources:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>An ADR is a short record of an architecturally significant decision, typically covering context, decision, and consequences (Michael Nygard, 2011; Thoughtworks Technology Radar — Lightweight Architecture Decision Records).&lt;/li>
&lt;li>A Spike (from Extreme Programming) is a time-boxed investigation used to reduce technical uncertainty before committing to an implementation path.&lt;/li>
&lt;li>Payment backends that retry across unreliable partners must assume duplicate delivery and enforce idempotency; store-and-forward and authorization retries make this explicit (&lt;em>the book&lt;/em>, Ch. 14–15).&lt;/li>
&lt;li>Architecture is largely trade-off analysis among competing characteristics, not selection of a universally “best” technology (Richards &amp;amp; Ford, &lt;em>Fundamentals of Software Architecture&lt;/em>).&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Interpretation (practitioner method):&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>“Spike first, ADR second” is a useful default under uncertainty. It is not a rule that every ADR requires a Spike, or that every Spike must produce an ADR.&lt;/li>
&lt;li>The refund / SQS example below is illustrative. Your broker, ordering needs, and partner SLAs will differ; the method transfers, the product choice may not.&lt;/li>
&lt;/ul>
&lt;h2 id="architecture-contains-uncertainty">Architecture contains uncertainty
&lt;/h2>&lt;p>Consider a refund processing path where an external GDS or airline API can be slow or temporarily unavailable:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/Spike first, ADR second 1.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/Spike first, ADR second 1.png" alt="Spike first, ADR second 1" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>Asynchronous processing is a reasonable starting assumption: the external system should not block the merchant-facing API indefinitely. That assumption does not answer the next layer of questions:&lt;/p>
&lt;ul>
&lt;li>Managed queue (for example SQS) or log-oriented broker (for example Kafka)?&lt;/li>
&lt;li>What ordering guarantees are actually required — global, per refund, or none?&lt;/li>
&lt;li>Can messages be delivered more than once?&lt;/li>
&lt;li>How do retries, dead-letter queues, and worker crashes interact?&lt;/li>
&lt;li>Is replay a real requirement for this workflow, or only an attractive feature?&lt;/li>
&lt;li>What throughput and latency budget does the partner path impose?&lt;/li>
&lt;/ul>
&lt;p>Drawing another box on the diagram papers over those unknowns. Naming the unknowns is more useful: the team does not know yet. That is the entry condition for a Spike.&lt;/p>
&lt;p>In POS systems the same pattern appears whenever the stack sits between a deterministic payment state machine and an unreliable upstream — store-and-forward sync, scheme timeouts, late issuer responses, and duplicate suppression via STAN/RRN or dedicated idempotency keys (&lt;em>the book&lt;/em>, Ch. 14–15; see also &lt;a class="link" href="https://corebaseit.com/corebaseit_posts/double-charging/" >double charging&lt;/a>).&lt;/p>
&lt;h2 id="spike-reduce-uncertainty-before-committing">Spike: reduce uncertainty before committing
&lt;/h2>&lt;p>A Spike is a &lt;strong>time-boxed technical investigation&lt;/strong> aimed at a specific question. It is not the production implementation. It may include a small proof of concept, a benchmark, an integration test against a partner sandbox, latency or throughput measurement, or structured comparison of two or three alternatives.&lt;/p>
&lt;p>The Spike starts with a question, for example:&lt;/p>
&lt;blockquote>
&lt;p>Can a managed FIFO/work-queue service meet the ordering, retry, and throughput requirements of our refund processing path, if consumers are designed for at-least-once delivery?&lt;/p>&lt;/blockquote>
&lt;p>Give the investigation a hard time box (often one to three days). Structure the work so findings are reusable:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/Spike first ADR second 2.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/Spike first ADR second 2.png" alt="Spike first ADR second 2" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>A useful Spike ends with evidence, not preference. Typical findings for this kind of path:&lt;/p>
&lt;ul>
&lt;li>Throughput is adequate for projected refund volume.&lt;/li>
&lt;li>Ordering is required only per refund identifier, not globally.&lt;/li>
&lt;li>Duplicate delivery must be assumed; workers need idempotent handlers.&lt;/li>
&lt;li>Retries plus a dead-letter path cover the partner failure modes in scope.&lt;/li>
&lt;li>Log replay is attractive but unnecessary for this workflow’s recovery model.&lt;/li>
&lt;/ul>
&lt;p>The decision can now rest on measured constraints. Months later, though, someone will still ask why the queue technology is what it is. Evidence that lived only in a chat thread or a demo branch will be gone. That is the ADR’s job.&lt;/p>
&lt;h2 id="adr-preserve-the-reasoning-behind-the-decision">ADR: preserve the reasoning behind the decision
&lt;/h2>&lt;p>An &lt;strong>Architecture Decision Record&lt;/strong> is a short document that records one architecturally significant decision and the forces around it. Nygard’s original shape is Status, Context, Decision, and Consequences. Many teams add Alternatives Considered; that extension is useful in payment systems where several brokers or sync models are always in play.&lt;/p>
&lt;p>A lightweight example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>ADR-017: Use a managed work queue for refund processing
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Status
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Accepted
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Context
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Refund processing is asynchronous. The external GDS can be slow or
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>unavailable. Workers can crash mid-flight. At-least-once delivery
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>must be assumed; duplicate refund side effects are unacceptable.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Decision
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Use a managed work queue (SQS-class) for refund jobs, with
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>idempotent consumers keyed by refund id (and STAN/RRN where the
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>payment network is involved).
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Alternatives considered
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Log-oriented broker (Kafka-class) for replay-first design
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Self-managed broker (RabbitMQ-class)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Synchronous refund calls from the API
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Consequences
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+ Managed operations and built-in retry / DLQ patterns
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+ Simple worker model aligned to job processing
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Consumers must be idempotent under duplicate delivery
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Weaker fit if full event replay becomes a primary requirement
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The decision line alone is cheap; the architecture diagram already shows the queue. The durable value is context, alternatives, and accepted downsides. Without that, a later engineer can “fix” an intentional trade-off — for example by introducing a replay-heavy broker when the original Spike showed replay was out of scope.&lt;/p>
&lt;h2 id="spike--adr-as-a-loop">Spike + ADR as a loop
&lt;/h2>&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/Spike first ADR second 3.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/Spike first ADR second 3.png" alt="Spike first ADR second 3" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>Compact form:&lt;/p>
&lt;blockquote>
&lt;p>Spike = investigate.&lt;br>
ADR = decide and document.&lt;/p>&lt;/blockquote>
&lt;p>A Spike does not always produce an ADR. An ADR does not always require a Spike. Some decisions are constrained enough that experimentation would waste calendar time. When uncertainty is material — partner behaviour, ordering, duplicate risk, certification impact — the combination is hard to beat on cost relative to the confusion it prevents.&lt;/p>
&lt;h2 id="why-diagrams-are-not-enough">Why diagrams are not enough
&lt;/h2>&lt;p>System diagrams show &lt;strong>what exists&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>API → queue → workers → PostgreSQL / partner API
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>They do not naturally show &lt;strong>why it exists&lt;/strong>: why this broker, why asynchronous rather than synchronous, why pessimistic rather than optimistic concurrency, why REST rather than an event bus for a given boundary.&lt;/p>
&lt;p>A working architecture therefore has a second layer behind the boxes:&lt;/p>
&lt;p style="text-align: center;">
&lt;a href="https://corebaseit.com/diagrams/Spike first ADR second 4.png" target="_blank" rel="noopener">
&lt;img src="https://corebaseit.com/diagrams/Spike first ADR second 4.png" alt="Spike first ADR second 4" style="max-width: 720px; width: 100%; height: auto;" />
&lt;/a>
&lt;/p>
&lt;p>In POS application design, Chapter 6’s principles — separation of concerns, deterministic state management, security by design, targeted observability — are the kinds of constraints that should appear in ADR context when a team chooses how refunds, reversals, or store-and-forward sync are structured (&lt;em>the book&lt;/em>, Ch. 6, 14).&lt;/p>
&lt;h2 id="architecture-is-trade-off-work">Architecture is trade-off work
&lt;/h2>&lt;p>Richards and Ford argue that architecture is fundamentally about understanding and balancing trade-offs. There is rarely a universally correct choice. A log-oriented broker is not simply “better” than a work queue. Microservices are not simply “better” than a modular monolith. Event-driven flows are not simply “better” than synchronous request/response.&lt;/p>
&lt;p>Each option improves some characteristics and degrades others. The productive question shifts from “What is the best technology?” to “Given our requirements and constraints, which trade-offs are we willing to accept?”&lt;/p>
&lt;p>Spikes surface those trade-offs under load, latency, and failure. ADRs make the accepted set explicit. &lt;em>Software Architecture: The Hard Parts&lt;/em> pushes the same style into decomposition, data ownership, coupling, orchestration versus choreography, and evolution — problems that rarely have perfect answers, only recorded compromises.&lt;/p>
&lt;p>Payment systems sharpen the stakes: a wrong retry policy can double-post; a missing idempotency key can create chargebacks and reconciliation debt; a store-and-forward design that ignores scheme and liability constraints can pass a demo and fail certification (&lt;em>the book&lt;/em>, Ch. 14–15).&lt;/p>
&lt;h2 id="keep-both-practices-light">Keep both practices light
&lt;/h2>&lt;p>Neither practice needs bureaucracy.&lt;/p>
&lt;ul>
&lt;li>A Spike answers a question inside a time box. It should not become an open-ended research programme.&lt;/li>
&lt;li>An ADR preserves a decision in a page or two. It should not become a 40-page design specification.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Question → Spike → Evidence → Trade-offs → Decision → ADR → Architecture
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Months later, when someone asks why the system looks the way it does, the answer need not be tribal memory about an engineer who left. The reasoning is still in the repository, next to the code that implements it.&lt;/p>
&lt;h2 id="references">References
&lt;/h2>&lt;ol>
&lt;li>Nygard, M. — “Documenting Architecture Decisions,” Cognitect blog, 15 Nov 2011. &lt;a class="link" href="https://www.cognitect.com/blog/2011/11/15/documenting-architecture-decisions" target="_blank" rel="noopener"
>https://www.cognitect.com/blog/2011/11/15/documenting-architecture-decisions&lt;/a>&lt;/li>
&lt;li>Thoughtworks Technology Radar — Lightweight Architecture Decision Records (Adopt). &lt;a class="link" href="https://www.thoughtworks.com/radar/techniques/lightweight-architecture-decision-records" target="_blank" rel="noopener"
>https://www.thoughtworks.com/radar/techniques/lightweight-architecture-decision-records&lt;/a>&lt;/li>
&lt;li>Fowler, M. — “Architecture Decision Record” (bliki). &lt;a class="link" href="https://martinfowler.com/bliki/ArchitectureDecisionRecord.html" target="_blank" rel="noopener"
>https://martinfowler.com/bliki/ArchitectureDecisionRecord.html&lt;/a>&lt;/li>
&lt;li>Richards, M. &amp;amp; Ford, N. — &lt;em>Fundamentals of Software Architecture: An Engineering Approach&lt;/em> (2nd ed.). O’Reilly.&lt;/li>
&lt;li>Ford, N., Richards, M., Sadalage, P. &amp;amp; Dehghani, Z. — &lt;em>Software Architecture: The Hard Parts&lt;/em>. O’Reilly.&lt;/li>
&lt;li>Extreme Programming / Kent Beck — Spike Solution (time-boxed investigation before committing to an implementation).&lt;/li>
&lt;li>Bevia, V. — &lt;em>Point-of-Sale Systems Architecture&lt;/em>, Chapters 6, 14, and 15: &lt;a class="link" href="https://corebaseit.com/my-books/" target="_blank" rel="noopener"
>https://corebaseit.com/my-books/&lt;/a>&lt;/li>
&lt;li>Corebaseit — &lt;a class="link" href="https://corebaseit.com/corebaseit_posts/double-charging/" >Double charging&lt;/a>; &lt;a class="link" href="https://corebaseit.com/corebaseit_posts/offline-emv-vs-store-and-forward/" >Offline EMV vs store-and-forward&lt;/a>.&lt;/li>
&lt;/ol></description></item></channel></rss>