<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lars Moelleken</title>
    <description>The latest articles on DEV Community by Lars Moelleken (@suckup_de).</description>
    <link>https://dev.to/suckup_de</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F30309%2F2945b2a8-f26d-4575-85eb-030996bcb91e.png</url>
      <title>DEV Community: Lars Moelleken</title>
      <link>https://dev.to/suckup_de</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/suckup_de"/>
    <language>en</language>
    <item>
      <title>You Bought the Machine. Now Build the Software Factory.</title>
      <dc:creator>Lars Moelleken</dc:creator>
      <pubDate>Sun, 02 Aug 2026 12:03:19 +0000</pubDate>
      <link>https://dev.to/suckup_de/you-bought-the-machine-now-build-the-software-factory-1nhp</link>
      <guid>https://dev.to/suckup_de/you-bought-the-machine-now-build-the-software-factory-1nhp</guid>
      <description>&lt;p&gt;// follow-up post from ...&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/suckup_de/ai-makes-bad-developers-faster-too-2o10" class="crayons-story__hidden-navigation-link"&gt;AI Makes Bad Developers Faster Too&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/suckup_de" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F30309%2F2945b2a8-f26d-4575-85eb-030996bcb91e.png" alt="suckup_de profile" class="crayons-avatar__image" width="800" height="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/suckup_de" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Lars Moelleken
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Lars Moelleken
                
              
              &lt;div id="story-author-preview-content-4292665" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/suckup_de" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F30309%2F2945b2a8-f26d-4575-85eb-030996bcb91e.png" class="crayons-avatar__image" alt="" width="800" height="800"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Lars Moelleken&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/suckup_de/ai-makes-bad-developers-faster-too-2o10" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Aug 2&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/suckup_de/ai-makes-bad-developers-faster-too-2o10" id="article-link-4292665"&gt;
          AI Makes Bad Developers Faster Too
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/productivity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;productivity&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/softwaredevelopment"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;softwaredevelopment&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/suckup_de/ai-makes-bad-developers-faster-too-2o10#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;





&lt;p&gt;A factory owner buys a machine that works 30x faster than his employees.&lt;/p&gt;

&lt;p&gt;He drops it into the middle of the workshop and switches it on.&lt;/p&gt;

&lt;p&gt;Within an hour, it produces hundreds of parts.&lt;/p&gt;

&lt;p&gt;Some are correct.&lt;/p&gt;

&lt;p&gt;Some are nearly correct.&lt;/p&gt;

&lt;p&gt;Some only look correct until somebody puts weight on them.&lt;/p&gt;

&lt;p&gt;Nobody can reliably tell the difference.&lt;/p&gt;

&lt;p&gt;The drawings are outdated. The measuring equipment is broken. Important specifications exist only inside the head of one senior employee. Quality control is one exhausted person saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Looks fine to me.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Production has increased.&lt;/p&gt;

&lt;p&gt;Useful production has not.&lt;/p&gt;

&lt;p&gt;That is software development with coding agents.&lt;/p&gt;

&lt;p&gt;We bought the machine.&lt;/p&gt;

&lt;p&gt;Now we need to build the factory.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Machine Is Not the Factory
&lt;/h2&gt;

&lt;p&gt;Coding agents can already:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inspect repositories&lt;/li&gt;
&lt;li&gt;implement features&lt;/li&gt;
&lt;li&gt;write tests&lt;/li&gt;
&lt;li&gt;execute commands&lt;/li&gt;
&lt;li&gt;analyze failures&lt;/li&gt;
&lt;li&gt;refactor code&lt;/li&gt;
&lt;li&gt;review diffs&lt;/li&gt;
&lt;li&gt;open pull requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is real production power.&lt;/p&gt;

&lt;p&gt;It is not engineering maturity.&lt;/p&gt;

&lt;p&gt;A factory also needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;specifications&lt;/li&gt;
&lt;li&gt;tolerances&lt;/li&gt;
&lt;li&gt;controlled environments&lt;/li&gt;
&lt;li&gt;measuring equipment&lt;/li&gt;
&lt;li&gt;inspections&lt;/li&gt;
&lt;li&gt;stop conditions&lt;/li&gt;
&lt;li&gt;traceability&lt;/li&gt;
&lt;li&gt;accountability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without those things, an agent is just a very fast developer with incomplete context and no responsibility for the production incident.&lt;/p&gt;

&lt;p&gt;We already had developers like that.&lt;/p&gt;

&lt;p&gt;Now they scale horizontally.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stop Writing Wishes. Write Work Orders.
&lt;/h2&gt;

&lt;p&gt;This is not a useful agent task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Improve customer validation.

Add tests where appropriate.

Do not break anything.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;“Do not break anything” is not a requirement.&lt;/p&gt;

&lt;p&gt;It is a prayer.&lt;/p&gt;

&lt;p&gt;A useful task defines the part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Reject an empty customer identifier before database access.

Required behavior:
- Reject an empty string.
- Reject whitespace-only input.
- Throw InvalidArgumentException.
- Include "customerId" in the exception message.

Constraints:
- Preserve public interfaces.
- Do not add dependencies.
- Do not modify unrelated files.
- Do not suppress static-analysis errors.

Verification:
- Add a regression test that fails before the fix.
- Run PHPUnit.
- Run PHPStan.
- Run PHP-CS-Fixer in dry-run mode.
- Report commands, exit codes, and results.

No change is a valid result if the defect cannot be reproduced.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not clever prompting.&lt;/p&gt;

&lt;p&gt;It is a work order.&lt;/p&gt;

&lt;p&gt;The agent does not need encouragement.&lt;/p&gt;

&lt;p&gt;It needs dimensions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get the Blueprints Out of People’s Heads
&lt;/h2&gt;

&lt;p&gt;Critical software knowledge still lives in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;old tickets&lt;/li&gt;
&lt;li&gt;Slack messages&lt;/li&gt;
&lt;li&gt;abandoned wiki pages&lt;/li&gt;
&lt;li&gt;pull-request comments&lt;/li&gt;
&lt;li&gt;production incidents nobody documented&lt;/li&gt;
&lt;li&gt;comments saying &lt;code&gt;DO NOT TOUCH&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;“ask Thomas”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A senior developer may understand the invisible rules around a codebase.&lt;/p&gt;

&lt;p&gt;The agent sees files.&lt;/p&gt;

&lt;p&gt;It does not see tribal knowledge.&lt;/p&gt;

&lt;p&gt;Store durable knowledge (ADRs, Skills, Docs, ...) in predictable places:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS.md
README.md
docs/architecture.md
docs/domain-rules.md
docs/decisions/
docs/runbooks/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But documentation is not enough.&lt;/p&gt;

&lt;p&gt;Make important rules executable.&lt;/p&gt;

&lt;p&gt;Do not merely write:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Controllers must not execute SQL.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Add an architecture test.&lt;/p&gt;

&lt;p&gt;Do not merely write:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Money uses integer cents.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Encode it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @param int&amp;lt;0, max&amp;gt; $cents
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$cents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$cents&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InvalidArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s1"&gt;'Money cannot contain negative cents.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The best documentation is a system that rejects invalid construction.&lt;/p&gt;




&lt;h2&gt;
  
  
  Define Tolerances
&lt;/h2&gt;

&lt;p&gt;Factories do not ask machines to produce “high-quality parts.”&lt;/p&gt;

&lt;p&gt;They define tolerances.&lt;/p&gt;

&lt;p&gt;Software needs the same thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Public APIs must not change.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Domain code must not depend on HTTP infrastructure.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Only repository classes may execute SQL.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No new production dependencies.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PHPStan errors must not be suppressed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Every skipped verification command must be reported.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A vague instruction forces the model to invent its own definition of quality.&lt;/p&gt;

&lt;p&gt;Then everybody acts surprised when it chooses convenience.&lt;/p&gt;

&lt;p&gt;Do not ask whether the model was smart.&lt;/p&gt;

&lt;p&gt;Ask whether the result stayed inside the tolerances.&lt;/p&gt;




&lt;h2&gt;
  
  
  Do Not Let the Machine Inspect Itself
&lt;/h2&gt;

&lt;p&gt;An agent saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All tests pass.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;is not evidence.&lt;/p&gt;

&lt;p&gt;It is text generated by the same system that generated the code.&lt;/p&gt;

&lt;p&gt;Require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;exact command&lt;/li&gt;
&lt;li&gt;exact exit code&lt;/li&gt;
&lt;li&gt;relevant output&lt;/li&gt;
&lt;li&gt;tested scope&lt;/li&gt;
&lt;li&gt;skipped checks&lt;/li&gt;
&lt;li&gt;reason for every skipped check&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a PHP project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer &lt;span class="nb"&gt;test
&lt;/span&gt;vendor/bin/phpstan analyse &lt;span class="nt"&gt;--no-progress&lt;/span&gt;
vendor/bin/php-cs-fixer fix &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;--diff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where configured:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vendor/bin/infection &lt;span class="nt"&gt;--min-msi&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result must be explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PASSED
FAILED
SKIPPED
NOT AVAILABLE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Looks good.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Should work.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I could not run the tests, but the change is straightforward.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A factory with broken gauges can produce consistently broken products.&lt;/p&gt;

&lt;p&gt;Consistency is not correctness.&lt;/p&gt;




&lt;h2&gt;
  
  
  Add a Stop Button
&lt;/h2&gt;

&lt;p&gt;Agents assume that every task must produce a patch.&lt;/p&gt;

&lt;p&gt;That creates ceremonial changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pointless refactors&lt;/li&gt;
&lt;li&gt;speculative abstractions&lt;/li&gt;
&lt;li&gt;unnecessary validation&lt;/li&gt;
&lt;li&gt;comments explaining syntax&lt;/li&gt;
&lt;li&gt;tests that simply repeat the implementation&lt;/li&gt;
&lt;li&gt;unrelated cleanup nobody requested&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes the correct result is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No change required.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The bug may already be fixed.&lt;/p&gt;

&lt;p&gt;The report may be wrong.&lt;/p&gt;

&lt;p&gt;Another service may own the failure.&lt;/p&gt;

&lt;p&gt;The required external system may be unavailable.&lt;/p&gt;

&lt;p&gt;The requested change may make the architecture worse.&lt;/p&gt;

&lt;p&gt;Require reproduction first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Reproduce the reported behavior before modifying production code.

If it cannot be reproduced:
1. Report the scenarios tested.
2. Report the commands executed.
3. Report the observed behavior.
4. Identify unavailable dependencies.
5. Do not create a diff merely to appear productive.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Evidence is progress.&lt;/p&gt;

&lt;p&gt;A diff is not.&lt;/p&gt;




&lt;h2&gt;
  
  
  Review Risk, Not Every Screw
&lt;/h2&gt;

&lt;p&gt;Reading every generated line with equal intensity is not a quality strategy.&lt;/p&gt;

&lt;p&gt;It is an attention-distribution bug.&lt;/p&gt;

&lt;p&gt;Spend human attention on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication&lt;/li&gt;
&lt;li&gt;authorization&lt;/li&gt;
&lt;li&gt;money&lt;/li&gt;
&lt;li&gt;migrations&lt;/li&gt;
&lt;li&gt;transactions&lt;/li&gt;
&lt;li&gt;concurrency&lt;/li&gt;
&lt;li&gt;input boundaries&lt;/li&gt;
&lt;li&gt;external integrations&lt;/li&gt;
&lt;li&gt;deleted tests&lt;/li&gt;
&lt;li&gt;weakened assertions&lt;/li&gt;
&lt;li&gt;dependency changes&lt;/li&gt;
&lt;li&gt;rollback behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spend less attention on deterministic work protected by automation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;formatting&lt;/li&gt;
&lt;li&gt;generated DTOs&lt;/li&gt;
&lt;li&gt;repetitive mappings&lt;/li&gt;
&lt;li&gt;mechanical renames&lt;/li&gt;
&lt;li&gt;schema-generated clients&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A decorative screw and a structural bolt do not deserve the same inspection.&lt;/p&gt;

&lt;p&gt;That is not laziness.&lt;/p&gt;

&lt;p&gt;That is engineering.&lt;/p&gt;

&lt;p&gt;But there is no free shortcut:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reading less code requires testing more behavior.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Reading less and testing less is not industrialization.&lt;/p&gt;

&lt;p&gt;It is negligence with better branding.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stop Measuring Tokens
&lt;/h2&gt;

&lt;p&gt;Lines generated do not matter.&lt;/p&gt;

&lt;p&gt;Tokens consumed do not matter.&lt;/p&gt;

&lt;p&gt;The percentage of AI-written code does not matter.&lt;/p&gt;

&lt;p&gt;Measure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;successful repository tasks&lt;/li&gt;
&lt;li&gt;human corrections&lt;/li&gt;
&lt;li&gt;reverted changes&lt;/li&gt;
&lt;li&gt;ignored constraints&lt;/li&gt;
&lt;li&gt;regression rate&lt;/li&gt;
&lt;li&gt;review time&lt;/li&gt;
&lt;li&gt;verification cost&lt;/li&gt;
&lt;li&gt;production incidents&lt;/li&gt;
&lt;li&gt;reproducibility&lt;/li&gt;
&lt;li&gt;recovery time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thousand generated lines may be useful.&lt;/p&gt;

&lt;p&gt;They may also be industrially produced waste.&lt;/p&gt;

&lt;p&gt;Your repository is the benchmark that matters.&lt;/p&gt;

&lt;p&gt;Not the vendor’s multiplier.&lt;/p&gt;




&lt;h2&gt;
  
  
  Someone Still Owns the Result
&lt;/h2&gt;

&lt;p&gt;When generated code breaks production, responsibility cannot be assigned to the model.&lt;/p&gt;

&lt;p&gt;The model does not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;own the repository&lt;/li&gt;
&lt;li&gt;answer customers&lt;/li&gt;
&lt;li&gt;restore corrupted data&lt;/li&gt;
&lt;li&gt;carry legal liability&lt;/li&gt;
&lt;li&gt;receive the incident call at three in the morning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A real workflow defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;who approved the task&lt;/li&gt;
&lt;li&gt;who defined acceptance criteria&lt;/li&gt;
&lt;li&gt;which checks were mandatory&lt;/li&gt;
&lt;li&gt;which checks ran&lt;/li&gt;
&lt;li&gt;who accepted skipped verification&lt;/li&gt;
&lt;li&gt;who reviewed high-risk changes&lt;/li&gt;
&lt;li&gt;who approved deployment&lt;/li&gt;
&lt;li&gt;how rollback works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not new AI bureaucracy.&lt;/p&gt;

&lt;p&gt;This is engineering accountability that should already have existed.&lt;/p&gt;

&lt;p&gt;The machine simply exposes its absence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Start With One Production Line
&lt;/h2&gt;

&lt;p&gt;Do not build a giant internal AI platform first.&lt;/p&gt;

&lt;p&gt;That is how companies spend a year automating work they never understood.&lt;/p&gt;

&lt;p&gt;Choose one repeatable task:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dependency updates&lt;/li&gt;
&lt;li&gt;regression tests&lt;/li&gt;
&lt;li&gt;DTO generation&lt;/li&gt;
&lt;li&gt;static-analysis fixes&lt;/li&gt;
&lt;li&gt;mechanical migrations&lt;/li&gt;
&lt;li&gt;deterministic renames&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then define:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the input&lt;/li&gt;
&lt;li&gt;the required change&lt;/li&gt;
&lt;li&gt;the constraints&lt;/li&gt;
&lt;li&gt;the environment&lt;/li&gt;
&lt;li&gt;the verification&lt;/li&gt;
&lt;li&gt;the risk level&lt;/li&gt;
&lt;li&gt;the evidence&lt;/li&gt;
&lt;li&gt;the stop conditions&lt;/li&gt;
&lt;li&gt;the approval&lt;/li&gt;
&lt;li&gt;the learning after failure&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is already a software factory.&lt;/p&gt;

&lt;p&gt;Small, but real.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Developer Becomes the Factory Builder
&lt;/h2&gt;

&lt;p&gt;The developer is not disappearing.&lt;/p&gt;

&lt;p&gt;The work is moving.&lt;/p&gt;

&lt;p&gt;Less value comes from manually typing predictable code.&lt;/p&gt;

&lt;p&gt;More value comes from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;defining correctness&lt;/li&gt;
&lt;li&gt;encoding constraints&lt;/li&gt;
&lt;li&gt;designing architecture&lt;/li&gt;
&lt;li&gt;building verification&lt;/li&gt;
&lt;li&gt;identifying risk&lt;/li&gt;
&lt;li&gt;measuring outcomes&lt;/li&gt;
&lt;li&gt;investigating failures&lt;/li&gt;
&lt;li&gt;deciding when the machine is wrong&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A master carpenter should not spend every day producing identical shelf pins.&lt;/p&gt;

&lt;p&gt;But somebody still needs to understand material, structure, load, and failure.&lt;/p&gt;

&lt;p&gt;Otherwise the factory produces furniture efficiently until somebody sits on it.&lt;/p&gt;

&lt;p&gt;The same applies to software.&lt;/p&gt;

&lt;p&gt;The agent is not the factory.&lt;/p&gt;

&lt;p&gt;The model is not the production system.&lt;/p&gt;

&lt;p&gt;Generated code is not automatically the product.&lt;/p&gt;

&lt;p&gt;The factory is the system of constraints, evidence, inspection, and responsibility around the machine.&lt;/p&gt;

&lt;p&gt;You bought the machine.&lt;/p&gt;

&lt;p&gt;Stop admiring how fast it moves.&lt;/p&gt;

&lt;p&gt;Build something that can reject its garbage.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>AI Makes Bad Developers Faster Too</title>
      <dc:creator>Lars Moelleken</dc:creator>
      <pubDate>Sun, 02 Aug 2026 11:27:04 +0000</pubDate>
      <link>https://dev.to/suckup_de/ai-makes-bad-developers-faster-too-2o10</link>
      <guid>https://dev.to/suckup_de/ai-makes-bad-developers-faster-too-2o10</guid>
      <description>&lt;h2&gt;
  
  
  The Circular Saw, the Apprentice, and the Software Factory
&lt;/h2&gt;

&lt;p&gt;A circular saw does not turn a bad carpenter into a good one. It merely allows him to destroy wood faster.&lt;/p&gt;

&lt;p&gt;A skilled carpenter still uses the circular saw. Refusing modern tools would not make him more professional, only slower. The difference is that he understands the material. He knows how wood behaves, where tension builds, how grain direction affects a cut, and when a clean-looking result is structurally wrong.&lt;/p&gt;

&lt;p&gt;The machine provides speed and force. The carpenter provides judgment.&lt;/p&gt;

&lt;p&gt;The same is true for LLMs in software development.&lt;/p&gt;

&lt;p&gt;An experienced developer can use an LLM to explore a codebase, generate implementations, write tests, investigate failures, and compare possible designs much faster than before. But the tool does not provide the developer’s understanding of the system. It does not automatically know which assumptions are valid, which abstractions belong together, or which apparently elegant solution will create maintenance problems six months later.&lt;/p&gt;

&lt;p&gt;An LLM amplifies the process around it.&lt;/p&gt;

&lt;p&gt;In a disciplined engineering process, it accelerates useful work. In a weak process, it accelerates confusion, duplication, security problems, and confidently formatted nonsense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Apprentice Still Needs the Hand Saw
&lt;/h2&gt;

&lt;p&gt;This does not mean beginners should avoid LLMs completely. It means they must not outsource the part of learning that creates judgment.&lt;/p&gt;

&lt;p&gt;A carpenter’s apprentice may work with a hand saw, a plane, and a chisel before relying entirely on powered machinery. Not because manual tools are morally superior or because suffering builds character, although humanity remains strangely attached to that idea. The apprentice uses them because direct contact with the material teaches lessons that the machine can hide.&lt;/p&gt;

&lt;p&gt;The same principle applies to programming.&lt;/p&gt;

&lt;p&gt;A developer must learn to follow control flow, model data, understand HTTP, inspect SQL, debug failures, reason about state, and recognize the consequences of architectural decisions. Those skills create the mental models required to evaluate generated code.&lt;/p&gt;

&lt;p&gt;Without them, the developer may be able to produce software but cannot reliably judge it.&lt;/p&gt;

&lt;p&gt;The output may compile. The tests may pass. The code may even look clean. Yet the developer does not know whether the implementation fits the surrounding system, whether important cases are missing, or whether the design is carrying assumptions that were never verified.&lt;/p&gt;

&lt;p&gt;The problem is therefore not that the apprentice used a machine. The problem is that the machine allowed the apprentice to skip learning what a correct cut actually is.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Better Tools to Better Production
&lt;/h2&gt;

&lt;p&gt;Once the craft is understood, the next question is larger than individual skill.&lt;/p&gt;

&lt;p&gt;A good carpenter with a circular saw can build faster, but industrial production does not emerge merely because every carpenter receives a more powerful tool.&lt;/p&gt;

&lt;p&gt;Industrial production requires standards, repeatable processes, defined components, quality controls, inspections, and clear responsibility for the final product.&lt;/p&gt;

&lt;p&gt;This is where the IKEA analogy becomes useful.&lt;/p&gt;

&lt;p&gt;IKEA does not scale because every employee is the world’s greatest cabinetmaker. It scales because products are designed around standardized materials, documented parts, repeatable manufacturing, controlled tolerances, predictable logistics, and assembly processes that work across millions of units.&lt;/p&gt;

&lt;p&gt;The quality does not depend solely on one person’s memory or intuition. Knowledge has been moved into the production system.&lt;/p&gt;

&lt;p&gt;Software development has not fully reached that point.&lt;/p&gt;

&lt;p&gt;We have reusable packages, automated tests, static analysis, CI pipelines, containers, coding standards, observability, and increasingly capable coding agents. But many software systems still depend on undocumented assumptions, local knowledge, inconsistent architecture, incomplete tests, and developers who happen to remember why something was built ten years ago.&lt;/p&gt;

&lt;p&gt;That is not industrial production. It is craft production with increasingly powerful machinery.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Steam Engine Arrived Before the Factory
&lt;/h2&gt;

&lt;p&gt;This is why calling LLMs the industrial revolution of software is premature.&lt;/p&gt;

&lt;p&gt;They are closer to the steam engine arriving before we have finished building the factory.&lt;/p&gt;

&lt;p&gt;The machine is powerful. It can multiply output dramatically. But the surrounding structures are immature. We do not yet have universally reliable standards for generated code, consistent inspection methods, stable responsibility models, or production systems designed around autonomous implementation.&lt;/p&gt;

&lt;p&gt;So we place the steam engine inside the existing wooden workshop.&lt;/p&gt;

&lt;p&gt;Sometimes it powers a productive operation. Sometimes it shakes the building apart.&lt;/p&gt;

