<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <generator uri="https://jekyllrb.com/" version="4.3.1">Jekyll</generator>
  <link href="http://flower.codes/feed.xml" rel="self" type="application/atom+xml" />
  <link href="http://flower.codes/" rel="alternate" type="text/html" />
  <updated>2024-02-23T00:17:10+00:00</updated>
  <id>http://flower.codes/feed.xml</id>
  <title type="html">flower.codes</title>
  <subtitle>Impostor.</subtitle>
  <author>
    <name>Zachary Flower</name>
  </author>
  <entry>
    <title type="html">Eloquent Interactions Redux</title>
    <link href="http://flower.codes/2024/02/20/eloquent-interactions-redux.html" rel="alternate" type="text/html" title="Eloquent Interactions Redux" />
    <published>2024-02-20T06:24:00+00:00</published>
    <updated>2024-02-20T06:24:00+00:00</updated>
    <id>http://flower.codes/2024/02/20/eloquent-interactions-redux</id><content type="html" xml:base="http://flower.codes/2024/02/20/eloquent-interactions-redux.html">&lt;p&gt;Eight years ago, I &lt;a href=&quot;/2018/03/09/introducing-eloquent-interactions.html&quot;&gt;published&lt;/a&gt; an open source implementation of the &lt;a href=&quot;https://refactoring.guru/design-patterns/command&quot;&gt;command pattern&lt;/a&gt; for Laravel called &lt;a href=&quot;https://github.com/zachflower/eloquent-interactions&quot;&gt;Eloquent Interactions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While my library found &lt;em&gt;some&lt;/em&gt; use in my professional life, it has largely sat unused for the past six or so years... at least by me; but last week, that illusion was shattered when I received an email from a developer in Australia whose company was using the library pretty heavily, but my relative abandonment made it impossible for them to upgrade their system to the latest version of Laravel.&lt;/p&gt;
&lt;p&gt;To be clear, this email was kindly and respectfully written, and the developer was asking if I had any recommendations for a replacement library he could use to unblock the version upgrade.&lt;/p&gt;
&lt;p&gt;I told him I would do him one better and catch Eloquent Interactions up to support the latest version of Laravel. Realistically, it would be as straightforward as updating the dependencies, but because I haven't actually used Eloquent Interactions in years, I wasn't entirely sure if that would be enough (spoiler alert: it was).&lt;/p&gt;
&lt;p&gt;Turns out, I wrote unit tests for my little library.&lt;/p&gt;
&lt;p&gt;If you are a developer, and you aren't writing unit tests, you are either wasting time &lt;em&gt;now&lt;/em&gt; or you are setting yourself up to waste time &lt;em&gt;later&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In order to catch Eloquent Interactions up to support the latest versions of both Laravel and PHP, I decided to do a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I migrated the continuous integration workflow to GitHub Actions from Travis-CI.&lt;/li&gt;
&lt;li&gt;I updated support for PHP 7.2.5 through 8.&lt;/li&gt;
&lt;li&gt;I updated support for Laravel to versions 7 through 10.&lt;/li&gt;
&lt;li&gt;I built out a test matrix that runs the unit tests for every combination of PHP and Laravel versions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;migrating-from-travis-ci-to-github-actions&quot; &gt;Migrating from Travis-CI to GitHub Actions&lt;/h2&gt;
&lt;p&gt;This was a surprisingly simple move that really took the form of a simple config change. Here is the original Travis-CI config file (&lt;code&gt;.travis.yml&lt;/code&gt;):&lt;/p&gt;
&lt;font color=&quot;#808080&quot;&gt;&lt;pre&gt;
&lt;font color=&quot;#268bd2&quot;&gt;language&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;php&lt;/font&gt;

&lt;font color=&quot;#268bd2&quot;&gt;php&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
  &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;5.6'&lt;/font&gt;
  &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;7.0'&lt;/font&gt;
  &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;7.1'&lt;/font&gt;
  &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;7.2'&lt;/font&gt;

&lt;font color=&quot;#268bd2&quot;&gt;sudo&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#b58900&quot;&gt;false&lt;/font&gt;

&lt;font color=&quot;#268bd2&quot;&gt;before_install&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
  &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;travis_retry composer self-update&lt;/font&gt;

&lt;font color=&quot;#268bd2&quot;&gt;install&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
  &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;travis_retry composer install --no-interaction --prefer-dist&lt;/font&gt;

&lt;font color=&quot;#268bd2&quot;&gt;script&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;vendor/bin/phpunit&lt;/font&gt;

&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;Essentially, what it does is installs all of the library's dependencies using &lt;a href=&quot;https://getcomposer.org/&quot;&gt;Composer&lt;/a&gt;, and then runs the unit tests (via &lt;a href=&quot;https://phpunit.de/&quot;&gt;PHPUnit&lt;/a&gt;) for every version of PHP defined in the &lt;code&gt;php&lt;/code&gt; array up above (in this case, versions 5.6 through 7.2). As you can see, PHPUnit and Composer do &lt;em&gt;most&lt;/em&gt; of the heavy lifting here. No complex setups required.&lt;/p&gt;
&lt;p&gt;But, like I said, I've been done with Travis-CI for quite a while, and the more external accounts I have to maintain to keep this library running, the more headache I'm inviting into my life. So the first thing I did was convert the Travis-CI config to a GitHub Actions config (placed in &lt;code&gt;.github/workflows/main.yml&lt;/code&gt;):&lt;/p&gt;
&lt;font color=&quot;#808080&quot;&gt;&lt;pre&gt;
&lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;CI&lt;/font&gt;

&lt;font color=&quot;#268bd2&quot;&gt;on&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;push&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#586e75&quot;&gt;pull_request&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;]&lt;/font&gt;

&lt;font color=&quot;#268bd2&quot;&gt;jobs&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
  &lt;font color=&quot;#268bd2&quot;&gt;build&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
    &lt;font color=&quot;#268bd2&quot;&gt;runs-on&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;ubuntu-latest&lt;/font&gt;

    &lt;font color=&quot;#268bd2&quot;&gt;strategy&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;matrix&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
        &lt;font color=&quot;#268bd2&quot;&gt;php-versions&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;5.6'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;7.0'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;7.1'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;7.2'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;]&lt;/font&gt;

    &lt;font color=&quot;#268bd2&quot;&gt;steps&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;uses&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;actions/checkout@v2&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Setup PHP&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;uses&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;shivammathur/setup-php@v2&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;with&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
        &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;$&lt;/font&gt;
        &lt;font color=&quot;#268bd2&quot;&gt;coverage&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;none&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Validate composer.json and composer.lock&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;run&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;composer validate&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Install dependencies&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;run&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;composer install --prefer-dist --no-progress --no-suggest&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Run tests&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;run&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;./vendor/bin/phpunit&lt;/font&gt;

&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;While this script is just a &lt;em&gt;tiny&lt;/em&gt; bit longer, it essentially does the same thing. The only exception is that you have to explicitly checkout the repository code and setup the PHP support. Otherwise it will run the same unit tests on every branch push and pull request for PHP versions 5.6 through 7.2.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-php-version-support&quot; &gt;Upgrading PHP Version Support&lt;/h2&gt;
&lt;p&gt;PHP 5.6 has been in end-of-life for five years now. Nobody should be using it. Hell, all versions of PHP 7, and even PHP 8.0 are EOL as well. While I could have excluded &lt;em&gt;all&lt;/em&gt; end-of-lifed versions of PHP, I decided to support and test the minimum versions of PHP supported by Laravel 7 (which I decided was to be the most backwards-compatible version Eloquent Interactions would support).&lt;/p&gt;
&lt;p&gt;Doing a little research, this landed me on PHP 7.2.5. So the next thing I did was update my test matrix to use PHP versions 7.2.5 through 8.3 (the current version of PHP):&lt;/p&gt;
&lt;font color=&quot;#808080&quot;&gt;&lt;pre&gt;
&lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;CI&lt;/font&gt;

&lt;font color=&quot;#268bd2&quot;&gt;on&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;push&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#586e75&quot;&gt;pull_request&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;]&lt;/font&gt;

&lt;font color=&quot;#268bd2&quot;&gt;jobs&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
  &lt;font color=&quot;#268bd2&quot;&gt;build&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
    &lt;font color=&quot;#268bd2&quot;&gt;runs-on&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;ubuntu-latest&lt;/font&gt;

    &lt;font color=&quot;#268bd2&quot;&gt;strategy&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;matrix&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
        &lt;font color=&quot;#268bd2&quot;&gt;php-versions&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;7.2.5'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;7.3'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;7.4'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;8.0'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;8.1'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;8.2'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;8.3'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;]&lt;/font&gt;

    &lt;font color=&quot;#268bd2&quot;&gt;steps&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;uses&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;actions/checkout@v2&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Setup PHP&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;uses&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;shivammathur/setup-php@v2&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;with&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
        &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;$&lt;/font&gt;
        &lt;font color=&quot;#268bd2&quot;&gt;coverage&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;none&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Validate composer.json and composer.lock&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;run&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;composer validate&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Install dependencies&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;run&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;composer install --prefer-dist --no-progress --no-suggest&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Run tests&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;run&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;./vendor/bin/phpunit&lt;/font&gt;

&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;We're not quite done yet, though. We also have to update the project's &lt;code&gt;composer.json&lt;/code&gt; file to indicate that those versions of PHP are supported:&lt;/p&gt;
&lt;font color=&quot;#808080&quot;&gt;&lt;pre&gt;
&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;name&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;zachflower/eloquent-interactions&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;description&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;An implementation of the interactor pattern for Laravel.&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;keywords&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;interactor&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;laravel&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;library&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;eloquent&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;],&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;license&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;MIT&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;authors&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
            &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;name&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;Zachary Flower&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
            &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;email&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;zach@zacharyflower.com&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;],&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;require&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;php&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;^7.2.5|^8.0&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;illuminate/validation&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;~5.3|~5.4|~5.5|~5.6&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;illuminate/support&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;~5.3|~5.4|~5.5|~5.6&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;illuminate/console&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;~5.3|~5.4|~5.5|~5.6&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;},&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;require-dev&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;mockery/mockery&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;~1.0&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;phpunit/phpunit&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;~5.0|~6.0|~7.0&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;orchestra/testbench&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;~3.0&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;},&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;autoload&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;psr-4&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
            &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;ZachFlower\\EloquentInteractions\\&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;src/EloquentInteractions&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;},&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;autoload-dev&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;psr-4&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
            &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;ZachFlower\\EloquentInteractions\\Tests\\&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;tests/&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;},&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;extra&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;laravel&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
            &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;providers&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
                &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;ZachFlower&lt;/font&gt;&lt;font color=&quot;#d33682&quot;&gt;\\&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;EloquentInteractions&lt;/font&gt;&lt;font color=&quot;#d33682&quot;&gt;\\&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;EloquentInteractionsServiceProvider&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
            &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;]&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
