<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Design on Brian Faust</title><link>https://wimdy.works/tags/design/</link><description>Recent content in Design 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/design/rss.xml" rel="self" type="application/rss+xml"/><item><title>A Design Principle Is a Compressed Failure History</title><link>https://wimdy.works/thoughts/a-design-principle-is-a-compressed-failure-history/</link><pubDate>Fri, 01 Jan 2021 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/a-design-principle-is-a-compressed-failure-history/</guid><description>&lt;p&gt;“This violates the single-responsibility principle” is not an explanation. It
may be the conclusion of one, but the useful part starts earlier:&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-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Lookup policy, selection policy, and construction policy change for different
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;reasons. One class owns all three. A lookup change therefore makes selection
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tests and construction code part of the review surface.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;Once that reasoning exists, “single responsibility” gives it a short name that
another engineer can retrieve. Without the reasoning, it is just a respectable
label which can justify almost any refactor.&lt;/p&gt;</description></item><item><title>Design Becomes Valuable When the Next Change Arrives</title><link>https://wimdy.works/thoughts/design-becomes-valuable-when-the-next-change-arrives/</link><pubDate>Tue, 01 Dec 2020 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/design-becomes-valuable-when-the-next-change-arrives/</guid><description>&lt;p&gt;One migration removed four vendor packages. Two payment drivers, their client
interfaces, and their factory interfaces did not change; the concrete clients
changed substantially.&lt;/p&gt;
&lt;p&gt;Two application controllers were less fortunate. They had constructed a
vendor connection directly to manage webhooks, so the replacement had to add a
small webhook-management role and move the remote protocol behind it.&lt;/p&gt;
&lt;p&gt;The same migration produced both results: some earlier seams absorbed the
change, while other paths showed exactly where the vendor had leaked through.
That tells us more than declaring the design “clean.” A design makes a
prediction about future change, and the next real change tells us which parts
of that prediction were right.&lt;/p&gt;</description></item><item><title>The Type a Caller Receives Defines the Role</title><link>https://wimdy.works/thoughts/the-type-a-caller-receives-defines-the-role/</link><pubDate>Sun, 01 Nov 2020 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/the-type-a-caller-receives-defines-the-role/</guid><description>&lt;p&gt;A payment driver received a client through a factory. The factory promised a
five-operation interface. The concrete client had nine additional public
methods.&lt;/p&gt;
&lt;p&gt;Those extra methods covered token charging, status checks, settlement,
cancellation, token management, payment-method lookup, and refund
cancellation. None of the callers used them. When the transport was
replaced, all nine disappeared along with more than a hundred lines of concrete
client code.&lt;/p&gt;
&lt;p&gt;The driver did not change, nor did its interface or factory interface. That is
what a narrow collaboration buys: not fewer methods everywhere, but a smaller
answer to “what may this caller rely on?”&lt;/p&gt;</description></item><item><title>A Method Should Tell You What Changed</title><link>https://wimdy.works/thoughts/a-method-should-tell-you-what-changed/</link><pubDate>Thu, 01 Oct 2020 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/a-method-should-tell-you-what-changed/</guid><description>&lt;p&gt;A balance reservation could be pending, captured, released, or expired, and
only a pending reservation could move to one of the other three states. That
gave the system three commands:&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-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;capture reservation
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;release reservation
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;expire reservation&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 did not get one method called &lt;code&gt;updateReservation()&lt;/code&gt; with a status argument.
The names said which transition the caller intended. The responses included the
resulting status, so a caller did not have to guess what a successful request
had produced.&lt;/p&gt;</description></item><item><title>Construction Should Not Hide Durable Writes</title><link>https://wimdy.works/thoughts/construction-should-not-hide-durable-writes/</link><pubDate>Tue, 01 Sep 2020 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/construction-should-not-hide-durable-writes/</guid><description>&lt;p&gt;A test called a model factory&amp;rsquo;s &lt;code&gt;make()&lt;/code&gt; method. The model itself was never
saved. Two related records were.&lt;/p&gt;
&lt;p&gt;The factory computed the model&amp;rsquo;s default address and account fields by creating
real database rows. A test which only needed an in-memory user therefore changed
shared state before it reached its first assertion.&lt;/p&gt;
&lt;p&gt;A surrounding test transaction usually hid the damage by rolling it back.
Tests without that transaction left the rows behind, while another test used
&lt;code&gt;TRUNCATE&lt;/code&gt; for cleanup, committed the MySQL transaction, and made earlier writes
survive the rollback. The method returned an unpersisted object, but its name
still gave the wrong account of what had happened.&lt;/p&gt;</description></item><item><title>Global State Makes Local Reasoning Impossible</title><link>https://wimdy.works/thoughts/global-state-makes-local-reasoning-impossible/</link><pubDate>Sat, 01 Aug 2020 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/global-state-makes-local-reasoning-impossible/</guid><description>&lt;p&gt;A repository test created a shipment two days before &lt;code&gt;now&lt;/code&gt;, then counted
shipments between the start and end of the current month. It passed most days.
During the first two days of a month, “two days ago” belonged to the previous
month and the count became zero.&lt;/p&gt;
&lt;p&gt;Nothing in the test name mentioned a calendar boundary, and nothing in the
method signature mentioned time. The same test logic produced a different
result because its generated data moved with one more input: the instant at
which the test ran. Freezing the clock in the middle of the month stabilized
the example. It did not make the dependency local.&lt;/p&gt;</description></item></channel></rss>