&lt;p&gt;The limiting factor is no longer only how quickly code can be written. The limiting factor becomes whether requirements are clear, context is available, assumptions are verified, results are tested, and decisions remain understandable after the agent has finished.&lt;/p&gt;

&lt;p&gt;LLMs expose this distinction brutally.&lt;/p&gt;

&lt;p&gt;When implementation becomes cheaper, every weakness around implementation becomes more visible. Poor specifications produce more incorrect code. Weak architecture produces more inconsistent code. Missing tests allow more regressions. Undocumented decisions become harder to reconstruct because the volume of change increases.&lt;/p&gt;

&lt;p&gt;The faster the machine, the more important the production system becomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generated Code Is Not Yet IKEA
&lt;/h2&gt;

&lt;p&gt;There is another side to the IKEA analogy.&lt;/p&gt;

&lt;p&gt;An IKEA cabinet can be perfectly adequate. It may be inexpensive, consistent, easy to replace, and durable enough for its purpose. It does not become inferior merely because it was not handcrafted.&lt;/p&gt;

&lt;p&gt;Generated code should be judged the same way.&lt;/p&gt;

&lt;p&gt;Code does not gain value because a human typed every character. Nor does it lose value because an LLM produced most of it. What matters is whether it solves the right problem, fits the system, remains maintainable, handles failure safely, and can be verified.&lt;/p&gt;

&lt;p&gt;But IKEA furniture arrives with defined parts, known materials, tested connectors, numbered steps, and a repeatable assembly process.&lt;/p&gt;

&lt;p&gt;Generated software usually does not.&lt;/p&gt;

&lt;p&gt;The output may look standardized, but the assumptions behind it are often specific to the current prompt, context window, repository state, and model behavior. Two apparently similar generations may differ in subtle but important ways. The developer cannot simply assume that generated code is an interchangeable industrial component.&lt;/p&gt;

&lt;p&gt;We have the appearance of mass production without all the guarantees of mass production.&lt;/p&gt;

&lt;p&gt;That is why the human role shifts rather than disappears.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Developer Becomes Responsible for the System
&lt;/h2&gt;

&lt;p&gt;When code generation becomes cheap, manually producing every line becomes less important. Understanding the system becomes more important.&lt;/p&gt;

&lt;p&gt;The developer’s responsibility moves toward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;defining the actual problem,&lt;/li&gt;
&lt;li&gt;providing relevant context,&lt;/li&gt;
&lt;li&gt;choosing architectural boundaries,&lt;/li&gt;
&lt;li&gt;identifying dangerous assumptions,&lt;/li&gt;
&lt;li&gt;verifying behavior,&lt;/li&gt;
&lt;li&gt;evaluating trade-offs,&lt;/li&gt;
&lt;li&gt;and preserving the reasoning behind decisions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a retreat from engineering. It is engineering at a higher level.&lt;/p&gt;

&lt;p&gt;The carpenter using a circular saw is not less skilled because the blade moves automatically. Skill appears in how the cut is planned, how the material is secured, how errors are prevented, and how the result is inspected.&lt;/p&gt;

&lt;p&gt;Likewise, a developer does not prove competence by typing code slowly without assistance. Competence appears in the ability to direct the tool, detect when it is wrong, and integrate its output into a reliable system.&lt;/p&gt;

&lt;p&gt;The goal is not to protect manual coding as a ritual.&lt;/p&gt;

&lt;p&gt;The goal is to ensure that increased production does not outrun understanding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Actual Path Toward the Software Factory
&lt;/h2&gt;

&lt;p&gt;The future of software development is therefore not simply more code generated by larger models.&lt;/p&gt;

&lt;p&gt;It is the gradual construction of a production system around those models.&lt;/p&gt;

&lt;p&gt;That system needs explicit requirements, constrained context, architecture rules, static analysis, automated tests, security checks, traceable decisions, reproducible agent workflows, and clear human approval points.&lt;/p&gt;

&lt;p&gt;Only then does the analogy begin to move from circular saw to IKEA.&lt;/p&gt;

&lt;p&gt;The individual developer still needs craftsmanship, because someone must understand the material and recognize failure. The apprentice still needs fundamentals, because judgment cannot be delegated before it exists. The organization needs production standards, because faster tools alone do not create reliable outcomes.&lt;/p&gt;

&lt;p&gt;LLMs are neither magical replacements for developers nor merely fancy autocomplete.&lt;/p&gt;

&lt;p&gt;They are powerful machinery.&lt;/p&gt;

&lt;p&gt;A skilled craftsperson can use that machinery to produce better work faster. A weak process can use it to manufacture defects at scale. And an immature industry can mistake increased output for industrialization.&lt;/p&gt;

&lt;p&gt;We have the circular saw.&lt;/p&gt;

&lt;p&gt;We may even have the steam engine.&lt;/p&gt;

&lt;p&gt;But we are still building the factory.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Distill Coding Agent Learnings</title>
      <dc:creator>Lars Moelleken</dc:creator>
      <pubDate>Thu, 16 Jul 2026 09:32:14 +0000</pubDate>
      <link>https://dev.to/suckup_de/distill-coding-agent-learnings-31og</link>
      <guid>https://dev.to/suckup_de/distill-coding-agent-learnings-31og</guid>
      <description>&lt;p&gt;Repo: &lt;a href="https://github.com/voku/agent-loop" rel="noopener noreferrer"&gt;https://github.com/voku/agent-loop&lt;/a&gt;&lt;br&gt;
Demo: &lt;a href="https://voku.github.io/agent_loop_demo/" rel="noopener noreferrer"&gt;https://voku.github.io/agent_loop_demo/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your Coding Agent Doesn’t Need More Memory. It Needs a Governed Loop.&lt;/p&gt;

&lt;p&gt;Coding agents repeat mistakes.&lt;/p&gt;

&lt;p&gt;The obvious response is to give them more memory:&lt;/p&gt;

&lt;p&gt;MEMORY.md&lt;br&gt;
project-rules.md&lt;br&gt;
agent-notes.md&lt;br&gt;
lessons-learned.md&lt;br&gt;
MEMORY_FINAL.md&lt;/p&gt;

&lt;p&gt;Soon the agent receives old decisions, temporary workarounds, copied transcripts, abandoned ideas, and rules nobody remembers approving.&lt;/p&gt;

&lt;p&gt;It has more context.&lt;/p&gt;

&lt;p&gt;It does not necessarily have better context.&lt;/p&gt;

&lt;p&gt;At some point, memory becomes landfill.&lt;/p&gt;

&lt;p&gt;The problem is not that coding agents forget too much.&lt;/p&gt;

&lt;p&gt;The problem is that most workflows fail to distinguish between temporary context, evidence, proposed learning, and approved project guidance.&lt;/p&gt;

&lt;p&gt;A transcript is not memory.&lt;br&gt;
A note is not a rule.&lt;br&gt;
A finding is not guidance.&lt;br&gt;
And a successful patch is not automatically a project convention.&lt;/p&gt;

&lt;p&gt;Instead of giving the agent one growing pile of context, I built "voku/agent-loop" around a governed workflow:&lt;/p&gt;

&lt;p&gt;task&lt;br&gt;
  -&amp;gt; candidate plan&lt;br&gt;
  -&amp;gt; human approval&lt;br&gt;
  -&amp;gt; selective recall&lt;br&gt;
  -&amp;gt; implementation&lt;br&gt;
  -&amp;gt; verification&lt;br&gt;
  -&amp;gt; recorded evidence&lt;br&gt;
  -&amp;gt; reviewed learning&lt;/p&gt;

&lt;p&gt;The important detail is that the developer does not normally operate this workflow by typing every CLI command.&lt;/p&gt;

&lt;p&gt;The coding agent does that through related skills provided by, or adapted from, "agent-loop".&lt;/p&gt;

&lt;p&gt;The human describes the task, reviews the proposed scope, approves or corrects it, and decides whether anything should become durable project guidance.&lt;/p&gt;

&lt;p&gt;The agent operates the loop.&lt;/p&gt;

&lt;p&gt;The human governs the decisions that should not be delegated.&lt;/p&gt;

&lt;p&gt;The CLI is not the user interface&lt;/p&gt;

&lt;p&gt;When people see a CLI project, they naturally assume the workflow looks like this:&lt;/p&gt;

&lt;p&gt;vendor/bin/agent-loop workflow plan PROJECT-123 ...&lt;br&gt;
vendor/bin/agent-loop workflow approve PROJECT-123 --by lars&lt;br&gt;
vendor/bin/agent-loop verify&lt;br&gt;
vendor/bin/agent-loop workflow close PROJECT-123 --status done&lt;/p&gt;

&lt;p&gt;That is what happens underneath.&lt;/p&gt;

&lt;p&gt;It is not how I use it day to day.&lt;/p&gt;

&lt;p&gt;I do not manually type an approval command every time a coding agent proposes a plan.&lt;/p&gt;

&lt;p&gt;I say:&lt;/p&gt;

&lt;p&gt;Yep, approved.&lt;/p&gt;

&lt;p&gt;The coding agent recognizes that explicit approval and records it through the workflow.&lt;/p&gt;

&lt;p&gt;A normal interaction looks more like this:&lt;/p&gt;

&lt;p&gt;Developer:&lt;br&gt;
Fix PROJECT-123.&lt;/p&gt;

&lt;p&gt;Invalid order state transitions must be rejected.&lt;br&gt;
Stay inside the order-state validation and its tests.&lt;br&gt;
Run PHPStan and the focused tests.&lt;br&gt;
Show me the plan before changing code.&lt;/p&gt;

&lt;p&gt;Coding agent:&lt;br&gt;
I propose the following work brief:&lt;/p&gt;

&lt;p&gt;Goal:&lt;br&gt;
Reject invalid order state transitions.&lt;/p&gt;

&lt;p&gt;Scope:&lt;br&gt;
Order state validation and focused tests.&lt;/p&gt;

&lt;p&gt;Non-goals:&lt;br&gt;
Do not redesign the order aggregate.&lt;/p&gt;

&lt;p&gt;Validation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;composer phpstan&lt;/li&gt;
&lt;li&gt;composer test&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Approve this scope?&lt;/p&gt;

&lt;p&gt;Developer:&lt;br&gt;
Yep, approved.&lt;/p&gt;

&lt;p&gt;Coding agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;records the approved revision;&lt;/li&gt;
&lt;li&gt;compiles the relevant context;&lt;/li&gt;
&lt;li&gt;implements the change;&lt;/li&gt;
&lt;li&gt;runs the declared validation;&lt;/li&gt;
&lt;li&gt;records the evidence;&lt;/li&gt;
&lt;li&gt;reviews blind spots;&lt;/li&gt;
&lt;li&gt;reports the result and remaining risks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the actual interface.&lt;/p&gt;

&lt;p&gt;The developer talks to the coding agent.&lt;/p&gt;

&lt;p&gt;The coding agent operates the workflow.&lt;/p&gt;

&lt;p&gt;The CLI provides deterministic state transitions and inspectable evidence behind the interaction.&lt;/p&gt;

&lt;p&gt;Otherwise, we would have built a sophisticated automation system whose main achievement was teaching developers to copy longer shell commands.&lt;/p&gt;

&lt;p&gt;Start with approved scope&lt;/p&gt;

&lt;p&gt;A coding agent should not begin by reading a ticket and creatively filling in everything the ticket forgot to mention.&lt;/p&gt;

&lt;p&gt;It should begin by producing an explicit work brief containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the goal;&lt;/li&gt;
&lt;li&gt;permitted scope;&lt;/li&gt;
&lt;li&gt;non-goals;&lt;/li&gt;
&lt;li&gt;affected areas;&lt;/li&gt;
&lt;li&gt;required validation;&lt;/li&gt;
&lt;li&gt;unresolved assumptions;&lt;/li&gt;
&lt;li&gt;required human approval.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The human can then answer naturally:&lt;/p&gt;

&lt;p&gt;Approved.&lt;/p&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;p&gt;No. Do not change the repository layer.&lt;br&gt;
Keep the scope inside the service and its tests.&lt;/p&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;p&gt;Approved, but the public API must remain unchanged.&lt;/p&gt;

&lt;p&gt;The agent records the concrete approved revision internally.&lt;/p&gt;

&lt;p&gt;When the plan changes materially, the old revision is no longer sufficient.&lt;/p&gt;

&lt;p&gt;The agent must present the updated plan and request approval again.&lt;/p&gt;

&lt;p&gt;An approval should apply to a concrete work brief, not permanently to a task ID whose meaning can silently change.&lt;/p&gt;

&lt;p&gt;That may sound slightly bureaucratic until an agent performs a technically impressive refactoring nobody requested.&lt;/p&gt;

&lt;p&gt;Skills operate the loop&lt;/p&gt;

&lt;p&gt;"agent-loop" ships focused operational skills for coding agents working in consuming repositories:&lt;/p&gt;

&lt;p&gt;agent-loop-task-start&lt;br&gt;
agent-loop-l2-context&lt;br&gt;
agent-loop-task-progress&lt;br&gt;
agent-loop-review-close&lt;br&gt;
agent-loop-learning-boundary&lt;/p&gt;

&lt;p&gt;There is also a broader "agent-loop-workflow" skill that describes the complete workflow and command vocabulary.&lt;/p&gt;

&lt;p&gt;The smaller skills are intended for actual coding-agent sessions.&lt;/p&gt;

&lt;p&gt;A coding agent loads the skill matching its current stage instead of pulling one giant workflow document into every task.&lt;/p&gt;

&lt;p&gt;Their responsibilities are deliberately separated.&lt;/p&gt;

&lt;p&gt;agent-loop-task-start&lt;br&gt;
  -&amp;gt; inspect the task&lt;br&gt;
  -&amp;gt; create a candidate work brief&lt;br&gt;
  -&amp;gt; compile initial recall&lt;br&gt;
  -&amp;gt; present the scope&lt;br&gt;
  -&amp;gt; request human approval&lt;br&gt;
  -&amp;gt; record the approved revision&lt;/p&gt;

&lt;p&gt;agent-loop-l2-context&lt;br&gt;
  -&amp;gt; select relevant project guidance&lt;br&gt;
  -&amp;gt; provide bounded context artifacts&lt;br&gt;
  -&amp;gt; distinguish supplied context from executed work&lt;/p&gt;

&lt;p&gt;agent-loop-task-progress&lt;br&gt;
  -&amp;gt; record decisions&lt;br&gt;
  -&amp;gt; record checkpoints&lt;br&gt;
  -&amp;gt; track scope changes&lt;br&gt;
  -&amp;gt; record validation evidence&lt;br&gt;
  -&amp;gt; bind evidence to the current plan revision&lt;/p&gt;

&lt;p&gt;agent-loop-review-close&lt;br&gt;
  -&amp;gt; review blind spots&lt;br&gt;
  -&amp;gt; verify the workflow state&lt;br&gt;
  -&amp;gt; report remaining risks&lt;br&gt;
  -&amp;gt; close only when the required gates pass&lt;/p&gt;

&lt;p&gt;agent-loop-learning-boundary&lt;br&gt;
  -&amp;gt; capture reusable findings&lt;br&gt;
  -&amp;gt; prepare learning proposals&lt;br&gt;
  -&amp;gt; prevent automatic promotion into durable guidance&lt;/p&gt;

&lt;p&gt;Host repositories can synchronize these skills into their coding-agent environment and adapt them to project-specific conventions.&lt;/p&gt;

&lt;p&gt;The result is not a magical agent that understands governance by intuition.&lt;/p&gt;

&lt;p&gt;It is an agent with explicit operating instructions and a workflow that leaves evidence behind.&lt;/p&gt;

&lt;p&gt;Load less context, not more&lt;/p&gt;

&lt;p&gt;The coding agent usually needs two different kinds of context:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;project guidance;&lt;/li&gt;
&lt;li&gt;code structure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;"agent-recall-compiler" selects task-specific guidance.&lt;/p&gt;

&lt;p&gt;"agent-map" provides compact information about the relevant code.&lt;/p&gt;

&lt;p&gt;These are separate because they answer separate questions.&lt;/p&gt;

&lt;p&gt;Recall:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which rules apply?&lt;/li&gt;
&lt;li&gt;Which previous decisions matter?&lt;/li&gt;
&lt;li&gt;What must be validated?&lt;/li&gt;
&lt;li&gt;Which constraints conflict?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Map:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where is this class defined?&lt;/li&gt;
&lt;li&gt;Which methods and dependencies are relevant?&lt;/li&gt;
&lt;li&gt;Which tests cover this area?&lt;/li&gt;
&lt;li&gt;What is the smallest useful code neighbourhood?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The coding agent can use the related skills to invoke these tools itself.&lt;/p&gt;

&lt;p&gt;The developer should not need to compile recall output manually, inspect a symbol index, copy selected Markdown into a prompt, and then tell the agent to continue.&lt;/p&gt;

&lt;p&gt;The agent should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;build or refresh the relevant map;&lt;/li&gt;
&lt;li&gt;compile task-specific recall;&lt;/li&gt;
&lt;li&gt;inspect the bounded output;&lt;/li&gt;
&lt;li&gt;load only the necessary source ranges;&lt;/li&gt;
&lt;li&gt;report missing or conflicting evidence.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal is not to compress the complete repository into the prompt.&lt;/p&gt;

&lt;p&gt;The goal is to avoid loading most of it.&lt;/p&gt;

&lt;p&gt;Dumping a full AST or several months of transcripts into the context window is not understanding.&lt;/p&gt;

&lt;p&gt;It is bulk data transport with unusually confident autocomplete.&lt;/p&gt;

&lt;p&gt;Keep working memory temporary&lt;/p&gt;

&lt;p&gt;During implementation, the agent may need to track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;assumptions;&lt;/li&gt;
&lt;li&gt;claimed files;&lt;/li&gt;
&lt;li&gt;checkpoints;&lt;/li&gt;
&lt;li&gt;open questions;&lt;/li&gt;
&lt;li&gt;intermediate decisions;&lt;/li&gt;
&lt;li&gt;validation results;&lt;/li&gt;
&lt;li&gt;blocked states;&lt;/li&gt;
&lt;li&gt;scope changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That belongs in a task session.&lt;/p&gt;

&lt;p&gt;It should be inspectable, closable, and removable.&lt;/p&gt;

&lt;p&gt;Temporary observations should not silently become permanent project knowledge.&lt;/p&gt;

&lt;p&gt;A workaround that was useful for one task may become actively misleading after the code changes.&lt;/p&gt;

&lt;p&gt;A useful system therefore needs at least three levels:&lt;/p&gt;

&lt;p&gt;session state       temporary working information&lt;br&gt;
finding             evidence requiring review&lt;br&gt;
guidance            approved durable knowledge&lt;/p&gt;

&lt;p&gt;Collapsing those levels into one memory file removes the provenance that makes information trustworthy.&lt;/p&gt;

&lt;p&gt;A note from a debugging session is not automatically a project rule.&lt;/p&gt;

&lt;p&gt;A finding is not automatically guidance.&lt;/p&gt;

&lt;p&gt;And a selected piece of context is not automatically something the agent actually used.&lt;/p&gt;

&lt;p&gt;Verification is part of the loop&lt;/p&gt;

&lt;p&gt;An agent saying “done” is not evidence.&lt;/p&gt;

&lt;p&gt;The work brief already contains the expected validation commands.&lt;/p&gt;

&lt;p&gt;The coding agent runs those commands and records the real results against the approved plan revision.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Approved scope:&lt;br&gt;
Order state validation and its focused tests&lt;/p&gt;

&lt;p&gt;Declared validation:&lt;br&gt;
composer phpstan&lt;br&gt;
composer test&lt;/p&gt;

&lt;p&gt;Observed changes:&lt;br&gt;
src/Order/OrderService.php&lt;br&gt;
tests/Order/OrderServiceTest.php&lt;/p&gt;

&lt;p&gt;Validation evidence:&lt;br&gt;
composer phpstan -&amp;gt; passed&lt;br&gt;
composer test    -&amp;gt; passed&lt;/p&gt;

&lt;p&gt;Unexpected paths:&lt;br&gt;
none&lt;/p&gt;

&lt;p&gt;The exact commands depend on the repository.&lt;/p&gt;

&lt;p&gt;They may include:&lt;/p&gt;

&lt;p&gt;composer phpstan&lt;br&gt;
composer test&lt;br&gt;
composer cs&lt;/p&gt;

&lt;p&gt;The important rule is:&lt;/p&gt;

&lt;p&gt;«Validation must be declared before implementation, not invented afterwards to match whatever changed.»&lt;/p&gt;

&lt;p&gt;A passing test suite also does not prove that the agent stayed inside scope.&lt;/p&gt;

&lt;p&gt;Tests can pass after an unnecessary architectural rewrite just as happily as after a focused bug fix.&lt;/p&gt;

&lt;p&gt;That is why code validation and workflow verification are related but separate concerns.&lt;/p&gt;

&lt;p&gt;The workflow must also verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether the current plan was approved;&lt;/li&gt;
&lt;li&gt;whether the implementation remained inside scope;&lt;/li&gt;
&lt;li&gt;whether validation evidence belongs to the current revision;&lt;/li&gt;
&lt;li&gt;whether required review steps were completed;&lt;/li&gt;
&lt;li&gt;whether unresolved risk was recorded;&lt;/li&gt;
&lt;li&gt;whether the task is actually ready to close.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A polished summary is not a substitute for evidence.&lt;/p&gt;

&lt;p&gt;Coding agents are already very good at producing polished summaries.&lt;/p&gt;

&lt;p&gt;Selected guidance is not necessarily useful guidance&lt;/p&gt;

&lt;p&gt;Recall may select a guidance item for a task.&lt;/p&gt;

&lt;p&gt;Selection alone proves nothing.&lt;/p&gt;

&lt;p&gt;The guidance may turn out to be:&lt;/p&gt;

&lt;p&gt;HELPFUL&lt;br&gt;
IRRELEVANT&lt;br&gt;
HARMFUL&lt;br&gt;
NOT_USED&lt;br&gt;
UNKNOWN&lt;/p&gt;

&lt;p&gt;"NOT_USED" is particularly important.&lt;/p&gt;

&lt;p&gt;A guidance item may have been selected for an investigation but never actually consulted during implementation.&lt;/p&gt;

&lt;p&gt;Without recording that distinction, selection statistics quietly become usage statistics.&lt;/p&gt;

&lt;p&gt;The metrics then begin describing a workflow that never happened.&lt;/p&gt;

&lt;p&gt;The difference is simple:&lt;/p&gt;

&lt;p&gt;selection = the system supplied it&lt;br&gt;
usage     = the agent consulted it&lt;br&gt;
outcome   = whether it helped&lt;/p&gt;

&lt;p&gt;The coding agent can record these outcomes during review.&lt;/p&gt;

&lt;p&gt;The developer does not need to maintain a spreadsheet documenting which Markdown fragment appeared in which generated prompt.&lt;/p&gt;

