<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Compatibility on Brian Faust</title><link>https://wimdy.works/tags/compatibility/</link><description>Recent content in Compatibility on Brian Faust</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Mon, 01 Jan 0001 00:00:00 +0000</lastBuildDate><atom:link href="https://wimdy.works/tags/compatibility/rss.xml" rel="self" type="application/rss+xml"/><item><title>A Rewrite Can Change Data Without Changing the Price</title><link>https://wimdy.works/thoughts/a-rewrite-can-change-data-without-changing-the-price/</link><pubDate>Thu, 01 Oct 2026 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/a-rewrite-can-change-data-without-changing-the-price/</guid><description>&lt;p&gt;The Go history append preserved the existing JSON. That looked reasonable:
read a stored transition list, add the new transition, leave everything else
alone. Unfortunately, leaving everything else alone wasn&amp;rsquo;t what the PHP
implementation did.&lt;/p&gt;
&lt;p&gt;The shared idempotency updater in my rating engine read history through an
Eloquent array cast, appended a transition, and assigned the resulting value
back to the model. That round trip could turn an old nested &lt;code&gt;{}&lt;/code&gt; into &lt;code&gt;[]&lt;/code&gt;.
The Go translation preserved &lt;code&gt;{}&lt;/code&gt; instead. Both could complete the operation
and return the same price while storing different histories.&lt;/p&gt;</description></item><item><title>Stored Data Is a Caller You Cannot Find with Code Search</title><link>https://wimdy.works/thoughts/stored-data-is-a-caller-you-cannot-find-with-code-search/</link><pubDate>Sun, 01 Dec 2019 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/stored-data-is-a-caller-you-cannot-find-with-code-search/</guid><description>&lt;p&gt;An enum migration looked mechanical. A package-backed value object became a
native PHP backed enum. The domain concept stayed the same, the new cases were
easy to search, and current code wrote the canonical values. It was exactly the
kind of refactor that looks finished after a clean source search.&lt;/p&gt;
&lt;p&gt;Then an older row loaded a lowercase value. The native enum expected the same
word with different casing and rejected it during hydration.&lt;/p&gt;</description></item><item><title>Deprecation Is a Migration, Not a Warning</title><link>https://wimdy.works/thoughts/deprecation-is-a-migration-not-a-warning/</link><pubDate>Tue, 01 Oct 2019 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/deprecation-is-a-migration-not-a-warning/</guid><description>&lt;p&gt;A billing rewrite introduced durable export records before removing several
legacy queue jobs. Each new worker carried a record identifier. The export
type, payload snapshot, attempts, failure details, and retry state lived in the
database. A registry selected the current handler.&lt;/p&gt;
&lt;p&gt;That order matters. A queued object is not merely code waiting to run. Its
serialized class name and properties are data, even if nobody thinks of them as
a schema. Delete the class while an old payload remains, and PHP can deserialize
it as an incomplete object which no longer has the method the worker expects.&lt;/p&gt;</description></item><item><title>Renaming a Field Is a Protocol Migration</title><link>https://wimdy.works/thoughts/renaming-a-field-is-a-protocol-migration/</link><pubDate>Thu, 01 Nov 2018 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/renaming-a-field-is-a-protocol-migration/</guid><description>&lt;p&gt;An API changes &lt;code&gt;serviceIds&lt;/code&gt; to &lt;code&gt;deliveryOptionIds&lt;/code&gt;. The new name describes the
domain better, and the implementation is easier to read. It is probably the
better name. That is also beside the point.&lt;/p&gt;
&lt;p&gt;An existing client still sends:&lt;/p&gt;
&lt;figure class="code-figure"&gt;
 &lt;div class="code-block" data-copy-code&gt;
 &lt;button class="copy-code" type="button" aria-label="Copy code"&gt;copy&lt;/button&gt;&lt;span class="sr-only" data-copy-status role="status" aria-live="polite"&gt;&lt;/span&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;serviceIds&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;express&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;The request now fails validation before any application code runs. Nothing
about the client&amp;rsquo;s intent changed. The server chose a cleaner name and turned
that preference into a breaking protocol change.&lt;/p&gt;</description></item><item><title>Data Outlives the Code That Created It</title><link>https://wimdy.works/thoughts/data-outlives-the-code-that-created-it/</link><pubDate>Fri, 01 Dec 2017 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/data-outlives-the-code-that-created-it/</guid><description>&lt;p&gt;A failed queue record kept returning. Its payload named a mail class the
running application could not resolve correctly, so retrying it could only
repeat the same failure.&lt;/p&gt;
&lt;p&gt;The workaround was blunt: once a minute, delete failed records whose
payload matched that job. It stopped an unusable delivery attempt from
disturbing the queue, but it obviously did not make the payload readable.&lt;/p&gt;
&lt;p&gt;That small incident exposes an awkward storage contract. Serializing an
executable object does not merely store its arguments. It preserves facts about
the code which created it: class name, namespace, property layout, and sometimes
framework behavior. The payload can live much longer than those facts.&lt;/p&gt;</description></item></channel></rss>