&lt;/font&gt;
&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;This is &lt;em&gt;pretty&lt;/em&gt; straightforward. What we needed to do to indicate support for the new PHP versions is update the &lt;code&gt;php&lt;/code&gt; directive in the &lt;code&gt;require&lt;/code&gt; object to &lt;code&gt;^7.2.5|^8.0&lt;/code&gt;. In other words, we told Composer that the minimum versions of PHP that are supported are everything above just before to the version with the next breaking change (which is what the &lt;code&gt;^&lt;/code&gt; symbol indicates).&lt;/p&gt;
&lt;h2 id=&quot;upgrading-laravel-version-support&quot; &gt;Upgrading Laravel Version Support&lt;/h2&gt;
&lt;p&gt;Alright, well, we're halfway there. I didn't feel like testing whether or not Laravel 5 properly ran on PHP 8.4, so I decided to go ahead and upgrade both Laravel and its dependencies. Like I said above, I wanted to support as far back as Laravel 7, so I updated the &lt;code&gt;illuminate/*&lt;/code&gt; dependencies (which are libraries provided by Laravel, and the only ones required for Eloquent Interactions to work):&lt;/p&gt;
&lt;font color=&quot;#808080&quot;&gt;&lt;pre&gt;
&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;name&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;zachflower/eloquent-interactions&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;description&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;An implementation of the interactor pattern for Laravel.&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;keywords&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;interactor&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;laravel&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;library&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;eloquent&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;],&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;license&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;MIT&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;authors&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
            &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;name&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;Zachary Flower&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
            &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;email&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;zach@zacharyflower.com&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;],&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;require&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;php&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;^7.2.5|^8.0&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;illuminate/validation&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;^7.0|^8.0|^9.0|^10.0&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;illuminate/support&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;^7.0|^8.0|^9.0|^10.0&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;illuminate/console&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;^7.0|^8.0|^9.0|^10.0&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;},&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;require-dev&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;mockery/mockery&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;^1.0&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;phpunit/phpunit&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;^8.0|^9.0&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;orchestra/testbench&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;^5.0|^6.0|^7.0|^8.0&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;dms/phpunit-arraysubset-asserts&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;^0.5.0&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;},&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;autoload&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;psr-4&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
            &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;ZachFlower\\EloquentInteractions\\&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;src/EloquentInteractions&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;},&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;autoload-dev&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;psr-4&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
            &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;ZachFlower\\EloquentInteractions\\Tests\\&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;tests/&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;},&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;extra&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;laravel&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
            &lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;&quot;providers&quot;&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt; &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
                &lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;&quot;ZachFlower&lt;/font&gt;&lt;font color=&quot;#d33682&quot;&gt;\\&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;EloquentInteractions&lt;/font&gt;&lt;font color=&quot;#d33682&quot;&gt;\\&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;EloquentInteractionsServiceProvider&quot;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
            &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;]&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
        &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
    &lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;
&lt;/font&gt;
&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;Now we're cooking with gas!&lt;/p&gt;
&lt;p&gt;As you can see, I indicated support for all major versions of Laravel from 7 through 10. I also (not directly indicated here) updated the development dependencies (namely &lt;code&gt;phpunit/phpunit&lt;/code&gt; and &lt;code&gt;orchestra/testbench&lt;/code&gt;) to be compatible with the indicated Laravel versions.&lt;/p&gt;
&lt;p&gt;As it stands, what this file now does is indicate which versions of which dependencies it can run on. If someone running Laravel 7 on PHP 7.3 installs Eloquent Interactions, I am signing off that it is supported.&lt;/p&gt;
&lt;p&gt;No pressure, right?&lt;/p&gt;
&lt;h2 id=&quot;putting-it-all-together&quot; &gt;Putting It All Together&lt;/h2&gt;
&lt;p&gt;Okay, so we have an updated Composer file, and a GitHub Actions runner. Now what?&lt;/p&gt;
&lt;p&gt;Remember our PHP version matrix? Well, we're going to have to make that a bit more complicated. Because beyond just the PHP version, we need to also test the different Laravel versions supported by each version of PHP:&lt;/p&gt;
&lt;font color=&quot;#808080&quot;&gt;&lt;pre&gt;
&lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;CI&lt;/font&gt;

&lt;font color=&quot;#268bd2&quot;&gt;on&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;push&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#586e75&quot;&gt;pull_request&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;]&lt;/font&gt;

&lt;font color=&quot;#268bd2&quot;&gt;jobs&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
  &lt;font color=&quot;#268bd2&quot;&gt;build&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
    &lt;font color=&quot;#268bd2&quot;&gt;runs-on&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;ubuntu-latest&lt;/font&gt;

    &lt;font color=&quot;#268bd2&quot;&gt;strategy&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;matrix&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
        &lt;font color=&quot;#268bd2&quot;&gt;include&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;7.2.5&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;7.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;7.3&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;7.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;7.3&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;8.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;7.4&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;7.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;7.4&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;8.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;8.0&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;8.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;8.0&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;9.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;8.1&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;8.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;8.1&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;9.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;8.1&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;10.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;8.2&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;8.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;8.2&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;9.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;8.2&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;10.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;8.3&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;8.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;8.3&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;9.*'&lt;/font&gt;
          &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;8.3&lt;/font&gt;
            &lt;font color=&quot;#268bd2&quot;&gt;laravel-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;10.*'&lt;/font&gt;

    &lt;font color=&quot;#268bd2&quot;&gt;steps&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;uses&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;actions/checkout@v2&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Setup PHP&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;uses&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;shivammathur/setup-php@v2&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;with&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt;
        &lt;font color=&quot;#268bd2&quot;&gt;php-version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;$&lt;/font&gt;
        &lt;font color=&quot;#268bd2&quot;&gt;coverage&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;none&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Validate composer.json and composer.lock&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;run&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;composer validate&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Pin Laravel version&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;run&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;composer require &quot;illuminate/validation:$&quot; --no-update&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Install other dependencies&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;run&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;composer install --prefer-dist --no-progress --no-suggest&lt;/font&gt;

    &lt;font color=&quot;#93a1a1&quot;&gt;-&lt;/font&gt; &lt;font color=&quot;#268bd2&quot;&gt;name&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;Run tests&lt;/font&gt;
      &lt;font color=&quot;#268bd2&quot;&gt;run&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;:&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;./vendor/bin/phpunit&lt;/font&gt;

&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;Two things should stand out here:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A number of PHP and Laravel version &lt;em&gt;pairs&lt;/em&gt; have been created, allowing us to explicitly test different versions alongside one another.&lt;/li&gt;
&lt;li&gt;A new CI step, called &lt;code&gt;Pin Laravel version&lt;/code&gt; explicitly installs a specific version of Laravel in order to install the other dependencies properly.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, everything looks good (albeit a bit complex). Let's test it out:&lt;/p&gt;
&lt;font color=&quot;#808080&quot;&gt;&lt;pre&gt;
&lt;font color=&quot;#93a1a1&quot;&gt;There was 1 failure:
&lt;/font&gt;&lt;font color=&quot;#002b36&quot;&gt;
&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;1) ZachFlower\EloquentInteractions\Tests\InteractionTest::testInvalidInput
Failed asserting that an array has the subset Array &amp;amp;0 (
&lt;/font&gt;    'meters' =&amp;gt; Array &amp;amp;1 (
        0 =&amp;gt; 'The meters field must be a number.'
    )
).
&lt;font color=&quot;#dc322f&quot;&gt;--- Expected
&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;+++ Actual
&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;@@ @@&lt;/font&gt;
 array (
   'meters' =&amp;gt;
   array (
&lt;font color=&quot;#dc322f&quot;&gt;-    0 =&amp;gt; 'The meters field must be a number.',
&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;+    0 =&amp;gt; 'The meters must be a number.',
&lt;/font&gt;   ),
 )

&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;Shit.&lt;/p&gt;
&lt;p&gt;Looks like Laravel changed the validation messages at some point (which turned out to be for Laravel 10). Thankfully this is &lt;em&gt;just&lt;/em&gt; in the tests (no actual library code is broken), so in order to get things working, all we need to do is update our tests to detect which Laravel version is being used and assert accordingly.&lt;/p&gt;
&lt;p&gt;Here is an example of that change:&lt;/p&gt;
&lt;font color=&quot;#808080&quot;&gt;&lt;pre&gt;
&lt;font color=&quot;#6c71c4&quot;&gt;if&lt;/font&gt; &lt;font color=&quot;#93a1a1&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;version_compare&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;$this&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;-&amp;gt;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;app&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;-&amp;gt;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;version&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;(),&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'10.0.0'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;,&lt;/font&gt; &lt;font color=&quot;#859900&quot;&gt;'&amp;gt;='&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;))&lt;/font&gt; &lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;
  &lt;font color=&quot;#586e75&quot;&gt;$this&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;-&amp;gt;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;assertArraySubset&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;([&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;'meters'&lt;/font&gt; &lt;font color=&quot;#93a1a1&quot;&gt;=&amp;gt;&lt;/font&gt; &lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;'The meters field must be a number.'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;]],&lt;/font&gt; &lt;font color=&quot;#586e75&quot;&gt;$outcome&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;-&amp;gt;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;errors&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;-&amp;gt;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;toArray&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;());&lt;/font&gt;
&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt; &lt;font color=&quot;#6c71c4&quot;&gt;else&lt;/font&gt; &lt;font color=&quot;#93a1a1&quot;&gt;{&lt;/font&gt;
  &lt;font color=&quot;#586e75&quot;&gt;$this&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;-&amp;gt;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;assertArraySubset&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;([&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;'meters'&lt;/font&gt; &lt;font color=&quot;#93a1a1&quot;&gt;=&amp;gt;&lt;/font&gt; &lt;font color=&quot;#93a1a1&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#859900&quot;&gt;'The meters must be a number.'&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;]],&lt;/font&gt; &lt;font color=&quot;#586e75&quot;&gt;$outcome&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;-&amp;gt;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;errors&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;-&amp;gt;&lt;/font&gt;&lt;font color=&quot;#586e75&quot;&gt;toArray&lt;/font&gt;&lt;font color=&quot;#93a1a1&quot;&gt;());&lt;/font&gt;
&lt;font color=&quot;#93a1a1&quot;&gt;}&lt;/font&gt;

&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;Laravel (or, more specifically, the Laravel Orchestra test bench) very helpfully provides us with a way to check the underlying version, so all we have to do is check it and update our assertions accordingly.&lt;/p&gt;
&lt;p&gt;And that's it! After that final tweak, everything built properly and all of the tests successfully ran, so I tagged the &lt;a href=&quot;https://github.com/zachflower/eloquent-interactions/releases/tag/v1.0.0&quot;&gt;new version&lt;/a&gt; (officially &lt;code&gt;v1.0.0&lt;/code&gt; because this is a major breaking change) and deployed it to &lt;a href=&quot;https://packagist.org/&quot;&gt;Packagist&lt;/a&gt; for my new pen pal's usage.&lt;/p&gt;
&lt;p&gt;By all accounts, it's working swimmingly out in the wild.&lt;/p&gt;&lt;p&gt;--&lt;/p&gt;
    &lt;p&gt;&lt;i&gt;This is post 032 of &lt;a href=&quot;https://100daystooffload.com&quot;&gt;#100DaysToOffload&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;</content>
    <author>
      <name>Zachary Flower</name>
    </author>
    <summary type="html">Eight years ago, I published an open source implementation of the command pattern for Laravel called Eloquent Interactions.</summary>
  </entry>
  <entry>
    <title type="html">Pulse Check — February 19, 2024</title>
    <link href="http://flower.codes/2024/02/19/pulse-check.html" rel="alternate" type="text/html" title="Pulse Check — February 19, 2024" />
    <published>2024-02-19T13:00:00+00:00</published>
    <updated>2024-02-19T13:00:00+00:00</updated>
    <id>http://flower.codes/2024/02/19/pulse-check</id><content type="html" xml:base="http://flower.codes/2024/02/19/pulse-check.html">&lt;p&gt;It's been a few weeks since I published my last &lt;a href=&quot;/2024/01/28/sunday-reboot.html&quot;&gt;Sunday Reboot&lt;/a&gt;. In fact, I've published just about nothing in February altogether.&lt;/p&gt;
&lt;p&gt;... it's been a long month so far. Not a bad month... just a long one.&lt;/p&gt;
&lt;p&gt;While I won't bore you with all of the details—or spoil some upcoming stories I'll be writing about—the last few weeks have had me doing a bunch of stuff I didn't expect (and a few things I did):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I gave some engineering leadership advice and guidance to an old friend's startup, making me consider taking the leap into leadership coaching.&lt;/li&gt;
&lt;li&gt;I gave a guest lecture to a high school computer science class about password security and (more importantly) insecurity, making me want to do more teaching.&lt;/li&gt;
&lt;li&gt;My wife and I took a short staycation at the oldest and (probably not) haunted hotel in Colorado, &lt;a href=&quot;https://www.brownpalace.com/&quot;&gt;The Brown Palace&lt;/a&gt;, making me want to spend a few months in a historic location to do nothing but write.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to the existential shit, I also:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Met with a real estate agent to start the process of listing our home for sale in the Spring.&lt;/li&gt;
&lt;li&gt;Turned 0x25 years old.&lt;/li&gt;
&lt;li&gt;And, finally, started the process of petitioning to join a local Masonic Lodge.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Like I said... it's been a month.&lt;/p&gt;
&lt;p&gt;Alongside all of that, I missed a few Sunday Reboots, and decided that the weekly format isn't doing me any favors. I love routine, but the chaos of family life makes &lt;em&gt;personal&lt;/em&gt; routines difficult to maintain, so I have made the decision to end my Sunday Reboots, and instead replace them with something that feels more... flexible: the &lt;strong&gt;Pulse Check&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The intent of the Pulse Check will be much the same of the Sunday Reboot, but with less of a focus on a specific day of the week or consistent cycle, and more of a focus on the things I actually &lt;em&gt;got&lt;/em&gt; out of the Sunday Reboots, which is a personal reflection on the things I'm thinking about, engaging with, and consuming.&lt;/p&gt;
&lt;p&gt;I may post weekly, but I also may post monthly. What I'm focusing on now is the content and not the schedule.&lt;/p&gt;
&lt;p&gt;Same great flavor, exciting new package.&lt;/p&gt;
&lt;h2 id=&quot;pondering&quot; &gt;Pondering...&lt;/h2&gt;
&lt;blockquote&gt;&lt;font color=&quot;#808080&quot;&gt;&lt;em&gt;
&lt;p&gt;&amp;quot;Don’t hope for better. Just be better.&amp;quot; — Mark Manson&lt;/p&gt;
&lt;/em&gt;&lt;/font&gt;&lt;/blockquote&gt;
&lt;p&gt;I've been doing a lot of &amp;quot;hoping&amp;quot; lately, so this quote is a particularly valuable reminder that change doesn't come from wishes and dreams, it comes from action. If I want to change my circumstances, or the trajectory of my life, I need to actually &lt;em&gt;do&lt;/em&gt; something about it, instead of just thinking and talking about it.&lt;/p&gt;
&lt;p&gt;That said, knowing &lt;em&gt;what&lt;/em&gt; to do is sometimes just as challenging as actually doing the thing. There are no easy answers in life, which is especially frustrating to my engineering brain that &lt;em&gt;really&lt;/em&gt; wants things to fit into nice little boxes.&lt;/p&gt;
&lt;p&gt;Sorry, brain. Life doesn't work that way. You're gonna have to go make some mistakes and learn a few things the hard way, just like the rest of us.&lt;/p&gt;
&lt;h2 id=&quot;enjoying&quot; &gt;Enjoying...&lt;/h2&gt;
&lt;p&gt;Birthdays are &lt;em&gt;weird&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For the sole achievement of surviving one more year, we reward people with cards, cake, and presents.&lt;/p&gt;
&lt;p&gt;While I've gotten fewer presents as I get older (believe me, I don't need more &lt;em&gt;things&lt;/em&gt;), I did get two gifts this year that I am pretty excited about. The first is an espresso machine from my wife—which is really a gift for the both of us—however the second is something the entire family went in on: a &lt;a href=&quot;https://remarkable.com/store/remarkable-2&quot;&gt;reMarkable 2&lt;/a&gt; writing tablet.&lt;/p&gt;
&lt;p&gt;Holy shit this thing is cool.&lt;/p&gt;
&lt;p&gt;A while back, I wrote a post about embracing &lt;a href=&quot;/2022/04/05/single-purpose-tech.html&quot;&gt;single-purpose technology&lt;/a&gt;, and while I've strayed a bit in the last year, I still have a deep appreciation for devices that do one thing and do it well; and the reMarkable is no exception.&lt;/p&gt;
&lt;p&gt;A wafer-thin E Ink digital tablet, the reMarkable 2 is for writing and writing only. Sure, while it does also support eBooks and PDFs, the thing I am most excited about is the ability to thin out the things that I own (including the way-too-many half-used notebooks cluttering up my drawers and bookshelves) by providing a simple and distraction-free place to keep handwritten notes.&lt;/p&gt;
&lt;p&gt;While I know digital handwritten notes are generally against the &amp;quot;plaintext only&amp;quot; ethos of sustainable digital formats, I have come to a personal understanding that any time I write something by hand, I almost &lt;em&gt;never&lt;/em&gt; refer back to it.&lt;/p&gt;
&lt;p&gt;The point of handwriting, for me, isn't for memory; it's for thinking.&lt;/p&gt;
&lt;p&gt;Why waste paper for something so ephemeral?&lt;/p&gt;
&lt;p&gt;I should caveat that it's only been about a week with this thing, and while I love it so far, short-term excitement shouldn't be construed as a purchase endorsement just yet; give me a few months and I will report back on how we are getting on.&lt;/p&gt;
&lt;h2 id=&quot;habituating&quot; &gt;Habituating...&lt;/h2&gt;
&lt;p&gt;I've never been &lt;em&gt;great&lt;/em&gt; at maintaining habits.&lt;/p&gt;
&lt;p&gt;To be honest, the one habit I've been able to keep more consistently than anything over the last few years has been &lt;a href=&quot;/library.html&quot;&gt;reading&lt;/a&gt;; but that's about it.&lt;/p&gt;
&lt;p&gt;Intermittent fasting has been... intermittent, writing tends to come in waves, meditation is mediocre, and don't even get me started on going to the gym.&lt;/p&gt;
&lt;p&gt;That said, I have made a few discoveries over the years about how I can better trick my brain into maintaining habits for longer than I used to (meaning instead of dropping a new habit within a week, it might take a month or two to lapse).&lt;/p&gt;
&lt;p&gt;The most important thing, for me, has been tracking. The reason my reading habit has stuck so well is because I made it easy, and I tracked my progress; and I didn't just have some app track my progress on my behalf, I actually took the time to log and track my reading by hand.&lt;/p&gt;
&lt;p&gt;The &amp;quot;by hand&amp;quot; part has turned out to be the key.&lt;/p&gt;
&lt;p&gt;Automatically tracking the number of days meditated in the Calm or Balance app isn't habit-building; but making a notch in my pocket notebook every day I meditated has been a lot more effective.&lt;/p&gt;
&lt;p&gt;I have to &lt;em&gt;actively&lt;/em&gt; track the habit in order to keep the momentum going.&lt;/p&gt;
&lt;p&gt;Unfortunately, my pocket notebook tracking system has added to the deluge of &lt;em&gt;things&lt;/em&gt; I have had to keep on my person at all times, which at this point has me carrying &lt;em&gt;way&lt;/em&gt; too many things. Right approach, wrong system.&lt;/p&gt;
&lt;p&gt;So I've gone back to using a gamified todo app on my phone (one I have used in the past), called &lt;a href=&quot;https://habitica.com/&quot;&gt;Habitica&lt;/a&gt;, with the notable change that I have actually started using the habit-building feature instead of the todo list features.&lt;/p&gt;
&lt;p&gt;So far it's been going really well, however if you are using (or interested in using) Habitica and don't yet have a party, please reach out! While soloing is fun, it's designed to be a multiplayer experience.&lt;/p&gt;
&lt;h2 id=&quot;tinkering&quot; &gt;Tinkering...&lt;/h2&gt;
&lt;p&gt;While I don't intend to read any real eBooks on my new reMarkable tablet, I did discover that it is the &lt;em&gt;perfect&lt;/em&gt; device for reading digital magazines and programming books (something a tablet and traditional Kindle both haven't met the mark for me before).&lt;/p&gt;
&lt;p&gt;So, aside from the books I am currently reading, I've loaded the thing up with a bunch of issues of &lt;a href=&quot;https://makezine.com/&quot;&gt;Make&lt;/a&gt; and &lt;a href=&quot;https://magpi.raspberrypi.com/&quot;&gt;MagPi&lt;/a&gt; magazines, some Arduino and Raspberry Pi project books, and a handful of other electronics and programming books. The form factor is &lt;em&gt;just&lt;/em&gt; perfect enough for this type of content, and has been inspiring to flip through (as I've been wanting to improve my aptitude for hardware-based projects).&lt;/p&gt;
&lt;p&gt;The first thing I am looking at tinkering around with is the classic magic mirror. I &lt;em&gt;think&lt;/em&gt; I have an old monitor in my basement to sacrifice to the cause, and &lt;em&gt;definitely&lt;/em&gt; have a microcomputer laying around somewhere too—and even if I don't have either of those things, I have a few old laptops I could cannibalize to achieve the same effect.&lt;/p&gt;
&lt;p&gt;Hell, I'm sure my first generation iPad is up to the task if I get &lt;em&gt;really&lt;/em&gt; desperate, though it's hardly within the spirit of the project.&lt;/p&gt;
&lt;p&gt;And, I know, It's not the most innovative of projects, but I've always wanted to make one, and figure it's about time to actually get hands-on.&lt;/p&gt;&lt;p&gt;--&lt;/p&gt;
    &lt;p&gt;&lt;i&gt;This is post 031 of &lt;a href=&quot;https://100daystooffload.com&quot;&gt;#100DaysToOffload&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;</content>
    <author>
      <name>Zachary Flower</name>
    </author>
    <summary type="html">It's been a few weeks since I published my last Sunday Reboot. In fact, I've published just about nothing in February altogether.</summary>
  </entry>
  <entry>
    <title type="html">Repositories Are at the Center of Development and Production</title>
    <link href="http://flower.codes/2024/02/02/repositories.html" rel="alternate" type="text/html" title="Repositories Are at the Center of Development and Production" />
    <published>2024-02-02T12:00:00+00:00</published>
    <updated>2024-02-02T12:00:00+00:00</updated>
    <id>http://flower.codes/2024/02/02/repositories</id><content type="html" xml:base="http://flower.codes/2024/02/02/repositories.html">&lt;p&gt;As mentioned in &lt;a href=&quot;/2024/01/21/sunday-reboot.html&quot;&gt;last week's Sunday Reboot&lt;/a&gt;, I've recovered a few of my old posts from the Wayback Machine—all from my time at the now shut-down Fixate.io (via their blog, Sweetcode). These are all freelance topics, so the style of writing is a bit different than normal (for me, at least), and the topics are a little wider-ranging than I would normally write about here. I can't quite remember who this piece was originally intended for. I &lt;em&gt;believe&lt;/em&gt; it might have been &lt;a href=&quot;http://web.archive.org/web/20160212191334/http://wercker.com/&quot;&gt;Wercker&lt;/a&gt; in 2016 (now owned by Oracle), but I'm not 100% sure.&lt;/p&gt;
&lt;hr size=&quot;1&quot; noshade /&gt;
&lt;p&gt;Have you ever tried to build a new development project without the support of a version control system? It sucks.&lt;/p&gt;
&lt;p&gt;We’ve all done it, though. It’s where we start as developers. The software development learning curve is steep enough without having to tack on a &lt;a href=&quot;https://git-scm.com/&quot;&gt;Git&lt;/a&gt; or &lt;a href=&quot;https://www.mercurial-scm.org/&quot;&gt;Mercurial&lt;/a&gt; tutorial as well, so we tend to get a crash course in FTP and learn about version control a little later.&lt;/p&gt;
&lt;p&gt;This project management wild west should be a temporary state, however. A professional project should never be passed around via USB drives and FTP transfers. Without a version control system, there is no developer accountability and an obvious &lt;a href=&quot;https://en.wikipedia.org/wiki/Code_smell&quot;&gt;smell&lt;/a&gt; to the project that alludes to bigger architectural and design issues.&lt;/p&gt;
&lt;p&gt;But once you start utilizing a version control system to safely manage your project, what then? Sure, it helps keep developers accountable, and ensures quality backups, but what about deployments?&lt;/p&gt;
&lt;p&gt;Release management is where we start to find differing opinions. I’ve worked on projects that have had wildly different deployment workflows. From pulling down repository changes directly on production servers to copying release-ready code to production servers, I have seen it all.&lt;/p&gt;
&lt;p&gt;My personal opinion is that if you are managing your own production servers, it is best to leave them ignorant of a version control system. While it is fairly common to simply do a git pull on the production server, this approach is insecure and unsustainable as your development team grows.&lt;/p&gt;
&lt;p&gt;The safest and most reliable deployment method I’ve had experience with is atomic deployments. &lt;a href=&quot;https://en.wikipedia.org/wiki/Atomicity_(database_systems)&quot;&gt;Atomicity&lt;/a&gt; is a concept that describes a transaction that either completes successfully, or doesn’t happen at all. This is ideal for deployments because if your deployment workflow fails at any point along the way, the production environment is unaffected. Unit tests, uploading and building code, and cleaning up artifacts should all happen in a safe environment that is only released to the end user if it all completes successfully.&lt;/p&gt;
&lt;p&gt;While there are a lot of tools that can be used to accomplish atomic deployments (&lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt;, &lt;a href=&quot;http://deploybot.com/&quot;&gt;DeployBot&lt;/a&gt;, &lt;a href=&quot;http://web.archive.org/web/20160212191334/http://wercker.com/&quot;&gt;Wercker&lt;/a&gt;, etc), the central piece involved with each one of them is that they are all backed by a version control system. This is important for a few reasons, the primary reason being that there is always a record of the state the code was in for each and every release.&lt;/p&gt;
&lt;p&gt;The more documentation, processes, and planning you have around your deployment workflow, the safer it will be. A version control system gives you the power to quickly and easily roll your production services back to various states of being with little more than a couple keystrokes or mouse clicks. This centralized system also normalizes the process for every single developer on a project, which means that what I deploy is no different than what you deploy.&lt;/p&gt;
&lt;p&gt;Another benefit of version control systems is that integrating with multiple third-party services is as simple as sharing your private repository. A centralized repository can be shared with distinct services that handle everything from unit test coverage analysis to release management, automatically and with little overhead.&lt;/p&gt;
&lt;p&gt;Unfortunately, there is one major drawback of version control systems, and that’s the management of private data. While it is technically possible to add passwords, API keys, and encryption keys to a repository, it is a really bad idea, even if it is privately hosted. The reason for this is that the likelihood of a breach increases for every developer on the project, and every third-party service that consumes your repository.&lt;/p&gt;
&lt;p&gt;All it takes is for one of your developer’s accounts to get hacked in order to compromise the entire organization. This isn’t a theoretical issue, either; it has happened to many companies before. While you can enforce two-factor authentication within your organization, not every service offers it, and not everyone bothers to set it up.&lt;/p&gt;
&lt;p&gt;While keeping secure information out of your repository can be incredibly inconvenient, there are a lot of services that provide options that mitigate the pain. Heroku is a great example of this. Environment variables can be managed directly from within the Heroku dashboard; for non-Heroku hosted applications, environment variables can still be managed at the operating system level, or even the application level through the use of one of the many &lt;a href=&quot;https://github.com/search?q=dotenv&amp;amp;ref=opensearch&quot;&gt;dotenv&lt;/a&gt; packages available.&lt;/p&gt;
&lt;p&gt;When utilized properly, or even improperly, utilizing a private repository on a version control system is one of the most useful things you can do for a project. There’s nothing like the feeling you get from being able to understand what is happening with your project, when it is happening, and why.&lt;/p&gt;</content>
    <author>
      <name>Zachary Flower</name>
    </author>
    <summary type="html">As mentioned in last week's Sunday Reboot, I've recovered a few of my old posts from the Wayback Machine—all from my time at the now shut-down Fixate.io (via their blog, Sweetcode). These are all freelance topics, so the style of writing is a bit different than normal (for me, at least), and the topics are a little wider-ranging than I would normally write about here. I can't quite remember who this piece was originally intended for. I believe it might have been Wercker in 2016 (now owned by Oracle), but I'm not 100% sure.</summary>
  </entry>
  <entry>
    <title type="html">Working with Serverless Log Data</title>
    <link href="http://flower.codes/2024/01/30/serverless-log-data.html" rel="alternate" type="text/html" title="Working with Serverless Log Data" />
    <published>2024-01-30T12:00:00+00:00</published>
    <updated>2024-01-30T12:00:00+00:00</updated>
    <id>http://flower.codes/2024/01/30/serverless-log-data</id><content type="html" xml:base="http://flower.codes/2024/01/30/serverless-log-data.html">&lt;p&gt;As mentioned in &lt;a href=&quot;/2024/01/21/sunday-reboot.html&quot;&gt;last week's Sunday Reboot&lt;/a&gt;, I've recovered a few of my old posts from the Wayback Machine—all from my time at the now shut-down Fixate.io (via their blog, Sweetcode). These are all freelance topics, so the style of writing is a bit different than normal (for me, at least), and the topics are a little wider-ranging than I would normally write about here. This particular piece was written and then subsequently cancelled for &lt;a href=&quot;https://www.paloaltonetworks.com/prisma/cloud&quot;&gt;Twistlock&lt;/a&gt; in about 2018 (now owned by Palo Alto Networks).&lt;/p&gt;
&lt;hr size=&quot;1&quot; noshade /&gt;
&lt;p&gt;When it comes to software development, log storage has historically been what you might call a “known known.” Log data is typically written to standard output, to standard error, or directly to a file using whatever mechanism the application’s operating system or programming language chooses to use. While different technologies can follow slightly different standards, “finding” logs generally requires you to look in only a few places.&lt;/p&gt;
&lt;p&gt;But, as new technologies hit the scene that allow us to develop and scale applications in new and exciting ways, the patterns that we’ve taken for granted in the past have started to change. Program execution, data management, log storage — All of these things can feel unintuitively designed as a result of the new paradigms established by the technology running them.&lt;/p&gt;
&lt;p&gt;One such change developers are just now learning to deal with is finding, accessing, and analyzing the log data coming out of serverless platforms. Most commonly implemented as “Functions as a Service,” these serverless platforms execute encapsulated business logic in fully managed stateless, event-based virtualized environments. Because these environments are ephemeral (only alive for as long as the requests take), traditional methods of accessing log data aren’t very practical.&lt;/p&gt;
&lt;p&gt;So, how do we extract and analyze log data generated from within a serverless environment?&lt;/p&gt;
&lt;p&gt;For the most part, the answer to this question is dependent entirely on the serverless provider. While diving into the logging methods for every serverless vendor isn’t all that practical, let’s take a look at how the three largest cloud providers handle serverless data.&lt;/p&gt;
&lt;h2 id=&quot;aws-lambda&quot; &gt;AWS Lambda&lt;/h2&gt;
&lt;p&gt;By default, all native logs within a Lambda function are stored in the function execution result within Lambda. Additionally, if you would like to review log information immediately after executing a function, invoking the Lambda function with the LogType parameter will retrieve the last 4KB of log data generated by the function. This information is returned in the &lt;code&gt;x-amz-log-results&lt;/code&gt; header in the HTTP response.&lt;/p&gt;
&lt;p&gt;While these methods are great ways to test and debug issues associated with individual function calls, they do not do much by way of analysis or alerting. Thankfully, the log data that is stored in the Lambda function result is also stored in CloudWatch, Amazon’s log aggregation service. To access the CloudWatch logs for a given function, you will need to know the log group and log stream names, which can be retrieved by adding them to the function call logs and retrieving them in the &lt;code&gt;x-amz-log-results&lt;/code&gt; response as mentioned above. As an example, this context can be retrieved and logged in Node.js like so:&lt;/p&gt;
&lt;font color=&quot;#808080&quot;&gt;&lt;pre&gt;
console.log(‘logGroupName =’, context.log_group_name);
console.log(‘logStreamName =’, context.log_stream_name);

&lt;/pre&gt;&lt;/font&gt;
&lt;h2 id=&quot;azure-functions&quot; &gt;Azure Functions&lt;/h2&gt;
&lt;p&gt;Similar to AWS Lambda, logs written within Azure Functions are stored within the function execution results in the Azure Portal. One thing worth pointing out is that Azure Functions offers custom logging mechanisms, rather than utilizing the built-in methods offered by each language. For example, the Node.js implementation requires using a context.log() method, rather than the standard console.log(). As above, this is valuable when debugging functions during development; however, it hardly helps with monitoring and analysis. To accomplish this, Azure Functions offers a built-in integration with Azure Application Insights, Microsoft Azure’s Application Performance Monitoring platform.&lt;/p&gt;
&lt;p&gt;It is important to note that, while AWS Lambda automatically writes logs directly to CloudWatch, some assembly is required to store Azure Functions logs in Azure Application Insights for an existing function (although the option to store logs in Azure Application Insights is made available upon function creation). Configuring Azure Application Insights for a given Azure Function is outside the scope of this article, so I highly recommend &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-functions/functions-monitoring&quot;&gt;reading about the process here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;google-cloud-functions&quot; &gt;Google Cloud Functions&lt;/h2&gt;
&lt;p&gt;While utilizing the built-in logging methods in Google Cloud Functions is the proper way of writing log data, Google Cloud Functions logs everything written to standard output at the INFO log level, everything written to standard error at the ERROR level, and all internal system messages at the DEBUG level. To access these logs, the gcloud command can be used at the global level, on an individual function, or even for a specific execution, like so:&lt;/p&gt;
&lt;font color=&quot;#808080&quot;&gt;&lt;pre&gt;
$ gcloud functions logs read
$ gcloud functions logs read FUNCTION_NAME
$ gcloud functions logs read FUNCTION_NAME –execution_id EXECUTION_ID

&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;Additionally, as with AWS Lambda and Azure Functions, Google Stackdriver can be used to analyze and monitor logs from Google Cloud Functions. Stackdriver offers both a dashboard interface as well as a REST API for querying, analyzing, and alerting on log metrics. Interestingly, Stackdriver also offers second-party triggers for reacting to specific logs.&lt;/p&gt;
&lt;h2 id=&quot;taking-things-further&quot; &gt;Taking Things Further&lt;/h2&gt;
&lt;p&gt;Serverless platforms, as with all new technologies, have introduced new paradigms into the software development lifecycle. But with the proper integration of the provider’s built-in log aggregation and application performance monitoring tools, the log data generated by these serverless functions can be analyzed just as easily as with other tools (if not more so). And with a little work, this data can be pulled into third-party performance monitoring platforms for even more end-to-end analytics and monitoring.&lt;/p&gt;</content>
    <author>
      <name>Zachary Flower</name>
    </author>
    <summary type="html">As mentioned in last week's Sunday Reboot, I've recovered a few of my old posts from the Wayback Machine—all from my time at the now shut-down Fixate.io (via their blog, Sweetcode). These are all freelance topics, so the style of writing is a bit different than normal (for me, at least), and the topics are a little wider-ranging than I would normally write about here. This particular piece was written and then subsequently cancelled for Twistlock in about 2018 (now owned by Palo Alto Networks).</summary>
  </entry>
  <entry>
    <title type="html">How I Read</title>
    <link href="http://flower.codes/2024/01/29/how-i-read.html" rel="alternate" type="text/html" title="How I Read" />
    <published>2024-01-29T12:00:00+00:00</published>
    <updated>2024-01-29T12:00:00+00:00</updated>
    <id>http://flower.codes/2024/01/29/how-i-read</id><content type="html" xml:base="http://flower.codes/2024/01/29/how-i-read.html">&lt;p&gt;I was at coffee with a close friend on Friday, and the subject of reading came up.&lt;/p&gt;
&lt;p&gt;He, like most people, reads a few books a year, but I tend to read a lot more than most people—last year, I read about 40 books, but in the two years prior I broke &lt;em&gt;80&lt;/em&gt;. As with most habits, I tend to read less when I'm overwhelmed, and 2023 was a particularly stressful year for me, but 40 books is still no small feat compared to most people.&lt;/p&gt;
&lt;p&gt;The thing is, I am by no means a &lt;em&gt;fast&lt;/em&gt; reader. In fact, I am often frustrated by how little progress I tend to make in a single session. So, how can I still knock out between one and two books a week (on average)?&lt;/p&gt;
&lt;p&gt;When I really put some thought into that question, the answer ultimately comes down to a few things: commitment, variety, and availability.&lt;/p&gt;
&lt;h2 id=&quot;first-commit&quot; &gt;First, Commit...&lt;/h2&gt;
&lt;p&gt;When something is important to you, you tend to make time for it. I'm not a gym rat—more like a pizza rat—so I don't think I'll &lt;em&gt;ever&lt;/em&gt; wake up at the ass crack of dawn for the sole purpose of sweating my ass off; but I will absolutely wake up early to read.&lt;/p&gt;
&lt;p&gt;My kids wake up to get ready for school at 6:15 in the morning in order to catch the bus at 7:15. I start work at around 8:45, which means I need to be dressed, ready, and walking out the door by 7:45 if I want to have time to commute, purchase an overpriced Americano, and do a mindfulness meditation in my car before the ritualistic torture that is &amp;quot;my job&amp;quot; begins.&lt;/p&gt;
&lt;p&gt;As you can imagine, my mornings can be chaotic, overwhelming, and (often) shitty; but reading helps. So I wake up at 5am, make some tea, and retire to my office where I turn on some lo-fi beats, flip the heater and essential oils diffuser on, and cozy up in the recliner to read for the next hour.&lt;/p&gt;
&lt;p&gt;If it sounds a little ritualistic, it's because it is. I need to start my day off right, and this has been the best way for me to at least reach a healthy baseline.&lt;/p&gt;
&lt;h2 id=&quot;but-not-too-much&quot; &gt;...But Not Too Much&lt;/h2&gt;
&lt;p&gt;If you visit my &lt;a href=&quot;/library.html&quot;&gt;library&lt;/a&gt; page, you'll see that I almost always have more than one book in progress. There are a few reasons for this, but the main one is that I like to have different books to meet different moods.&lt;/p&gt;
&lt;p&gt;Sometimes I want to read a graphic novel (which is absolutely still reading), or a philosophy book, or a biography, or a technical book, or a fucking self help book; which means that having a few different books in progress gives me some variety to choose from.&lt;/p&gt;
&lt;p&gt;If you only read one book at a time, then you are at the whims of &lt;em&gt;just that one book&lt;/em&gt;. If you don't feel like reading about leadership principles or how awesome Tim Ferriss's life is, then something that should be enjoyable becomes a slog.&lt;/p&gt;
&lt;p&gt;Give yourself options and let your reading follow your moods in order to make a dent in your massive book backlog.&lt;/p&gt;
&lt;p&gt;I'd also like to call out that another side benefit to reading multiple books at the same time is synchronicities. I experienced this a lot in college, where the materials from one course overlapped in weird and unexpected ways with other ones I was taking, resulting in a kind of feedback loop that helped the subjects sink in better.&lt;/p&gt;
&lt;p&gt;Reading is no different.&lt;/p&gt;
&lt;p&gt;You'd be surprised how seemingly different books complement each other, allowing you to create connections that you might not have otherwise noticed if you single-threaded your reading.&lt;/p&gt;
&lt;h2 id=&quot;make-it-easy&quot; &gt;Make It Easy&lt;/h2&gt;
&lt;p&gt;One of the key components to habit building, as per &lt;a href=&quot;https://jamesclear.com/atomic-habits&quot;&gt;James Clear&lt;/a&gt;, is making it easy.&lt;/p&gt;
&lt;p&gt;To repeat myself from about 4 sentences ago: reading is no different.&lt;/p&gt;
&lt;p&gt;While I read multiple books at the same time, I am careful to deliberately read &lt;em&gt;multiple books on multiple mediums&lt;/em&gt; at the same time.&lt;/p&gt;
&lt;p&gt;WTF does that mean?&lt;/p&gt;
&lt;p&gt;It means that I almost always have a physical book in progress (you know, the kind printed on dead trees), a Kindle book in progress, an eBook in progress&lt;a href=&quot;http://moondownload.com/&quot;&gt; (Moon+ Reader Pro&lt;/a&gt; for Android is a must-have), and sometimes even an audiobook in progress.&lt;/p&gt;
&lt;p&gt;By having access to a book at all times, I'm more likely to read &lt;em&gt;that&lt;/em&gt; when I have a moment than scroll social media (although I also don't have social media or news apps on any of my devices, and relegate entertainment apps like Netflix to my tablet only).&lt;/p&gt;
&lt;p&gt;You may be wondering why I maintain a distinction between Kindle books and eBooks; in short, it's because they are read on two different types of devices. Sure, I &lt;em&gt;can&lt;/em&gt; read a Kindle book on both my phone and Kindle device, but that convenience doesn't apply so readily to eBooks acquired outside of the Amazon ecosystem (and, while I know that you can upload external eBooks to the Kindle, the highlights don't automatically sync to &lt;a href=&quot;https://readwise.io/&quot;&gt;Readwise&lt;/a&gt;, which is how I backup and reinforce what I read and learn).&lt;/p&gt;
&lt;p&gt;So I keep them separate, and it works for me.&lt;/p&gt;
&lt;h2 id=&quot;finding-your-zen&quot; &gt;Finding Your Zen&lt;/h2&gt;
&lt;p&gt;There's a common refrain about time management that it's not that we don't &lt;em&gt;have&lt;/em&gt; the time to do the things we want to do, it's that we don't &lt;em&gt;make&lt;/em&gt; time.&lt;/p&gt;
&lt;p&gt;While that is technically true, the reality is more complicated.&lt;/p&gt;
&lt;p&gt;It's not that we don't &lt;em&gt;make&lt;/em&gt; the time, it's that we don't have the energy to do what we want with that time.&lt;/p&gt;
&lt;p&gt;If you want to read more—or do &lt;em&gt;anything&lt;/em&gt; more, for that matter—it's not just about prioritizing it. It has to fill your cup. You have to work it into your life in a way that doesn't feel like a chore, but instead like a gift.&lt;/p&gt;
&lt;p&gt;I not only love to read, I &lt;em&gt;need&lt;/em&gt; to read. It's how I keep cool when the world feels like it is falling apart around me. It's what slows me down and brings me to my center.&lt;/p&gt;&lt;p&gt;--&lt;/p&gt;
    &lt;p&gt;&lt;i&gt;This is post 030 of &lt;a href=&quot;https://100daystooffload.com&quot;&gt;#100DaysToOffload&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;</content>
    <author>
      <name>Zachary Flower</name>
    </author>
    <summary type="html">I was at coffee with a close friend on Friday, and the subject of reading came up.</summary>
  </entry>
  <entry>
    <title type="html">Sunday Reboot — January 28, 2024</title>
    <link href="http://flower.codes/2024/01/28/sunday-reboot.html" rel="alternate" type="text/html" title="Sunday Reboot — January 28, 2024" />
    <published>2024-01-28T17:16:00+00:00</published>
    <updated>2024-01-28T17:16:00+00:00</updated>
    <id>http://flower.codes/2024/01/28/sunday-reboot</id><content type="html" xml:base="http://flower.codes/2024/01/28/sunday-reboot.html">&lt;p&gt;Happy Sunday, friends.&lt;/p&gt;
&lt;p&gt;It's been a fucking week, so this issue has taken me a lot longer to knock out that it normally does. I think I've spent at least 4 hours, time-on-screen, working through it (as opposed to my normal 45 minutes).&lt;/p&gt;
&lt;p&gt;There's not much say about &lt;em&gt;why&lt;/em&gt; that is. Those who know me probably know why, and those who don't are more than welcome to shoot me an &lt;a href=&quot;mailto:%7A%61%63%68%40%66%6C%6F%77%65%72%2E%63%6F%64%65%73&quot;&gt;email&lt;/a&gt; and ask. I welcome and enjoy hearing from anyone who reads these posts.&lt;/p&gt;
&lt;p&gt;The big theme for this past week has turned out to be &amp;quot;&lt;strong&gt;Retrocomputing&lt;/strong&gt;&amp;quot; (that's right, I made it one word, fight me). I've been feeling more nostalgic than usual, probably in no small part due to increased stress and anxiety—there's something about looking back to a time when things were personally simpler to both calm your nerves and make you frustrated with the present state of things.&lt;/p&gt;
&lt;p&gt;I don't have much else to add today, so I'll jump into the reboot, and hope that next week's is a bit more fruitful.&lt;/p&gt;
&lt;h2 id=&quot;pondering&quot; &gt;Pondering...&lt;/h2&gt;
&lt;blockquote&gt;&lt;font color=&quot;#808080&quot;&gt;&lt;em&gt;
&lt;p&gt;&amp;quot;If our lives are oceans, then our days are waves; some big, some small.&amp;quot; — Ryder Carroll&lt;/p&gt;
&lt;/em&gt;&lt;/font&gt;&lt;/blockquote&gt;
&lt;p&gt;I pulled out &lt;a href=&quot;https://www.rydercarroll.com/&quot;&gt;Ryder Carroll&lt;/a&gt;'s book, &lt;a href=&quot;https://bulletjournal.com/pages/book&quot;&gt;The Bullet Journal Method&lt;/a&gt;, just to pick through it again recently and this highlighted quote jumped out at me because, lately, life has felt like a fucking tsunami, with wave after wave pounding the rocks that are my soul.&lt;/p&gt;
&lt;p&gt;The quote is a good reminder that every day won't bring a tidal wave of dread and anxiety, but at the moment I'm exhausted.&lt;/p&gt;
&lt;p&gt;I think, though, that the key isn't to just learn to put up with the waves and hope things get better before the rocks get pounded into sand; it's to relocate to a calmer beach. I'm sure those of you who read my reboots have noticed this recurring theme, but at the moment my beach feels like its on an island and I missed the last boat to the mainland.&lt;/p&gt;
&lt;p&gt;My wife came home from a brunch with some friends earlier today, and said that it feels like we're living life on &amp;quot;hard mode,&amp;quot; and damn if that isn't the truth; so my mission at the moment is to figure out where the damn settings menu is so I can turn down the difficulty from &amp;quot;Nightmare!&amp;quot; down to a more manageable &amp;quot;Hey, not too rough.&amp;quot;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id=&quot;learning&quot; &gt;Learning...&lt;/h2&gt;
&lt;p&gt;I just completed &lt;a href=&quot;https://bits.ashleyblewer.com/halt-and-catch-fire-syllabus/classes/03.html&quot;&gt;Class 3 of the Halt and Catch Fire Syllabus&lt;/a&gt; and am so happy that I've started doing this. While I had already bought into the cult following of this show long before discovering the syllabus, the added layers of emulators, historical RFCs, and selected readings alongside the episodes is like turning a good steak into a five star, four-course meal.&lt;/p&gt;
&lt;p&gt;It's interesting to consider how &amp;quot;personalization&amp;quot; was such a revolutionary concept in the early 1980s. It wasn't their utility that turned computers from an appliance into a necessity, but the underlying &lt;em&gt;fun&lt;/em&gt; that can be had with them.&lt;/p&gt;
&lt;p&gt;I remember when &lt;em&gt;I&lt;/em&gt; got my first computer—back in a time when families had &amp;quot;computer rooms&amp;quot; and you had to wait your turn to use it. I was &lt;em&gt;obsessed&lt;/em&gt; from day one, and still remember the feeling that real &lt;em&gt;magic&lt;/em&gt; was happening underneath all of the plastic and wires. Personally, I feel like I've lost a lot of that wonder, but rewatching this show so intentionally is helping revive some of that feeling again.&lt;/p&gt;
&lt;p&gt;Looking ahead to &lt;a href=&quot;https://bits.ashleyblewer.com/halt-and-catch-fire-syllabus/classes/04.html&quot;&gt;Class 4&lt;/a&gt;, we will be wrapping up Season 1 and pondering the cultural, societal, and environmental impact of the personal computing revolution on the world in the early 90s through today.&lt;/p&gt;
&lt;h2 id=&quot;hobbying&quot; &gt;Hobby...ing...&lt;/h2&gt;
&lt;p&gt;A little over a week ago, I revived the &lt;a href=&quot;https://mudcoders.com/dockerize-envymud/&quot;&gt;MUD Coders Guild blog&lt;/a&gt; with a post about wrapping the 30-year-old Envy MUD source code in a Docker container. While it's the first post we've shared in four years (things kind of fizzled out when COVID hit), I've been having fun tinkering around with the Envy MUD source code again.&lt;/p&gt;
&lt;p&gt;To be clear, Envy isn't my &lt;em&gt;favorite&lt;/em&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/DikuMUD&quot;&gt;DikuMUD&lt;/a&gt; variant (the grandpappy of most 90s and early-aughts codebases), but it &lt;em&gt;is&lt;/em&gt; the core codebase that my favorite variant &lt;em&gt;was&lt;/em&gt; based on—&lt;a href=&quot;https://www.mudbytes.net/files/778/&quot;&gt;Eye of the Storm&lt;/a&gt; (EoS).&lt;/p&gt;
&lt;p&gt;Envy is my tinkerable of choice right now because it is a &lt;em&gt;very&lt;/em&gt; paired down version of EoS; in other words, it has the core components of what I love about EoS, but has a lot more room for experimentation.&lt;/p&gt;
&lt;p&gt;While my life is overwhelming enough right now to keep this project moving &lt;em&gt;slowly&lt;/em&gt;, I do intend to drip out more legacy MUD content over the coming months because (if I'm being perfectly honest), it's one of the few things brining me joy at the moment.&lt;/p&gt;
&lt;h2 id=&quot;reading&quot; &gt;Reading...&lt;/h2&gt;
&lt;p&gt;Continuing down my forays into retro computing, I've been reading a lot of blog posts and essays lately. A few have been plucked from the Halt and Catch Fire Syllabus, but others have found their way to me more organically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Dumbing-Down of Programming (Parts &lt;a href=&quot;https://web.archive.org/web/20140831034920/http://www.salon.com/1998/05/12/feature_321/&quot;&gt;One&lt;/a&gt; and &lt;a href=&quot;http://web.archive.org/web/20130825184044/http://www.salon.com/1998/05/13/feature_320/&quot;&gt;Two&lt;/a&gt;)&lt;/strong&gt;&lt;/em&gt; — Ellen Ullman shares her experience of buying and installing the Linux operating system instead of Windows in 1998, reflecting on the profession of programming and how technical expertise has changed. The author contemplates the layers of complexity that have been added to the (then) modern programming tools and the temptation to rely on wizards and shortcuts rather than truly understanding the underlying code.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;&lt;a href=&quot;https://www.fromjason.xyz/p/notebook/where-have-all-the-websites-gone/&quot;&gt;Where Have All the Websites Gone?&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt; — &amp;quot;It’s a technical marvel, that internet. Something so mindblowingly impressive that if you showed it to someone even thirty years ago, their face would melt the fuck off. So why does it feel like something’s missing? Why are we all so collectively unhappy with the state of the web?&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://thomask.sdf.org/blog/2023/09/09/memories-from-old-lan-parties.html&quot;&gt;Memories from Old Lan Parties&lt;/a&gt; — Some top-notch reminiscing about late 90s, early 2000s LAN parties. While the article does a good job aggregating and posting a large list of anachronisms, one thing that I personally miss from LAN parties is the IRL of it all. Multiplayer gaming used to be a social affair true to the word &amp;quot;party,&amp;quot; (except for nerds). It wasn't &lt;em&gt;just&lt;/em&gt; about gaming, but fellowship and togetherness.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://plbrault.com/blog-posts/i-used-netscape-composer-in-2024-en/&quot;&gt;I Used Netscape Composer in 2024&lt;/a&gt; — A absurdly delightful post about recreating a web page (the author's personal website) using Netscape Composer. TBH, I loved this so much I will likely be doing something similar (although, for the sake of variety, I might use the copy of Macromedia Dreamweaver I still have installed on my old Windows tablet PC).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tedium.co/2023/11/24/weird-html-hacks-history/&quot;&gt;10 Weird HTML Hacks That Shaped The Internet&lt;/a&gt; — Tedium is an excellent blog in its own right, but this particular article hits home for me. As a matter of fact, I utilize a handful of these hacks on &lt;em&gt;this&lt;/em&gt; very blog in order to better maintain its backwards compatibility.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not everything is &amp;quot;vintage computing&amp;quot; related, but they do all hold similar themes around the concept of low-and-slow-tech (as it would be defined &lt;em&gt;today&lt;/em&gt;, not 30 years ago), and are doing everything they can to reinforce my desires to slow the fuck down and live a more reasoned life where the technology I use is something that I either &lt;em&gt;enjoy&lt;/em&gt; or get &lt;em&gt;real&lt;/em&gt; value out of, rather than simply &lt;del&gt;deal with&lt;/del&gt; accept.&lt;/p&gt;
&lt;br /&gt;&lt;hr size=&quot;1&quot; noshade=&quot;&quot;&gt;&lt;small&gt;&lt;section class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Footnotes&lt;/h4&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://doom.fandom.com/wiki/Skill_level#Doom,_Doom_II_and_Final_Doom_skill_levels&quot;&gt;https://doom.fandom.com/wiki/Skill_level#Doom,_Doom_II_and_Final_Doom_skill_levels&lt;/a&gt; &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/small&gt;&lt;p&gt;--&lt;/p&gt;
    &lt;p&gt;&lt;i&gt;This is post 029 of &lt;a href=&quot;https://100daystooffload.com&quot;&gt;#100DaysToOffload&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;</content>
    <author>
      <name>Zachary Flower</name>
    </author>
    <summary type="html">Happy Sunday, friends.</summary>
  </entry>
  <entry>
    <title type="html">How Cloud9 Kept Me on Track after a Hardware Failure</title>
    <link href="http://flower.codes/2024/01/26/cloud9.html" rel="alternate" type="text/html" title="How Cloud9 Kept Me on Track after a Hardware Failure" />
    <published>2024-01-26T13:30:00+00:00</published>
    <updated>2024-01-26T13:30:00+00:00</updated>
    <id>http://flower.codes/2024/01/26/cloud9</id><content type="html" xml:base="http://flower.codes/2024/01/26/cloud9.html">&lt;p&gt;As mentioned in &lt;a href=&quot;/2024/01/21/sunday-reboot.html&quot;&gt;this week's Sunday Reboot&lt;/a&gt;, I've recovered a few of my old posts from the Wayback Machine—all from my time at the now shut-down Fixate.io (via their blog, Sweetcode). These are all freelance topics, so the style of writing is a bit different than normal (for me, at least), and the topics are a little wider-ranging than I would normally write about here.&lt;/p&gt;
&lt;p&gt;If I remember correctly, I wrote this one around 2016 to help the company try and bring on &lt;a href=&quot;http://www.c9.io/&quot;&gt;Cloud9&lt;/a&gt; as a customer (before they got acquired by Amazon). It &lt;em&gt;is&lt;/em&gt; a true story (I did use Cloud9 in a pinch for one whole day to get some work over the line), but I honestly don't know if the sales pitch worked.&lt;/p&gt;
&lt;hr size=&quot;1&quot; noshade /&gt;
&lt;p&gt;Earlier this year, the GPU on my MacBook failed about 2 days before a big project deadline. I needed to code, and &lt;a href=&quot;http://www.c9.io/&quot;&gt;Cloud9&lt;/a&gt; saved me.&lt;/p&gt;
&lt;p&gt;Thankfully, the repair was covered by Apple as a known issue for my particular model, but taking a sudden week off of work to get it fixed isn’t something my clients would have been too happy about. I still had a ton of work to complete, but at least I didn’t have to buy a new laptop.&lt;/p&gt;
&lt;p&gt;While I (like most nerds out there) have a handful of “vintage” computers stuffed in the various nooks and crannies of my home, none of them could be considered “developer” ready. Trying to run a virtual machine on a 7 year old laptop I bought at Walmart for $100 is one of the more painful things I’ve ever failed at, so my traditional development environment wasn’t going to work out.&lt;/p&gt;
&lt;h2 id=&quot;enter-cloud9&quot; &gt;Enter Cloud9&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://c9.io/&quot;&gt;Cloud9&lt;/a&gt; is a cloud-based development environment powered by Docker that packages a powerful IDE and built-in terminal in an easy-to-use browser-accessible interface. With the ability to import projects from GitHub and BitBucket, Cloud9 was the perfect solution to keep my projects on track with the least amount of overhead.&lt;/p&gt;
&lt;h3 id=&quot;cross-platform&quot; &gt;Cross-Platform&lt;/h3&gt;
&lt;p&gt;Because Cloud9 is cloud-slash-browser-based, it is cross platform and usable on pretty much any device that can run Google Chrome. This was incredibly useful for me because running Google Chrome is pretty much the only thing my old laptop is capable of doing anymore. The big advantage to this is, had I not had another laptop, is that I could have picked up a cheapo Chromebook (or even borrowed a computer from a friend) without losing any functionality.&lt;/p&gt;
&lt;p&gt;Unfortunately, because Cloud9 is browser-based, many of the standard keyboard shortcuts I’m used to have to be thrown out the window. A few of my browser’s keybindings take priority over the Cloud9 keybindings, which means some of the muscle memory I built over the years is rendered useless.&lt;/p&gt;
&lt;p&gt;While missing my standard keybindings is a bit of a pain, I think this issue might be remedied with a dedicated Chrome app, or even a lightweight cross-platform desktop app that adds some wrapper functionality around the website (think Slack or Franz).&lt;/p&gt;
&lt;h3 id=&quot;containerization&quot; &gt;Containerization&lt;/h3&gt;
&lt;p&gt;While Cloud9 couldn’t run my projects’ Vagrant provisioners out of the box, each workspace provides a containerized Ubuntu container which I was able to manually provision with minimal effort (it took less than 30 minutes to get a development environment up and running). It &lt;em&gt;is&lt;/em&gt; worth noting that this time could have been drastically reduced if I was using a shell provisioner instead of Puppet.&lt;/p&gt;
&lt;p&gt;Because of the popularity of containerized development environments like Docker and Vagrant, I think that providing some support for the configuration files of those platforms would go a long way to making Cloud9 a powerful development environment replacement. It would allow remote teams to quickly hop onto a workspace, provision it, and pair program a problem without very much overhead.&lt;/p&gt;
&lt;p&gt;Cloud9 definitely helped me out of a jam, and I would recommend it to anyone who is in need of a fast, lightweight, and affordable development environment.&lt;/p&gt;</content>
    <author>
      <name>Zachary Flower</name>
    </author>
    <summary type="html">As mentioned in this week's Sunday Reboot, I've recovered a few of my old posts from the Wayback Machine—all from my time at the now shut-down Fixate.io (via their blog, Sweetcode). These are all freelance topics, so the style of writing is a bit different than normal (for me, at least), and the topics are a little wider-ranging than I would normally write about here.</summary>
  </entry>
  <entry>
    <title type="html">CI/CD/CV: Emphasizing Continuous Visibility</title>
    <link href="http://flower.codes/2024/01/25/continuous-visibility.html" rel="alternate" type="text/html" title="CI/CD/CV: Emphasizing Continuous Visibility" />
    <published>2024-01-25T09:18:00+00:00</published>
    <updated>2024-01-25T09:18:00+00:00</updated>
    <id>http://flower.codes/2024/01/25/continuous-visibility</id><content type="html" xml:base="http://flower.codes/2024/01/25/continuous-visibility.html">&lt;p&gt;As mentioned in &lt;a href=&quot;/2024/01/21/sunday-reboot.html&quot;&gt;this week's Sunday Reboot&lt;/a&gt;, I've recovered a few of my old posts from the Wayback Machine—all from my time at the now shut-down Fixate.io (via their blog, Sweetcode). These are all freelance topics, so the style of writing is a bit different than normal (for me, at least), and the topics are a little wider-ranging than I would normally write about here. I can't remember, but I &lt;em&gt;think&lt;/em&gt; this one was originally written for &lt;a href=&quot;https://rollbar.com&quot;&gt;Rollbar&lt;/a&gt;, but ultimately scrapped for whatever reason.&lt;/p&gt;
&lt;hr size=&quot;1&quot; noshade /&gt;
&lt;p&gt;&lt;strong&gt;Original Title:&lt;/strong&gt; &lt;em&gt;Error Tracking and Continuous Visibility: Why to Track Errors Across the CI/CD Pipeline&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;User-generated error reports are valuable for identifying the pressing issues in your application. Yet they are also notoriously unreliable and difficult to read.&lt;/p&gt;
&lt;p&gt;To a user, every problem is a major one, and the tone of voice that often accompanies user-generated reports can be difficult to parse and diagnose. Users just want their problems fixed. Asking them to run through a series of tests to find reproduction steps and appropriate error messages can be trying at best. At worst, the users don’t follow through, and you can’t get the details you need to fix a problem.&lt;/p&gt;
&lt;p&gt;This is why error tracking solutions like Rollbar and RayGun are so important. They provide the continuous visibility that you need to maintain user expectations, without the subjectivity and inconsistency of user-generated error reports.&lt;/p&gt;
&lt;p&gt;Continuous visibility means the ability to trace errors at all stages of the CI/CD workflow. Continuous visibility is much easier than relying on post-deployment error reports to identify and attempt to trace software problems. As I explain in this post, with the help of tools like Rollbar, you can find and fix errors throughout your continuous delivery process, and, ideally, avoid releasing user-impacting bugs into production altogether.&lt;/p&gt;
&lt;h2 id=&quot;achieving-continuous-visibility-at-all-stages-of-the-cicd-pipeline&quot; &gt;Achieving Continuous Visibility at All Stages of the CI/CD Pipeline&lt;/h2&gt;
&lt;p&gt;Why integrate error tracking into all stages of the development process? Because integrating error tracking into production and staging environments, as well as post-deployment environments provides transparency into the health of your application, eases the diagnosis of issues, and identifies problems before users even know they exist.&lt;/p&gt;
&lt;p&gt;In addition, by integrating error tracking into your entire workflow, it becomes easier to identify environment-specific errors by tracking exactly which environments and branches your errors exist in.&lt;/p&gt;
&lt;h2 id=&quot;test-suites-are-not-enough&quot; &gt;Test Suites are Not Enough&lt;/h2&gt;
&lt;p&gt;You might be thinking: “I run software tests pre-deployment, so I’m covered. I already have continuous visibility into my CI/CD pipeline.”&lt;/p&gt;
&lt;p&gt;In reality, however, software testing is not the same thing as error tracking, and it doesn’t deliver the same type of continuous visibility. Your Jenkins (or TeamCity, or Bamboo, or whatever CI server you prefer) integration tests help you do what their name implies: Test code as you integrate it into your codebase. Meanwhile, software usability, performance and quality tests using platforms like Selenium or Cucumber help you to verify that your application works as expected, but not find every application error, or identify the root cause of errors.&lt;/p&gt;
&lt;p&gt;In short, a typical test suite may show you what failed, and possibly even how. Yet not every exception results in a failed test. Plus, in the case of poorly written tests—which happens to the best of us—or integration tests, a successful test may trigger an exception that you never see because you aren’t looking for it.&lt;/p&gt;
&lt;h2 id=&quot;apm-is-not-enough&quot; &gt;APM Is Not Enough&lt;/h2&gt;
&lt;p&gt;Just as pre-deployment software test suites aren’t enough to provide continuous visibility, post-deployment monitoring also fails to deliver all of the visibility you need in order to guarantee a positive user experience.&lt;/p&gt;
&lt;p&gt;SolarWinds, Nagios, Splunk and the like are all great tools, and you should include them in your stack. But don’t make the mistake of thinking that they cover all of your post-deployment visibility needs. They will help to notify you when something in your application breaks or experiences a service degradation, but in most cases they won’t identify application errors.  Your Web app could even be spitting out error messages that your users see, as long as the application continues to run, an APM tool generally won’t notice there being a problem.&lt;/p&gt;
&lt;p&gt;APM tools look for performance patterns that seem out of the ordinary, and for services that stop being available. They often lack the ability to track errors at the application level unless those errors cause the application to go down entirely.&lt;/p&gt;
&lt;h2 id=&quot;achieving-where-error-tracking-fits-in&quot; &gt;Achieving Where Error Tracking Fits In&lt;/h2&gt;
&lt;p&gt;All of the above is why error tracking is so important. Adding error tracking to all stages of your CI/CD pipeline bolsters the visibility that automated testing provides pre-deployment, and that APM provides post-deployment. Error tracking offers unique visibility that other types of tools don’t provide.&lt;/p&gt;
&lt;p&gt;In addition, error tracking tools help you not only to identify problems before they reach a production environment, but also to identify exactly &lt;em&gt;when&lt;/em&gt; tricky issues get introduced into the codebase.&lt;/p&gt;
&lt;p&gt;Identifying the &lt;em&gt;when&lt;/em&gt; of an error is particularly important. Not every issue is guaranteed to be raised by customers immediately after a deployment. It can therefore be difficult to identify exactly how long something has been a problem. With a thorough testing routine that involves automated tests as well as error tracking tools like Rollbar, exceptions are far more likely to be raised almost immediately. This will give you much more insight into your application, both in and out of test process.&lt;/p&gt;
&lt;p&gt;When it comes to tracking errors, there is no such thing as too much data. By integrating error monitoring into your CI/CD process, you can achieve Continuous Visibility into a great deal more than your test suite and build process.&lt;/p&gt;
&lt;h2 id=&quot;the-value-of-error-data-identifying-trends&quot; &gt;The Value of Error Data: Identifying Trends&lt;/h2&gt;
&lt;p&gt;Error data is useful not just for fixing a particular problem, but also for identifying trends in your development process, and tracking how well your team resolves issues as they happen. If an issue is identified in a production environment, the next step in the process should be replicating that issue in your test suite, and then pushing up a fix for it. If you can replicate a problem in your CI/CD suite, you can track the exact moment when it gets fixed, and verify that fix immediately. Once you mark the error as resolved in your error tracking solution, it can continue monitoring the error in production, and notify you if it reoccurs.&lt;/p&gt;
&lt;p&gt;Ultimately, the power of exception monitoring isn’t in the identification of issues, but in the tracking of them. Knowing the who, what, where, when, and why of an issue will provide far more insight into your application than ever before, and by integrating this information into other areas of your application development process—like code reviews and retrospectives—you will be far more prepared to handle issues when users run into them.&lt;/p&gt;</content>
    <author>
      <name>Zachary Flower</name>
    </author>
    <summary type="html">As mentioned in this week's Sunday Reboot, I've recovered a few of my old posts from the Wayback Machine—all from my time at the now shut-down Fixate.io (via their blog, Sweetcode). These are all freelance topics, so the style of writing is a bit different than normal (for me, at least), and the topics are a little wider-ranging than I would normally write about here. I can't remember, but I think this one was originally written for Rollbar, but ultimately scrapped for whatever reason.</summary>
  </entry>
  <entry>
    <title type="html">Post-Mortem Incident Report Do’s and Don’ts</title>
    <link href="http://flower.codes/2024/01/23/postmortem-tips.html" rel="alternate" type="text/html" title="Post-Mortem Incident Report Do’s and Don’ts" />
    <published>2024-01-23T19:44:00+00:00</published>
    <updated>2024-01-23T19:44:00+00:00</updated>
    <id>http://flower.codes/2024/01/23/postmortem-tips</id><content type="html" xml:base="http://flower.codes/2024/01/23/postmortem-tips.html">&lt;p&gt;As mentioned in &lt;a href=&quot;/2024/01/21/sunday-reboot.html&quot;&gt;this week's Sunday Reboot&lt;/a&gt;, I've recovered a few of my old posts from the Wayback Machine—all from my time at the now shut-down Fixate.io (via their blog, Sweetcode). This is the first of those posts, which I believe was originally written for VictorOps but ultimately scrapped for whatever reason.&lt;/p&gt;
&lt;hr size=&quot;1&quot; noshade /&gt;
&lt;p&gt;&lt;strong&gt;Original Title:&lt;/strong&gt; &lt;em&gt;8 Tips to Create an Accurate and Helpful Post-Mortem Incident Report&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stuff breaks, it’s inevitable. People make mistakes, technology breaks down, and processes aren’t infallible. But, when incidents happen, what can we do about it? What can we learn?&lt;/p&gt;
&lt;p&gt;As with all things, learning isn’t a binary action, it’s a process. And, when an incident occurs, organizations typically conduct a post-mortem analysis and generate a post-incident review to uncover what went wrong and why. These reports are critical for identifying where our processes and guardrails break down so we can learn how to do better next time.&lt;/p&gt;
&lt;h2 id=&quot;post-mortem-incident-report-tips&quot; &gt;Post-mortem incident report tips&lt;/h2&gt;
&lt;p&gt;When it comes to incident response, committing to learn from it is half the battle. The other half is setting up a successful process for continuous education by creating accurate and helpful post-mortem incident reports. While the goal of these reports is to provide you with the information you need to grow, there are a few things you should (and shouldn’t) do to ensure you’re getting the most out of them.&lt;/p&gt;
&lt;h3 id=&quot;1dontassign-blame&quot; &gt;1) &lt;em&gt;Don’t&lt;/em&gt; assign blame&lt;/h3&gt;
&lt;p&gt;We’ve all heard about “blameless post-mortems.” But, what does it really mean to be “blameless” in DevOps and IT? While it doesn’t mean there are no consequences for malicious actions, a blameless culture recognizes that everyone makes mistakes and that consequences without context will de-emphasize learning and continuous improvement over time.&lt;/p&gt;
&lt;p&gt;When creating a post-incident review, it’s critical to avoid assigning blame to any one person. Instead, focus on where the process broke down (or where more process is needed). It doesn’t matter if Joe pushed the button or Jacob wrote the function – those actions may have contributed to the incident but the true failure is almost always a lack of checks and balances along the way.&lt;/p&gt;
&lt;h3 id=&quot;2dotake-responsibility&quot; &gt;2) &lt;em&gt;Do&lt;/em&gt; take responsibility&lt;/h3&gt;
&lt;p&gt;A good post-mortem report should avoid pointing fingers, everyone involved should take responsibility for both the process and the incident itself. In order to foster a blameless culture, it’s important to emphasize the fact that everyone owns the quality process. When a problem that “you caused” gets re-framed into a problem that “we own,” it allows engineers to focus more clearly on what can be done to make things better rather than waste time trying to deflect blame.&lt;/p&gt;
&lt;h3 id=&quot;3dontprocrastinate&quot; &gt;3) &lt;em&gt;Don’t&lt;/em&gt; procrastinate&lt;/h3&gt;
&lt;p&gt;When should you perform a post-mortem? If your answer to that question wasn’t “immediately,” then you’re not doing them soon enough. While it may sound counterintuitive, you should always create a post-mortem incident report while the proverbial incident iron is still hot. This way, the incident is treated with an appropriate level of criticality and all of the details are still fresh in everyone’s minds. If you wait too long to recap and evaluate, details will be missed, passion will be low and the need to improve the process won’t feel so urgent. If you’re going to conduct a post-incident review, do it now or don’t do it at all.&lt;/p&gt;
&lt;h3 id=&quot;4dogather-information&quot; &gt;4) &lt;em&gt;Do&lt;/em&gt; gather information&lt;/h3&gt;
&lt;p&gt;When it comes to post-mortems, data is like time – it’s better to have too much and not need it than not enough and need more. Start by establishing a timeline of what exactly happened and then flesh it out with as much detail as possible. This should include the sequence of events that led up to the incident, how and when the incident itself occurred, who was impacted, how many support cases were generated, who responded to the incident, how quickly, what the response team did to resolve the incident and anything else you can think of. This post-mortem information will be invaluable in determining the root cause and will make identifying areas for improvement significantly easier.&lt;/p&gt;
&lt;h3 id=&quot;5dontbe-vague&quot; &gt;5) &lt;em&gt;Don’t&lt;/em&gt; be vague&lt;/h3&gt;
&lt;p&gt;Details, details, details. When creating a post-mortem report, don’t be vague. While the minutiae may seem unimportant, these details can be crucial to root cause analysis. More importantly, by putting as much detail as possible in the report, you eliminate the need to regroup unnecessarily with the incident response team, ensuring that learnings can be extracted directly from the report itself.&lt;/p&gt;
&lt;h3 id=&quot;6dodefine-clear-owners&quot; &gt;6) &lt;em&gt;Do&lt;/em&gt; define clear owners&lt;/h3&gt;
&lt;p&gt;While “we” should always take responsibility, it’s important to identify who owns any action items that come out of the post-incident review. As the saying goes, “if everyone owns it, nobody owns it.” By defining clear owners for action items, you ensure any work that needs to get done as a result of the incident report has a person accountable for it.&lt;/p&gt;
&lt;h3 id=&quot;7dontlose-focus&quot; &gt;7) &lt;em&gt;Don’t&lt;/em&gt; lose focus&lt;/h3&gt;
&lt;p&gt;Engineers like solving problems. Unfortunately, a post-mortem isn’t always the time to do that. Don’t get me wrong, the purpose of a post-mortem is to identify what went wrong and how we can prevent it from happening in the future but it’s not always the time to get into the weeds when it comes to technical problems. In some cases, a post-mortem is a great place to do a root cause analysis. However, some problems have nuanced technical causes that require deeper investigation. While many of us may want to dig into these problems right away, they should be identified as action items coming out of a post-incident review rather than being allowed to distract from the goal of the entire process.&lt;/p&gt;
&lt;h3 id=&quot;8douse-a-consistent-template&quot; &gt;8) &lt;em&gt;Do&lt;/em&gt; use a consistent template&lt;/h3&gt;
&lt;p&gt;The best way to maintain focus when creating a post-mortem incident report is to use a fixed template. When time is critical, it’s important not to waste it by performing a post-mortem without an agenda. A fixed template can be used for every post-mortem at your organization to ensure the timeline, discovery, ownership and focus all follow a consistent pattern. Templates can, in turn, allow you to perform post-mortems on your post-mortem workflows to further improve the overall process over time.&lt;/p&gt;
&lt;h2 id=&quot;always-be-learning&quot; &gt;Always be learning&lt;/h2&gt;
&lt;p&gt;Incidents happen. But, that doesn’t mean we can’t do something about them. By defining what a high-quality and clearly defined post-mortem incident report looks like, you can ensure the lessons learned with each incident aren’t lost. Eliminating blame, taking responsibility, gathering information, and focusing on tangible outcomes are all critical steps towards building a failure-tolerant culture that can learn from its mistakes.&lt;/p&gt;</content>
    <author>
      <name>Zachary Flower</name>
    </author>
    <summary type="html">As mentioned in this week's Sunday Reboot, I've recovered a few of my old posts from the Wayback Machine—all from my time at the now shut-down Fixate.io (via their blog, Sweetcode). This is the first of those posts, which I believe was originally written for VictorOps but ultimately scrapped for whatever reason.</summary>
  </entry>
  <entry>
    <title type="html">Techmento Mori</title>
    <link href="http://flower.codes/2024/01/22/techmento-mori.html" rel="alternate" type="text/html" title="Techmento Mori" />
    <published>2024-01-22T06:29:00+00:00</published>
    <updated>2024-01-22T06:29:00+00:00</updated>
    <id>http://flower.codes/2024/01/22/techmento-mori</id><content type="html" xml:base="http://flower.codes/2024/01/22/techmento-mori.html">&lt;p&gt;&lt;em&gt;Shhhhhh! This post is for RSS subscribers only. &lt;a href=&quot;https://daverupert.com/2018/01/welcome-to-rss-club/&quot;&gt;Look here&lt;/a&gt; for more information (and to join in on the fun).&lt;/em&gt;&lt;/p&gt;

    &lt;p&gt;--&lt;/p&gt;&lt;p&gt;I've &lt;a href=&quot;/2021/08/20/getting-thrifty.html&quot;&gt;written before&lt;/a&gt; about my love for thrift stores.&lt;/p&gt;
&lt;p&gt;While I'm going through a pretty serious &lt;em&gt;purging&lt;/em&gt; phase right now, I still enjoy taking a stroll around my local thrift store after dropping off a trunk full of &lt;del&gt;junk&lt;/del&gt; donations—on the off chance someone has donated something on my mental shopping list.&lt;/p&gt;
&lt;p&gt;Well, that actually happened this week (as it so often does); but first, some background.&lt;/p&gt;
&lt;h2 id=&quot;in-the-beginning&quot; &gt;In The Beginning...&lt;/h2&gt;
&lt;p&gt;A while back, I replaced my Google Wi-Fi mesh network with Nighthawk routers that I flashed with the &lt;a href=&quot;https://dd-wrt.com/&quot;&gt;dd-wrt firmware&lt;/a&gt;, and while it &lt;em&gt;worked&lt;/em&gt; (and felt nice to &amp;quot;own&amp;quot;), the coverage of an individual router was subpar for the size and construction of my house (the damn network trunk is in the basement) and multiple routers provided better coverage but our devices (phones, tablets, etc.) didn't do a &lt;em&gt;great&lt;/em&gt; job picking the closest access point.&lt;/p&gt;
&lt;p&gt;I generally don't mind managing this stuff, but I've been thinking about my own mortality more lately (don't ask me why), so I've been considering what the second-order effects of my death on my family might be. Beyond the first-order effects (such as grief and finances), the second-order effects are the answers to questions like &lt;em&gt;&amp;quot;if I died tomorrow, would my wife be able to deal with a technology problem given our current setup?&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Turns out, the answer is a resounding &lt;em&gt;&amp;quot;hell no!&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The curse of a tinkering nerd is that we make the people around us hopelessly dependent on our presence to get through the day (or week). Something break? We fix it, not because we're the ones who &lt;em&gt;can&lt;/em&gt;, but because we're the ones who set up the whole complicated system in the first place.&lt;/p&gt;
&lt;p&gt;So, one simple answer to the more complex question of &amp;quot;what are the consequences of the consequences of my death?&amp;quot; is to &lt;em&gt;simplify the technology setup in my home using commercially available and well-supported consumer technology&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The first phase to moving in that direction is moving our Wi-Fi setup back to the Google Wi-Fi mesh network. It's simple to manage, is well documented, and &amp;quot;just works.&amp;quot; So, I restored the three access points we had, and threw the Nighthawk routers in a box to donate.&lt;/p&gt;
&lt;h2 id=&quot;behold-hope&quot; &gt;Behold, Hope!&lt;/h2&gt;
&lt;p&gt;While this setup is simpler and plays nicer with our devices, the access points aren't &lt;em&gt;quite&lt;/em&gt; good enough to get coverage where it needs to be. I need a fourth one to properly extend the network to a relatively dead corner of our home, but I also have no intention of spending any real coin to get one.&lt;/p&gt;
&lt;p&gt;Enter, my quiet stroll around the thrift store.&lt;/p&gt;
&lt;p&gt;Like I said above, I maintain a mental shopping list of things that I don't &lt;em&gt;need&lt;/em&gt;, but could &lt;em&gt;use&lt;/em&gt; that I reference whenever I enter a thrift store. Sometimes it's simple, easy to find stuff (like a calculator for my ham radio exam, or paper for my typewriter), but other times it's more specific, like the brand new leather Samsonite laptop bag I found &lt;em&gt;one hour&lt;/em&gt; after my late grandmother told me about her gratitude for said company that gave her, an unmarried single mother in the 1950's, a job and a future.&lt;/p&gt;
&lt;p&gt;For some reason, I've always had luck finding what I need, and this time held no exception.&lt;/p&gt;
&lt;p&gt;After my drop off, I knew that I wanted to find a fourth Google Wi-Fi access point to extend my network (which, I'm sure you guessed, I &lt;em&gt;did&lt;/em&gt; find on the shelves for just a couple bucks), but another item on my mental shopping list also revealed itself.&lt;/p&gt;
&lt;h2 id=&quot;but-wait-theres-more&quot; &gt;But Wait, There's More&lt;/h2&gt;
&lt;p&gt;About a year ago, I picked up a fancy new folding phone, with the deluded consumerist reasoning that &amp;quot;I can read books on it!&amp;quot; While I do read a lot of books on the phone, it hardly has the weeks-long battery life of the Kindle I promptly gave to my wife, and has a hell of a lot of distractions baked in as well (when was the last time your Kindle alerted you of &lt;em&gt;anything&lt;/em&gt; while you were reading?).&lt;/p&gt;
&lt;p&gt;I'm not &lt;em&gt;quite&lt;/em&gt; ready to ditch the folding distraction machine yet, but I have been wanting a single-purpose digital device again that lets me read books (and nothing else) while still syncing all of my notes and highlights to Readwise, and the Kindle fits that bill pretty well.&lt;/p&gt;
&lt;p&gt;But, as you can imagine, my &amp;quot;problem&amp;quot; and my wallet are often in disagreement.&lt;/p&gt;
&lt;p&gt;I'm not about to fork over another couple hundred bucks just for the privilege of fewer distractions and a better battery life; so, &amp;quot;a Kindle&amp;quot; made its way onto my &amp;quot;synchronicity shopping list.&amp;quot;&lt;/p&gt;
&lt;p&gt;A Kindle that I found on the shelf last week for $2.99.&lt;/p&gt;
&lt;p&gt;Interestingly, this baby is the now-discontinued Kindle Touch, a fourth generation Kindle (the first with the integrated touch screen, I believe), and is the exact model of my &lt;em&gt;first&lt;/em&gt; Kindle (that I gave away to my sister-in-law a few years ago). It predates the integrated backlight, and hasn't received any updates from Amazon in quite some time, but can &lt;em&gt;still&lt;/em&gt; be registered and download purchased books.&lt;/p&gt;
&lt;p&gt;What I like most about this particular model is that it is also incompatible with the newest &amp;quot;look at all of our ads!&amp;quot; trend in the latest Kindle models, with a simple home screen and not a ton of bells-and-whistles.&lt;/p&gt;
&lt;p&gt;For my needs, it's well worth the $3 and 45 minutes I spent to acquire and refurbish it.&lt;/p&gt;&lt;p&gt;--&lt;/p&gt;
    &lt;p&gt;&lt;i&gt;This is post 028 of &lt;a href=&quot;https://100daystooffload.com&quot;&gt;#100DaysToOffload&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;</content>
    <author>
      <name>Zachary Flower</name>
    </author>
    <summary type="html">I've written before about my love for thrift stores.</summary>
  </entry>
</feed>