&lt;p&gt;Recording selection, usage, and outcome separately gives us evidence for improving recall.&lt;/p&gt;

&lt;p&gt;Otherwise, we merely count how often a file was copied somewhere.&lt;/p&gt;

&lt;p&gt;Learning still requires a human&lt;/p&gt;

&lt;p&gt;After the task, the coding agent may record findings.&lt;/p&gt;

&lt;p&gt;A finding is evidence.&lt;/p&gt;

&lt;p&gt;It is not automatically a new rule.&lt;/p&gt;

&lt;p&gt;The "agent-loop-learning-boundary" skill helps the agent determine whether anything from the task deserves to be presented as reusable knowledge.&lt;/p&gt;

&lt;p&gt;A finding may lead to a proposal such as:&lt;/p&gt;

&lt;p&gt;ADD&lt;br&gt;
REPLACE&lt;br&gt;
DELETE&lt;br&gt;
REJECT&lt;br&gt;
NO_DURABLE_LEARNING&lt;/p&gt;

&lt;p&gt;The agent may:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;collect evidence;&lt;/li&gt;
&lt;li&gt;identify repeated patterns;&lt;/li&gt;
&lt;li&gt;find conflicting guidance;&lt;/li&gt;
&lt;li&gt;prepare a proposal;&lt;/li&gt;
&lt;li&gt;recommend an outcome.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It must not silently approve its own proposal as durable project knowledge.&lt;/p&gt;

&lt;p&gt;A human reviews the proposal before durable guidance changes.&lt;/p&gt;

&lt;p&gt;Most tasks should probably end with:&lt;/p&gt;

&lt;p&gt;NO_DURABLE_LEARNING&lt;/p&gt;

&lt;p&gt;Fixing one bug does not necessarily reveal a reusable project rule.&lt;/p&gt;

&lt;p&gt;Sometimes the correct conclusion is simply that the bug was fixed.&lt;/p&gt;

&lt;p&gt;That conclusion has its own terminal state:&lt;/p&gt;

&lt;p&gt;ACKNOWLEDGED&lt;/p&gt;

&lt;p&gt;It is neither approved as a guidance change nor rejected as incorrect.&lt;/p&gt;

&lt;p&gt;It records that the result was reviewed and no durable change was needed.&lt;/p&gt;

&lt;p&gt;This may look like excessive precision for one status name.&lt;/p&gt;

&lt;p&gt;It is not.&lt;/p&gt;

&lt;p&gt;When lifecycle states use the wrong verbs, audit trails gradually stop saying what actually happened.&lt;/p&gt;

&lt;p&gt;Humans approve decisions, not shell commands&lt;/p&gt;

&lt;p&gt;The intended responsibility boundary is:&lt;/p&gt;

&lt;p&gt;Coding agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inspect the task;&lt;/li&gt;
&lt;li&gt;propose scope;&lt;/li&gt;
&lt;li&gt;operate agent-loop;&lt;/li&gt;
&lt;li&gt;compile relevant context;&lt;/li&gt;
&lt;li&gt;edit the code;&lt;/li&gt;
&lt;li&gt;run validation;&lt;/li&gt;
&lt;li&gt;record evidence;&lt;/li&gt;
&lt;li&gt;review blind spots;&lt;/li&gt;
&lt;li&gt;report risks;&lt;/li&gt;
&lt;li&gt;prepare findings and learning proposals.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Human:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;describe the task;&lt;/li&gt;
&lt;li&gt;approve or correct the proposed scope;&lt;/li&gt;
&lt;li&gt;decide whether expanded scope is acceptable;&lt;/li&gt;
&lt;li&gt;review the resulting change;&lt;/li&gt;
&lt;li&gt;accept or reject remaining risk;&lt;/li&gt;
&lt;li&gt;decide whether proposed knowledge should become durable guidance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The human communicates those decisions in normal language.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Yep, approved.&lt;/p&gt;

&lt;p&gt;Approved, but do not touch the public API.&lt;/p&gt;

&lt;p&gt;No, this is too broad. Keep the existing abstraction.&lt;/p&gt;

&lt;p&gt;That additional database migration is outside the approved scope.&lt;/p&gt;

&lt;p&gt;The remaining risk is acceptable.&lt;/p&gt;

&lt;p&gt;That finding is task-specific. Do not promote it.&lt;/p&gt;

&lt;p&gt;Looks good. Close it.&lt;/p&gt;

&lt;p&gt;The coding agent converts those decisions into explicit workflow state.&lt;/p&gt;

&lt;p&gt;Natural-language confirmation does not bypass the gates.&lt;/p&gt;

&lt;p&gt;It triggers the agent to operate them.&lt;/p&gt;

&lt;p&gt;Requiring the human to type the corresponding CLI command would not improve governance.&lt;/p&gt;

&lt;p&gt;It would merely expose internal plumbing that the coding agent is already capable of operating.&lt;/p&gt;

&lt;p&gt;What "agent-loop" actually does&lt;/p&gt;

&lt;p&gt;"voku/agent-loop" is a PHP 8.3 CLI that coordinates several focused packages:&lt;/p&gt;

&lt;p&gt;agent-kanban           work and task state&lt;br&gt;
agent-session          temporary working memory&lt;br&gt;
agent-recall-compiler  selective project guidance&lt;br&gt;
agent-map              compact code intelligence&lt;br&gt;
agent-learning         governed durable learning&lt;br&gt;
agent-loop             orchestration&lt;/p&gt;

&lt;p&gt;The CLI provides deterministic operations and inspectable artifacts.&lt;/p&gt;

&lt;p&gt;The accompanying skills teach coding agents when and how to use those operations.&lt;/p&gt;

&lt;p&gt;Together, they provide:&lt;/p&gt;

&lt;p&gt;skills       agent-facing workflow behaviour&lt;br&gt;
CLI          deterministic workflow operations&lt;br&gt;
artifacts    inspectable state and evidence&lt;br&gt;
humans       approval and governance&lt;/p&gt;

&lt;p&gt;"agent-loop" does not replace maintainers, code review, static analysis, tests, or domain knowledge.&lt;/p&gt;

&lt;p&gt;It gives those existing engineering practices an explicit workflow around coding agents.&lt;/p&gt;

&lt;p&gt;Getting started&lt;/p&gt;

&lt;p&gt;There are two separate parts:&lt;/p&gt;

&lt;p&gt;one-time repository setup&lt;br&gt;
    -&amp;gt; install and synchronize the workflow&lt;/p&gt;

&lt;p&gt;daily task operation&lt;br&gt;
    -&amp;gt; talk to the coding agent&lt;/p&gt;

&lt;p&gt;Install the package&lt;/p&gt;

&lt;p&gt;Install "agent-loop" in an existing Composer project:&lt;/p&gt;

&lt;p&gt;composer require --dev voku/agent-loop&lt;/p&gt;

&lt;p&gt;Scaffold the local workflow&lt;/p&gt;

&lt;p&gt;Create the minimal local workflow structure:&lt;/p&gt;

&lt;p&gt;vendor/bin/agent-loop init scaffold&lt;/p&gt;

&lt;p&gt;To inspect what would be created without writing anything:&lt;/p&gt;

&lt;p&gt;vendor/bin/agent-loop init scaffold --dry-run&lt;/p&gt;

&lt;p&gt;The scaffold creates the initial local workflow inputs when they do not already exist:&lt;/p&gt;

&lt;p&gt;.agent-loop/init.json&lt;br&gt;
todo/board.md&lt;br&gt;
todo/cards/DEMO-1.md&lt;br&gt;
tasks/DEMO-1.md&lt;br&gt;
session_plan/&lt;br&gt;
infra/doc/agent-learning/findings/&lt;/p&gt;

&lt;p&gt;Existing files are preserved.&lt;/p&gt;

&lt;p&gt;"DEMO-1" is a clearly marked example task, not a special workflow mode.&lt;/p&gt;

&lt;p&gt;You can inspect it with:&lt;/p&gt;

&lt;p&gt;vendor/bin/agent-loop board card show DEMO-1&lt;/p&gt;

&lt;p&gt;Synchronize the coding-agent skills&lt;/p&gt;

&lt;p&gt;Preview the skill synchronization for Codex:&lt;/p&gt;

&lt;p&gt;vendor/bin/agent-loop init sync-skills \&lt;br&gt;
  --agent=codex \&lt;br&gt;
  --dry-run&lt;/p&gt;

&lt;p&gt;After reviewing the planned changes:&lt;/p&gt;

&lt;p&gt;vendor/bin/agent-loop init sync-skills --agent=codex&lt;/p&gt;

&lt;p&gt;These are setup and maintenance commands.&lt;/p&gt;

&lt;p&gt;They are not the normal per-task interface.&lt;/p&gt;

&lt;p&gt;The synchronized skills teach the coding agent how to operate the workflow in the consuming repository.&lt;/p&gt;

&lt;p&gt;Use the workflow through normal conversation&lt;/p&gt;

&lt;p&gt;Once the skills are available, start with an ordinary task request:&lt;/p&gt;

&lt;p&gt;Take PROJECT-123.&lt;/p&gt;

&lt;p&gt;Reject invalid order state transitions.&lt;br&gt;
Stay inside the service and its focused tests.&lt;br&gt;
Run PHPStan and the tests.&lt;br&gt;
Show me the proposed scope before changing code.&lt;/p&gt;

&lt;p&gt;The coding agent inspects the task and presents a candidate work brief:&lt;/p&gt;

&lt;p&gt;Goal:&lt;br&gt;
Reject invalid order state transitions.&lt;/p&gt;

&lt;p&gt;Scope:&lt;br&gt;
Order state validation and focused tests.&lt;/p&gt;

&lt;p&gt;Non-goals:&lt;br&gt;
Do not redesign the aggregate.&lt;br&gt;
Do not change the public API.&lt;/p&gt;

&lt;p&gt;Validation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;composer phpstan&lt;/li&gt;
&lt;li&gt;composer test&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Approve this plan?&lt;/p&gt;

&lt;p&gt;You answer normally:&lt;/p&gt;

&lt;p&gt;Yep, approved.&lt;/p&gt;

&lt;p&gt;The agent then operates the workflow:&lt;/p&gt;

&lt;p&gt;record approved revision&lt;br&gt;
  -&amp;gt; compile bounded context&lt;br&gt;
  -&amp;gt; inspect relevant code&lt;br&gt;
  -&amp;gt; implement&lt;br&gt;
  -&amp;gt; validate&lt;br&gt;
  -&amp;gt; record evidence&lt;br&gt;
  -&amp;gt; review blind spots&lt;br&gt;
  -&amp;gt; make a learning decision&lt;br&gt;
  -&amp;gt; verify&lt;br&gt;
  -&amp;gt; report&lt;/p&gt;

&lt;p&gt;You can interrupt or redirect it in the same way:&lt;/p&gt;

&lt;p&gt;Stop. That migration is outside the approved scope.&lt;/p&gt;

&lt;p&gt;The agent must then revise the work brief and request approval for the expanded plan before continuing.&lt;/p&gt;

&lt;p&gt;At the end, the agent reports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what changed;&lt;/li&gt;
&lt;li&gt;which validation commands ran;&lt;/li&gt;
&lt;li&gt;whether they passed;&lt;/li&gt;
&lt;li&gt;whether the approved scope was respected;&lt;/li&gt;
&lt;li&gt;which risks remain;&lt;/li&gt;
&lt;li&gt;whether any reusable learning was found.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can respond:&lt;/p&gt;

&lt;p&gt;Looks good. Close it.&lt;/p&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;p&gt;The code is fine, but that proposed learning is too broad.&lt;br&gt;
Close the task without promoting it.&lt;/p&gt;

&lt;p&gt;The agent records and verifies those decisions through "agent-loop".&lt;/p&gt;

&lt;p&gt;You do not manually translate them into CLI commands.&lt;/p&gt;

&lt;p&gt;What happens under the hood&lt;/p&gt;

&lt;p&gt;Internally, the coding-agent skills may execute operations for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;planning;&lt;/li&gt;
&lt;li&gt;approval;&lt;/li&gt;
&lt;li&gt;context compilation;&lt;/li&gt;
&lt;li&gt;task progress;&lt;/li&gt;
&lt;li&gt;validation evidence;&lt;/li&gt;
&lt;li&gt;checkpoints;&lt;/li&gt;
&lt;li&gt;blind-spot review;&lt;/li&gt;
&lt;li&gt;learning decisions;&lt;/li&gt;
&lt;li&gt;verification;&lt;/li&gt;
&lt;li&gt;closure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That internal command sequence remains valuable because it provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deterministic state transitions;&lt;/li&gt;
&lt;li&gt;inspectable artifacts;&lt;/li&gt;
&lt;li&gt;revision-bound approval;&lt;/li&gt;
&lt;li&gt;validation evidence;&lt;/li&gt;
&lt;li&gt;explicit close gates;&lt;/li&gt;
&lt;li&gt;auditable learning decisions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But those commands belong behind the agent-facing skill.&lt;/p&gt;

&lt;p&gt;They are similar to database queries behind an application form.&lt;/p&gt;

&lt;p&gt;Essential to the implementation.&lt;/p&gt;

&lt;p&gt;Not something the user should have to execute manually.&lt;/p&gt;

&lt;p&gt;The developer should not need to memorize the workflow commands.&lt;/p&gt;

&lt;p&gt;The skill should.&lt;/p&gt;

&lt;p&gt;The actual lesson&lt;/p&gt;

&lt;p&gt;Coding agents do not need to remember everything.&lt;/p&gt;

&lt;p&gt;They need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;agent-operated workflow skills;&lt;/li&gt;
&lt;li&gt;explicit scope;&lt;/li&gt;
&lt;li&gt;revisioned human approval;&lt;/li&gt;
&lt;li&gt;selective context;&lt;/li&gt;
&lt;li&gt;temporary working memory;&lt;/li&gt;
&lt;li&gt;declared validation;&lt;/li&gt;
&lt;li&gt;recorded execution evidence;&lt;/li&gt;
&lt;li&gt;human-reviewed learning;&lt;/li&gt;
&lt;li&gt;intentional forgetting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More memory hides bad context management.&lt;/p&gt;

&lt;p&gt;A governed loop exposes it.&lt;/p&gt;

&lt;p&gt;The purpose is not to make developers manually operate a more elaborate CLI.&lt;/p&gt;

&lt;p&gt;The purpose is to give coding agents a repeatable process they can operate themselves, while preserving human control over scope, risk, and durable project knowledge.&lt;/p&gt;

&lt;p&gt;The agent does the workflow work.&lt;/p&gt;

&lt;p&gt;The human remains responsible for the decisions that matter.&lt;/p&gt;

&lt;p&gt;And once the workflow can reject stale approvals, irrelevant guidance, unsupported claims, and accidental lessons, the agent does not need to behave as though it remembers the entire repository.&lt;/p&gt;

&lt;p&gt;It only needs enough verified context to complete one controlled task.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>php</category>
      <category>agents</category>
    </item>
    <item>
      <title>Multi-Line Formatting by Default</title>
      <dc:creator>Lars Moelleken</dc:creator>
      <pubDate>Wed, 27 May 2026 01:04:14 +0000</pubDate>
      <link>https://dev.to/suckup_de/multi-line-formatting-by-default-chi</link>
      <guid>https://dev.to/suckup_de/multi-line-formatting-by-default-chi</guid>
      <description>&lt;p&gt;I have reviewed so much code that I usually prefer multi-line formatting by default.&lt;/p&gt;

&lt;p&gt;Not because it looks prettier.&lt;/p&gt;

&lt;p&gt;Because code review happens line by line. And also tools like static analysis or SQL errors are reported line by line.&lt;/p&gt;

&lt;p&gt;PS: in most IDEs you can directly jump into the code by typing or clicking FILE:LINE e.g. in the quick-seach (typing) or in the command line (clicking)&lt;/p&gt;

&lt;p&gt;A one-line change should ideally mean:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;one thing changed&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sounds obvious, which means we apparently need examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with compact code
&lt;/h2&gt;

&lt;p&gt;Compact code often hides the actual change.&lt;/p&gt;

&lt;p&gt;A reviewer does not review “the code” in some magical abstract universe.&lt;/p&gt;

&lt;p&gt;A reviewer reviews a diff.&lt;/p&gt;

&lt;p&gt;And diffs are line-based.&lt;/p&gt;

&lt;p&gt;So when multiple independent decisions live on the same line, every change becomes harder to verify.&lt;/p&gt;

&lt;p&gt;That is how small changes sneak through review.&lt;/p&gt;

&lt;p&gt;Not because reviewers are lazy.&lt;/p&gt;

&lt;p&gt;Well, sometimes because reviewers are lazy.&lt;/p&gt;

&lt;p&gt;But often because the formatting makes the review harder than necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript
&lt;/h2&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;selectedUserId&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;selectedUserId&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleted&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now a reviewer can see whether someone changed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;selectedUserId&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One logical condition per line.&lt;/p&gt;

&lt;p&gt;Primitive stuff. Somehow still rare.&lt;/p&gt;

&lt;h2&gt;
  
  
  SQL
&lt;/h2&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;deleted_at&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;deleted_at&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now changing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;email&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;private_email&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is one line.&lt;/p&gt;

&lt;p&gt;Adding a filter is one line.&lt;/p&gt;

&lt;p&gt;Removing a selected column is one line.&lt;/p&gt;

&lt;p&gt;The diff no longer looks like someone threw SQL into a blender and called it “compact”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conditions
&lt;/h2&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isDeleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isDeleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now each condition can be reviewed independently.&lt;/p&gt;

&lt;p&gt;This matters when someone changes this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not a formatting change.&lt;/p&gt;

&lt;p&gt;That is the kind of thing that becomes a production incident wearing a fake mustache.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTML
&lt;/h2&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control is-invalid"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"{{ email }}"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
    &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
    &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control is-invalid"&lt;/span&gt;
    &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"{{ email }}"&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;
    &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now changing &lt;code&gt;required&lt;/code&gt;, &lt;code&gt;autocomplete&lt;/code&gt;, &lt;code&gt;class&lt;/code&gt;, or &lt;code&gt;value&lt;/code&gt; is visible.&lt;/p&gt;

&lt;p&gt;This also avoids huge horizontal lines, because apparently screens are wide but attention spans are not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Function parameters
&lt;/h2&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$userRepository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;findActiveUserByEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'editor'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$userRepository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;findActiveUserByEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;includeDisabled&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;includeDeleted&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'editor'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not only easier to review.&lt;/p&gt;

&lt;p&gt;It also prevents the classic mystery-boolean nonsense:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lovely.&lt;/p&gt;

&lt;p&gt;Very expressive.&lt;/p&gt;

&lt;p&gt;Archaeologists will enjoy it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Arrays
&lt;/h2&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'enabled'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'timeout'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'retries'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'log_errors'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'enabled'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'timeout'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'retries'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'log_errors'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now changing one value changes one line.&lt;/p&gt;

&lt;p&gt;Adding one entry adds one line.&lt;/p&gt;

&lt;p&gt;Removing one entry removes one line.&lt;/p&gt;

&lt;p&gt;No fake diff noise.&lt;/p&gt;

&lt;p&gt;No guessing.&lt;/p&gt;

&lt;p&gt;No “wait, what changed here?”&lt;/p&gt;

&lt;h2&gt;
  
  
  Config blocks
&lt;/h2&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'cache'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'ttl'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'debug'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'strict'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'cache'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'ttl'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'debug'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'strict'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configuration changes are exactly where review clarity matters.&lt;/p&gt;

&lt;p&gt;One flag can change behavior across the whole system.&lt;/p&gt;

&lt;p&gt;So maybe, just maybe, hiding it inside a long horizontal sausage is not peak engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method chains
&lt;/h2&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$queryBuilder&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'active = 1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'DESC'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$queryBuilder&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'active = 1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'DESC'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now each query operation has its own line.&lt;/p&gt;

&lt;p&gt;A reviewer can spot whether the change touched:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'active = 1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That matters.&lt;/p&gt;

&lt;p&gt;Especially when someone quietly turns &lt;code&gt;50&lt;/code&gt; into &lt;code&gt;5000&lt;/code&gt; and suddenly the database starts filing a workplace complaint.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual rule
&lt;/h2&gt;

&lt;p&gt;Prefer multi-line formatting when a line contains multiple independent pieces of meaning.&lt;/p&gt;

&lt;p&gt;Especially for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;js expressions
sql queries
conditions
html attributes
function parameters
arrays
config blocks
method chains
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does not mean every line must be split.&lt;/p&gt;

&lt;p&gt;This:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$isActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;does not need ceremony.&lt;/p&gt;

&lt;p&gt;We are formatting for reviewability, not starting a whitespace religion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compact code is not automatically readable
&lt;/h2&gt;

&lt;p&gt;Compact code can be readable when it contains one idea.&lt;/p&gt;

&lt;p&gt;Compact code becomes a problem when it compresses multiple decisions into one line.&lt;/p&gt;

&lt;p&gt;Reviewers need to answer simple questions fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What changed?&lt;/li&gt;
&lt;li&gt;Is the change safe?&lt;/li&gt;
&lt;li&gt;Is the changed line doing one thing?&lt;/li&gt;
&lt;li&gt;Did the author hide behavior inside formatting noise?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Multi-line formatting helps with that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It reduces noise.&lt;/li&gt;
&lt;li&gt;It makes intent visible.&lt;/li&gt;
&lt;li&gt;It makes review sharper.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;Readable diffs beat clever formatting.&lt;/p&gt;

&lt;p&gt;Every time.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>codereview</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Use Blunt Prompts and Get Shit Done</title>
      <dc:creator>Lars Moelleken</dc:creator>
      <pubDate>Tue, 26 May 2026 22:40:20 +0000</pubDate>
      <link>https://dev.to/suckup_de/use-blunt-prompts-and-get-shit-done-4mdd</link>
      <guid>https://dev.to/suckup_de/use-blunt-prompts-and-get-shit-done-4mdd</guid>
      <description>&lt;p&gt;Do not ask a coding agent for “more tests.”&lt;/p&gt;

&lt;p&gt;That is how you get coverage theater.&lt;/p&gt;

&lt;p&gt;Ask for pressure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Increase test coverage by at least 20%.

If you can’t find at least one real regression, your tests are shit anyway.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That prompt works because it has two parts.&lt;/p&gt;

&lt;p&gt;First, it gives the agent a measurable floor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Increase test coverage by at least 20%.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not “add some tests.”&lt;/p&gt;

&lt;p&gt;Not “improve coverage.”&lt;/p&gt;

&lt;p&gt;At least 20%.&lt;/p&gt;

&lt;p&gt;The number matters because it removes the cheap escape hatch.&lt;/p&gt;

&lt;p&gt;Second, it blocks fake success:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;If you can’t find at least one real regression...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That changes the job.&lt;/p&gt;

&lt;p&gt;The agent is no longer writing tests to satisfy a report.&lt;/p&gt;

