<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>HanLHo. - Fractional Architect &amp; Software Product Engineer - developer-experience</title>
    <link rel="self" type="application/atom+xml" href="https://hanlho.com/tags/developer-experience/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://hanlho.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-02-04T00:00:00+00:00</updated>
    <id>https://hanlho.com/tags/developer-experience/atom.xml</id>
    <entry xml:lang="en">
        <title>AI’s Opportunity: Pacing Control Loops with Development</title>
        <published>2026-02-04T00:00:00+00:00</published>
        <updated>2026-02-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/ais-opportunity-pacing-control-loops-with-development/"/>
        <id>https://hanlho.com/p/ais-opportunity-pacing-control-loops-with-development/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/ais-opportunity-pacing-control-loops-with-development/">&lt;p&gt;What caught my attention in the book &lt;em&gt;Vibe Coding&lt;&#x2F;em&gt; by Gene Kim and Steve Yegge is the idea that, as LLMs and coding agents change how we build software, control loops—tests, reviews, and other signals that tell you whether a change behaves as expected—should be faster and more integrated into development feedback loops than before. My intuition says this makes perfect sense.&lt;&#x2F;p&gt;
&lt;p&gt;For example, when there is a dedicated test stage or a QA role that tests after the fact, that role inevitably struggles to keep up with the speed of development. Over time, this makes it increasingly difficult to sustain a &#x27;testing after the fact&#x27; organisation of quality.&lt;&#x2F;p&gt;
&lt;p&gt;So how do we solve this?&lt;&#x2F;p&gt;
&lt;p&gt;Some may think that introducing AI by implementing it at the test level after the fact, could be the solution. However, at the rate of development I see and read about, this approach will be hard to keep up with. One either has to accept not fully taking advantage of what AI can help development with, or rethink how testing is integrated into the development process.&lt;&#x2F;p&gt;
&lt;p&gt;Put bluntly: if AI lets you produce a feature in hours but the first meaningful acceptance signal only arrives days later in a separate stage, quality assurance become the bottleneck.&lt;&#x2F;p&gt;
&lt;p&gt;To me, the logical consequence is a stronger shift towards automated quality controls, including acceptance tests and code reviews at the least. I refer to acceptance tests here as writing executable specifications of expected behaviour (in domain language) before or alongside the code. This implies that testing &lt;em&gt;has&lt;&#x2F;em&gt; to move earlier in the development chain &lt;em&gt;because&lt;&#x2F;em&gt; of AI.&lt;&#x2F;p&gt;
&lt;p&gt;AI is an opportunity to start writing acceptance tests if you have not yet. It pushes us to invest time in strategic test design, testing against stable contracts, testing from a behavioural point of view, and isolating test descriptions from the actual implementation.&lt;&#x2F;p&gt;
&lt;p&gt;Put differently, the shift in development practices that LLMs are causing should inspire &lt;em&gt;more&lt;&#x2F;em&gt; adherence to testing best practices, not less. That is, if you want to keep on adding new features, fix and prevent bugs, and keep up the pace of development.&lt;&#x2F;p&gt;
&lt;p&gt;More broadly, to keep benefiting from AI over time, we should shift towards tightly coupled feedback loops embedded in everyday development. This is not limited to testing but also applies to, for example, reviews. In that sense, AI doesn’t remove quality practices; it raises the stakes if you don’t have them.&lt;&#x2F;p&gt;
&lt;p&gt;If testing &#x27;shifts left&#x27;, team structures must change as well. This evolution points towards smaller, more autonomous teams where testing, development, and feedback are inseparable rather than sequential.&lt;&#x2F;p&gt;
&lt;p&gt;AI presents us with an opportunity: not faster quality control after the fact, but to design systems, processes, and teams that make quality the fastest path forward, so control loops can keep up with the increasing pace of development loops.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Continuous Deployment for Personal CLI Tools</title>
        <published>2025-03-25T00:00:00+00:00</published>
        <updated>2025-03-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/continuous-deployment-for-personal-cli-tools/"/>
        <id>https://hanlho.com/p/continuous-deployment-for-personal-cli-tools/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/continuous-deployment-for-personal-cli-tools/">&lt;p&gt;Git pre-push hooks can automate local installation of your personal CLI tools, creating a development workflow where your working environment always has the latest version of your code.&lt;&#x2F;p&gt;
&lt;p&gt;When developing CLI tools, for example for personal use, I often want to run the latest version locally to quickly identify issues and get a feel for changes. Constantly installing updates manually or running from source creates unnecessary friction. This article shows how to automate this process using Git pre-push hooks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-simple-solution-local-continuous-deployment&quot;&gt;A Simple Solution: Local Continuous Deployment&lt;&#x2F;h2&gt;
&lt;p&gt;Automatically installing an updated CLI command locally whenever you push changes to your repository creates a featherweight continuous deployment pipeline. This keeps your local environment in sync with your latest code changes with minimal effort.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-are-git-hooks&quot;&gt;What Are Git Hooks?&lt;&#x2F;h2&gt;
&lt;p&gt;Git hooks are scripts that Git executes before or after events like commit, push, or receive. Pre-push hooks run automatically before your code is pushed to a remote repository.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;implementation-git-pre-push-hooks&quot;&gt;Implementation: Git Pre-Push Hooks&lt;&#x2F;h2&gt;
&lt;p&gt;The implementation is straightforward. Use git&#x27;s pre-push hooks to trigger installation automatically:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Edit the git &lt;code&gt;pre-push&lt;&#x2F;code&gt; hook file:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vim&lt;&#x2F;span&gt;&lt;span&gt; .git&#x2F;hooks&#x2F;pre-push
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Make it executable:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;chmod&lt;&#x2F;span&gt;&lt;span&gt; +x .git&#x2F;hooks&#x2F;pre-push
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Add installation commands to the hook:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#a7adba;&quot;&gt;#!&#x2F;bin&#x2F;sh
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;install.sh
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;exit &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;? &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a7adba;&quot;&gt;# Propagate the exit code
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;install.sh&lt;&#x2F;code&gt; script in this example should contain whatever commands you would normally use to install your CLI tool locally. If you use build tools like &lt;code&gt;make&lt;&#x2F;code&gt; or &lt;code&gt;just&lt;&#x2F;code&gt;, you can call those commands directly.&lt;&#x2F;p&gt;
&lt;p&gt;For a tool written in Rust your &lt;code&gt;install.sh&lt;&#x2F;code&gt; script may contain:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cargo&lt;&#x2F;span&gt;&lt;span&gt; install&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --path&lt;&#x2F;span&gt;&lt;span&gt; .
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This approach automatically rebuilds and installs your application on every push to the repository and ensures you&#x27;re always using the latest version without any manual steps.&lt;&#x2F;p&gt;
&lt;p&gt;Note:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;This works best when developing directly on the main branch. If you work with feature branches, you&#x27;ll need to consider which version you want running locally at any given time.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;For added robustness, you can extend this approach to run tests or lint your code before installation.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Hooks are not pushed to your repository by default. You will need to set them up on each development machine.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Thank you for reading, Hans&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
