<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Home on Brian Faust</title><link>https://vacua.dev/</link><description>Recent content in Home on Brian Faust</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Tue, 21 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://vacua.dev/rss.xml" rel="self" type="application/rss+xml"/><item><title>A Command Bus Must Pay for Its Indirection</title><link>https://vacua.dev/a-command-bus-must-pay-for-its-indirection/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/a-command-bus-must-pay-for-its-indirection/</guid><description>&lt;p&gt;Four Laravel routes handle two commands in the &lt;a href="https://github.com/faustbrian/vacua.dev/tree/main/editorial/reproductions/cmd-02"&gt;reproducible
fixture&lt;/a&gt;. Two routes inject typed handlers. Two inject Laravel&amp;rsquo;s
dispatcher. All four return 204, and both call graphs leave the same SQLite
rows behind.&lt;/p&gt;
&lt;p&gt;Then one line disappears from the dispatcher&amp;rsquo;s handler map. The bus route
still resolves its controller, constructs &lt;code&gt;CancelOrder&lt;/code&gt;, and enters the
pipeline. It returns 500 without selecting a handler. The direct controller
has no equivalent registry entry to lose because its constructor already
names &lt;code&gt;DirectCancelOrderHandler&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>A Composition Root Makes Choices Visible</title><link>https://vacua.dev/a-composition-root-makes-choices-visible/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/a-composition-root-makes-choices-visible/</guid><description>&lt;p&gt;Remove the &lt;code&gt;ProductPrices&lt;/code&gt; binding from a Laravel service provider, then ask
the container for &lt;code&gt;QuoteProduct&lt;/code&gt;. Laravel refuses to construct it:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Target [App\Application\ProductPrices] is not instantiable while building
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[App\Application\QuoteProduct].&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;Move the same lookup into &lt;code&gt;QuoteProduct::execute()&lt;/code&gt; and construction succeeds.
The missing dependency does not become visible until a quote request reaches
that line. The application object looks simpler because its constructor says
nothing. Its object graph is not simpler; part of the graph has moved into
method code and configuration.&lt;/p&gt;</description></item><item><title>A Hexagon Is Not a Directory Layout</title><link>https://vacua.dev/a-hexagon-is-not-a-directory-layout/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/a-hexagon-is-not-a-directory-layout/</guid><description>&lt;p&gt;A Laravel controller calls a catalogue API, reads &lt;code&gt;price_cents&lt;/code&gt;, and returns a
quote. Moving that HTTP code into &lt;code&gt;Application/QuoteProduct.php&lt;/code&gt; makes the
controller thinner. It also leaves the application service coupled to
Laravel&amp;rsquo;s HTTP client, the provider URL, and the provider&amp;rsquo;s JSON.&lt;/p&gt;
&lt;p&gt;The tree looks more architectural. The source dependencies have not moved.&lt;/p&gt;
&lt;p&gt;That difference becomes visible when the catalogue replaces &lt;code&gt;price_cents&lt;/code&gt;
with &lt;code&gt;price.amount_minor&lt;/code&gt;. A folder name cannot decide where the resulting
change lands. A useful hexagonal boundary can: application policy defines the
conversation it needs, while an outside adapter owns the provider mechanism.&lt;/p&gt;</description></item><item><title>A Mock Fortress Tests a Call Script</title><link>https://vacua.dev/a-mock-fortress-tests-a-call-script/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/a-mock-fortress-tests-a-call-script/</guid><description>&lt;p&gt;Two tests produce the same checkout quote. One builds five Mockery doubles,
specifies every argument, fixes their global call order, and makes a serializer
mock return the expected JSON. The other resolves the use case through
Laravel&amp;rsquo;s container, replaces one HTTP catalogue, and asserts the JSON emitted
by the real policies and serializer.&lt;/p&gt;
&lt;p&gt;Both are green. That tells us they agree with today&amp;rsquo;s code. It does not tell us
what either test will reject tomorrow.&lt;/p&gt;</description></item><item><title>A Pull Request Is a Review Narrative, Not a Template</title><link>https://vacua.dev/a-pull-request-is-a-review-narrative/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/a-pull-request-is-a-review-narrative/</guid><description>&lt;p&gt;Most pull-request templates start with good intentions and end as paperwork.&lt;/p&gt;
&lt;p&gt;They ask for a summary, testing instructions, screenshots, a ticket, a risk
assessment, a deployment plan, a rollback plan, and twelve checkboxes. A small
change answers half of them with “not applicable.” A large change fills them
with links. The template is complete, yet the reviewer still has to reverse
engineer the actual decision from the diff.&lt;/p&gt;
&lt;p&gt;The failure is not Markdown. It is treating the presence of headings as proof
that communication happened.&lt;/p&gt;</description></item><item><title>A Queued Command Changes the Contract</title><link>https://vacua.dev/a-queued-command-changes-the-contract/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/a-queued-command-changes-the-contract/</guid><description>&lt;p&gt;Send the same payment-capture request through two Laravel routes.&lt;/p&gt;
&lt;p&gt;The synchronous route returns 204 after the provider has created charge
&lt;code&gt;ch_001&lt;/code&gt; and the order records that reference. When the provider returns 503,
the HTTP request returns 500 and the order remains unpaid.&lt;/p&gt;
&lt;p&gt;The queued route returns 202 while the order is still unpaid and the provider
ledger is empty. Its response contains an operation URL. Cancel the order
before a worker starts and that operation later becomes &lt;code&gt;refused&lt;/code&gt;; the
provider is never called.&lt;/p&gt;</description></item><item><title>A Surviving Mutant Is a Question, Not a Score</title><link>https://vacua.dev/a-surviving-mutant-is-a-question/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/a-surviving-mutant-is-a-question/</guid><description>&lt;p&gt;Two PHPUnit suites are green. The first checks a known product. The second also
checks that a missing product throws &lt;code&gt;ProductNotFound&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Run two mutations against them. The extra assertion kills the missing-exception
defect, exactly as intended. Yet a 100% mutation-score gate rejects both suites.
The stronger suite finishes at 50% because a second mutation changes no behavior
for any input the method accepts.&lt;/p&gt;
&lt;p&gt;The gate has calculated its number correctly. It has not interpreted the
survivor.&lt;/p&gt;</description></item><item><title>A Valid Command Can Still Be Refused</title><link>https://vacua.dev/a-valid-command-can-still-be-refused/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/a-valid-command-can-still-be-refused/</guid><description>&lt;p&gt;Send this cancellation request to two orders:&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;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;reason&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;customer_request&amp;#34;&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 placed order returns 204 and becomes cancelled. The shipped order returns
409 and remains shipped. Both requests pass the same Laravel Form Request.&lt;/p&gt;
&lt;p&gt;Change the reason to &lt;code&gt;unknown&lt;/code&gt; and the result is different again: Laravel
returns 422 before the controller constructs a command. Three requests crossed
two different decision boundaries. Calling one result “valid” and the others
“invalid” hides the part of the system which made each decision.&lt;/p&gt;</description></item><item><title>An Interface Does Not Make a Fake Substitutable</title><link>https://vacua.dev/shared-contract-tests-make-substitutability-measurable/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/shared-contract-tests-make-substitutability-measurable/</guid><description>&lt;p&gt;An HTTP product catalogue and an in-memory fake both implement this interface:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ProductCatalogue&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/** @throws ProductNotFound */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;priceCents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$sku&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&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;Both return &lt;code&gt;10000&lt;/code&gt; for &lt;code&gt;CHAIR-BLACK&lt;/code&gt;. Both make the checkout test green. Both
pass PHP&amp;rsquo;s signature checks.&lt;/p&gt;
&lt;p&gt;Now seed one divergence. When the product is absent, the HTTP adapter throws
&lt;code&gt;ProductNotFound&lt;/code&gt; while the fake returns zero. The interface remains satisfied,
and the familiar checkout test still passes because it never asks for a
missing SKU.&lt;/p&gt;</description></item><item><title>Choose the Test Boundary from the Defect</title><link>https://vacua.dev/choose-the-test-boundary-from-the-defect/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/choose-the-test-boundary-from-the-defect/</guid><description>&lt;p&gt;Four test boundaries protect the same reservation flow. Then four defects
arrive:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a quantity of zero becomes valid;&lt;/li&gt;
&lt;li&gt;a database migration loses a uniqueness constraint;&lt;/li&gt;
&lt;li&gt;an inventory provider renames &lt;code&gt;available&lt;/code&gt; to &lt;code&gt;stock&lt;/code&gt;; and&lt;/li&gt;
&lt;li&gt;browser JavaScript submits an empty string instead of the entered quantity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Calling all four tests “feature tests” would tell us almost nothing. Putting
them into a pyramid would tell us how many tests we hope to own, but not which
one can catch each defect.&lt;/p&gt;</description></item><item><title>Coverage Tells You What Ran, Not What Your Tests Would Catch</title><link>https://vacua.dev/coverage-tells-you-what-ran/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/coverage-tells-you-what-ran/</guid><description>&lt;p&gt;Here are two PHPUnit suites for the same shipping-fee rule. Both report 100%
line coverage. Both also report 100% branch and path coverage. One suite lets
an off-by-one defect escape; the other catches it.&lt;/p&gt;
&lt;p&gt;Nothing is wrong with the coverage report. The mistake is asking it a question
it cannot answer.&lt;/p&gt;
&lt;p&gt;Coverage can tell us which executable structure a test run visited. It cannot
tell us whether the chosen inputs and assertions would notice a defect that
matters. The distinction sounds modest. It changes how a coverage target
should be used.&lt;/p&gt;</description></item><item><title>Intent Pull Requests</title><link>https://vacua.dev/specifications/intent-pull-requests/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/specifications/intent-pull-requests/</guid><description>&lt;h2 id="abstract"&gt;Abstract&lt;/h2&gt;
&lt;p&gt;The Intent Pull Requests Specification defines what a pull request must
communicate before people or automation decide whether to integrate it. A pull
request is a review artifact: it describes the complete proposed result, why
that result is needed, how the implementation achieves it, why that approach
was selected, what it affects, and what evidence supports its claims.&lt;/p&gt;
&lt;p&gt;A pull request resembles a small changelog because both explain change. Their
audiences and timing differ. A pull request helps reviewers decide whether a
proposal should become history. A changelog helps consumers understand history
that was released.&lt;/p&gt;</description></item><item><title>Prepare an Intent Pull Request</title><link>https://vacua.dev/skills/prepare-intent-pull-request/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/skills/prepare-intent-pull-request/</guid><description>&lt;p&gt;This skill applies the
&lt;a href="https://vacua.dev/specifications/intent-pull-requests/"&gt;Intent Pull Requests Specification&lt;/a&gt;.
It turns a complete branch diff, Project Profile, and verified decision sources
into a review-ready title, body, and portable record without opening a remote
pull request or inventing claims.&lt;/p&gt;
&lt;h2 id="install"&gt;Install&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://vacua.dev/skills/prepare-intent-pull-request/bundle.tar.gz"&gt;Download the complete skill package&lt;/a&gt;
or copy and run:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CODEX_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.codex&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/skills&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://vacua.dev/skills/prepare-intent-pull-request/bundle.tar.gz &lt;span class="se"&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; tar -xz -C &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CODEX_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.codex&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/skills&amp;#34;&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;h2 id="invoke"&gt;Invoke&lt;/h2&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$prepare-intent-pull-request prepare this branch for review&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href="https://vacua.dev/downloads/skills/prepare-intent-pull-request/SKILL.md"&gt;Read the raw SKILL.md&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Commit with Intent</title><link>https://vacua.dev/skills/commit-with-intent/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/skills/commit-with-intent/</guid><description>&lt;p&gt;This skill combines repository-safe Git packaging with the
&lt;a href="https://vacua.dev/specifications/intent-commits/"&gt;Intent Commits Specification&lt;/a&gt;. It keeps type,
scope, impact, migration, affected release units, and changeset links
evidence-bound. After committing, it uses ACK&amp;rsquo;s repository-aware link validator
to detect missing or contradictory Intent Changesets decisions.&lt;/p&gt;
&lt;p&gt;It composes the existing &lt;code&gt;commit-changes&lt;/code&gt; safety workflow instead of replacing
explicit staging, secret checks, line-length validation, or commit verification.&lt;/p&gt;
&lt;h2 id="install"&gt;Install&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://vacua.dev/skills/commit-with-intent/bundle.tar.gz"&gt;Download the complete skill package&lt;/a&gt;
or copy and run:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CODEX_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.codex&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/skills&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://vacua.dev/skills/commit-with-intent/bundle.tar.gz &lt;span class="se"&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; tar -xz -C &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CODEX_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.codex&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/skills&amp;#34;&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;h2 id="invoke"&gt;Invoke&lt;/h2&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$commit-with-intent commit the staged changes using our ACK profile&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 skill returns &lt;code&gt;NEEDS_INPUT&lt;/code&gt; instead of inventing scope, release impact,
migration guidance, issue references, or changeset identifiers.&lt;/p&gt;</description></item><item><title>Configure an Intent Project</title><link>https://vacua.dev/skills/configure-intent-project/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/skills/configure-intent-project/</guid><description>&lt;p&gt;This skill creates or reviews the
&lt;a href="https://vacua.dev/specifications/project-profile/"&gt;Project Profile&lt;/a&gt; shared by Intent Commits,
Intent Changesets, Intent Changelog, Release Manifests, and ACK. It discovers
real release units and streams instead of duplicating policy in each tool.&lt;/p&gt;
&lt;h2 id="install"&gt;Install&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://vacua.dev/skills/configure-intent-project/bundle.tar.gz"&gt;Download the complete skill package&lt;/a&gt;
or copy and run:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CODEX_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.codex&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/skills&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://vacua.dev/skills/configure-intent-project/bundle.tar.gz &lt;span class="se"&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; tar -xz -C &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CODEX_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.codex&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/skills&amp;#34;&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;h2 id="invoke"&gt;Invoke&lt;/h2&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$configure-intent-project configure ACK for this monorepo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href="https://vacua.dev/downloads/skills/configure-intent-project/SKILL.md"&gt;Read the raw SKILL.md&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>From Commit to Changelog: An Intent-Aware Release Pipeline</title><link>https://vacua.dev/from-commit-to-changelog/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/from-commit-to-changelog/</guid><description>&lt;p&gt;Most release processes postpone the important questions.&lt;/p&gt;
&lt;p&gt;A developer commits a change. A pull request describes some of it. Somebody
adds a changeset because CI demands a file. Much later, another person opens an
&lt;code&gt;Unreleased&lt;/code&gt; section and tries to reconstruct what users need to know.&lt;/p&gt;
&lt;p&gt;The tools are connected by chronology, but not by meaning.&lt;/p&gt;
&lt;p&gt;That is why release day becomes an archaeological exercise. The diff still
exists, but the reason, audience, migration path, affected application, and
release judgment have been scattered across Git, an issue tracker, review
comments, and somebody&amp;rsquo;s memory.&lt;/p&gt;</description></item><item><title>Intent Changelog</title><link>https://vacua.dev/specifications/intent-changelog/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/specifications/intent-changelog/</guid><description>&lt;h2 id="abstract"&gt;Abstract&lt;/h2&gt;
&lt;p&gt;The Intent Changelog Specification defines a structured release ledger
for software projects. It treats an unreleased release as a real release whose
publication date is not yet known, rather than as an inbox of uncategorized
changes.&lt;/p&gt;
&lt;p&gt;Each release record belongs to one release unit and contains complete,
categorized entries. An entry records what changed, why it changed, who needs
to know, its release impact, migration guidance, and its provenance. Projects
may define their own change types without forcing unrelated changes into a
fixed universal taxonomy.&lt;/p&gt;</description></item><item><title>Intent Changesets</title><link>https://vacua.dev/specifications/intent-changesets/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/specifications/intent-changesets/</guid><description>&lt;h2 id="abstract"&gt;Abstract&lt;/h2&gt;
&lt;p&gt;The Intent Changesets Specification defines a small, structured artifact
for one independently understandable release decision. A changeset explains
what consumers will experience, why the change exists, which release units it
affects, and what release impact each unit should receive.&lt;/p&gt;
&lt;p&gt;Intent Changesets sits between commit history and release history:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vacua.dev/specifications/intent-commits/"&gt;Intent Commits Specification&lt;/a&gt; messages record the intent of atomic Git
changes and link to a changeset with a &lt;code&gt;Changeset&lt;/code&gt; trailer;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vacua.dev/specifications/intent-pull-requests/"&gt;Intent Pull Requests&lt;/a&gt; records may link reviewed integration
context to one or more changesets;&lt;/li&gt;
&lt;li&gt;an Intent Changesets record combines one or more commits or pull requests
into one releasable decision; and&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vacua.dev/specifications/intent-changelog/"&gt;Intent Changelog Specification&lt;/a&gt; entries consume that decision into the
canonical release ledger.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A changeset is not a release, changelog, pull request template, version-bump
command, or mandatory file for every commit. Projects define which changes are
noteworthy enough to require one.&lt;/p&gt;</description></item><item><title>Intent Commits</title><link>https://vacua.dev/specifications/intent-commits/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/specifications/intent-commits/</guid><description>&lt;h2 id="abstract"&gt;Abstract&lt;/h2&gt;
&lt;p&gt;The Intent Commits Specification is a lightweight protocol for commit
messages. It preserves the familiar &lt;code&gt;type(scope): description&lt;/code&gt; header while
separating four concerns that are often conflated:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the kind of work performed;&lt;/li&gt;
&lt;li&gt;the area affected;&lt;/li&gt;
&lt;li&gt;the release impact requested; and&lt;/li&gt;
&lt;li&gt;the information consumers need to adopt or reverse the change.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Intent Commits uses Git-compatible trailers for machine-readable metadata. A commit type
classifies the work; it does not determine a version increment by itself.&lt;/p&gt;</description></item><item><title>Intent Commits: Commit Types Are Not Release Decisions</title><link>https://vacua.dev/intent-commits/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/intent-commits/</guid><description>&lt;p&gt;Conventional Commits solved a real problem. It gave teams a small shared
grammar for a part of software development that had mostly been left to taste:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;feat(auth): support passkeys&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;That line is easy to write, easy to scan, and easy to parse. It is a much
better foundation than histories full of &lt;code&gt;changes&lt;/code&gt;, &lt;code&gt;updates&lt;/code&gt;, and &lt;code&gt;fix stuff&lt;/code&gt;.
It can drive changelogs, release automation, and navigation through an
unfamiliar codebase.&lt;/p&gt;</description></item><item><title>Maintain a Release Manifest</title><link>https://vacua.dev/skills/maintain-release-manifest/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/skills/maintain-release-manifest/</guid><description>&lt;p&gt;This skill applies the
&lt;a href="https://vacua.dev/specifications/release-manifest/"&gt;Release Manifest Specification&lt;/a&gt; to record
and verify what was actually published. It distinguishes repository-level
proof from remote artifacts that were not fetched or verified.&lt;/p&gt;
&lt;h2 id="install"&gt;Install&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://vacua.dev/skills/maintain-release-manifest/bundle.tar.gz"&gt;Download the complete skill package&lt;/a&gt;
or copy and run:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CODEX_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.codex&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/skills&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://vacua.dev/skills/maintain-release-manifest/bundle.tar.gz &lt;span class="se"&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; tar -xz -C &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CODEX_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.codex&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/skills&amp;#34;&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;h2 id="invoke"&gt;Invoke&lt;/h2&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$maintain-release-manifest verify the worker 1.18.3 release&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href="https://vacua.dev/downloads/skills/maintain-release-manifest/SKILL.md"&gt;Read the raw SKILL.md&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Maintain an Intent Changelog</title><link>https://vacua.dev/skills/maintain-intent-changelog/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/skills/maintain-intent-changelog/</guid><description>&lt;p&gt;This skill applies the
&lt;a href="https://vacua.dev/specifications/intent-changelog/"&gt;Intent Changelog Specification&lt;/a&gt;. It keeps
unreleased records complete, consumes changeset targets, validates and renders them
with ACK, and enforces date-only publication. Canonical generation carries
verified commit provenance through changesets into the correct release-unit
records.&lt;/p&gt;
&lt;p&gt;It does not turn &lt;code&gt;Unreleased&lt;/code&gt; into an editorial inbox or use commit-derived
Markdown as the canonical release ledger.&lt;/p&gt;
&lt;h2 id="install"&gt;Install&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://vacua.dev/skills/maintain-intent-changelog/bundle.tar.gz"&gt;Download the complete skill package&lt;/a&gt;
or copy and run:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CODEX_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.codex&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/skills&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://vacua.dev/skills/maintain-intent-changelog/bundle.tar.gz &lt;span class="se"&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; tar -xz -C &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CODEX_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.codex&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/skills&amp;#34;&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;h2 id="invoke"&gt;Invoke&lt;/h2&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$maintain-intent-changelog add this change to the worker release record&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href="https://vacua.dev/downloads/skills/maintain-intent-changelog/SKILL.md"&gt;Read the raw SKILL.md&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Maintain an Intent Changeset</title><link>https://vacua.dev/skills/maintain-intent-changeset/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/skills/maintain-intent-changeset/</guid><description>&lt;p&gt;This skill applies the
&lt;a href="https://vacua.dev/specifications/intent-changesets/"&gt;Intent Changesets Specification&lt;/a&gt;. It helps
an agent decide whether a noteworthy change needs a changeset, link relevant
commits, and consume each target into the correct changelog release record.&lt;/p&gt;
&lt;p&gt;One changeset represents one release decision—not one commit or pull request.
The skill uses ACK to validate the shared profile, enforce identifier
uniqueness, create canonical pending records, validate commit links, consume
every release-unit target, and gate publication until consumption is complete.&lt;/p&gt;</description></item><item><title>Project Profile</title><link>https://vacua.dev/specifications/project-profile/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/specifications/project-profile/</guid><description>&lt;h2 id="abstract"&gt;Abstract&lt;/h2&gt;
&lt;p&gt;The Project Profile Specification defines one versioned YAML document that
connects Intent Commits, Intent Pull Requests, Intent Changesets, Intent
Changelog, and Release Manifest records to a repository&amp;rsquo;s actual boundaries
and policies.&lt;/p&gt;
&lt;p&gt;The other specifications deliberately avoid prescribing one universal set of
types, scopes, release units, audiences, channels, or versioning rules. Without
a portable profile, however, two implementations cannot resolve those
project-defined values in the same way. This specification makes that shared
policy explicit.&lt;/p&gt;</description></item><item><title>Release Manifest</title><link>https://vacua.dev/specifications/release-manifest/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/specifications/release-manifest/</guid><description>&lt;h2 id="abstract"&gt;Abstract&lt;/h2&gt;
&lt;p&gt;The Release Manifest Specification defines an immutable evidence record for one
published release of one release stream. It answers a question that commits,
changesets, and changelogs deliberately do not: &lt;strong&gt;what exactly shipped?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A manifest binds the release identity to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the source repository, commit, and tag;&lt;/li&gt;
&lt;li&gt;the published Intent Changelog record and its digest;&lt;/li&gt;
&lt;li&gt;the release decisions represented by that record;&lt;/li&gt;
&lt;li&gt;every declared artifact and its cryptographic digest; and&lt;/li&gt;
&lt;li&gt;optional supply-chain evidence such as an SBOM or build attestation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A manifest is not a deployment plan, package-manager command, mutable release
dashboard, or substitute for a changelog. It records a completed publication
boundary in a form people, CI, and downstream automation can verify.&lt;/p&gt;</description></item><item><title>Unreleased Is Not a Junk Drawer</title><link>https://vacua.dev/unreleased-is-not-a-junk-drawer/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/unreleased-is-not-a-junk-drawer/</guid><description>&lt;p&gt;&lt;a href="https://keepachangelog.com/en/1.1.0/"&gt;&lt;em&gt;Keep a Changelog&lt;/em&gt;&lt;/a&gt; got one foundational idea exactly
right: a changelog is for people. It should explain noteworthy changes instead
of dumping commit history into a Markdown file.&lt;/p&gt;
&lt;p&gt;That principle is sound. The document model built around it is where the
frustration begins.&lt;/p&gt;
&lt;p&gt;The problem becomes most visible under this heading:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;## Unreleased&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 failure mode is easy to recognize. Everything remotely noteworthy goes
there while work is in progress. When a release approaches, somebody finally
decides which application the entries belong to, rewrites their summaries,
moves them under categories, removes internal noise, adds migration notes, and
tries to reconstruct why half of the changes mattered.&lt;/p&gt;</description></item><item><title>EventStorming Finds Disagreement Before It Finds Services</title><link>https://vacua.dev/domain-modeling-workshops-eventstorming-in-practice/</link><pubDate>Sun, 19 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/domain-modeling-workshops-eventstorming-in-practice/</guid><description>&lt;p&gt;Ask sales, support, finance, and engineering when an order becomes cancelled
and the answers may sound compatible until they share a wall.&lt;/p&gt;
&lt;p&gt;Sales says cancellation happens when the customer asks. Support says it
happens after a case is approved. Finance says a paid order remains active
until the refund clears. Engineering points to a &lt;code&gt;cancelled_at&lt;/code&gt; column written
before the payment provider responds.&lt;/p&gt;
&lt;p&gt;That disagreement is not workshop noise. It is the model.&lt;/p&gt;</description></item><item><title>Shared Kernel or Published Language: Choose Where Coordination Lives</title><link>https://vacua.dev/integration-patterns-shared-kernel-vs-published-language/</link><pubDate>Sat, 18 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/integration-patterns-shared-kernel-vs-published-language/</guid><description>&lt;p&gt;Billing and fulfilment both use the word “order.” Sharing an &lt;code&gt;Order&lt;/code&gt; class
looks like the obvious way to keep them consistent.&lt;/p&gt;
&lt;p&gt;Then billing adds credit notes, tax evidence, and settlement state. Fulfilment
adds picking waves, split shipments, and packing exceptions. The shared class
either accumulates both models or becomes a negotiation every time one team
changes it.&lt;/p&gt;
&lt;p&gt;Integration always creates coordination. A Shared Kernel and a Published
Language place that coordination in different locations. The first shares a
small piece of model and requires teams to change it together. The second
shares a versioned language at the boundary and lets each side translate it
into its own model.&lt;/p&gt;</description></item><item><title>A Process Manager Remembers What the Queue Cannot</title><link>https://vacua.dev/process-managers-long-running-business-processes/</link><pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/process-managers-long-running-business-processes/</guid><description>&lt;p&gt;An order is paid at 10:00. Inventory is reserved at 10:01. The warehouse does
not respond until 14:30. Shipping fails the next morning, after two worker
deployments and a payment-provider timeout.&lt;/p&gt;
&lt;p&gt;No request, transaction, or queue worker owns that whole timeline. Chaining
jobs can move execution from one step to the next, but the queue does not know
whether the business process is waiting, complete, compensating, or stuck.&lt;/p&gt;
&lt;p&gt;A Process Manager exists to remember that state and decide what should happen
when a relevant message arrives. Its value begins where call-stack control
ends.&lt;/p&gt;</description></item><item><title>CQRS Starts When Reads Need a Different Model</title><link>https://vacua.dev/command-query-separation-vs-cqrs/</link><pubDate>Thu, 16 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/command-query-separation-vs-cqrs/</guid><description>&lt;p&gt;An order-details page needs customer name, payment status, shipment progress,
line totals, tax labels, and the latest support case. The write model needs to
protect payment, cancellation, and fulfilment invariants.&lt;/p&gt;
&lt;p&gt;Trying to make one Eloquent graph serve both jobs creates a familiar mess:
relationships exist for screen composition, write methods expose persistence
concerns, and every request loads a different subset of a model that is never
quite complete.&lt;/p&gt;
&lt;p&gt;That tension can justify different read and write models. It does not
automatically justify two databases, an event store, a command bus, or eventual
consistency. CQRS is the model split; the infrastructure is a separate set of
decisions.&lt;/p&gt;</description></item><item><title>A Repository Is a Domain Collection, Not an ORM Wrapper</title><link>https://vacua.dev/what-repositories-really-do/</link><pubDate>Wed, 15 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/what-repositories-really-do/</guid><description>&lt;p&gt;This interface appears in many Laravel codebases:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Repository&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Collection&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nx"&gt;Model&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Model&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Model&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bool&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;It hides the word Eloquent and preserves everything else about Eloquent&amp;rsquo;s
world: models, attribute arrays, record IDs, and CRUD operations. Callers still
need to know which fields are writable, which relationships are loaded, and
which operations preserve domain rules.&lt;/p&gt;
&lt;p&gt;That is not a useful persistence boundary. It is a smaller, less capable ORM.&lt;/p&gt;</description></item><item><title>Entity, Value Object, Aggregate, Model, DTO: Name the Role</title><link>https://vacua.dev/demystifying-ddd-aggregates-entities-models-dtos-value-objects/</link><pubDate>Tue, 14 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/demystifying-ddd-aggregates-entities-models-dtos-value-objects/</guid><description>&lt;p&gt;An &lt;code&gt;Order&lt;/code&gt; can be an Eloquent model, a domain entity, an aggregate root, an API
resource, and a row in a database. Those statements describe different roles.
Treating them as synonyms makes design conversations sound precise while each
person is discussing a different boundary.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://martinfowler.com/bliki/DomainDrivenDesign.html"&gt;DDD&amp;rsquo;s modelling vocabulary&lt;/a&gt; becomes useful through concrete
questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does this thing remain the same when its attributes change?&lt;/li&gt;
&lt;li&gt;Is equality based on identity or on all constituent values?&lt;/li&gt;
&lt;li&gt;Which rules must be consistent before one transaction commits?&lt;/li&gt;
&lt;li&gt;Is this shape for domain behavior, persistence, or transfer?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The labels follow those answers.&lt;/p&gt;</description></item><item><title>Strategy Chooses How; Command Records What to Do</title><link>https://vacua.dev/strategy-vs-command-pattern/</link><pubDate>Mon, 13 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/strategy-vs-command-pattern/</guid><description>&lt;p&gt;Two PHP types can have almost identical shapes and still solve different
problems:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ShippingRate&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Shipment&lt;/span&gt; &lt;span class="nv"&gt;$shipment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Money&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;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ApplicationCommand&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;void&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;Both hide behavior behind a method. Both can be injected and tested. Their
surface similarity makes “algorithm versus action” an easy first distinction,
but it is not enough for application architecture.&lt;/p&gt;
&lt;p&gt;The more useful distinction appears after execution fails. A strategy is a
collaborator used while another operation is already in progress. A command
represents work that can acquire its own lifecycle. Once work must be queued,
retried, deduplicated, authorized, or audited independently, it is no longer
merely a choice of implementation.&lt;/p&gt;</description></item><item><title>A Null Object Should Mean Nothing Happened</title><link>https://vacua.dev/null-object-pattern/</link><pubDate>Sun, 12 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/null-object-pattern/</guid><description>&lt;p&gt;A missing coupon is not an error. Checkout should continue, the discount
should be zero, and callers should not care whether a coupon was supplied.&lt;/p&gt;
&lt;p&gt;A missing payment gateway is different. Pretending that a charge succeeded
would corrupt the order workflow. Even doing nothing would turn a deployment
mistake into a plausible-looking transaction.&lt;/p&gt;
&lt;p&gt;Both dependencies can be typed as nullable, but only one has an honest neutral
behavior. That is the boundary for the Null Object pattern: use it when
absence means “perform the same operation with no effect,” not whenever an
&lt;code&gt;if&lt;/code&gt; statement looks untidy.&lt;/p&gt;</description></item><item><title>Tell, Don't Ask Means Keep the Decision with the State</title><link>https://vacua.dev/tell-dont-ask/</link><pubDate>Sat, 11 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/tell-dont-ask/</guid><description>&lt;p&gt;This controller looks reasonable:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;Draft&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;isNotEmpty&lt;/span&gt;&lt;span class="p"&gt;())&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="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;Placed&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="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;placed_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&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="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;save&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;It reads state, makes a decision, mutates more state, and persists the result.
The problem begins when an API controller, an import command, and an admin
action each reproduce that sequence with slightly different conditions.&lt;/p&gt;
&lt;p&gt;“Tell, don&amp;rsquo;t ask” is useful when it moves a decision back to the object that
owns the relevant state. It is not a ban on queries, getters, or conditional
logic. The smell is asking an object for its internals so another object can
enforce its rules.&lt;/p&gt;</description></item><item><title>The Law of Demeter Is About Knowledge, Not Dots</title><link>https://vacua.dev/law-of-demeter/</link><pubDate>Fri, 10 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/law-of-demeter/</guid><description>&lt;p&gt;&lt;code&gt;$order-&amp;gt;customer-&amp;gt;primaryAddress-&amp;gt;city&lt;/code&gt; looks harmless. It may even execute
the right number of queries. The problem appears six months later, when an
order can have several delivery destinations and every caller has encoded the
old path to a city.&lt;/p&gt;
&lt;p&gt;This is the useful part of the Law of Demeter: keep structural knowledge near
the object or module that owns the structure. Counting arrows is a poor
substitute for that reasoning. A fluent query builder can have a long chain
without crossing a boundary; a single getter can expose an object that the
caller has no business navigating.&lt;/p&gt;</description></item><item><title>Composition Over Inheritance Is a Decision, Not a Rule</title><link>https://vacua.dev/composition-vs-inheritance/</link><pubDate>Thu, 09 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/composition-vs-inheritance/</guid><description>&lt;p&gt;“Favor composition over inheritance” is useful advice right up to the point
where it becomes a reflex. Replacing every parent class with an interface and a
service-container binding does not make a design better. It merely exchanges
one form of coupling for another.&lt;/p&gt;
&lt;p&gt;The decision is about how behavior is allowed to vary.&lt;/p&gt;
&lt;p&gt;Inheritance fixes variation into a type hierarchy. Composition puts variation
behind collaborators that can change independently. When tax, discounts,
shipping, and payment rules evolve along different axes, forcing them into one
family tree is expensive. When a subtype genuinely preserves a small, stable
parent contract, inheritance may be the clearest tool available.&lt;/p&gt;</description></item><item><title>Dependency Inversion Lets Policy Own the Boundary</title><link>https://vacua.dev/dependency-inversion-principle/</link><pubDate>Wed, 08 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/dependency-inversion-principle/</guid><description>&lt;p&gt;This class uses constructor injection and still points in the wrong direction:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QuoteShipment&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;GuzzleHttp\Client&lt;/span&gt; &lt;span class="nv"&gt;$http&lt;/span&gt;&lt;span class="p"&gt;)&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Shipment&lt;/span&gt; &lt;span class="nv"&gt;$shipment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Money&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/carrier/rates&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&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="s1"&gt;&amp;#39;json&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;CarrierPayload&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;fromShipment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$shipment&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;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;EUR&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="nx"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getBody&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;price_cents&amp;#39;&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;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="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 dependency is visible and testable, but the application use case knows an
HTTP client, carrier endpoint, payload, response shape, and currency
assumption. Replacing &lt;code&gt;new Client()&lt;/code&gt; with an injected client improved assembly;
it did not protect policy from the detail.&lt;/p&gt;</description></item><item><title>Interfaces Belong to Their Clients</title><link>https://vacua.dev/interface-segregation-principle/</link><pubDate>Tue, 07 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/interface-segregation-principle/</guid><description>&lt;p&gt;A carrier integration often begins with one generous interface:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Carrier&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Shipment&lt;/span&gt; &lt;span class="nv"&gt;$shipment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ShippingQuote&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buyLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Shipment&lt;/span&gt; &lt;span class="nv"&gt;$shipment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Label&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;cancelLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;LabelId&lt;/span&gt; &lt;span class="nv"&gt;$labelId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;void&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TrackingNumber&lt;/span&gt; &lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TrackingStatus&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bookPickup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PickupRequest&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Pickup&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;closeManifest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;LocalDate&lt;/span&gt; &lt;span class="nv"&gt;$date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Manifest&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 checkout page needs only &lt;code&gt;quote()&lt;/code&gt;. A tracking job needs only &lt;code&gt;track()&lt;/code&gt;.
One carrier may not support pickups; another may not use manifests. The broad
interface makes every consumer and implementation participate in capabilities
they do not share.&lt;/p&gt;
&lt;p&gt;The Interface Segregation Principle asks for client-specific contracts. It
does not demand one method per interface. Split where clients, implementations,
or change reasons diverge.&lt;/p&gt;</description></item><item><title>Substitution Is a Behavioral Contract</title><link>https://vacua.dev/liskov-substitution-principle/</link><pubDate>Mon, 06 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/liskov-substitution-principle/</guid><description>&lt;p&gt;Both of these classes implement the same interface:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;InvoiceArchive&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;InvoiceId&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PdfDocument&lt;/span&gt; &lt;span class="nv"&gt;$document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Location&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Location&lt;/span&gt; &lt;span class="nv"&gt;$location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PdfDocument&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;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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NullInvoiceArchive&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;InvoiceArchive&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;InvoiceId&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PdfDocument&lt;/span&gt; &lt;span class="nv"&gt;$document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Location&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Location&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;memory://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.pdf&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;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Location&lt;/span&gt; &lt;span class="nv"&gt;$location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PdfDocument&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;RuntimeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Nothing was stored.&amp;#39;&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;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;PHP accepts the implementation. A client that stores a document and later
reads the returned location does not. The method signatures match while the
behavioral contract is broken.&lt;/p&gt;
&lt;p&gt;The Liskov Substitution Principle is about that gap. Code written against a
supertype must continue to work when it receives any subtype. Interfaces,
inheritance, fakes, decorators, and adapters all create subtype promises; the
principle is not limited to class hierarchies.&lt;/p&gt;</description></item><item><title>Open–Closed Protects Stable Policy from Repeated Variation</title><link>https://vacua.dev/open-closed-principle/</link><pubDate>Sun, 05 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/open-closed-principle/</guid><description>&lt;p&gt;The third shipping carrier usually exposes the design more clearly than the
first.&lt;/p&gt;
&lt;p&gt;With one carrier, a conditional is honest. With three, adding a carrier may
require editing quote calculation, label purchase, tracking links, validation,
service-provider bindings, and tests. The same variation keeps reopening code
that was already working.&lt;/p&gt;
&lt;p&gt;The Open–Closed Principle addresses that pattern: establish a stable policy
that is closed to this recurring modification while new variants arrive
through an explicit extension point. It does not say existing code must never
change. It says repeated variation should stop causing shotgun surgery.&lt;/p&gt;</description></item><item><title>Single Responsibility Is About Change, Not Class Size</title><link>https://vacua.dev/single-responsibility-principle/</link><pubDate>Sat, 04 Jul 2026 00:00:00 +0000</pubDate><guid>https://vacua.dev/single-responsibility-principle/</guid><description>&lt;p&gt;A class with one public method can still mix pricing policy, PDF layout,
storage, and email delivery:&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SendInvoice&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Order&lt;/span&gt; &lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;void&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;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$tax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;billing.tax_rate&amp;#39;&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="nv"&gt;$pdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Pdf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;invoice&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;compact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;order&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tax&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;render&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="nx"&gt;Storage&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;disk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;invoices&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.pdf&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$pdf&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="nx"&gt;Mail&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;InvoiceMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pdf&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;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;Its method count is one. Its reasons to change include tax rules, document
presentation, retention, storage infrastructure, and delivery policy. “Do one
thing” is too vague to expose that coupling.&lt;/p&gt;
&lt;p&gt;The Single Responsibility Principle is more useful as a change rule: group
code that changes for the same reason and separate code that changes for
different reasons. Robert Martin&amp;rsquo;s &lt;a href="https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html"&gt;clarification of SRP&lt;/a&gt;
connects those reasons to the people or business functions requesting them.&lt;/p&gt;</description></item><item><title>About</title><link>https://vacua.dev/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://vacua.dev/about/</guid><description>&lt;p&gt;Hello! I’m Brian, a self-taught senior software engineer focused on developer
experience and tooling. I build open-source packages and practical systems
that remove friction from everyday engineering work.&lt;/p&gt;
&lt;p&gt;Over the past two decades, I’ve worked as a freelance engineer, independent
contributor, and consultant for teams around the world. My work often begins
where a product, platform, or engineering organization has become difficult to
change. I help clarify the technical direction, renew the foundations, and
leave teams with systems they can confidently own.&lt;/p&gt;</description></item><item><title>Projects</title><link>https://vacua.dev/projects/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://vacua.dev/projects/</guid><description>&lt;p&gt;Open-source tools I build to make engineering work more explicit, dependable,
and easier to operate.&lt;/p&gt;</description></item><item><title>Thoughts</title><link>https://vacua.dev/thoughts/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://vacua.dev/thoughts/</guid><description>&lt;p&gt;Notes on design, code, and the details that make software feel considered.&lt;/p&gt;</description></item></channel></rss>