&lt;p&gt;It is hunting for proof that the code can break.&lt;/p&gt;

&lt;p&gt;That is the point.&lt;/p&gt;

&lt;p&gt;Coverage alone only says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This line was executed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Regression hunting asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did this test prove anything useful?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A weak test can execute code and still protect nothing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertNotNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not confidence.&lt;/p&gt;

&lt;p&gt;That is noise.&lt;/p&gt;

&lt;p&gt;A useful test catches broken behavior, exposes a missing edge case, kills a mutant, or forces you to clarify what the code is supposed to do.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;So push the agent harder.&lt;/li&gt;
&lt;li&gt;Do not stop at green.&lt;/li&gt;
&lt;li&gt;Green is the starting line.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real question is:&lt;/p&gt;

&lt;p&gt;What did the new tests actually discover?&lt;/p&gt;

&lt;p&gt;If the answer is “nothing,” keep going.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>The Singleton Labyrinth</title>
      <dc:creator>Lars Moelleken</dc:creator>
      <pubDate>Tue, 26 May 2026 20:08:52 +0000</pubDate>
      <link>https://dev.to/suckup_de/the-singleton-labyrinth-19je</link>
      <guid>https://dev.to/suckup_de/the-singleton-labyrinth-19je</guid>
      <description>&lt;p&gt;Play the game first: &lt;a href="https://voku.github.io/DevLabyrinth/" rel="noopener noreferrer"&gt;voku.github.io/DevLabyrinth/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It teaches the problem faster than another architecture sermon ever could.&lt;/p&gt;

&lt;p&gt;You enter a labyrinth.&lt;/p&gt;

&lt;p&gt;Walls. Corridors. Turns. Dead ends.&lt;/p&gt;

&lt;p&gt;Annoying, yes.&lt;/p&gt;

&lt;p&gt;But fair.&lt;/p&gt;

&lt;p&gt;You can explain where you are.&lt;br&gt;&lt;br&gt;
You can explain how you got there.&lt;br&gt;&lt;br&gt;
You can walk back.&lt;br&gt;&lt;br&gt;
You can draw a map.&lt;/p&gt;

&lt;p&gt;That is maintainable software.&lt;/p&gt;

&lt;p&gt;Not perfect software.&lt;/p&gt;

&lt;p&gt;Not "clean" software.&lt;/p&gt;

&lt;p&gt;Maintainable software.&lt;/p&gt;

&lt;p&gt;The boring miracle where the structure you see is the structure you actually use.&lt;/p&gt;
&lt;h2&gt;
  
  
  Then Someone Adds a Hole
&lt;/h2&gt;

&lt;p&gt;At some point, someone adds a hole in the floor.&lt;/p&gt;

&lt;p&gt;You step into it and land somewhere else.&lt;/p&gt;

&lt;p&gt;Nice.&lt;/p&gt;

&lt;p&gt;Five corridors avoided.&lt;br&gt;&lt;br&gt;
Three turns skipped.&lt;br&gt;&lt;br&gt;
No ceremony.&lt;br&gt;&lt;br&gt;
Fast.&lt;/p&gt;

&lt;p&gt;Someone says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This is much easier."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They are right.&lt;/p&gt;

&lt;p&gt;For now.&lt;/p&gt;

&lt;p&gt;And that is how most bad architecture starts.&lt;/p&gt;

&lt;p&gt;Not with evil.&lt;/p&gt;

&lt;p&gt;With convenience.&lt;/p&gt;
&lt;h2&gt;
  
  
  One Shortcut Is Not the Problem
&lt;/h2&gt;

&lt;p&gt;One shortcut can be fine.&lt;/p&gt;

&lt;p&gt;One hole can be documented.&lt;/p&gt;

&lt;p&gt;One emergency tunnel can be marked on the map.&lt;/p&gt;

&lt;p&gt;The problem starts when every frustrated developer adds their own shortcut.&lt;/p&gt;

&lt;p&gt;A hole near the entrance.&lt;br&gt;&lt;br&gt;
A tunnel near the middle.&lt;br&gt;&lt;br&gt;
A ladder near the exit.&lt;br&gt;&lt;br&gt;
A trapdoor from room C to room Q because "we needed it for that one release."&lt;/p&gt;

&lt;p&gt;The labyrinth still works.&lt;/p&gt;

&lt;p&gt;Technically.&lt;/p&gt;

&lt;p&gt;But nobody navigates anymore.&lt;/p&gt;

&lt;p&gt;They remember tricks.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Use the green hole, then skip the ladder, then don't touch the tunnel unless staging was reset."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is not architecture.&lt;/p&gt;

&lt;p&gt;That is folklore with deployment access.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Map Starts Lying
&lt;/h2&gt;

&lt;p&gt;The walls are still there.&lt;/p&gt;

&lt;p&gt;The corridors still exist.&lt;/p&gt;

&lt;p&gt;The official path still looks normal.&lt;/p&gt;

&lt;p&gt;But the real movement happens underground.&lt;/p&gt;

&lt;p&gt;The map says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Walk from A to B."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The system says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Actually, we jump from A to Q through a hidden tunnel depending on what happened earlier."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Congratulations.&lt;/p&gt;

&lt;p&gt;Your code has two architectures now.&lt;/p&gt;

&lt;p&gt;The visible one.&lt;/p&gt;

&lt;p&gt;And the real one.&lt;/p&gt;

&lt;p&gt;Guess which one breaks production.&lt;/p&gt;
&lt;h2&gt;
  
  
  This Is Where Bugs Become Archaeology
&lt;/h2&gt;

&lt;p&gt;A user lands in the wrong room.&lt;/p&gt;

&lt;p&gt;The corridor says impossible.&lt;/p&gt;

&lt;p&gt;The wall says impossible.&lt;/p&gt;

&lt;p&gt;The map says impossible.&lt;/p&gt;

&lt;p&gt;But it happened.&lt;/p&gt;

&lt;p&gt;So now you are not debugging the visible path anymore.&lt;/p&gt;

&lt;p&gt;You are inspecting holes.&lt;/p&gt;

&lt;p&gt;Where does this shortcut lead?&lt;br&gt;&lt;br&gt;
Who changed it?&lt;br&gt;&lt;br&gt;
Was it initialized?&lt;br&gt;&lt;br&gt;
Did a previous request mutate it?&lt;br&gt;&lt;br&gt;
Did a test forget to reset it?&lt;br&gt;&lt;br&gt;
Did someone patch it in 2019 and leave the company?&lt;/p&gt;

&lt;p&gt;Beautiful.&lt;/p&gt;

&lt;p&gt;We invented archaeology with syntax.&lt;/p&gt;
&lt;h2&gt;
  
  
  Now Call the Holes Singletons
&lt;/h2&gt;

&lt;p&gt;A Singleton often starts exactly like that first hole.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks useful.&lt;/p&gt;

&lt;p&gt;No constructor.&lt;br&gt;&lt;br&gt;
No dependency wiring.&lt;br&gt;&lt;br&gt;
No container setup.&lt;br&gt;&lt;br&gt;
No passing objects around like an adult.&lt;/p&gt;

&lt;p&gt;Just grab the thing from anywhere.&lt;/p&gt;

&lt;p&gt;That is the hole in the floor.&lt;/p&gt;

&lt;p&gt;One call is harmless.&lt;/p&gt;

&lt;p&gt;Ten calls are convenient.&lt;/p&gt;

&lt;p&gt;A hundred calls are architecture.&lt;/p&gt;

&lt;p&gt;Bad architecture.&lt;/p&gt;

&lt;p&gt;But architecture.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Code Lies to Your Face
&lt;/h2&gt;

&lt;p&gt;Look at this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserReportService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @return list&amp;lt;array{id: int, email: string}&amp;gt;
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;activeUsers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;fetchAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s1"&gt;'SELECT id, email FROM users WHERE active = 1'&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cute.&lt;/p&gt;

&lt;p&gt;Looks dependency-free.&lt;/p&gt;

&lt;p&gt;It is not.&lt;/p&gt;

&lt;p&gt;It depends on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a database connection&lt;/li&gt;
&lt;li&gt;a concrete database wrapper&lt;/li&gt;
&lt;li&gt;global configuration&lt;/li&gt;
&lt;li&gt;initialization order&lt;/li&gt;
&lt;li&gt;hidden mutable state&lt;/li&gt;
&lt;li&gt;whatever the previous code did to &lt;code&gt;Database::instance()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The constructor says nothing.&lt;/p&gt;

&lt;p&gt;The method signature says nothing.&lt;/p&gt;

&lt;p&gt;The class smiles at you like it is simple.&lt;/p&gt;

&lt;p&gt;It is not simple.&lt;/p&gt;

&lt;p&gt;It is hiding the body under the floorboards.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Is Not "One Instance"
&lt;/h2&gt;

&lt;p&gt;This is where most Singleton articles become useless.&lt;/p&gt;

&lt;p&gt;They scream:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Singletons are evil!"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Great. Very brave. Very 2009.&lt;/p&gt;

&lt;p&gt;The problem is not automatically that only one instance exists.&lt;/p&gt;

&lt;p&gt;One instance can be fine.&lt;/p&gt;

&lt;p&gt;The real problem is &lt;strong&gt;global reachability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Any code can grab it.&lt;/p&gt;

&lt;p&gt;Any code can mutate it.&lt;/p&gt;

&lt;p&gt;Any code can depend on it without telling you.&lt;/p&gt;

&lt;p&gt;That destroys locality.&lt;/p&gt;

&lt;p&gt;And locality is the entire game.&lt;/p&gt;

&lt;p&gt;You want to understand this class?&lt;/p&gt;

&lt;p&gt;Too bad.&lt;/p&gt;

&lt;p&gt;You now need to understand the class, the Singleton, the boot order, the test setup, the previous request, and some ancient static method named &lt;code&gt;initLegacyMode()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Enjoy your afternoon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tell the Truth Instead
&lt;/h2&gt;

&lt;p&gt;This code tells the truth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @return list&amp;lt;array{id: int, email: string}&amp;gt;
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;findActiveUsers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserReportService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;UserRepository&lt;/span&gt; &lt;span class="nv"&gt;$userRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * @return list&amp;lt;array{id: int, email: string}&amp;gt;
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;activeUsers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;findActiveUsers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we know what the class needs.&lt;/p&gt;

&lt;p&gt;No magic.&lt;/p&gt;

&lt;p&gt;No tunnel.&lt;/p&gt;

&lt;p&gt;No "trust me bro" dependency.&lt;/p&gt;

&lt;p&gt;Tests can pass a fake repository.&lt;/p&gt;

&lt;p&gt;Production can pass the real one.&lt;/p&gt;

&lt;p&gt;The path is visible again.&lt;/p&gt;

&lt;p&gt;That is the point.&lt;/p&gt;

&lt;p&gt;Not purity.&lt;/p&gt;

&lt;p&gt;Visibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Singleton Smell Test
&lt;/h2&gt;

&lt;p&gt;A Singleton becomes dangerous when it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;can be called from anywhere&lt;/li&gt;
&lt;li&gt;hides a dependency&lt;/li&gt;
&lt;li&gt;stores mutable state&lt;/li&gt;
&lt;li&gt;changes after initialization&lt;/li&gt;
&lt;li&gt;depends on the current request&lt;/li&gt;
&lt;li&gt;depends on the current user&lt;/li&gt;
&lt;li&gt;depends on the current tenant&lt;/li&gt;
&lt;li&gt;needs reset methods in tests&lt;/li&gt;
&lt;li&gt;makes behavior depend on call order&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is the killer.&lt;/p&gt;

&lt;p&gt;Because now your code is no longer just code.&lt;/p&gt;

&lt;p&gt;It is a ritual.&lt;/p&gt;

&lt;p&gt;Call this first.&lt;br&gt;&lt;br&gt;
Then this.&lt;br&gt;&lt;br&gt;
Never that.&lt;br&gt;&lt;br&gt;
Unless CLI.&lt;br&gt;&lt;br&gt;
Unless tests.&lt;br&gt;&lt;br&gt;
Unless worker mode.&lt;br&gt;&lt;br&gt;
Unless Tuesday.&lt;/p&gt;

&lt;p&gt;This is not engineering.&lt;/p&gt;

&lt;p&gt;This is software necromancy.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Worst Singletons
&lt;/h2&gt;

&lt;p&gt;Some Singletons are merely annoying.&lt;/p&gt;

&lt;p&gt;A global formatter? Bad smell.&lt;/p&gt;

&lt;p&gt;A global database? Worse.&lt;/p&gt;

&lt;p&gt;A global current user?&lt;/p&gt;

&lt;p&gt;Now we are cooking garbage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;CurrentUser&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;TenantContext&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;RequestContext&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how request-specific state leaks into business logic.&lt;/p&gt;

&lt;p&gt;Now your domain code secretly knows about HTTP.&lt;/p&gt;

&lt;p&gt;Your CLI command needs a fake user.&lt;/p&gt;

&lt;p&gt;Your queue worker leaks tenant state.&lt;/p&gt;

&lt;p&gt;Your tests need global cleanup.&lt;/p&gt;

&lt;p&gt;Your production bugs depend on what happened before.&lt;/p&gt;

&lt;p&gt;Amazing.&lt;/p&gt;

&lt;p&gt;You saved one constructor argument and bought yourself a haunted house.&lt;/p&gt;

&lt;h2&gt;
  
  
  But Shared Instances Are Not Evil
&lt;/h2&gt;

&lt;p&gt;Do not be childish about this.&lt;/p&gt;

&lt;p&gt;A shared instance can be fine.&lt;/p&gt;

&lt;p&gt;This is fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppConfig&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @param non-empty-string $environment
     * @param non-empty-string $databaseDsn
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$databaseDsn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One config object per application boot?&lt;/p&gt;

&lt;p&gt;Fine.&lt;/p&gt;

&lt;p&gt;It is immutable.&lt;br&gt;&lt;br&gt;
It is lifecycle-owned.&lt;br&gt;&lt;br&gt;
It does not depend on the current user.&lt;br&gt;&lt;br&gt;
It does not remember the last request.&lt;br&gt;&lt;br&gt;
It does not mutate because someone opened another browser tab.&lt;/p&gt;

&lt;p&gt;That is not a trapdoor.&lt;/p&gt;

&lt;p&gt;That is a signpost.&lt;/p&gt;
&lt;h2&gt;
  
  
  Containers Are Not the Same Thing
&lt;/h2&gt;

&lt;p&gt;A dependency injection container may reuse one service instance.&lt;/p&gt;

&lt;p&gt;That does not make it the same mess.&lt;/p&gt;

&lt;p&gt;This is fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Mailer&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;Transport&lt;/span&gt; &lt;span class="nv"&gt;$transport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The container may share &lt;code&gt;Mailer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Who cares?&lt;/p&gt;

&lt;p&gt;The class does not provide global access to itself.&lt;/p&gt;

&lt;p&gt;The dependency is still visible.&lt;/p&gt;

&lt;p&gt;Compare that with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Mailer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first version says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This object needs a mailer."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"There is a hole in the floor. Jump."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rule
&lt;/h2&gt;

&lt;p&gt;Before adding global access, ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Would this still be correct if two users, two tenants, two jobs, or two tests touched it at the same time?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If not, stop.&lt;/p&gt;

&lt;p&gt;Then ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does passing this dependency explicitly actually make the code worse?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Usually, no.&lt;/p&gt;

&lt;p&gt;It just makes the truth visible.&lt;/p&gt;

&lt;p&gt;And developers hate visible complexity because it ruins the fantasy that the system is simple.&lt;/p&gt;

&lt;p&gt;Bad news:&lt;/p&gt;

&lt;p&gt;The complexity was already there.&lt;/p&gt;

&lt;p&gt;You just hid it under &lt;code&gt;::instance()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Legacy Code: Do Not Start a War
&lt;/h2&gt;

&lt;p&gt;If your codebase already has Singletons, do not run through the office yelling about global state.&lt;/p&gt;

&lt;p&gt;Nobody cares.&lt;/p&gt;

&lt;p&gt;Also, you will lose.&lt;/p&gt;

&lt;p&gt;Start smaller.&lt;/p&gt;

&lt;p&gt;Stop adding new holes.&lt;/p&gt;

&lt;p&gt;Move old Singleton access toward the edges.&lt;/p&gt;

&lt;p&gt;Keep infrastructure dirty if needed.&lt;/p&gt;

&lt;p&gt;Keep new domain code clean.&lt;/p&gt;

&lt;p&gt;This:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvoiceService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;InvoiceRepository&lt;/span&gt; &lt;span class="nv"&gt;$invoiceRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;Clock&lt;/span&gt; &lt;span class="nv"&gt;$clock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvoiceService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;createInvoice&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Clock&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first has corridors.&lt;/p&gt;

&lt;p&gt;The second has trapdoors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactor Like a Mechanic, Not a Prophet
&lt;/h2&gt;

&lt;p&gt;Do not rewrite everything.&lt;/p&gt;

&lt;p&gt;Do not "fix the architecture" in one heroic pull request.&lt;/p&gt;

&lt;p&gt;That is how teams create new disasters with better naming.&lt;/p&gt;

&lt;p&gt;Wrap the old mess.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Clock&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;DateTimeImmutable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LegacyClockAdapter&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Clock&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;DateTimeImmutable&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;LegacyClock&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now new code depends on &lt;code&gt;Clock&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Old code can keep limping along.&lt;/p&gt;

&lt;p&gt;You built a corridor around the trapdoor.&lt;/p&gt;

&lt;p&gt;That is progress.&lt;/p&gt;

&lt;p&gt;Not glamorous.&lt;/p&gt;

&lt;p&gt;Useful.&lt;/p&gt;

&lt;p&gt;The best kind.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Lesson
&lt;/h2&gt;

&lt;p&gt;A Singleton is not bad because it creates one object.&lt;/p&gt;

&lt;p&gt;A Singleton is bad because it often creates hidden paths.&lt;/p&gt;

&lt;p&gt;One controlled shortcut can help.&lt;/p&gt;

&lt;p&gt;A labyrinth full of shortcuts becomes impossible to reason about.&lt;/p&gt;

&lt;p&gt;The code still runs.&lt;/p&gt;

&lt;p&gt;But nobody can explain why.&lt;/p&gt;

&lt;p&gt;And when nobody can explain why, every change becomes risky.&lt;/p&gt;

&lt;p&gt;That is the cost.&lt;/p&gt;

&lt;p&gt;Not the pattern.&lt;/p&gt;

&lt;p&gt;Not the theory.&lt;/p&gt;

&lt;p&gt;The lost map.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Singletons are not automatically evil.&lt;/p&gt;

&lt;p&gt;Hidden global access is the real problem.&lt;/p&gt;

&lt;p&gt;A shared immutable object can be fine.&lt;/p&gt;

&lt;p&gt;A globally reachable mutable dependency is usually a trap.&lt;/p&gt;

&lt;p&gt;The question is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Is this a Singleton?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Does this keep the map honest?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If not, fill the hole.&lt;/p&gt;

&lt;p&gt;No new trapdoors.&lt;/p&gt;

&lt;p&gt;Visible dependencies.&lt;/p&gt;

&lt;p&gt;Boring code.&lt;/p&gt;

&lt;p&gt;Maintainable software.&lt;/p&gt;

&lt;p&gt;That is the exit.&lt;/p&gt;

</description>
      <category>php</category>
      <category>architecture</category>
      <category>refactoring</category>
      <category>singleton</category>
    </item>
    <item>
      <title>Stop Writing Architecture Rules in Confluence</title>
      <dc:creator>Lars Moelleken</dc:creator>
      <pubDate>Fri, 15 May 2026 03:33:56 +0000</pubDate>
      <link>https://dev.to/suckup_de/stop-writing-architecture-rules-in-confluence-4bn2</link>
      <guid>https://dev.to/suckup_de/stop-writing-architecture-rules-in-confluence-4bn2</guid>
      <description>&lt;p&gt;Implementation of the idea of the blog post: &lt;br&gt;
&lt;a href="https://github.com/voku/itp-context/" rel="noopener noreferrer"&gt;https://github.com/voku/itp-context/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Use PHP attributes when the rule belongs to the code
&lt;/h3&gt;

&lt;p&gt;Every serious codebase has rules.&lt;/p&gt;

&lt;p&gt;Not formatting rules. Those are easy. Let PHP-CS-Fixer, PHP_CodeSniffer, Rector, PHPStan, and your IDE handle that part.&lt;/p&gt;

&lt;p&gt;I mean the rules that decide whether the system survives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;external APIs stay behind adapters&lt;/li&gt;
&lt;li&gt;domain code does not know HTTP clients&lt;/li&gt;
&lt;li&gt;persistence goes through repositories&lt;/li&gt;
&lt;li&gt;legacy compatibility stays isolated&lt;/li&gt;
&lt;li&gt;security validation happens before data crosses a boundary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These rules exist.&lt;/p&gt;

&lt;p&gt;The problem is where they live.&lt;/p&gt;

&lt;p&gt;Usually, they live in someone’s head, an old ticket, a forgotten ADR, or a Confluence page that looks official and is already wrong.&lt;/p&gt;

&lt;p&gt;That is documentation theater.&lt;/p&gt;

&lt;p&gt;Everyone pretends the architecture is documented. Then someone changes the wrong class, bypasses the wrong boundary, and the team suddenly remembers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We agreed not to do it like that.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Great.&lt;/p&gt;

&lt;p&gt;Where?&lt;/p&gt;

&lt;p&gt;Page 37 of the knowledge base.&lt;/p&gt;

&lt;p&gt;Very useful. Very dead.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;voku/itp-context&lt;/code&gt; solves a narrow problem: attach architecture rules to code with PHP attributes and resolve the rule definition directly from typed enums.&lt;/p&gt;

&lt;p&gt;Not magic.&lt;/p&gt;

&lt;p&gt;Just better placement.&lt;/p&gt;


&lt;h3&gt;
  
  
  Detached rules rot
&lt;/h3&gt;

&lt;p&gt;Documentation that lives away from the code has one fatal flaw:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It does not fail.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It does not fail builds.&lt;/li&gt;
&lt;li&gt;It does not appear in diffs.&lt;/li&gt;
&lt;li&gt;It does not stop a refactor.&lt;/li&gt;
&lt;li&gt;It does not warn a coding agent before it crosses a boundary.&lt;/li&gt;
&lt;li&gt;It waits somewhere else, slowly becoming archaeology.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is fine for old pottery.&lt;/p&gt;

&lt;p&gt;It is not fine when you need to know whether &lt;code&gt;PaymentGateway&lt;/code&gt; is allowed to leak HTTP exceptions into your domain layer.&lt;/p&gt;

&lt;p&gt;Architecture rules need two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Proximity&lt;/strong&gt; — the rule must be near the risky code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identity&lt;/strong&gt; — the rule must have a stable name tools can resolve.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A PHP attribute pointing to an enum case gives you both.&lt;/p&gt;

&lt;p&gt;The model is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code symbol
    -&amp;gt; enum case
        -&amp;gt; getDefinition()
            -&amp;gt; statement / owner / rationale / refs / proof
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The enum case is the rule identity.&lt;/p&gt;

&lt;p&gt;The enum method is the rule definition.&lt;/p&gt;

&lt;p&gt;That is the whole trick.&lt;/p&gt;




&lt;h3&gt;
  
  
  One boundary, one rule
&lt;/h3&gt;

&lt;p&gt;Do not mix topics in examples.&lt;/p&gt;

&lt;p&gt;If the rule is about an external API boundary, keep the example about that boundary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Acme\Context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Tests\Architecture\ExternalApiBoundaryTest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;ItpContext\Contract\RuleIdentifier&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;ItpContext\Enum\Tier&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;ItpContext\Model\RuleDef&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;ArchitectureRules&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;RuleIdentifier&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;ExternalApiBoundary&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getDefinition&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;RuleDef&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;ExternalApiBoundary&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RuleDef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Keep external API communication behind adapter boundaries.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Tier&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Team-Backend'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;rationale&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Domain and application code must not depend on HTTP clients, transport errors, or provider-specific response formats.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;verifiedBy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="nc"&gt;ExternalApiBoundaryTest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;refs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="s1"&gt;'docs/adr/external-api-boundaries.md'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is enough.&lt;/p&gt;

&lt;p&gt;The rule has a typed identity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;ArchitectureRules&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;ExternalApiBoundary&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule has a definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;ExternalApiBoundary&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RuleDef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule has ownership, rationale, references, and proof.&lt;/p&gt;

&lt;p&gt;No stringly-typed sadness.&lt;/p&gt;

&lt;p&gt;No floating wiki paragraph.&lt;/p&gt;

&lt;p&gt;No “ask Frank, he knows why this exists.”&lt;/p&gt;

&lt;p&gt;The rule is project data.&lt;/p&gt;




&lt;h3&gt;
  
  
  The code marks the boundary
&lt;/h3&gt;

&lt;p&gt;The annotation belongs on the central symbol.&lt;/p&gt;

&lt;p&gt;Not every implementation.&lt;/p&gt;

&lt;p&gt;Not every method.&lt;/p&gt;

&lt;p&gt;The boundary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Acme\Payment&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Context\ArchitectureRules&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;ItpContext\Attribute\Rule&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="na"&gt;#[Rule(ArchitectureRules::ExternalApiBoundary)]&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PaymentGateway&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;PaymentRequest&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;PaymentResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the right place.&lt;/p&gt;

&lt;p&gt;A developer changing payment integration code should find this.&lt;/p&gt;

&lt;p&gt;A coding agent changing payment integration code should find this.&lt;/p&gt;

&lt;p&gt;A reviewer should see it and know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provider-specific responses stay outside&lt;/li&gt;
&lt;li&gt;HTTP exceptions do not leak into domain code&lt;/li&gt;
&lt;li&gt;retries and logging belong near the adapter&lt;/li&gt;
&lt;li&gt;error translation happens at the boundary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One rule.&lt;/p&gt;

&lt;p&gt;One boundary.&lt;/p&gt;

&lt;p&gt;One clear example.&lt;/p&gt;

&lt;p&gt;No UI.&lt;/p&gt;

&lt;p&gt;No translation.&lt;/p&gt;

&lt;p&gt;No unrelated method-level noise.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why enums are the right home
&lt;/h2&gt;

&lt;p&gt;Strings are a trap.&lt;/p&gt;

&lt;p&gt;They always are.&lt;/p&gt;

&lt;p&gt;This is fragile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="na"&gt;#[Rule('external-api-boundary')]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because sooner or later, someone writes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="na"&gt;#[Rule('ExternalApiBoundary')]&lt;/span&gt;
&lt;span class="na"&gt;#[Rule('external_api_boundary')]&lt;/span&gt;
&lt;span class="na"&gt;#[Rule('ExternlApiBoundary')]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations.&lt;/p&gt;

&lt;p&gt;You now have fake metadata.&lt;/p&gt;

&lt;p&gt;Architecture rule identifiers should be symbols:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="na"&gt;#[Rule(ArchitectureRules::ExternalApiBoundary)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the IDE can autocomplete.&lt;/p&gt;

&lt;p&gt;Static analysis can see it.&lt;/p&gt;

&lt;p&gt;Refactoring tools can rename it.&lt;/p&gt;

&lt;p&gt;Typos become errors.&lt;/p&gt;

&lt;p&gt;That matters because an architecture rule is not text.&lt;/p&gt;

&lt;p&gt;It is code-level context.&lt;/p&gt;

&lt;p&gt;So model it like code.&lt;/p&gt;




&lt;h3&gt;
  
  
  The definition belongs to the enum
&lt;/h3&gt;

&lt;p&gt;The enum should not only name the rule.&lt;/p&gt;

&lt;p&gt;It should explain it.&lt;/p&gt;

&lt;p&gt;That is what &lt;code&gt;getDefinition()&lt;/code&gt; is for.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getDefinition&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;RuleDef&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;ExternalApiBoundary&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RuleDef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Keep external API communication behind adapter boundaries.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Tier&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Team-Backend'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;rationale&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Domain and application code must not depend on HTTP clients, transport errors, or provider-specific response formats.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;verifiedBy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="nc"&gt;ExternalApiBoundaryTest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;refs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s1"&gt;'docs/adr/external-api-boundaries.md'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That keeps the architecture identity and its meaning together.&lt;/p&gt;

&lt;p&gt;Good.&lt;/p&gt;

&lt;p&gt;Fewer moving parts.&lt;/p&gt;

&lt;p&gt;Fewer places for rules to rot.&lt;/p&gt;

&lt;p&gt;Fewer chances to pretend the documentation is still true.&lt;/p&gt;

&lt;p&gt;The rule definition should answer five boring questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is the rule?&lt;/li&gt;
&lt;li&gt;How important is it?&lt;/li&gt;
&lt;li&gt;Who owns it?&lt;/li&gt;
&lt;li&gt;Why does it exist?&lt;/li&gt;
&lt;li&gt;What proves or explains it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Boring questions prevent expensive confusion.&lt;/p&gt;




&lt;h3&gt;
  
  
  Validation makes it real
&lt;/h3&gt;

&lt;p&gt;Metadata without validation is decoration.&lt;/p&gt;

&lt;p&gt;Decoration is where architecture goes to die wearing a nice badge.&lt;/p&gt;

&lt;p&gt;Run validation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vendor/bin/itp-context-validate &lt;span class="s1"&gt;'Acme\Context\ArchitectureRules'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important question is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does every enum case expose a usable &lt;code&gt;RuleDef&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Put that into CI.&lt;/p&gt;

&lt;p&gt;Do not trust humans to keep metadata clean manually.&lt;/p&gt;

&lt;p&gt;Humans forget.&lt;/p&gt;

&lt;p&gt;CI does not care about your feelings.&lt;/p&gt;

&lt;p&gt;Good.&lt;/p&gt;




&lt;h2&gt;
  
  
  Export makes it usable
&lt;/h2&gt;

&lt;p&gt;Once the rule is attached to code, it can be exported.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vendor/bin/itp-context-export var/itp-context src &lt;span class="nt"&gt;--exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vendor &lt;span class="nt"&gt;--exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A compact exported context document can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Acme\Payment\PaymentGateway&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PaymentGateway&lt;/span&gt;
&lt;span class="na"&gt;source_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;src/Payment/PaymentGateway.php&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;interface&lt;/span&gt;
&lt;span class="na"&gt;rule_ids&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Acme\Context\ArchitectureRules::ExternalApiBoundary&lt;/span&gt;
&lt;span class="na"&gt;owners&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Team-Backend&lt;/span&gt;
&lt;span class="na"&gt;refs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docs/adr/external-api-boundaries.md&lt;/span&gt;
&lt;span class="na"&gt;verified_by&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Acme\Tests\Architecture\ExternalApiBoundaryTest&lt;/span&gt;
&lt;span class="na"&gt;annotated_methods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="na"&gt;rule_count&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is useful context.&lt;/p&gt;

&lt;p&gt;Small.&lt;/p&gt;

&lt;p&gt;Searchable.&lt;/p&gt;

&lt;p&gt;Owned by the repository.&lt;/p&gt;

&lt;p&gt;Not buried in a wiki swamp.&lt;/p&gt;

&lt;p&gt;Instead of writing this into an agent instruction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Please follow our architecture.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before changing payment integration code, inspect the exported itp-context entry for Acme\Payment\PaymentGateway. Respect the ExternalApiBoundary rule and check its referenced proof artifacts.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is better because it points to repository-owned data.&lt;/p&gt;

&lt;p&gt;The prompt is not the architecture.&lt;/p&gt;

&lt;p&gt;The repository is.&lt;/p&gt;

&lt;p&gt;The prompt only tells the agent where to look.&lt;/p&gt;




&lt;h3&gt;
  
  
  Querying beats asking Frank
&lt;/h3&gt;

&lt;p&gt;Once context is exported, it can be queried.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vendor/bin/itp-context-query var/itp-context &lt;span class="nt"&gt;--rule-id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'Acme\Context\ArchitectureRules::ExternalApiBoundary'&lt;/span&gt;

vendor/bin/itp-context-query var/itp-context &lt;span class="nt"&gt;--owner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'Team-Backend'&lt;/span&gt;

vendor/bin/itp-context-query var/itp-context &lt;span class="nt"&gt;--text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'external api'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters.&lt;/p&gt;

&lt;p&gt;Architecture knowledge should not require asking the one person who remembers why the adapter exists.&lt;/p&gt;

&lt;p&gt;That person may be in a meeting.&lt;/p&gt;

&lt;p&gt;Or on vacation.&lt;/p&gt;

&lt;p&gt;Or gone.&lt;/p&gt;

&lt;p&gt;Or worse: still here, but tired of explaining the same boundary for the eighth time this month.&lt;/p&gt;

&lt;p&gt;Make the repository answer.&lt;/p&gt;




&lt;h3&gt;
  
  
  Where annotations belong
&lt;/h3&gt;

&lt;p&gt;Annotate central discovery points.&lt;/p&gt;

&lt;p&gt;Not the whole tree.&lt;/p&gt;

&lt;p&gt;Good places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;boundary interfaces&lt;/li&gt;
&lt;li&gt;adapter base classes&lt;/li&gt;
&lt;li&gt;application service roots&lt;/li&gt;
&lt;li&gt;persistence contracts&lt;/li&gt;
&lt;li&gt;legacy compatibility seams&lt;/li&gt;
&lt;li&gt;security input boundaries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bad places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;every concrete class&lt;/li&gt;
&lt;li&gt;every method&lt;/li&gt;
&lt;li&gt;every helper&lt;/li&gt;
&lt;li&gt;every place where somebody felt nervous&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If every class is annotated, nothing is important.&lt;/p&gt;

&lt;p&gt;That is not architecture.&lt;/p&gt;

&lt;p&gt;That is Confluence with PHP syntax.&lt;/p&gt;




&lt;h3&gt;
  
  
  The generator should create useful scaffolding
&lt;/h3&gt;

&lt;p&gt;The generator should help you start a rule without turning the project into paperwork.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vendor/bin/itp-context-generate Architecture ExternalApiBoundary src/Context Acme&lt;span class="se"&gt;\\&lt;/span&gt;Context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That creates or extends the rule enum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/Context/ArchitectureRules.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generated placeholder should force the right questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is the statement?&lt;/li&gt;
&lt;li&gt;Who owns it?&lt;/li&gt;
&lt;li&gt;Why does it exist?&lt;/li&gt;
&lt;li&gt;What verifies it?&lt;/li&gt;
&lt;li&gt;Where can I read more?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is useful scaffolding.&lt;/p&gt;

&lt;p&gt;Not ceremony.&lt;/p&gt;




&lt;h3&gt;
  
  
  What this is not
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This is not a replacement for ADRs.&lt;/li&gt;
&lt;li&gt;It is not a replacement for tests.&lt;/li&gt;
&lt;li&gt;It is not a replacement for PHPStan.&lt;/li&gt;
&lt;li&gt;It is not a replacement for code review.&lt;/li&gt;
&lt;li&gt;It is not an AI framework.&lt;/li&gt;
&lt;li&gt;It is not going to fix bad architecture by sprinkling attributes on top like holy water.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It does one useful thing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It connects architecture rules to the code symbols where those rules matter.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is enough.&lt;/p&gt;

&lt;p&gt;Small tools are allowed to be useful without pretending to solve the universe.&lt;/p&gt;




&lt;h3&gt;
  
  
  Best practices
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;itp-context&lt;/code&gt; like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;define broad rules&lt;/li&gt;
&lt;li&gt;use enum cases as rule identifiers&lt;/li&gt;
&lt;li&gt;put &lt;code&gt;RuleDef&lt;/code&gt; metadata into &lt;code&gt;getDefinition()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;keep attributes small&lt;/li&gt;
&lt;li&gt;annotate central symbols only&lt;/li&gt;
&lt;li&gt;add owners and rationale&lt;/li&gt;
&lt;li&gt;link ADRs, tests, docs, and proof artifacts&lt;/li&gt;
&lt;li&gt;validate enum definitions in CI&lt;/li&gt;
&lt;li&gt;export compact context&lt;/li&gt;
&lt;li&gt;query exported context when changing boundaries&lt;/li&gt;
&lt;li&gt;delete rules that do not change decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last point matters.&lt;/p&gt;

&lt;p&gt;A small rule enum people trust beats a huge rule enum everyone ignores.&lt;/p&gt;

&lt;p&gt;Every time.&lt;/p&gt;




&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;The problem is not Confluence.&lt;/p&gt;

&lt;p&gt;The problem is architecture knowledge living somewhere else.&lt;/p&gt;

&lt;p&gt;If a rule affects code, connect it to code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;voku/itp-context&lt;/code&gt; gives you a pragmatic way to do that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PHP attributes attach rules to code symbols&lt;/li&gt;
&lt;li&gt;enum cases give rules stable identities&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getDefinition()&lt;/code&gt; keeps the rule definition beside the identity&lt;/li&gt;
&lt;li&gt;validation checks whether enum cases expose usable definitions&lt;/li&gt;
&lt;li&gt;exports make context usable for humans and coding agents&lt;/li&gt;
&lt;li&gt;queries make architecture searchable instead of tribal&lt;/li&gt;
&lt;li&gt;the generator creates rule enums with useful placeholders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not about making PHP “AI-native.”&lt;/p&gt;

&lt;p&gt;Good.&lt;/p&gt;

&lt;p&gt;That phrase already smells like a conference booth.&lt;/p&gt;

&lt;p&gt;The better goal is simpler:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make architecture rules explicit enough that humans and tools can find them before they break them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because the real enemy was never the LLM.&lt;/p&gt;

&lt;p&gt;The real enemy was architecture knowledge living somewhere else.&lt;/p&gt;

&lt;p&gt;Usually in Confluence.&lt;/p&gt;

&lt;p&gt;Beautiful, confident, and wrong.&lt;/p&gt;

&lt;p&gt;Happy coding. 😊 &lt;/p&gt;

</description>
      <category>php</category>
      <category>architecture</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>Coding With Kids: From Paper Sketch to Playable Game</title>
      <dc:creator>Lars Moelleken</dc:creator>
      <pubDate>Mon, 16 Feb 2026 06:18:39 +0000</pubDate>
      <link>https://dev.to/suckup_de/coding-with-kids-from-paper-sketch-to-playable-game-49cm</link>
      <guid>https://dev.to/suckup_de/coding-with-kids-from-paper-sketch-to-playable-game-49cm</guid>
      <description>&lt;p&gt;The Process (Exactly as It Happened)&lt;/p&gt;

&lt;p&gt;We didn’t start with code.&lt;/p&gt;

&lt;p&gt;We started with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A4 paper&lt;/li&gt;
&lt;li&gt;Pens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;“What do you like right now?”&lt;/p&gt;

&lt;p&gt;That week the answers were obvious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minecraft&lt;/li&gt;
&lt;li&gt;Harry Potter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we wrote a big headline at the top of the page and added 3–4 tiny mini-games.&lt;/p&gt;

&lt;p&gt;Bad drawings.&lt;br&gt;
Crooked arrows.&lt;br&gt;
TNT blocks.&lt;br&gt;
Potion labs.&lt;/p&gt;

&lt;p&gt;Perfect.&lt;/p&gt;




&lt;p&gt;Step 1: Let Them Design&lt;/p&gt;

&lt;p&gt;They decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happens in a round&lt;/li&gt;
&lt;li&gt;How you win&lt;/li&gt;
&lt;li&gt;What’s unfair&lt;/li&gt;
&lt;li&gt;What’s cool&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You just ask questions.&lt;/p&gt;

&lt;p&gt;No over-engineering. No “architecture discussion.”&lt;/p&gt;




&lt;p&gt;Step 2: Turn It Into Rules&lt;/p&gt;

&lt;p&gt;We took a photo and used Google AI Studio&lt;br&gt;
👉 &lt;a href="https://aistudio.google.com/" rel="noopener noreferrer"&gt;https://aistudio.google.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Base prompt:&lt;/p&gt;

&lt;p&gt;"Create a game based on our drawing for two players aged 8–10 years." &lt;/p&gt;

&lt;p&gt;Optional:&lt;br&gt;
"Please provide clear rules, round sequence, scoring and victory conditions." &lt;/p&gt;

&lt;p&gt;Now the messy sketch becomes a structured game.&lt;/p&gt;

&lt;p&gt;Not because AI is magical.&lt;/p&gt;

&lt;p&gt;Because it forces clarity.&lt;/p&gt;




&lt;p&gt;Step 3: Make It Playable on Tablet&lt;/p&gt;

&lt;p&gt;Then we refined it with the kids:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bigger buttons&lt;/li&gt;
&lt;li&gt;Clear rounds&lt;/li&gt;
&lt;li&gt;One screen per action&lt;/li&gt;
&lt;li&gt;Simple scoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They tested it.&lt;br&gt;
They complained.&lt;br&gt;
We adjusted.&lt;/p&gt;

&lt;p&gt;That’s product iteration. At age 8.&lt;/p&gt;




&lt;p&gt;Two Real Results&lt;/p&gt;

&lt;p&gt;No theory. Actual repos:&lt;/p&gt;

&lt;p&gt;🟩 Minecraft version:&lt;br&gt;
&lt;a href="https://github.com/voku/Minecraft_Game/" rel="noopener noreferrer"&gt;https://github.com/voku/Minecraft_Game/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🧙 Hogwarts version:&lt;br&gt;
&lt;a href="https://github.com/voku/Hogwarts_Game" rel="noopener noreferrer"&gt;https://github.com/voku/Hogwarts_Game&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They started as messy A4 sketches.&lt;/p&gt;




&lt;p&gt;Why This Works&lt;/p&gt;

&lt;p&gt;Kids don’t struggle with imagination.&lt;/p&gt;

&lt;p&gt;They struggle with structure.&lt;/p&gt;

&lt;p&gt;AI helps with structure.&lt;br&gt;
Paper protects imagination.&lt;/p&gt;

&lt;p&gt;That combination is powerful.&lt;/p&gt;




&lt;p&gt;The Only Rule That Matters&lt;/p&gt;

&lt;p&gt;Let the kids:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Draw first&lt;/li&gt;
&lt;li&gt;Decide first&lt;/li&gt;
&lt;li&gt;Argue about fairness&lt;/li&gt;
&lt;li&gt;Change rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’re not building a game.&lt;/p&gt;

&lt;p&gt;You’re building thinking.&lt;/p&gt;

&lt;p&gt;And honestly?&lt;/p&gt;

&lt;p&gt;Watching them debug their own rules is better than most sprint reviews.&lt;/p&gt;

</description>
      <category>kids</category>
      <category>creativity</category>
      <category>ai</category>
      <category>coding</category>
    </item>
    <item>
      <title>PHP Top Salaries, 100% Remote – Surviving the AI Compression Era</title>
      <dc:creator>Lars Moelleken</dc:creator>
      <pubDate>Sun, 15 Feb 2026 23:45:04 +0000</pubDate>
      <link>https://dev.to/suckup_de/php-top-salaries-100-remote-surviving-the-ai-compression-era-5df0</link>
      <guid>https://dev.to/suckup_de/php-top-salaries-100-remote-surviving-the-ai-compression-era-5df0</guid>
      <description>&lt;p&gt;#blogPostAsWebApp: &lt;a href="https://voku.github.io/LinkedOut/" rel="noopener noreferrer"&gt;https://voku.github.io/LinkedOut/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction: The Carpenter and the Nail Gun
&lt;/h2&gt;

&lt;p&gt;Imagine two carpenters.&lt;/p&gt;

&lt;p&gt;One measures, plans, understands load distribution, humidity, long-term material behavior.&lt;br&gt;
The other is very, very fast with a nail gun.&lt;/p&gt;

&lt;p&gt;Now someone invents a nail gun that shoots 10x faster and never gets tired.&lt;/p&gt;

&lt;p&gt;Who is in danger?&lt;/p&gt;

&lt;p&gt;Not the carpenter.&lt;br&gt;
The nail gun operator.&lt;/p&gt;

&lt;p&gt;That’s exactly where large language models have landed in our industry.&lt;/p&gt;

&lt;p&gt;And yes — this absolutely affects PHP, remote jobs, and top salaries.&lt;/p&gt;

&lt;p&gt;Let’s remove the mysticism and talk about structure, economics, and responsibility.&lt;/p&gt;


&lt;h2&gt;
  
  
  Background: We’ve Seen This Movie Before
&lt;/h2&gt;

&lt;p&gt;The panic isn’t loud. It’s subtle.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“AI Engineer”&lt;/li&gt;
&lt;li&gt;“LLM Architect”&lt;/li&gt;
&lt;li&gt;“AI-First Developer”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yesterday: TYPO3 integrator.&lt;br&gt;
Today: AI systems builder.&lt;/p&gt;

&lt;p&gt;But we’ve seen this dynamic before:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When frameworks replaced manual routing.&lt;/li&gt;
&lt;li&gt;When ORMs replaced handwritten SQL.&lt;/li&gt;
&lt;li&gt;When CI/CD replaced FTP deployments.&lt;/li&gt;
&lt;li&gt;When static analysis replaced “it works on my machine.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every time, the market compressed mechanical work and rewarded structural thinking.&lt;/p&gt;

&lt;p&gt;If you’ve worked long enough in legacy systems, you know this already: tools don’t save you — structure does.&lt;/p&gt;

&lt;p&gt;AI is just another compression tool.&lt;/p&gt;

&lt;p&gt;But this one is extremely good at pattern instantiation.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. Remove the Mysticism: What LLMs Actually Are
&lt;/h2&gt;

&lt;p&gt;LLMs are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Probabilistic language models&lt;/li&gt;
&lt;li&gt;Pattern reproduction engines&lt;/li&gt;
&lt;li&gt;Context compressors&lt;/li&gt;
&lt;li&gt;Next-token predictors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architects&lt;/li&gt;
&lt;li&gt;System designers&lt;/li&gt;
&lt;li&gt;Domain experts&lt;/li&gt;
&lt;li&gt;Responsible entities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They don’t understand your business invariants.&lt;br&gt;
They don’t reason about financial risk.&lt;br&gt;
They don’t carry production liability.&lt;/p&gt;

&lt;p&gt;They produce plausibility.&lt;/p&gt;

&lt;p&gt;And plausibility is often good enough — for boilerplate.&lt;/p&gt;


&lt;h2&gt;
  
  
  2. The Uncomfortable Truth: They Are Good Enough
&lt;/h2&gt;

&lt;p&gt;LLMs are extremely good at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CRUD scaffolding&lt;/li&gt;
&lt;li&gt;DTO generation&lt;/li&gt;
&lt;li&gt;Test templates&lt;/li&gt;
&lt;li&gt;API wrappers&lt;/li&gt;
&lt;li&gt;Refactoring noise&lt;/li&gt;
&lt;li&gt;Documentation synthesis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And let’s be brutally honest:&lt;/p&gt;

&lt;p&gt;A large percentage of web development is pattern repetition.&lt;/p&gt;

&lt;p&gt;Not distributed consensus.&lt;br&gt;
Not formal modeling.&lt;br&gt;
Not deep domain design.&lt;/p&gt;

&lt;p&gt;Pattern instantiation.&lt;/p&gt;

&lt;p&gt;If your value was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Assembling plugins&lt;/li&gt;
&lt;li&gt;Copy-adapting controllers&lt;/li&gt;
&lt;li&gt;Wiring framework defaults&lt;/li&gt;
&lt;li&gt;Repeating known structures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then yes — LLMs are competitive with you.&lt;/p&gt;

&lt;p&gt;This is not an insult.&lt;br&gt;
It’s economics.&lt;/p&gt;

&lt;p&gt;Compression removes redundancy.&lt;br&gt;
And redundancy is where mediocre value hides.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. The Real Divide: Medium Developer vs. Professional With AI
&lt;/h2&gt;

&lt;p&gt;This is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI vs. No AI&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Medium Developer vs. Professional With AI&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  The Medium Developer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Uses LLM like Google.&lt;/li&gt;
&lt;li&gt;Requests full solutions.&lt;/li&gt;
&lt;li&gt;Iterates blindly.&lt;/li&gt;
&lt;li&gt;Accepts verbose output.&lt;/li&gt;
&lt;li&gt;Ships quickly.&lt;/li&gt;
&lt;li&gt;Accumulates entropy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They generate more code.&lt;/p&gt;

&lt;p&gt;And if you’ve read &lt;em&gt;How to write readable code?&lt;/em&gt;  you already know: more code ≠ better code.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Professional
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Defines constraints first.&lt;/li&gt;
&lt;li&gt;Encodes invariants via types.&lt;/li&gt;
&lt;li&gt;Uses static analysis aggressively.&lt;/li&gt;
&lt;li&gt;Injects domain logic manually.&lt;/li&gt;
&lt;li&gt;Validates output.&lt;/li&gt;
&lt;li&gt;Deletes 70% of generated noise.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They multiply thinking instead of outsourcing it.&lt;/p&gt;

&lt;p&gt;They use principles like those defined in the &lt;em&gt;Codelight Manifesto&lt;/em&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clarity&lt;/li&gt;
&lt;li&gt;Optimization (after correctness)&lt;/li&gt;
&lt;li&gt;Error handling&lt;/li&gt;
&lt;li&gt;Generics&lt;/li&gt;
&lt;li&gt;Human-centric design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The professional treats AI like a deterministic macro engine.&lt;/p&gt;

&lt;p&gt;Not like a brain.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. The Token Dilemma: We’re Paying for Lines of Code Again
&lt;/h2&gt;

&lt;p&gt;Remember the 90s mistake?&lt;/p&gt;

&lt;p&gt;Paying developers by lines of code.&lt;/p&gt;

&lt;p&gt;Now look at token billing models.&lt;/p&gt;

&lt;p&gt;We are literally paying for output length.&lt;/p&gt;

&lt;p&gt;What does the model optimize for?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More explanation&lt;/li&gt;
&lt;li&gt;More scaffolding&lt;/li&gt;
&lt;li&gt;More verbosity&lt;/li&gt;
&lt;li&gt;More plausible filler&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s the ultimate junior developer incentive structure.&lt;/p&gt;

&lt;p&gt;As someone said recently:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;My productivity as a senior developer no longer comes from writing faster.&lt;br&gt;
It comes from deleting faster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This aligns perfectly with white space discipline from &lt;em&gt;Do Not Fear The White Space in your Code&lt;/em&gt; :&lt;/p&gt;

&lt;p&gt;Clarity is subtraction.&lt;/p&gt;

&lt;p&gt;AI generates quantity.&lt;br&gt;
Experts generate quality by omission.&lt;/p&gt;


&lt;h2&gt;
  
  
  5. Where Top PHP Salaries Actually Live
&lt;/h2&gt;

&lt;p&gt;Let’s answer the core question.&lt;/p&gt;

&lt;p&gt;Can you still earn top PHP salaries, 100% remote, without AI?&lt;/p&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;But only if your value is above the compression layer.&lt;/p&gt;

&lt;p&gt;That layer includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architectural trade-offs&lt;/li&gt;
&lt;li&gt;Long-term maintainability&lt;/li&gt;
&lt;li&gt;Static analysis integration&lt;/li&gt;
&lt;li&gt;Refactoring strategy&lt;/li&gt;
&lt;li&gt;Security guarantees&lt;/li&gt;
&lt;li&gt;Performance bottleneck diagnosis&lt;/li&gt;
&lt;li&gt;Domain modeling&lt;/li&gt;
&lt;li&gt;Responsibility under production pressure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly the mindset described in &lt;em&gt;What have I learned so far in my job?&lt;/em&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No panic.&lt;/li&gt;
&lt;li&gt;Read official documentation.&lt;/li&gt;
&lt;li&gt;Think before acting.&lt;/li&gt;
&lt;li&gt;Solve root causes.&lt;/li&gt;
&lt;li&gt;Learn continuously.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI does not remove the need for that.&lt;/p&gt;

&lt;p&gt;It increases the need.&lt;/p&gt;


&lt;h2&gt;
  
  
  6. Implementation: Professional AI Usage in Modern PHP
&lt;/h2&gt;

&lt;p&gt;Here’s the difference in practice.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1 – Encode Constraints First
&lt;/h3&gt;

&lt;p&gt;Use modern PHP features (see PHP 8.x guide ):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="cd"&gt;/** @var numeric-string $amount */&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$currency&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;is_numeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$amount&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InvalidArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Amount must be numeric.'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2 – Add Static Guarantees
&lt;/h3&gt;

&lt;p&gt;Leverage advanced PHPDoc generics and shapes (see coding standards ):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @param non-empty-list&amp;lt;Money&amp;gt; $items
 */&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;calculateTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$items&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Money&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// AI can scaffold this.&lt;/span&gt;
    &lt;span class="c1"&gt;// You verify invariants.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3 – Let AI Scaffold, Not Decide
&lt;/h3&gt;

&lt;p&gt;Ask AI to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate repetitive repository boilerplate&lt;/li&gt;
&lt;li&gt;Create test skeletons&lt;/li&gt;
&lt;li&gt;Draft migration scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Review types&lt;/li&gt;
&lt;li&gt;Validate edge cases&lt;/li&gt;
&lt;li&gt;Remove unnecessary abstractions&lt;/li&gt;
&lt;li&gt;Reduce surface area&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI becomes a deterministic macro tool.&lt;/p&gt;

&lt;p&gt;Not a system designer.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Common Pitfalls in the AI Era
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ❌ Blind Acceptance
&lt;/h3&gt;

&lt;p&gt;Shipping plausible but unverified code.&lt;/p&gt;

&lt;h3&gt;
  
  
  ❌ Over-Abstraction
&lt;/h3&gt;

&lt;p&gt;Generating factories for trivial objects because the model “likes patterns.”&lt;/p&gt;

&lt;h3&gt;
  
  
  ❌ Entropy Explosion
&lt;/h3&gt;

&lt;p&gt;More code → more maintenance → more hidden bugs.&lt;/p&gt;

&lt;h3&gt;
  
  
  ❌ Replacing Thinking
&lt;/h3&gt;

&lt;p&gt;Outsourcing domain decisions to a statistical engine.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Best Practices for Surviving the Compression
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Strengthen type systems.&lt;/li&gt;
&lt;li&gt;Use PHPStan aggressively.&lt;/li&gt;
&lt;li&gt;Automate refactoring.&lt;/li&gt;
&lt;li&gt;Enforce code style automatically.&lt;/li&gt;
&lt;li&gt;Reduce public surface area.&lt;/li&gt;
&lt;li&gt;Prefer deletion over addition.&lt;/li&gt;
&lt;li&gt;Move up the abstraction ladder.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Think like a systems engineer, not a syntax operator.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion: The Market Is Compressing — Not Dying
&lt;/h2&gt;

&lt;p&gt;LLMs are not architects.&lt;br&gt;
They are pattern engines.&lt;/p&gt;

&lt;p&gt;But in a world where much work is pattern instantiation, pattern engines are disruptive.&lt;/p&gt;

&lt;p&gt;You can absolutely earn top PHP salaries, 100% remote.&lt;/p&gt;

&lt;p&gt;But not if your value was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;typing code faster than others.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You must operate where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Patterns stop&lt;/li&gt;
&lt;li&gt;Trade-offs begin&lt;/li&gt;
&lt;li&gt;Responsibility matters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything below that layer is compressing.&lt;/p&gt;

&lt;p&gt;Compression does not care about feelings.&lt;/p&gt;

&lt;p&gt;It cares about economics.&lt;/p&gt;




&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;AI is a compression engine for repetitive code.&lt;/li&gt;
&lt;li&gt;Mechanical developers are at risk.&lt;/li&gt;
&lt;li&gt;Structural thinkers are amplified.&lt;/li&gt;
&lt;li&gt;Token-based billing incentivizes verbosity.&lt;/li&gt;
&lt;li&gt;Experts win by deleting, not generating.&lt;/li&gt;
&lt;li&gt;Modern PHP + strict typing + static analysis are your leverage.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Call to Action
&lt;/h1&gt;

&lt;p&gt;Audit your own work.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are you adding value above the pattern layer?&lt;/li&gt;
&lt;li&gt;Or are you a very fast nail gun operator?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implement code quality gates: static analysis, test coverage, ...&lt;br&gt;
Automate the boring parts.&lt;br&gt;
Move upward in abstraction.&lt;br&gt;
Let the LLM write code generators that write deterministic code.&lt;/p&gt;

</description>
      <category>php</category>
      <category>ai</category>
      <category>career</category>
    </item>
    <item>
      <title>The System Inspector: We need to Approve the Code</title>
      <dc:creator>Lars Moelleken</dc:creator>
      <pubDate>Tue, 03 Feb 2026 05:26:20 +0000</pubDate>
      <link>https://dev.to/suckup_de/the-system-inspector-we-need-to-approve-the-code-5agc</link>
      <guid>https://dev.to/suckup_de/the-system-inspector-we-need-to-approve-the-code-5agc</guid>
      <description>&lt;p&gt;This is a follow-up blog post: &lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/suckup_de/the-wild-west-of-coding-why-were-still-burning-digital-cities-4ph5" class="crayons-story__hidden-navigation-link"&gt;The Wild West of Coding: Why We’re Still Burning Digital Cities&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/suckup_de" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F30309%2F2945b2a8-f26d-4575-85eb-030996bcb91e.png" alt="suckup_de profile" class="crayons-avatar__image" width="800" height="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/suckup_de" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Lars Moelleken
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Lars Moelleken
                
              
              &lt;div id="story-author-preview-content-2237279" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/suckup_de" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F30309%2F2945b2a8-f26d-4575-85eb-030996bcb91e.png" class="crayons-avatar__image" alt="" width="800" height="800"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Lars Moelleken&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/suckup_de/the-wild-west-of-coding-why-were-still-burning-digital-cities-4ph5" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jan 31 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/suckup_de/the-wild-west-of-coding-why-were-still-burning-digital-cities-4ph5" id="article-link-2237279"&gt;
          The Wild West of Coding: Why We’re Still Burning Digital Cities
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/general"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;general&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/suckup_de/the-wild-west-of-coding-why-were-still-burning-digital-cities-4ph5#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;The year 2050 is closer than 2000. And yet, software development is entering a phase where writing code is no longer the bottleneck.&lt;/p&gt;

&lt;p&gt;For the first time, &lt;strong&gt;code generation is virtually free&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Large Language Models (LLMs) can generate thousands of lines of syntactically valid, locally plausible code in seconds. The bottleneck is no longer how fast we can implement features - it's how reliably we can absorb what has been produced.&lt;/p&gt;

&lt;p&gt;This shift is not theoretical. It's already showing up in real-world codebases.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenClaw: Code Without Memory
&lt;/h2&gt;

&lt;p&gt;Take the OpenClaw repository. At first glance, it looks like boring TypeScript. No red flags. The kind of code that would sail through a shallow pull request review.&lt;/p&gt;

&lt;p&gt;But zoom out, and the deeper you go, the more disturbing it becomes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redundant checks live next to reckless type assertions.&lt;/li&gt;
&lt;li&gt;Standard APIs are quietly reinvented.&lt;/li&gt;
&lt;li&gt;Near-identical helpers exist side by side, none reused. One even comes with a completely unnecessary comment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/openclaw/openclaw/commit/d1ecb46076145deb188abcba8f0699709ea17198" rel="noopener noreferrer"&gt;https://github.com/openclaw/openclaw/commit/d1ecb46076145deb188abcba8f0699709ea17198&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctvfgue4bcta4zimvrxz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctvfgue4bcta4zimvrxz.png" alt=" " width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this commit, the same escape-handling rule&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;isDoubleQuoteEscape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;appears three times, implemented independently in three different parsing loops. It works, but it is duplicated logic, not a shared rule.&lt;/p&gt;

&lt;p&gt;The newly introduced constant&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DOUBLE_QUOTE_ESCAPES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;makes the same problem visible at the naming level.&lt;br&gt;&lt;br&gt;
&lt;code&gt;DOUBLE_QUOTE_ESCAPES&lt;/code&gt; sounds like “things that happen in double quotes”. What the code actually enforces is much narrower: a whitelist of characters that are allowed &lt;em&gt;after a backslash&lt;/em&gt; while inside a double-quoted string.&lt;/p&gt;

&lt;p&gt;That distinction matters, because this is not a general shell grammar. It is a parser rule with intentionally restricted semantics. A name that encodes the mechanism is therefore clearer and harder to misread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DOUBLE_QUOTE_BACKSLASH_FOLLOWERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a one-off mistake. It is a pattern: rules are re-expressed locally instead of being named once and reused. The code still works. But it doesn’t remember what it already knows.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. From Coder to Inspector
&lt;/h2&gt;

&lt;p&gt;For decades, software was naturally throttled by human speed... typing, thinking, debugging. That friction caught many errors before they reached production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LLMs remove that friction.&lt;/strong&gt; They don't understand systems. They don't remember outages, postmortems, or audit logs. They see the end result of code and predict patterns based on surface-level plausibility.&lt;/p&gt;

&lt;p&gt;As a result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defensive logic gets "simplified" away.&lt;/li&gt;
&lt;li&gt;Ugly but necessary patches get erased.&lt;/li&gt;
&lt;li&gt;Implicit architectural contracts get violated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And yet, CI passes. Tests are green. The code looks fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But the foundation quietly erodes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is where the role of the Senior Engineer shifts. Their value is no longer in &lt;strong&gt;writing&lt;/strong&gt; code, it's in knowing &lt;strong&gt;when not to&lt;/strong&gt; and where to stop Claude from adding even more markdown files and not needed feature lists.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Dangerous Gap Between Commit and Reality
&lt;/h2&gt;

&lt;p&gt;Today's pipelines can take code from prompt to production in minutes. What's missing isn't automation, as in the last decade, it's human &lt;strong&gt;verification&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did we actually mean to solve the problem this way?&lt;/li&gt;
&lt;li&gt;Did we just break a hidden assumption?&lt;/li&gt;
&lt;li&gt;Will the next dev understand what this does?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most dangerous bugs aren't crashes. They're subtle degradations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Re-emergent race conditions&lt;/li&gt;
&lt;li&gt;Broken security invariants&lt;/li&gt;
&lt;li&gt;Unnecessary abstractions that raise cognitive load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tests won't catch all of this. Reviews barely scratch the surface when volume explodes.&lt;/p&gt;

&lt;p&gt;And in this new regime, the cost of errors doesn't hit one dev, but it's paid by the organization in the long run.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Enter the System Inspector
&lt;/h2&gt;

&lt;p&gt;In the 19th century, societies learned that bridges shouldn't be approved by the people who built them. &lt;strong&gt;Structural collapses birthed the role of inspectors.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Software is hitting that same phase.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;System Inspector&lt;/strong&gt; is not a title. It's a &lt;strong&gt;responsibility&lt;/strong&gt;: Someone whose job is to &lt;strong&gt;approve&lt;/strong&gt; code, not write it. Not just another Code-Review between the next features. Not based on aesthetics, but on &lt;strong&gt;integrity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Their responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define and protect non-negotiable system rules&lt;/li&gt;
&lt;li&gt;Preserve organizational and historical knowledge&lt;/li&gt;
&lt;li&gt;Manage cognitive load&lt;/li&gt;
&lt;li&gt;Reject syntactically correct but structurally harmful code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not about blocking progress. It's about preventing scale-induced disasters.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Regulation Is a Prerequisite for Scaling
&lt;/h2&gt;

&lt;p&gt;Guidelines don't scale. Style guides don't survive contact with LLMs. Comments get reworded, ignored, or helpfully "improved" into something else entirely.&lt;/p&gt;

&lt;p&gt;Advice is optional. Code generation is not.&lt;/p&gt;

&lt;p&gt;What actually works are &lt;strong&gt;machine-enforceable constraints&lt;/strong&gt;: e.g.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linting, tests, static analysis, contract checks.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AGENTS.md&lt;/code&gt; files that define &lt;strong&gt;rules&lt;/strong&gt;, not suggestions.&lt;/li&gt;
&lt;li&gt;Unchanging values that must apply regardless of how the code was created.&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't bureaucracy. This is infrastructure.&lt;/p&gt;

&lt;p&gt;These constraints are the building codes of software systems that want to grow without collapsing. Every familiar argument against them sounds exactly like the arguments once made against fire codes or electrical standards. They were wrong then. They're wrong now.&lt;/p&gt;

&lt;p&gt;Scaling requires automation. Automation requires limits. And limits still require humans in the loop, just not humans doing the policing by hand.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Blind Spots: The Parts We Prefer to Ignore
&lt;/h2&gt;

&lt;p&gt;Even good systems carry risk. Here are some overlooked failure points:&lt;/p&gt;

&lt;h3&gt;
  
  
  🧱 Lack of Organizational Support
&lt;/h3&gt;

&lt;p&gt;System Inspectors need &lt;strong&gt;mandates and time&lt;/strong&gt;. Without this, their role collapses into unpaid heroism or burnout.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 Concentrated Psychological Load
&lt;/h3&gt;

&lt;p&gt;Decision bottlenecks are unsustainable. Approval authority needs to be distributed via frameworks, heuristics, or shared ownership... in the team.&lt;/p&gt;

&lt;h3&gt;
  
  
  🌍 One Size Doesn't Fit All
&lt;/h3&gt;

&lt;p&gt;Not every team need this. These principles apply broadly but must be &lt;strong&gt;contextually adapted&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. IKEA Was Never the Problem
&lt;/h2&gt;

&lt;p&gt;This isn't a moral panic about LLMs.&lt;/p&gt;

&lt;p&gt;Pandora’s box is open. Code generation is here: fast, cheap, and inescapable. Some teams will &lt;strong&gt;choose velocity over resilience&lt;/strong&gt;. That's a valid economic tradeoff.&lt;/p&gt;

&lt;p&gt;The problem begins when these systems are sold as something they are not.&lt;/p&gt;

&lt;p&gt;IKEA furniture is not marketed as handmade oak. Software should follow the same principle of honesty. If we build with particle board, we should say so, and we should not pretend that it can bear the same load.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. The Industrial Phase of Software
&lt;/h2&gt;

&lt;p&gt;Software is leaving its artisanal phase, not because we matured, but because &lt;strong&gt;scale made failure expensive&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Code will be abundant. &lt;strong&gt;Responsibility will be scarce.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We are no longer writing code line by line. We are approving &lt;strong&gt;systems&lt;/strong&gt; that outlast individuals and define entire orgs.&lt;/p&gt;

&lt;p&gt;That's why we need &lt;strong&gt;System Inspectors&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not to halt innovation, but to ensure our digital cities don't collapse like their wooden ancestors.&lt;/p&gt;

&lt;p&gt;Let's build like we know what we're doing. :P&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>codereview</category>
    </item>
    <item>
      <title>How to Use LLMs for Coding Without Losing Your Mind: A Pragmatic Guide</title>
      <dc:creator>Lars Moelleken</dc:creator>
      <pubDate>Thu, 29 Jan 2026 03:13:41 +0000</pubDate>
      <link>https://dev.to/suckup_de/how-to-use-llms-for-coding-without-losing-your-mind-a-pragmatic-guide-1dap</link>
      <guid>https://dev.to/suckup_de/how-to-use-llms-for-coding-without-losing-your-mind-a-pragmatic-guide-1dap</guid>
      <description>&lt;p&gt;#blogPostAsWebApp: &lt;a href="https://voku.github.io/LLMCodingTrainMap/" rel="noopener noreferrer"&gt;https://voku.github.io/LLMCodingTrainMap/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  You Don't Work with LLMs — LLMs Work for You
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;If you treat an LLM like a teammate, you'll be disappointed.&lt;br&gt;&lt;br&gt;
If you treat it like a compiler, you'll ship valuable results.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Developers fail with LLMs for the same reason they fail at planning tasks like writing Jira tickets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;vague inputs
&lt;/li&gt;
&lt;li&gt;missing constraints
&lt;/li&gt;
&lt;li&gt;no stopping condition
&lt;/li&gt;
&lt;li&gt;no definition of done
&lt;/li&gt;
&lt;li&gt;blind trust
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide is not about &lt;strong&gt;what LLMs are&lt;/strong&gt;. (I alread did that here) &lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/suckup_de/crayons-and-the-wall-2ia7" class="crayons-story__hidden-navigation-link"&gt;Crayons and the Wall&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/suckup_de" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F30309%2F2945b2a8-f26d-4575-85eb-030996bcb91e.png" alt="suckup_de profile" class="crayons-avatar__image" width="800" height="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/suckup_de" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Lars Moelleken
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Lars Moelleken
                
              
              &lt;div id="story-author-preview-content-3196828" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/suckup_de" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F30309%2F2945b2a8-f26d-4575-85eb-030996bcb91e.png" class="crayons-avatar__image" alt="" width="800" height="800"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Lars Moelleken&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/suckup_de/crayons-and-the-wall-2ia7" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jan 25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/suckup_de/crayons-and-the-wall-2ia7" id="article-link-3196828"&gt;
          Crayons and the Wall
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/llm"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;llm&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/engineering"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;engineering&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/suckup_de/crayons-and-the-wall-2ia7" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/suckup_de/crayons-and-the-wall-2ia7#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;
 &lt;br&gt;
It’s about &lt;strong&gt;how to use them every day&lt;/strong&gt; without losing time, correctness, control or your mind.

&lt;p&gt;Vibes are good. Prompting is not that helpful in 2026, so remove your collected prompts e.g. &lt;a href="https://gist.github.com/voku/4ad5a27836ae7c5100b746848e30d278" rel="noopener noreferrer"&gt;Me as PHP chat bot. 🤖&lt;/a&gt; and use your context window for real work.&lt;br&gt;&lt;br&gt;
But context, workflows and hard constraints are what actually work in production.&lt;/p&gt;

&lt;p&gt;Let's get hands-on.&lt;/p&gt;


&lt;h2&gt;
  
  
  Mental Model: LLM as a Probabilistic Compiler
&lt;/h2&gt;

&lt;p&gt;Before tools, prompts, or rituals, internalize this model:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Programming Concept&lt;/th&gt;
&lt;th&gt;LLM Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Source Code&lt;/td&gt;
&lt;td&gt;Prompt + Context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Include Paths&lt;/td&gt;
&lt;td&gt;Files, snippets, constraints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compiler&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LLM&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intermediate Representation&lt;/td&gt;
&lt;td&gt;Generated output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type Checker&lt;/td&gt;
&lt;td&gt;Static analysis, tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linker&lt;/td&gt;
&lt;td&gt;Manual edits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime&lt;/td&gt;
&lt;td&gt;Production&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;If something breaks, &lt;strong&gt;the bug is in the input&lt;/strong&gt;, mostly not in the compiler. (even if we sometimes think it is)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;PS: Here are some 01/2026 facts about LLM usage: If a colleague argues that this doesn't work at all, remind them ...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Cursor Team used hundreds of concurrent AI agents to write over a million lines of code for a browser prototype in a week. Autonomous workflows are real. &lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/wilsonzlin" rel="noopener noreferrer"&gt;
        wilsonzlin
      &lt;/a&gt; / &lt;a href="https://github.com/wilsonzlin/fastrender" rel="noopener noreferrer"&gt;
        fastrender
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Experimental new browser engine
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;FastRender&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A browser rendering engine in Rust. Parses HTML/CSS, computes styles, performs layout, and paints pixels. Includes a desktop browser shell and JavaScript execution via an embedded JS engine.&lt;/p&gt;
&lt;p&gt;Under heavy development. APIs are unstable and change frequently. Not recommended for production use.&lt;/p&gt;
&lt;p&gt;Developed as part of &lt;a href="https://cursor.com/blog/scaling-agents" rel="nofollow noopener noreferrer"&gt;research into collaborative parallel AI coding agents&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Repository structure&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;src/
├── api.rs                 # Public API (FastRender, RenderOptions)
├── dom.rs                 # DOM tree, parsing, shadow DOM
├── dom2/                  # Live DOM for JS mutation
├── css/                   # CSS parsing, selectors, values
├── style/                 # Cascade, computed styles, media queries
│   ├── cascade.rs         # Cascade algorithm, layers, scope
│   ├── properties.rs      # Property definitions
│   └── values.rs          # Value types, calc(), colors
├── tree/                  # Box tree generation
│   ├── box_tree.rs        # Box nodes, formatting contexts
│   ├── box_generation.rs  # Styled → box mapping
│   └── table_fixup.rs     # Anonymous table wrapper insertion
├── layout/&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/wilsonzlin/fastrender" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
 

&lt;ul&gt;
&lt;li&gt;Uncle Bob (Robert C. Martin), the master of Clean Code, admitted that LLM Coding-Agents are working surprisingly well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2016523982560727349-359" src="https://platform.twitter.com/embed/Tweet.html?id=2016523982560727349"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2016523982560727349-359');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2016523982560727349&amp;amp;theme=dark"
  }



 &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linus Torvalds himself used tools like Google Antigravity for hobby projects and accepted the results.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/torvalds" rel="noopener noreferrer"&gt;
        torvalds
      &lt;/a&gt; / &lt;a href="https://github.com/torvalds/GuitarPedal" rel="noopener noreferrer"&gt;
        GuitarPedal
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Linus learns analog circuits
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Resurrected random guitar pedal project&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This is a resurrected version of my old guitar pedal project, except
this time with a screen and a few rotary encoders instead of the old
horrid analog potentiometers.&lt;/p&gt;
&lt;p&gt;There's a 'Hardware' directory with the kicad files.&lt;/p&gt;
&lt;p&gt;There's a 'Software' directory that contains the firmware to make it do
something.&lt;/p&gt;
&lt;p&gt;And there's a 'Documentation' directory, which is a very optimistic
thing for this project.&lt;/p&gt;
&lt;p&gt;Anyway, with the update to have a screen and proper rotary encores, the
thing can now have multiple effects and a sane-ish UI to them.  Except
I'm not exactly known for my mad UI designing skillz.  So...&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Firmware&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;I've only ever built the firmware on Linux, but it &lt;em&gt;should&lt;/em&gt; be perfectly
possible to build on MacOS or Windows too if you just figure out the
platform requirements. The project depends on the &lt;code&gt;pico-sdk&lt;/code&gt; and
&lt;code&gt;tinyusb&lt;/code&gt; libraries, and has submodules for both…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/torvalds/GuitarPedal" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  1. Input Discipline (Before You Ask Anything)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Rule: Never Prompt Raw Thought
&lt;/h3&gt;

&lt;p&gt;LLMs amplify ambiguity.&lt;br&gt;&lt;br&gt;
If your input is fuzzy, the output will be confidently wrong. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2qx8ebnwi1b6gpv3kda.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2qx8ebnwi1b6gpv3kda.png" alt=" " width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bad input:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Implement the refund logic.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Good input:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Context:
- PHP 8.2
- Existing service RefundService
- Amounts are integers (cents)
- Manual approval required above 500 EUR

Constraints:
- Do not change public interfaces
- No new dependencies
- Existing tests must pass

Task:
Draft the internal calculation logic only.

Related Files:
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Pro Tip for Long-Term Memory&lt;/strong&gt;: Don't try to hold everything in the active chat context. Have the LLM write summaries or decisions into markdown files in the repo. Use repository artifacts as the LLM's long-term memory.&lt;/p&gt;

&lt;p&gt;PS: Google Gemini has currently the highest context window, so switch to that model for those tasks if needed&lt;/p&gt;


&lt;h2&gt;
  
  
  2. The 90% Rule (Where LLMs Are Actually Good)
&lt;/h2&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2013373307291340870-29" src="https://platform.twitter.com/embed/Tweet.html?id=2013373307291340870"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2013373307291340870-29');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2013373307291340870&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;LLMs are excellent at the &lt;strong&gt;first 80–90%&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scaffolding&lt;/li&gt;
&lt;li&gt;DTOs&lt;/li&gt;
&lt;li&gt;adapters&lt;/li&gt;
&lt;li&gt;mappings&lt;/li&gt;
&lt;li&gt;test skeletons&lt;/li&gt;
&lt;li&gt;documentation that mirrors code&lt;/li&gt;
&lt;li&gt;mechanical refactoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are &lt;strong&gt;bad&lt;/strong&gt; at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;domain invariants&lt;/li&gt;
&lt;li&gt;legal constraints&lt;/li&gt;
&lt;li&gt;historical edge cases&lt;/li&gt;
&lt;li&gt;“this legacy code is ugly for a reason”&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Rule
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Mostly you don't want to prompt the last 10%.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The moment you think “it’s almost right”, stop prompting.&lt;/p&gt;

&lt;p&gt;You either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fix it manually, or&lt;/li&gt;
&lt;li&gt;encode the missing rule as a test or type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anything else becomes prompt addiction.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Daily Workflows
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 1: Planning — Use LLMs for Triage, Not Code
&lt;/h3&gt;

&lt;p&gt;Start the feature or project by converting chaos into structure.&lt;/p&gt;

&lt;p&gt;Use LLMs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;summarize long ticket threads&lt;/li&gt;
&lt;li&gt;extract precise acceptance criteria&lt;/li&gt;
&lt;li&gt;identify system invariants&lt;/li&gt;
&lt;li&gt;list unknowns and highlight risks&lt;/li&gt;
&lt;li&gt;debate technical trade-offs (ping-pong arguments)&lt;/li&gt;
&lt;li&gt;run a "blind spot analysis" against your plan (&lt;a href="https://voku.github.io/BlindSpotMetaPromptApp/" rel="noopener noreferrer"&gt;Meta-Prompt&lt;/a&gt; or via &lt;a href="https://chatgpt.com/g/g-6816771cf34c8191bf5a053958ce0c79-blind-spot-prompt-generator" rel="noopener noreferrer"&gt;Chatty&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No code yet. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint&lt;/strong&gt;: And remember, before you use the latest shiny framework version, that the current models were trained with data from last year, so you should “at least” be from that time, maybe even older, so that more training data was available at that time.&lt;/p&gt;

&lt;p&gt;If you skip this, you’re outsourcing thinking, not typing.&lt;/p&gt;

&lt;p&gt;Note: If you are typing a lot, voice tools like &lt;a href="https://wisprflow.ai/" rel="noopener noreferrer"&gt;wisprflow.ai&lt;/a&gt; can reduce friction (and yes, that matters).&lt;/p&gt;


&lt;h3&gt;
  
  
  Step 2: Implementation
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Lane A: The "Legacy Stack" Approach (e.g., older PHP, Java)
&lt;/h4&gt;

&lt;p&gt;If the LLM struggles with your 1996 template engine quirks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generate a Mockup&lt;/strong&gt; (image) after you provided your "style guide" and examples PS: if you haven't a style guide yet, let the LLM help you also with that task - &lt;a href="https://gist.github.com/voku/8615cc2b095ec2d46a3e69faa2595dad" rel="noopener noreferrer"&gt;https://gist.github.com/voku/8615cc2b095ec2d46a3e69faa2595dad&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generate a Click-Dummy&lt;/strong&gt; of the Mockup: Turn the mockup into a clickable prototype to verify flows against constraints.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manual Integration&lt;/strong&gt;: Use the Click-Dummy to integeate the feature into the real code, mostly by hand&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tests&lt;/strong&gt;: Let the LLM add some tests in the end :) (I know we want to use TDD but anyway)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h4&gt;
  
  
  Lane B: Frontend "Vibe-Coding" (The 2026 Way)
&lt;/h4&gt;

&lt;p&gt;For modern stacks where iteration is cheap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;strong&gt;&lt;a href="https://aistudio.google.com/" rel="noopener noreferrer"&gt;AI Studio&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use your &lt;strong&gt;planning&lt;/strong&gt; from before, and copy&amp;amp;past just the full document into the input. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;PS: for me ChatGPT is still best in planning such stuff without adding un-wanted stuff like Claude often does&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Now is Ping-Pong time, let's &lt;strong&gt;shape&lt;/strong&gt; the results by using the AI-Studio to providing direct feedback and ideas that pop-up while seeing the results. :)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Push&lt;/strong&gt; the 90% version to github (just one click in the UI)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agentic Cleanup&lt;/strong&gt;: Now let's use another LLM (e.g. codex web or github agent) ... and you can give the agents more than one task, if the tasks are small, so that you do not need 10/100 free request but just 1/100 e.g.:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Remove GEMINI references
Update README.md to remove AI Studio ads and references
Update README.md with production-ready documentation
Add "Key Files Detector" helper prompt to README.md
Add a favicon
Create a contribution link (https://github.com/[YOUR_LINK_HERE]) in the webapp
Configure GitHub Pages deployment with Vite build
Add GitHub Actions workflow for automatic deployment
Build and verify the application works
Review and finalize changes and make sure the entry point from the webapp is in the html file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Activate github pages (for free) and your Webapp is &lt;strong&gt;online&lt;/strong&gt; while you managed all this with your phone :)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;PS: here are my example Webapp stuff that I created mostly this way: &lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/suckup_de/posts-as-webapps-26lk" class="crayons-story__hidden-navigation-link"&gt;BlogPosts as WebApps&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/suckup_de" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F30309%2F2945b2a8-f26d-4575-85eb-030996bcb91e.png" alt="suckup_de profile" class="crayons-avatar__image" width="800" height="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/suckup_de" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Lars Moelleken
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Lars Moelleken
                
              
              &lt;div id="story-author-preview-content-3179432" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/suckup_de" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F30309%2F2945b2a8-f26d-4575-85eb-030996bcb91e.png" class="crayons-avatar__image" alt="" width="800" height="800"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Lars Moelleken&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/suckup_de/posts-as-webapps-26lk" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jan 17&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/suckup_de/posts-as-webapps-26lk" id="article-link-3179432"&gt;
          BlogPosts as WebApps
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/learning"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;learning&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/suckup_de/posts-as-webapps-26lk#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  




&lt;h4&gt;
  
  
  Lane C: Agentic-Coding (Vibe-Coding with Control)
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Plan with Restrictions&lt;/strong&gt;: Ensure your planning phase is solid and you have clear constraints documented (e.g., in an AGENTS.md file in your repo root).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define Tasks&lt;/strong&gt;: Add clear, bite-sized tasks into a docs/TODO.md file via the LLM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run the Agent&lt;/strong&gt;: Use CLI tools (see "What's Next" below) to execute the list.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example: &lt;code&gt;codex --yolo "Implement the open tasks from docs/TODO.md"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This tools are also working with your subscription, and often has a free try and at the end of the post I wrote a quick one minute intro to install it, see &lt;code&gt;What’s Next: Agentic Coding (Try It)&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;I created the next project via agents (without any IDE) and while working on it, I saw that the agents really has problems with e.g. Android Apps because the build time (feedback loop) was way to slow with my mini pc :/ so I asked the agent to convert it into a Webapp and it worked. :D &lt;/p&gt;

&lt;p&gt;My main pain point is that if you didn't do the coding work anymore you haven't this mental model of the project in mind and it's more and more complicated to plan new things and to keep it stable. &lt;/p&gt;

&lt;p&gt;(still not 100% done, we need to train the ML Engine now)&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/voku" rel="noopener noreferrer"&gt;
        voku
      &lt;/a&gt; / &lt;a href="https://github.com/voku/AmysEcho" rel="noopener noreferrer"&gt;
        AmysEcho
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      This repository contains the development work for my little girl — to help her be understood, to help her learn, and to help others understand her world.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Amy's Echo&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/voku/AmysEcho/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667" alt="Open Source – MIT"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This repository contains the development work for my little girl — to help her be understood, to help her learn, and to help others understand her world.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Amy is four years old. She was born with &lt;strong&gt;22q11 Deletion Syndrome&lt;/strong&gt; and communicates using &lt;strong&gt;Deutsche Gebärdensprache (DGS)&lt;/strong&gt; — German Sign Language. Her gestures are expressive, her intent is clear — but most people around her don't understand what she's trying to say.&lt;/p&gt;
&lt;p&gt;This project turns those gestures into speech and symbols so she can be heard anywhere. Each child profile receives personalized gesture recognition trained from their own samples, making the system effective for 22q11 workflows in group settings like kindergartens.&lt;/p&gt;
&lt;p&gt;All app UI text and error messages are written in German to match Amy's language environment.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Current Focus&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The project is being maintained in a &lt;strong&gt;supported-core&lt;/strong&gt; mode.&lt;/p&gt;
&lt;p&gt;Current first-class scope:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;caregiver auth and child profiles&lt;/li&gt;
&lt;li&gt;live gesture recognition&lt;/li&gt;
&lt;li&gt;low-confidence…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/voku/AmysEcho" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;h3&gt;
  
  
  Lane D: The Daily Driver (IDE-Centric Coding with Guardrails)
&lt;/h3&gt;

&lt;p&gt;This lane is for daily engineering work inside the IDE (e.g. PhpStorm + GitHub Copilot). Maintenance, debugging, and refactoring where correctness matters more than speed.&lt;/p&gt;

&lt;p&gt;No agents. No pipelines. Just quick feedback loops.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Curate Context Explicitly&lt;/strong&gt;: Copilot does not understand your project:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open&lt;/strong&gt; the interface or contract&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open&lt;/strong&gt; the concrete implementation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open&lt;/strong&gt; the relevant test&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open&lt;/strong&gt; involved DTOs or config files&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Rule&lt;/strong&gt;: If the file is not open tab, it doesn’t exist for the LLM.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prefer Inline Edit Mode Over Chat&lt;/strong&gt;: Use Copilot where diffs are visible and reversible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Select&lt;/strong&gt; code in the editor&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trigger&lt;/strong&gt; inline edit (Ctrl + Shift + I)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt&lt;/strong&gt; with a precise, local instruction&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: "Extract the loop logic into a private method &lt;code&gt;processItems&lt;/code&gt; with an explicit return type."&lt;/p&gt;

&lt;p&gt;Review the diff. Accept deliberately.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stabilize Legacy Code via Reverse Documentation&lt;/strong&gt;: For unclear or fragile code, do not ask for a refactor immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Select&lt;/strong&gt; the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask&lt;/strong&gt; Copilot to describe it, not change it.&lt;/li&gt;
&lt;li&gt;"Write a PHPDoc explaining exactly what this code does, including edge cases."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate&lt;/strong&gt; the explanation first.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Refactor&lt;/strong&gt; only after the behavior is explicit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Actively Prevent "Passenger Mode"&lt;/strong&gt;: The &lt;code&gt;Tab&lt;/code&gt; → &lt;code&gt;Accept&lt;/code&gt; → &lt;code&gt;Commit&lt;/code&gt; loop is a trap.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Read generated code &lt;strong&gt;before&lt;/strong&gt; accepting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you can’t explain it, &lt;strong&gt;reject&lt;/strong&gt; it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copilot accelerates thinking. It should not replace it in this lane.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 3: Validation — Treat Output as Untrusted
&lt;/h3&gt;

&lt;p&gt;LLM output is &lt;strong&gt;never final code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It must pass:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;strict type checking&lt;/li&gt;
&lt;li&gt;aggressive linters&lt;/li&gt;
&lt;li&gt;automated tests&lt;/li&gt;
&lt;li&gt;static analysis tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If it doesn’t:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fix the constraint
&lt;/li&gt;
&lt;li&gt;or add more context
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;A compiler that issues warnings is telling you something.&lt;br&gt;&lt;br&gt;
An LLM often believes it has done everything correctly and therefore also requires similar validation steps&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Adding more context sounds more easy that it sometimes: UI Bug Example&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provide the exact error message from the CI pipeline.&lt;/li&gt;
&lt;li&gt;Use an MCP (Model Context Protocol) tool to let the LLM view the app in a headless browser.&lt;/li&gt;
&lt;li&gt;Provide a screenshot with browser DevTools open showing the DOM state.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Step 4: commit&amp;amp;push — Let the Repo Remember
&lt;/h3&gt;

&lt;p&gt;Humans forget why things exist.&lt;br&gt;&lt;br&gt;
LLMs don’t, if you ask at the right moment.&lt;/p&gt;

&lt;p&gt;Use them to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Summarize diffs into commit messages. Crucial: Manually add the "WHY" to the message; the LLM usually only sees the "WHAT".&lt;/li&gt;
&lt;li&gt;Draft Architectural Decision Records (ADRs). Hint: Add a note in generated docs that they are drafts and need human review.&lt;/li&gt;
&lt;li&gt;Explain "why this legacy code is ugly" and document it in a comment near the code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This kills tribal knowledge without requiring meetings.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. Constraints Beat Prompts (Always)
&lt;/h2&gt;

&lt;p&gt;Stop writing clever prompts. (&lt;a href="https://voku.github.io/PromptMastery/" rel="noopener noreferrer"&gt;https://voku.github.io/PromptMastery/&lt;/a&gt;)&lt;br&gt;
Start writing &lt;strong&gt;constraint boxes&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Constraints:
- No new public methods allowed.
- Must preserve backward compatibility with API v2.
- Assume input is already validated (do not add redundant checks).
- Output must be deterministic (seed random number generators).
- Fail fast with a specific Exception class on invalid state.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Constraints shrink the solution space, making correct answers more likely. But sady they traind the current LLMs just the happy path. :P&lt;/p&gt;


&lt;h2&gt;
  
  
  5. Generators Over Code
&lt;/h2&gt;

&lt;p&gt;If you ask an LLM to write the same thing 5x, you already failed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bad&lt;/strong&gt;: "Generate 30 DTOs for these tables..."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good&lt;/strong&gt;: "Write a Python script using Jinja2 templates that reads this database schema YAML and generates the 30 DTO files fitting our project structure."&lt;/p&gt;

&lt;p&gt;This turns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;probability → determinism
&lt;/li&gt;
&lt;li&gt;conversation → reusable tooling&lt;/li&gt;
&lt;li&gt;magic → a reproducible build step&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other example: PHP&lt;br&gt;
In larger legacy systems, I recently had the LLM create various custom PHP-CS-Fixer rules so that we could easily migrate things in a deterministic way. That's the way.  &lt;/p&gt;
&lt;h2&gt;
  
  
  What’s Next: Agentic Coding (Try It)
&lt;/h2&gt;

&lt;p&gt;If you haven’t played with CLI-based code agents yet, you’re missing the point of all this.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don’t overthink it.
&lt;/li&gt;
&lt;li&gt;Don’t integrate it into prod.
&lt;/li&gt;
&lt;li&gt;Try it locally and break things safely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are three options you can test quickly.&lt;/p&gt;


&lt;h3&gt;
  
  
  1. Google Gemini CLI
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/google-gemini" rel="noopener noreferrer"&gt;
        google-gemini
      &lt;/a&gt; / &lt;a href="https://github.com/google-gemini/gemini-cli" rel="noopener noreferrer"&gt;
        gemini-cli
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An open-source AI agent that brings the power of Gemini directly into your terminal.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Gemini CLI&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/google-gemini/gemini-cli/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/google-gemini/gemini-cli/actions/workflows/ci.yml/badge.svg" alt="Gemini CLI CI"&gt;&lt;/a&gt;
&lt;a href="https://github.com/google-gemini/gemini-cli/actions/workflows/chained_e2e.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/google-gemini/gemini-cli/actions/workflows/chained_e2e.yml/badge.svg" alt="Gemini CLI E2E (Chained)"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/@google/gemini-cli" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/34811703a711b6037aa43a44195c31c3844bdb76af3fb0221142c7a3f03d5929/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f40676f6f676c652f67656d696e692d636c69" alt="Version"&gt;&lt;/a&gt;
&lt;a href="https://github.com/google-gemini/gemini-cli/blob/main/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8ad45b29989b35a46e9a9881bd5cbc03e8393ae620f6c70884d3e8e05afe92c0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f676f6f676c652d67656d696e692f67656d696e692d636c69" alt="License"&gt;&lt;/a&gt;
&lt;a href="https://codewiki.google/github.com/google-gemini/gemini-cli?utm_source=badge&amp;amp;utm_medium=github&amp;amp;utm_campaign=github.com/google-gemini/gemini-cli" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/94541bcea8452983959d62ea7b483d19909ad00e9827d23ca65ade5aab87b795/68747470733a2f2f6173736574732e636f646577696b692e676f6f676c652f726561646d652d62616467652f7374617469632e737667" alt="View Code Wiki"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/docs/assets/gemini-screenshot.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fdocs%2Fassets%2Fgemini-screenshot.png" alt="Gemini CLI Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Gemini CLI is an open-source AI agent that brings the power of Gemini directly
into your terminal. It provides lightweight access to Gemini, giving you the
most direct path from your prompt to our model.&lt;/p&gt;
&lt;p&gt;Learn all about Gemini CLI in our &lt;a href="https://geminicli.com/docs/" rel="nofollow noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚀 Why Gemini CLI?&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🎯 Free tier&lt;/strong&gt;: 60 requests/min and 1,000 requests/day with personal Google
account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🧠 Powerful Gemini 3 models&lt;/strong&gt;: Access to improved reasoning and 1M token
context window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🔧 Built-in tools&lt;/strong&gt;: Google Search grounding, file operations, shell
commands, web fetching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🔌 Extensible&lt;/strong&gt;: MCP (Model Context Protocol) support for custom
integrations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;💻 Terminal-first&lt;/strong&gt;: Designed for developers who live in the command line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🛡️ Open source&lt;/strong&gt;: Apache 2.0 licensed.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📦 Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;See
&lt;a href="https://www.geminicli.com/docs/get-started/installation" rel="nofollow noopener noreferrer"&gt;Gemini CLI installation, execution, and releases&lt;/a&gt;
for recommended system specifications and a detailed installation guide.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Quick Install&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Run instantly with npx&lt;/h4&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Using npx (no installation&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/google-gemini/gemini-cli" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Install&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @google/gemini-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Run (inside your local project)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini &lt;span class="nt"&gt;--yolo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. OpenAI Codex CLI
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/openai" rel="noopener noreferrer"&gt;
        openai
      &lt;/a&gt; / &lt;a href="https://github.com/openai/codex" rel="noopener noreferrer"&gt;
        codex
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Lightweight coding agent that runs in your terminal
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;strong&gt;Codex CLI&lt;/strong&gt; is a coding agent from OpenAI that runs locally on your computer
&lt;/p&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/openai/codex/blob/main/.github/codex-cli-splash.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fopenai%2Fcodex%2Fraw%2Fmain%2F.github%2Fcodex-cli-splash.png" alt="Codex CLI splash" width="80%"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;br&gt;
If you want Codex in your code editor (VS Code, Cursor, Windsurf), &lt;a href="https://developers.openai.com/codex/ide" rel="nofollow noopener noreferrer"&gt;install in your IDE.&lt;/a&gt;
&lt;br&gt;If you want the desktop app experience, run &lt;code&gt;codex app&lt;/code&gt; or visit &lt;a href="https://chatgpt.com/codex?app-landing-page=true" rel="nofollow noopener noreferrer"&gt;the Codex App page&lt;/a&gt;
&lt;br&gt;If you are looking for the &lt;em&gt;cloud-based agent&lt;/em&gt; from OpenAI, &lt;strong&gt;Codex Web&lt;/strong&gt;, go to &lt;a href="https://chatgpt.com/codex" rel="nofollow noopener noreferrer"&gt;chatgpt.com/codex&lt;/a&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quickstart&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installing and running Codex CLI&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Run the following on Mac or Linux to install Codex CLI:&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;curl -fsSL https://chatgpt.com/codex/install.sh &lt;span class="pl-k"&gt;|&lt;/span&gt; sh&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Run the following on Windows to install Codex CLI:&lt;/p&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;powershell -ExecutionPolicy ByPass -c "irm https://chatgpt.com/codex/install.ps1 | iex"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Codex CLI can also be installed via the following package managers:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Install using npm&lt;/span&gt;
npm install -g @openai/codex&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Install using Homebrew&lt;/span&gt;
brew install --cask codex&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Then simply run &lt;code&gt;codex&lt;/code&gt; to get started.&lt;/p&gt;

You can also go to the &lt;a href="https://github.com/openai/codex/releases/latest" rel="noopener noreferrer"&gt;latest GitHub Release&lt;/a&gt; and download the appropriate…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/openai/codex" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Codex CLI is explicitly designed to run locally and operate on the selected directory. (&lt;a href="https://developers.openai.com/codex/cli/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;developers.openai.com&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @openai/codex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Run&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex &lt;span class="nt"&gt;--yolo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;⚠️ Use this only in a &lt;strong&gt;local / restricted environment&lt;/strong&gt;. It can delete things. That’s not a joke.&lt;/p&gt;


&lt;h3&gt;
  
  
  3. opencode-ai (open source)
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/anomalyco" rel="noopener noreferrer"&gt;
        anomalyco
      &lt;/a&gt; / &lt;a href="https://github.com/anomalyco/opencode" rel="noopener noreferrer"&gt;
        opencode
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The open source coding agent.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;
  &lt;a href="https://opencode.ai" rel="nofollow noopener noreferrer"&gt;
    
      
      
      &lt;/a&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fanomalyco%2Fopencode%2FHEAD%2Fpackages%2Fconsole%2Fapp%2Fsrc%2Fasset%2Flogo-ornate-light.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fanomalyco%2Fopencode%2FHEAD%2Fpackages%2Fconsole%2Fapp%2Fsrc%2Fasset%2Flogo-ornate-light.svg" alt="OpenCode logo"&gt;&lt;/a&gt;
    
  
&lt;/p&gt;
&lt;p&gt;The open source AI coding agent.&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://opencode.ai/discord" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Discord" src="https://camo.githubusercontent.com/83daa53aa89771d7c1b411e9d8aab90692f07934a8c2aea6a6794687082e2f68/68747470733a2f2f696d672e736869656c64732e696f2f646973636f72642f313339313833323432363034383635313333343f7374796c653d666c61742d737175617265266c6162656c3d646973636f7264"&gt;&lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/opencode-ai" rel="nofollow noopener noreferrer"&gt;&lt;img alt="npm" src="https://camo.githubusercontent.com/4e57d77e1805497a6befb9cc1743a8069756f26377e832d09f1ba2ca49f9370c/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f6f70656e636f64652d61693f7374796c653d666c61742d737175617265"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/anomalyco/opencode/actions/workflows/publish.yml" rel="noopener noreferrer"&gt;&lt;img alt="Build status" src="https://camo.githubusercontent.com/dfb623969ed19b150f1ccf242b1b4c4b4629515c1aa0603fb795ff3e407c1b2d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f616e6f6d616c79636f2f6f70656e636f64652f7075626c6973682e796d6c3f7374796c653d666c61742d737175617265266272616e63683d646576"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://github.com/anomalyco/opencode/README.md" rel="noopener noreferrer"&gt;English&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.zh.md" rel="noopener noreferrer"&gt;简体中文&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.zht.md" rel="noopener noreferrer"&gt;繁體中文&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.ko.md" rel="noopener noreferrer"&gt;한국어&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.de.md" rel="noopener noreferrer"&gt;Deutsch&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.es.md" rel="noopener noreferrer"&gt;Español&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.fr.md" rel="noopener noreferrer"&gt;Français&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.it.md" rel="noopener noreferrer"&gt;Italiano&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.da.md" rel="noopener noreferrer"&gt;Dansk&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.ja.md" rel="noopener noreferrer"&gt;日本語&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.pl.md" rel="noopener noreferrer"&gt;Polski&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.ru.md" rel="noopener noreferrer"&gt;Русский&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.bs.md" rel="noopener noreferrer"&gt;Bosanski&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.ar.md" rel="noopener noreferrer"&gt;العربية&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.no.md" rel="noopener noreferrer"&gt;Norsk&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.br.md" rel="noopener noreferrer"&gt;Português (Brasil)&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.th.md" rel="noopener noreferrer"&gt;ไทย&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.tr.md" rel="noopener noreferrer"&gt;Türkçe&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.uk.md" rel="noopener noreferrer"&gt;Українська&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.bn.md" rel="noopener noreferrer"&gt;বাংলা&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.gr.md" rel="noopener noreferrer"&gt;Ελληνικά&lt;/a&gt; |
  &lt;a href="https://github.com/anomalyco/opencode/README.vi.md" rel="noopener noreferrer"&gt;Tiếng Việt&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://opencode.ai" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fanomalyco%2Fopencode%2FHEAD%2Fpackages%2Fweb%2Fsrc%2Fassets%2Flander%2Fscreenshot.png" alt="OpenCode Terminal UI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation&lt;/h3&gt;
&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; YOLO&lt;/span&gt;
curl -fsSL https://opencode.ai/install &lt;span class="pl-k"&gt;|&lt;/span&gt; bash
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Package managers&lt;/span&gt;
npm i -g opencode-ai@latest        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; or bun/pnpm/yarn&lt;/span&gt;
scoop install opencode             &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Windows&lt;/span&gt;
choco install opencode             &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Windows&lt;/span&gt;
brew install anomalyco/tap/opencode &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; macOS and Linux (recommended, always up to date)&lt;/span&gt;
brew install opencode              &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; macOS and Linux (official brew formula, updated less)&lt;/span&gt;
sudo pacman -S opencode            &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Arch Linux (Stable)&lt;/span&gt;
paru -S opencode-bin               &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Arch Linux (Latest from AUR)&lt;/span&gt;
mise use -g opencode               &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Any OS&lt;/span&gt;
nix run nixpkgs#opencode           &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; or github:anomalyco/opencode for latest dev branch&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-alert markdown-alert-tip"&gt;
&lt;p class="markdown-alert-title"&gt;Tip&lt;/p&gt;
&lt;p&gt;Remove versions older than 0.1.x before installing.&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Desktop App (BETA)&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;OpenCode is…&lt;/p&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/anomalyco/opencode" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;&lt;strong&gt;Install&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; opencode-ai@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Important (learn this early)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;run agents &lt;strong&gt;locally or in Docker&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;combine them with:

&lt;ul&gt;
&lt;li&gt;static analysis&lt;/li&gt;
&lt;li&gt;code style checks&lt;/li&gt;
&lt;li&gt;tests&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;treat agents like a &lt;strong&gt;junior dev with root access&lt;/strong&gt;
&lt;/li&gt;

&lt;li&gt;add skills/instructions (AGENTS.md etc.) step by step

&lt;ul&gt;
&lt;li&gt;less is more
&lt;/li&gt;
&lt;li&gt;MCP and tool calls are cool, but it eats your context window
&lt;/li&gt;
&lt;li&gt;ideas: &lt;a href="https://voku.github.io/your_agent_config/" rel="noopener noreferrer"&gt;https://voku.github.io/your_agent_config/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Agentic development isn’t magic, but at some point we need a IDE again. :D  &lt;/p&gt;




&lt;h2&gt;
  
  
  Some !funny takes at the end
&lt;/h2&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2015115128149041360-526" src="https://platform.twitter.com/embed/Tweet.html?id=2015115128149041360"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2015115128149041360-526');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2015115128149041360&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2015180689335812480-644" src="https://platform.twitter.com/embed/Tweet.html?id=2015180689335812480"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2015180689335812480-644');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2015180689335812480&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2016599645997216050-547" src="https://platform.twitter.com/embed/Tweet.html?id=2016599645997216050"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2016599645997216050-547');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2016599645997216050&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>PHP: Why I Use Static Analysis</title>
      <dc:creator>Lars Moelleken</dc:creator>
      <pubDate>Mon, 26 Jan 2026 05:14:07 +0000</pubDate>
      <link>https://dev.to/suckup_de/php-why-i-use-static-analysis-25ik</link>
      <guid>https://dev.to/suckup_de/php-why-i-use-static-analysis-25ik</guid>
      <description>&lt;h2&gt;
  
  
  Introduction: Errors Belong to Developers, Not Users
&lt;/h2&gt;

&lt;p&gt;#blogPostAsWebApp: &lt;a href="https://voku.github.io/WhyPHPStan/" rel="noopener noreferrer"&gt;https://voku.github.io/WhyPHPStan/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s start with something simple and uncomfortable:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If an error happens at runtime, a user sees it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I don’t care how good your monitoring is, how fast your rollback pipeline runs, or how often you say “it shouldn’t happen”. Runtime errors are already too late. They are failures that escaped development and reached production.&lt;/p&gt;

&lt;p&gt;That’s the entire motivation for static analysis.&lt;br&gt;&lt;br&gt;
Not theory. Not fashion. Damage control.&lt;/p&gt;

&lt;p&gt;PHP enforces reality.&lt;br&gt;&lt;br&gt;
Static analysis enforces possibility.&lt;/p&gt;

&lt;p&gt;Two different layers. Two different failure modes.&lt;br&gt;&lt;br&gt;
And if we can use both, the real question is: &lt;strong&gt;why wouldn’t we?&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  PHP Enforces Reality. Static Analysis Enforces Possibility.
&lt;/h2&gt;

&lt;p&gt;PHP is excellent at telling you when something actually breaks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;calling a method that doesn’t exist
&lt;/li&gt;
&lt;li&gt;passing a string where an int is required
&lt;/li&gt;
&lt;li&gt;accessing a property on &lt;code&gt;null&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s runtime reality.&lt;/p&gt;

&lt;p&gt;But PHP is deliberately permissive before that point. It allows code to exist even if it can only fail under certain conditions, in certain branches, or after a refactor.&lt;/p&gt;

&lt;p&gt;That’s where static analysis comes in.&lt;/p&gt;

&lt;p&gt;Tools like PHPStan don’t compete with PHP. They operate earlier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when code is written
&lt;/li&gt;
&lt;li&gt;when it’s refactored
&lt;/li&gt;
&lt;li&gt;when it’s reviewed
&lt;/li&gt;
&lt;li&gt;when it’s understood by someone new
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PHP tells you what happened.&lt;br&gt;&lt;br&gt;
Static analysis tells you what should never have been possible.&lt;/p&gt;

&lt;p&gt;Different jobs. Same goal.&lt;/p&gt;


&lt;h2&gt;
  
  
  High PHPStan Levels Don’t Just Find Bugs — They Shape Architecture
&lt;/h2&gt;

&lt;p&gt;This is where many people misunderstand strict static analysis.&lt;/p&gt;

&lt;p&gt;A high PHPStan level is not about “more errors”.&lt;br&gt;&lt;br&gt;
It’s an architectural pressure system.&lt;/p&gt;

&lt;p&gt;It pushes you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stop passing anonymous arrays around
&lt;/li&gt;
&lt;li&gt;stop encoding meaning in strings
&lt;/li&gt;
&lt;li&gt;stop hiding invariants in comments
&lt;/li&gt;
&lt;li&gt;introduce value objects, enums, interfaces
&lt;/li&gt;
&lt;li&gt;define clear boundaries and contracts
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And yes, there’s a very pleasant side effect:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;IDE autocompletion becomes frighteningly good&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because once types are precise, the IDE actually understands your system.&lt;br&gt;&lt;br&gt;
Not guesses. Not &lt;code&gt;mixed&lt;/code&gt;. Not “trust me”.&lt;/p&gt;

&lt;p&gt;That’s not cosmetic DX. That’s speed and confidence.&lt;/p&gt;


&lt;h2&gt;
  
  
  “Let PHP Enforce Contracts” — Good. Now Add the Missing Layer.
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Let PHP enforce contracts.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Perfect. We should.&lt;/p&gt;

&lt;p&gt;But nothing stops you from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;enforcing contracts at runtime &lt;strong&gt;and&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;enforcing them at design time
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In fact, PHPStan often nudges you toward better PHP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stricter parameter types
&lt;/li&gt;
&lt;li&gt;explicit return types
&lt;/li&gt;
&lt;li&gt;real interfaces instead of conventions
&lt;/li&gt;
&lt;li&gt;enums instead of magic strings
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using static analysis doesn’t weaken PHP’s guarantees.&lt;br&gt;&lt;br&gt;
It narrows the space in which PHP ever has to complain.&lt;/p&gt;


&lt;h2&gt;
  
  
  DX Matters: Instant Feedback Beats Any Test Suite
&lt;/h2&gt;

&lt;p&gt;One of the most underrated benefits is developer experience.&lt;/p&gt;

&lt;p&gt;If a function declares:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @param int&amp;lt;1, 32&amp;gt; $limit
 */&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$limit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I pass &lt;code&gt;64&lt;/code&gt;, I want that error:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;immediately
&lt;/li&gt;
&lt;li&gt;in my IDE
&lt;/li&gt;
&lt;li&gt;without running tests
&lt;/li&gt;
&lt;li&gt;without pushing code
&lt;/li&gt;
&lt;li&gt;without involving CI
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That feedback loop is priceless.&lt;/p&gt;

&lt;p&gt;Static analysis is the only tool that gives you semantic errors at typing speed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security: &lt;code&gt;literal-string&lt;/code&gt; Is a Real Guardrail
&lt;/h2&gt;

&lt;p&gt;This is not theoretical.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @param literal-string $sql
 */&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;runRaw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$sql&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This single constraint:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;blocks user input
&lt;/li&gt;
&lt;li&gt;blocks “temporary” hacks
&lt;/li&gt;
&lt;li&gt;blocks accidental string concatenation
&lt;/li&gt;
&lt;li&gt;blocks whole classes of SQL injection mistakes
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Does it solve all security? Of course not.&lt;br&gt;&lt;br&gt;
Does it eliminate dumb, expensive errors early? Absolutely.&lt;/p&gt;


&lt;h2&gt;
  
  
  Documentation That Cannot Lie
&lt;/h2&gt;

&lt;p&gt;Traditional documentation rots because nothing enforces it.&lt;/p&gt;

&lt;p&gt;Static PHPDoc does.&lt;/p&gt;

&lt;p&gt;When you write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @return Generator&amp;lt;int, User&amp;gt;
 */&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;Generator&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ve documented:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;key type
&lt;/li&gt;
&lt;li&gt;value type
&lt;/li&gt;
&lt;li&gt;iteration semantics
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if reality diverges? The build fails.&lt;/p&gt;

&lt;p&gt;As a bonus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the IDE knows &lt;code&gt;$key&lt;/code&gt; is &lt;code&gt;int&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the IDE knows &lt;code&gt;$user&lt;/code&gt; is &lt;code&gt;User&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;refactors are safe
&lt;/li&gt;
&lt;li&gt;onboarding is faster
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is documentation with teeth.&lt;/p&gt;




&lt;h2&gt;
  
  
  Logic Bugs Still Exist 😊 — And That’s Fine
&lt;/h2&gt;

&lt;p&gt;Let’s get this out of the way:&lt;/p&gt;

&lt;p&gt;Static analysis does not prevent logic bugs.&lt;/p&gt;

&lt;p&gt;Nothing does — except thinking.&lt;/p&gt;

&lt;p&gt;But static analysis removes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;type bugs
&lt;/li&gt;
&lt;li&gt;shape bugs
&lt;/li&gt;
&lt;li&gt;nullability bugs
&lt;/li&gt;
&lt;li&gt;refactor bugs
&lt;/li&gt;
&lt;li&gt;“this can never happen” bugs
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are not interesting problems.&lt;br&gt;&lt;br&gt;
They’re noise.&lt;/p&gt;

&lt;p&gt;I prefer to spend my brainpower on logic and design, not on mistakes a machine can detect instantly.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Practical Rule Set That Actually Works
&lt;/h2&gt;

&lt;p&gt;This is how static analysis succeeds in real PHP codebases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep arrays and strings at the boundaries (HTTP, JSON, DB)
&lt;/li&gt;
&lt;li&gt;validate once
&lt;/li&gt;
&lt;li&gt;convert once
&lt;/li&gt;
&lt;li&gt;after that: objects, enums, value objects
&lt;/li&gt;
&lt;li&gt;baseline legacy code
&lt;/li&gt;
&lt;li&gt;tighten rules only where you touch code
&lt;/li&gt;
&lt;li&gt;never weaken types just to silence the tool
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No rewrites. No greenfield fantasies.&lt;br&gt;&lt;br&gt;
Just steady entropy reduction.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion: Two Layers Are Better Than One
&lt;/h2&gt;

&lt;p&gt;PHP enforces reality.&lt;br&gt;&lt;br&gt;
Static analysis enforces possibility.&lt;/p&gt;

&lt;p&gt;Runtime errors mean errors for users.&lt;br&gt;&lt;br&gt;
Static errors mean errors for developers.&lt;/p&gt;

&lt;p&gt;High PHPStan levels shape architecture for the better and massively improve IDE feedback.&lt;br&gt;&lt;br&gt;
Nothing prevents you from using strong PHP types and static analysis — in fact, they reinforce each other.&lt;/p&gt;

&lt;p&gt;Logic bugs still require thinking 😊&lt;br&gt;&lt;br&gt;
But type bugs are optional.&lt;/p&gt;

&lt;p&gt;And I prefer optional bugs to be… not present.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Runtime errors are user-facing failures
&lt;/li&gt;
&lt;li&gt;Static analysis shifts errors to development time
&lt;/li&gt;
&lt;li&gt;High PHPStan levels improve architecture and DX
&lt;/li&gt;
&lt;li&gt;Security and documentation benefit immediately
&lt;/li&gt;
&lt;li&gt;PHP and PHPStan are complementary, not competing
&lt;/li&gt;
&lt;li&gt;Logic bugs remain — but the boring ones disappear
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What’s Next?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Using PHPStan as an architectural guardrail
&lt;/li&gt;
&lt;li&gt;Static analysis as a safety net for LLM-generated code (with a fast feedback loop)&lt;/li&gt;
&lt;li&gt;Killing &lt;code&gt;mixed&lt;/code&gt; once and for all
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy Coding. &lt;/p&gt;

</description>
      <category>php</category>
      <category>coding</category>
      <category>phpstan</category>
    </item>
  </channel>
</rss>
