<?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>Forem: Drew Marshall</title>
    <description>The latest articles on Forem by Drew Marshall (@stinklewinks).</description>
    <link>https://forem.com/stinklewinks</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F832808%2Fa1b7233f-14c6-4bcd-8a1e-c9f338124447.png</url>
      <title>Forem: Drew Marshall</title>
      <link>https://forem.com/stinklewinks</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/stinklewinks"/>
    <language>en</language>
    <item>
      <title>Configuration Is Not Secondary. It Is the System.</title>
      <dc:creator>Drew Marshall</dc:creator>
      <pubDate>Sun, 10 May 2026 15:30:00 +0000</pubDate>
      <link>https://forem.com/stinklewinks/configuration-is-not-secondary-it-is-the-system-2ikp</link>
      <guid>https://forem.com/stinklewinks/configuration-is-not-secondary-it-is-the-system-2ikp</guid>
      <description>&lt;p&gt;Most applications treat configuration as an afterthought.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;.env&lt;/code&gt; file here.&lt;br&gt;
A config object there.&lt;br&gt;
Maybe a JSON or YAML file for convenience.&lt;/p&gt;

&lt;p&gt;Configuration is usually seen as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup&lt;/li&gt;
&lt;li&gt;Defaults&lt;/li&gt;
&lt;li&gt;Environment variables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But not the system itself.&lt;/p&gt;

&lt;p&gt;That’s the mistake.&lt;/p&gt;


&lt;h2&gt;
  
  
  What We Typically Do
&lt;/h2&gt;

&lt;p&gt;In most projects, the real logic lives in code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routes define behavior&lt;/li&gt;
&lt;li&gt;Functions define flow&lt;/li&gt;
&lt;li&gt;Classes define structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configuration just tweaks things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ports&lt;/li&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;Feature flags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It supports the system.&lt;/p&gt;

&lt;p&gt;It doesn’t define it.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Problem With Code-First Systems
&lt;/h2&gt;

&lt;p&gt;When behavior is defined primarily in code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logic becomes scattered&lt;/li&gt;
&lt;li&gt;Patterns become inconsistent&lt;/li&gt;
&lt;li&gt;Intent is harder to see&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You have to read through multiple files to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What an endpoint does&lt;/li&gt;
&lt;li&gt;What data it expects&lt;/li&gt;
&lt;li&gt;What it returns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system exists…&lt;/p&gt;

&lt;p&gt;…but it’s buried in implementation.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Shift: Configuration as the Source of Truth
&lt;/h2&gt;

&lt;p&gt;What if configuration didn’t just support the system…&lt;/p&gt;

&lt;p&gt;What if it &lt;em&gt;defined&lt;/em&gt; it?&lt;/p&gt;

&lt;p&gt;Instead of writing behavior first and configuring it later:&lt;/p&gt;

&lt;p&gt;You define behavior up front.&lt;/p&gt;

&lt;p&gt;Code becomes the execution layer.&lt;/p&gt;


&lt;h2&gt;
  
  
  What This Looks Like
&lt;/h2&gt;

&lt;p&gt;Instead of writing logic like this:&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;products&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;You define it 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;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;product&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;GetAllProducts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;
      &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;number&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;number&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The definition describes the system.&lt;/p&gt;

&lt;p&gt;The code runs it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Configuration Becomes the Interface
&lt;/h2&gt;

&lt;p&gt;When configuration is the system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It becomes the first place you look&lt;/li&gt;
&lt;li&gt;It becomes the documentation&lt;/li&gt;
&lt;li&gt;It becomes the contract&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t need to reverse-engineer behavior.&lt;/p&gt;

&lt;p&gt;You can read it directly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code Becomes the Engine
&lt;/h2&gt;

&lt;p&gt;If configuration defines behavior, then what does code do?&lt;/p&gt;

&lt;p&gt;It enforces and executes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parses definitions&lt;/li&gt;
&lt;li&gt;Validates structure&lt;/li&gt;
&lt;li&gt;Builds execution steps&lt;/li&gt;
&lt;li&gt;Runs pipelines&lt;/li&gt;
&lt;li&gt;Handles errors consistently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You write the engine once.&lt;/p&gt;

&lt;p&gt;You use it everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Visibility
&lt;/h3&gt;

&lt;p&gt;You can understand the system without digging through code.&lt;/p&gt;




&lt;h3&gt;
  
  
  Consistency
&lt;/h3&gt;

&lt;p&gt;Every feature follows the same structure.&lt;/p&gt;




&lt;h3&gt;
  
  
  Maintainability
&lt;/h3&gt;

&lt;p&gt;Change the engine, and everything improves.&lt;/p&gt;




&lt;h3&gt;
  
  
  Speed
&lt;/h3&gt;

&lt;p&gt;You’re not rewriting patterns.&lt;/p&gt;

&lt;p&gt;You’re defining variations.&lt;/p&gt;




&lt;h2&gt;
  
  
  “Isn’t This Limiting?”
&lt;/h2&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;And that’s the point.&lt;/p&gt;

&lt;p&gt;When everything is possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Patterns drift&lt;/li&gt;
&lt;li&gt;Systems become inconsistent&lt;/li&gt;
&lt;li&gt;Complexity increases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Constraints force:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clarity&lt;/li&gt;
&lt;li&gt;Discipline&lt;/li&gt;
&lt;li&gt;Predictability&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Where This Breaks Down
&lt;/h2&gt;

&lt;p&gt;Not everything should be configuration-driven.&lt;/p&gt;

&lt;p&gt;Highly custom logic still belongs in code.&lt;/p&gt;

&lt;p&gt;But most applications are not mostly custom.&lt;/p&gt;

&lt;p&gt;They are mostly patterns.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CRUD operations&lt;/li&gt;
&lt;li&gt;Validation&lt;/li&gt;
&lt;li&gt;Data transformation&lt;/li&gt;
&lt;li&gt;Standard workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those belong in configuration.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Layered View
&lt;/h2&gt;

&lt;p&gt;When you zoom out, this approach connects everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI defined by structure&lt;/li&gt;
&lt;li&gt;APIs defined by contracts&lt;/li&gt;
&lt;li&gt;Backends acting as compilers&lt;/li&gt;
&lt;li&gt;Requests flowing through pipelines&lt;/li&gt;
&lt;li&gt;Infrastructure defined declaratively&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each layer follows the same idea:&lt;/p&gt;

&lt;p&gt;Define first. Execute second.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Shift
&lt;/h2&gt;

&lt;p&gt;This isn’t about YAML vs code.&lt;/p&gt;

&lt;p&gt;It’s about mindset.&lt;/p&gt;

&lt;p&gt;From:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing behavior repeatedly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defining behavior once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And letting a system handle the rest.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Configuration has always been treated as secondary.&lt;/p&gt;

&lt;p&gt;But when you promote it to the source of truth, something changes:&lt;/p&gt;

&lt;p&gt;The system becomes visible.&lt;/p&gt;

&lt;p&gt;The system becomes consistent.&lt;/p&gt;

&lt;p&gt;The system becomes scalable.&lt;/p&gt;

&lt;p&gt;That’s when you stop assembling applications…&lt;/p&gt;

&lt;h2&gt;
  
  
  …and start defining them.
&lt;/h2&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Your Backend Should Be a Compiler, Not a Collection of Handlers</title>
      <dc:creator>Drew Marshall</dc:creator>
      <pubDate>Sat, 09 May 2026 15:30:00 +0000</pubDate>
      <link>https://forem.com/stinklewinks/your-backend-should-be-a-compiler-not-a-collection-of-handlers-5a9c</link>
      <guid>https://forem.com/stinklewinks/your-backend-should-be-a-compiler-not-a-collection-of-handlers-5a9c</guid>
      <description>&lt;p&gt;Most backends are built the same way.&lt;/p&gt;

&lt;p&gt;You define routes.&lt;br&gt;
You write handlers.&lt;br&gt;
You wire everything together.&lt;/p&gt;

&lt;p&gt;Over time, you end up with dozens—sometimes hundreds—of functions that all follow similar patterns but live in different places.&lt;/p&gt;

&lt;p&gt;It works.&lt;/p&gt;

&lt;p&gt;But it doesn’t scale cleanly.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Handler Mindset
&lt;/h2&gt;

&lt;p&gt;A typical backend looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Route definition&lt;/li&gt;
&lt;li&gt;Controller or handler&lt;/li&gt;
&lt;li&gt;Validation logic&lt;/li&gt;
&lt;li&gt;Database query&lt;/li&gt;
&lt;li&gt;Response formatting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repeat that structure across your entire application.&lt;/p&gt;

&lt;p&gt;Even if you organize it well, you still end up with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repeated patterns&lt;/li&gt;
&lt;li&gt;Slight inconsistencies&lt;/li&gt;
&lt;li&gt;Logic spread across multiple files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’re not building a system.&lt;/p&gt;

&lt;p&gt;You’re assembling one manually.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Realization
&lt;/h2&gt;

&lt;p&gt;Most handlers don’t do anything unique.&lt;/p&gt;

&lt;p&gt;They follow a pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Accept input&lt;/li&gt;
&lt;li&gt;Validate it&lt;/li&gt;
&lt;li&gt;Execute some operation&lt;/li&gt;
&lt;li&gt;Return a result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The structure is always the same.&lt;/p&gt;

&lt;p&gt;Only the data changes.&lt;/p&gt;


&lt;h2&gt;
  
  
  So Why Are We Writing Them Over and Over?
&lt;/h2&gt;

&lt;p&gt;Instead of writing handlers, what if we defined behavior?&lt;/p&gt;

&lt;p&gt;Not in code first…&lt;/p&gt;

&lt;p&gt;…but as a contract.&lt;/p&gt;


&lt;h2&gt;
  
  
  Thinking Like a Compiler
&lt;/h2&gt;

&lt;p&gt;A compiler takes a definition and turns it into execution.&lt;/p&gt;

&lt;p&gt;It doesn’t care about your specific use case.&lt;/p&gt;

&lt;p&gt;It cares about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structure&lt;/li&gt;
&lt;li&gt;Rules&lt;/li&gt;
&lt;li&gt;Transformation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now imagine your backend doing the same thing.&lt;/p&gt;

&lt;p&gt;Instead of this:&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&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;insert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;You define 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;create&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;CreateUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
      &lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$input.name&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$input.email&lt;/span&gt;
      &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;number&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Just a definition.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the Backend Becomes
&lt;/h2&gt;

&lt;p&gt;Instead of a collection of handlers…&lt;/p&gt;

&lt;p&gt;Your backend becomes a compiler.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Reads definitions&lt;/li&gt;
&lt;li&gt;Validates structure&lt;/li&gt;
&lt;li&gt;Builds execution logic&lt;/li&gt;
&lt;li&gt;Runs it through a pipeline&lt;/li&gt;
&lt;li&gt;Returns a response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code you write once replaces hundreds of repeated patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Execution Flow
&lt;/h2&gt;

&lt;p&gt;Every request follows the same path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request → Load Definition → Validate Input → Build Operation → Execute → Format Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing is hidden.&lt;/p&gt;

&lt;p&gt;Nothing is scattered.&lt;/p&gt;

&lt;p&gt;Everything is predictable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Is Better
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Consistency
&lt;/h3&gt;

&lt;p&gt;Every endpoint behaves the same way.&lt;/p&gt;

&lt;p&gt;No surprises. No deviations.&lt;/p&gt;




&lt;h3&gt;
  
  
  Maintainability
&lt;/h3&gt;

&lt;p&gt;Change the system once, and every endpoint benefits.&lt;/p&gt;

&lt;p&gt;You’re not hunting through files to fix the same bug.&lt;/p&gt;




&lt;h3&gt;
  
  
  Clarity
&lt;/h3&gt;

&lt;p&gt;You can read the system without digging through code.&lt;/p&gt;

&lt;p&gt;Definitions describe behavior directly.&lt;/p&gt;




&lt;h3&gt;
  
  
  Scalability
&lt;/h3&gt;

&lt;p&gt;As your application grows, complexity doesn’t explode.&lt;/p&gt;

&lt;p&gt;It stays structured.&lt;/p&gt;




&lt;h2&gt;
  
  
  “But What About Custom Logic?”
&lt;/h2&gt;

&lt;p&gt;Not everything fits into a strict pattern.&lt;/p&gt;

&lt;p&gt;That’s fine.&lt;/p&gt;

&lt;p&gt;A compiler-based backend can still support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom steps in the pipeline&lt;/li&gt;
&lt;li&gt;Extension points where needed&lt;/li&gt;
&lt;li&gt;Escape hatches for complex cases&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Custom logic becomes the exception, not the default.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code Moves Up a Level
&lt;/h2&gt;

&lt;p&gt;You’re still writing code.&lt;/p&gt;

&lt;p&gt;Just not the same code over and over again.&lt;/p&gt;

&lt;p&gt;Instead of writing handlers, you write:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The compiler&lt;/li&gt;
&lt;li&gt;The pipeline&lt;/li&gt;
&lt;li&gt;The rules of the system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You move from:&lt;/p&gt;

&lt;p&gt;“Implement this endpoint”&lt;/p&gt;

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

&lt;p&gt;“Define how endpoints work”&lt;/p&gt;




&lt;h2&gt;
  
  
  This Is About Leverage
&lt;/h2&gt;

&lt;p&gt;Handler-based systems scale linearly.&lt;/p&gt;

&lt;p&gt;More features = more code.&lt;/p&gt;

&lt;p&gt;Compiler-based systems scale differently.&lt;/p&gt;

&lt;p&gt;More features = more definitions.&lt;/p&gt;

&lt;p&gt;The engine does the heavy lifting.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;This idea doesn’t stop at APIs.&lt;/p&gt;

&lt;p&gt;It connects to everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI driven by structure&lt;/li&gt;
&lt;li&gt;APIs driven by contracts&lt;/li&gt;
&lt;li&gt;Infrastructure driven by configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each layer becomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Predictable&lt;/li&gt;
&lt;li&gt;Composable&lt;/li&gt;
&lt;li&gt;Aligned&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Handlers feel powerful because they give you control.&lt;/p&gt;

&lt;p&gt;But they also force you to repeat yourself.&lt;/p&gt;

&lt;p&gt;A compiler feels restrictive at first.&lt;/p&gt;

&lt;p&gt;But it gives you something better:&lt;/p&gt;

&lt;p&gt;Leverage.&lt;/p&gt;

&lt;p&gt;That’s why I stopped building backends as collections of handlers…&lt;/p&gt;

&lt;h2&gt;
  
  
  …and started building them like compilers.
&lt;/h2&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Stop Writing Endpoints. Start Defining Systems.</title>
      <dc:creator>Drew Marshall</dc:creator>
      <pubDate>Fri, 08 May 2026 15:30:00 +0000</pubDate>
      <link>https://forem.com/stinklewinks/stop-writing-endpoints-start-defining-systems-4j1g</link>
      <guid>https://forem.com/stinklewinks/stop-writing-endpoints-start-defining-systems-4j1g</guid>
      <description>&lt;p&gt;For a long time, I thought building APIs meant writing endpoints.&lt;/p&gt;

&lt;p&gt;You know the pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define a route&lt;/li&gt;
&lt;li&gt;Validate input&lt;/li&gt;
&lt;li&gt;Query the database&lt;/li&gt;
&lt;li&gt;Transform the result&lt;/li&gt;
&lt;li&gt;Send a response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do that over and over again.&lt;/p&gt;

&lt;p&gt;Different routes. Same structure.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Illusion of Control
&lt;/h2&gt;

&lt;p&gt;Writing endpoints feels productive.&lt;/p&gt;

&lt;p&gt;You’re in control of everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The logic&lt;/li&gt;
&lt;li&gt;The validation&lt;/li&gt;
&lt;li&gt;The data flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But after a while, something becomes obvious:&lt;/p&gt;

&lt;p&gt;You’re not building systems.&lt;/p&gt;

&lt;p&gt;You’re repeating patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Problem
&lt;/h2&gt;

&lt;p&gt;Most APIs look like this:&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Missing id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&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;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not found&lt;/span&gt;&lt;span class="dl"&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;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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 multiply that by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dozens of endpoints&lt;/li&gt;
&lt;li&gt;Multiple resources&lt;/li&gt;
&lt;li&gt;Different validation rules&lt;/li&gt;
&lt;li&gt;Slight variations in logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You end up with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repeated code&lt;/li&gt;
&lt;li&gt;Inconsistent patterns&lt;/li&gt;
&lt;li&gt;Hard-to-maintain systems&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  You’re Not Writing Logic. You’re Rewriting Structure.
&lt;/h2&gt;

&lt;p&gt;Look closer at most endpoints.&lt;/p&gt;

&lt;p&gt;They follow the same shape:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extract input&lt;/li&gt;
&lt;li&gt;Validate input&lt;/li&gt;
&lt;li&gt;Execute query&lt;/li&gt;
&lt;li&gt;Handle errors&lt;/li&gt;
&lt;li&gt;Return response&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The structure doesn’t change.&lt;/p&gt;

&lt;p&gt;Only the details do.&lt;/p&gt;

&lt;p&gt;So why are we rewriting the structure every time?&lt;/p&gt;




&lt;h2&gt;
  
  
  The Shift: Define, Don’t Rewrite
&lt;/h2&gt;

&lt;p&gt;Instead of writing endpoints…&lt;/p&gt;

&lt;p&gt;Define them.&lt;/p&gt;

&lt;p&gt;What if your API looked like this instead?&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;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;GetUserById&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;number&lt;/span&gt;
      &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$param.id&lt;/span&gt;
      &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;number&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No route handler.&lt;/p&gt;

&lt;p&gt;No repeated boilerplate.&lt;/p&gt;

&lt;p&gt;Just a definition.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Changes
&lt;/h2&gt;

&lt;p&gt;When you define systems instead of writing endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structure becomes consistent&lt;/li&gt;
&lt;li&gt;Validation becomes automatic&lt;/li&gt;
&lt;li&gt;Queries become predictable&lt;/li&gt;
&lt;li&gt;Behavior becomes visible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’re no longer guessing how something works.&lt;/p&gt;

&lt;p&gt;You can read it directly.&lt;/p&gt;




&lt;h2&gt;
  
  
  From Endpoints to Systems
&lt;/h2&gt;

&lt;p&gt;Traditional approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every endpoint is custom&lt;/li&gt;
&lt;li&gt;Logic is scattered&lt;/li&gt;
&lt;li&gt;Behavior is implicit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;System-driven approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Endpoints follow a pattern&lt;/li&gt;
&lt;li&gt;Logic is structured&lt;/li&gt;
&lt;li&gt;Behavior is explicit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You move from “code-first” to “contract-first.”&lt;/p&gt;




&lt;h2&gt;
  
  
  Where the Code Goes
&lt;/h2&gt;

&lt;p&gt;This doesn’t eliminate code.&lt;/p&gt;

&lt;p&gt;It moves it.&lt;/p&gt;

&lt;p&gt;Instead of writing endpoint logic repeatedly…&lt;/p&gt;

&lt;p&gt;You write:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A compiler that reads definitions&lt;/li&gt;
&lt;li&gt;A pipeline that executes them&lt;/li&gt;
&lt;li&gt;A system that enforces rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Code becomes the engine.&lt;/p&gt;

&lt;p&gt;Not the repetition.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example Flow
&lt;/h2&gt;

&lt;p&gt;With a system-driven approach, a request might flow like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request → Parse Definition → Validate → Build Query → Execute → Format Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;The flow is constant&lt;/li&gt;
&lt;li&gt;The behavior is defined in configuration&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;Without this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every developer writes endpoints differently&lt;/li&gt;
&lt;li&gt;Bugs are repeated across routes&lt;/li&gt;
&lt;li&gt;Refactoring becomes painful&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Patterns are enforced&lt;/li&gt;
&lt;li&gt;Behavior is predictable&lt;/li&gt;
&lt;li&gt;Systems scale cleanly&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  “Isn’t This Less Flexible?”
&lt;/h2&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;And that’s the point.&lt;/p&gt;

&lt;p&gt;Unlimited flexibility leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inconsistency&lt;/li&gt;
&lt;li&gt;Complexity&lt;/li&gt;
&lt;li&gt;Fragile systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Constraints lead to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clarity&lt;/li&gt;
&lt;li&gt;Stability&lt;/li&gt;
&lt;li&gt;Speed&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Where This Fits
&lt;/h2&gt;

&lt;p&gt;This kind of system works best when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have repeated CRUD patterns&lt;/li&gt;
&lt;li&gt;You want consistent APIs&lt;/li&gt;
&lt;li&gt;You care about long-term maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It doesn’t replace every use case.&lt;/p&gt;

&lt;p&gt;But it replaces most of the boring, repetitive ones.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Idea
&lt;/h2&gt;

&lt;p&gt;This isn’t just about APIs.&lt;/p&gt;

&lt;p&gt;It’s about how we build software.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing everything manually&lt;/li&gt;
&lt;li&gt;Repeating patterns&lt;/li&gt;
&lt;li&gt;Hoping for consistency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define systems&lt;/li&gt;
&lt;li&gt;Enforce structure&lt;/li&gt;
&lt;li&gt;Let the engine handle execution&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Writing endpoints feels like control.&lt;/p&gt;

&lt;p&gt;But it’s often just repetition.&lt;/p&gt;

&lt;p&gt;Defining systems feels restrictive at first.&lt;/p&gt;

&lt;p&gt;But it leads to something better:&lt;/p&gt;

&lt;p&gt;Clarity.&lt;/p&gt;

&lt;p&gt;Consistency.&lt;/p&gt;

&lt;p&gt;Scalability.&lt;/p&gt;

&lt;p&gt;That’s why I stopped writing endpoints…&lt;/p&gt;

&lt;h2&gt;
  
  
  …and started defining systems.
&lt;/h2&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Hooks vs Pipelines: Why I Stopped Injecting Logic and Started Designing Flow</title>
      <dc:creator>Drew Marshall</dc:creator>
      <pubDate>Thu, 07 May 2026 15:30:00 +0000</pubDate>
      <link>https://forem.com/stinklewinks/hooks-vs-pipelines-why-i-stopped-injecting-logic-and-started-designing-flow-loj</link>
      <guid>https://forem.com/stinklewinks/hooks-vs-pipelines-why-i-stopped-injecting-logic-and-started-designing-flow-loj</guid>
      <description>&lt;p&gt;Hooks are everywhere.&lt;/p&gt;

&lt;p&gt;If you’ve worked with systems like WordPress, React, or Express-style middleware, you’ve used them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Tap into this lifecycle”&lt;/li&gt;
&lt;li&gt;“Modify behavior here”&lt;/li&gt;
&lt;li&gt;“Extend functionality without touching core”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On paper, hooks sound great.&lt;/p&gt;

&lt;p&gt;In practice, they create problems that only show up at scale.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Hooks Promise
&lt;/h2&gt;

&lt;p&gt;Hooks promise flexibility.&lt;/p&gt;

&lt;p&gt;They let you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inject behavior into existing systems&lt;/li&gt;
&lt;li&gt;Extend functionality without modifying source code&lt;/li&gt;
&lt;li&gt;Build plugin ecosystems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why platforms like WordPress became so powerful.&lt;/p&gt;

&lt;p&gt;You can hook into almost anything.&lt;/p&gt;

&lt;p&gt;And that’s also the problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Hooks Actually Do
&lt;/h2&gt;

&lt;p&gt;Hooks turn your system into a web of invisible connections.&lt;/p&gt;

&lt;p&gt;Instead of a clear execution path, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logic scattered across multiple files&lt;/li&gt;
&lt;li&gt;Execution order that depends on registration timing&lt;/li&gt;
&lt;li&gt;Side effects that aren’t obvious&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You end up asking questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Where is this value being changed?”&lt;/li&gt;
&lt;li&gt;“Why is this running twice?”&lt;/li&gt;
&lt;li&gt;“What is triggering this behavior?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system works…&lt;/p&gt;

&lt;p&gt;…but understanding it becomes harder over time.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hidden Cost of Hooks
&lt;/h2&gt;

&lt;p&gt;Hooks scale &lt;em&gt;functionality&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;They don’t scale &lt;em&gt;clarity&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As systems grow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debugging becomes slower&lt;/li&gt;
&lt;li&gt;Onboarding becomes harder&lt;/li&gt;
&lt;li&gt;Refactoring becomes risky&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because behavior isn’t centralized.&lt;/p&gt;

&lt;p&gt;It’s injected.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Alternative: Pipelines
&lt;/h2&gt;

&lt;p&gt;Instead of injecting behavior into a system…&lt;/p&gt;

&lt;p&gt;You define a flow through it.&lt;/p&gt;

&lt;p&gt;A pipeline is a sequence of steps that every request (or operation) follows.&lt;/p&gt;

&lt;p&gt;Simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request → Validate → Transform → Execute → Respond
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it.&lt;/p&gt;

&lt;p&gt;No hidden entry points. No surprise execution paths.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Pipelines Change
&lt;/h2&gt;

&lt;p&gt;Pipelines force you to be explicit.&lt;/p&gt;

&lt;p&gt;Every step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Has a defined responsibility&lt;/li&gt;
&lt;li&gt;Runs in a predictable order&lt;/li&gt;
&lt;li&gt;Is visible in one place&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t “hook into” the system.&lt;/p&gt;

&lt;p&gt;You move through it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hooks vs Pipelines (Side-by-Side)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hooks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Behavior is injected&lt;/li&gt;
&lt;li&gt;Execution order can be unclear&lt;/li&gt;
&lt;li&gt;Logic is distributed&lt;/li&gt;
&lt;li&gt;Harder to trace bugs&lt;/li&gt;
&lt;li&gt;Easy to extend, hard to reason about&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pipelines
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Behavior is structured&lt;/li&gt;
&lt;li&gt;Execution order is fixed&lt;/li&gt;
&lt;li&gt;Logic is centralized&lt;/li&gt;
&lt;li&gt;Easier to trace and debug&lt;/li&gt;
&lt;li&gt;Slightly more rigid, much more predictable&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Real-World Example
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hook-Based Thinking
&lt;/h3&gt;

&lt;p&gt;“After a user is created, run these 5 different things from different parts of the system.”&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send email&lt;/li&gt;
&lt;li&gt;Log analytics&lt;/li&gt;
&lt;li&gt;Modify data&lt;/li&gt;
&lt;li&gt;Trigger webhook&lt;/li&gt;
&lt;li&gt;Update cache&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these might live in different files, registered at different times.&lt;/p&gt;

&lt;p&gt;Good luck tracing that later.&lt;/p&gt;




&lt;h3&gt;
  
  
  Pipeline Thinking
&lt;/h3&gt;

&lt;p&gt;Define the flow once:&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;CreateUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ValidateInput&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NormalizeData&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;InsertUser&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SendEmail&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;LogAnalytics&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;UpdateCache&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ordered&lt;/li&gt;
&lt;li&gt;Visible&lt;/li&gt;
&lt;li&gt;Intentional&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can read the flow like a story.&lt;/p&gt;




&lt;h2&gt;
  
  
  “But Hooks Are More Flexible”
&lt;/h2&gt;

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

&lt;p&gt;That’s why they’re popular.&lt;/p&gt;

&lt;p&gt;But flexibility without structure leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inconsistent patterns&lt;/li&gt;
&lt;li&gt;Hard-to-maintain systems&lt;/li&gt;
&lt;li&gt;Debugging nightmares&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pipelines trade a bit of flexibility for a lot of clarity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Hooks Still Make Sense
&lt;/h2&gt;

&lt;p&gt;Hooks aren’t useless.&lt;/p&gt;

&lt;p&gt;They’re useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You’re building a plugin ecosystem&lt;/li&gt;
&lt;li&gt;You need external extensibility&lt;/li&gt;
&lt;li&gt;You don’t control all the code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But for core system design?&lt;/p&gt;

&lt;p&gt;They introduce more problems than they solve.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Chose Pipelines
&lt;/h2&gt;

&lt;p&gt;I don’t want systems where behavior is hidden.&lt;/p&gt;

&lt;p&gt;I want systems where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can trace execution instantly&lt;/li&gt;
&lt;li&gt;You can reason about flow without guessing&lt;/li&gt;
&lt;li&gt;You can refactor without fear&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pipelines give me that.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;This isn’t just about request handling.&lt;/p&gt;

&lt;p&gt;It’s about how systems are designed.&lt;/p&gt;

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

&lt;p&gt;“Add behavior anywhere.”&lt;/p&gt;

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

&lt;p&gt;“Define behavior clearly.”&lt;/p&gt;

&lt;p&gt;That difference shows up in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintainability&lt;/li&gt;
&lt;li&gt;Debugging&lt;/li&gt;
&lt;li&gt;Scalability&lt;/li&gt;
&lt;li&gt;Developer experience&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Hooks optimize for extension.&lt;/p&gt;

&lt;p&gt;Pipelines optimize for understanding.&lt;/p&gt;

&lt;p&gt;At small scale, it doesn’t matter.&lt;/p&gt;

&lt;p&gt;At large scale, it matters a lot.&lt;/p&gt;

&lt;p&gt;That’s why I stopped hooking into systems…&lt;/p&gt;

&lt;h2&gt;
  
  
  …and started designing flows instead.
&lt;/h2&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
    <item>
      <title>The Web Doesn’t Need Another Framework. It Needs an Engine.</title>
      <dc:creator>Drew Marshall</dc:creator>
      <pubDate>Wed, 06 May 2026 15:45:36 +0000</pubDate>
      <link>https://forem.com/stinklewinks/the-web-doesnt-need-another-framework-it-needs-an-engine-29jb</link>
      <guid>https://forem.com/stinklewinks/the-web-doesnt-need-another-framework-it-needs-an-engine-29jb</guid>
      <description>&lt;p&gt;I didn’t set out to build a web engine.&lt;/p&gt;

&lt;p&gt;I set out to solve a frustration I kept running into over and over again:&lt;/p&gt;

&lt;p&gt;Every project felt like starting from zero.&lt;/p&gt;

&lt;p&gt;Different stack.&lt;br&gt;
Different patterns.&lt;br&gt;
Different rules.&lt;/p&gt;

&lt;p&gt;Same problems.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Illusion of Progress
&lt;/h2&gt;

&lt;p&gt;We’ve made huge progress in web development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better frameworks&lt;/li&gt;
&lt;li&gt;Better tooling&lt;/li&gt;
&lt;li&gt;Better DX&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But under the surface, we’re still doing the same things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rebuilding API layers&lt;/li&gt;
&lt;li&gt;Rewiring state management&lt;/li&gt;
&lt;li&gt;Reconfiguring infrastructure&lt;/li&gt;
&lt;li&gt;Re-learning patterns per stack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We didn’t remove complexity.&lt;/p&gt;

&lt;p&gt;We just moved it around.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Real Problem: No Shared Contract
&lt;/h2&gt;

&lt;p&gt;The biggest issue isn’t tooling.&lt;/p&gt;

&lt;p&gt;It’s the lack of a shared contract between layers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI doesn’t know your API structure&lt;/li&gt;
&lt;li&gt;APIs don’t strongly enforce shape beyond runtime&lt;/li&gt;
&lt;li&gt;Infrastructure is configured separately from application logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything is loosely connected, but not intentionally designed to work together.&lt;/p&gt;


&lt;h2&gt;
  
  
  What Is a Web Engine?
&lt;/h2&gt;

&lt;p&gt;A web engine is not a framework.&lt;/p&gt;

&lt;p&gt;It’s not just a library.&lt;/p&gt;

&lt;p&gt;It’s a system that defines how applications are built end-to-end.&lt;/p&gt;

&lt;p&gt;Game engines figured this out a long time ago.&lt;/p&gt;

&lt;p&gt;They don’t just render graphics.&lt;br&gt;
They define how everything fits together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Assets&lt;/li&gt;
&lt;li&gt;Systems&lt;/li&gt;
&lt;li&gt;Logic&lt;/li&gt;
&lt;li&gt;Scaling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t rebuild those pieces every time.&lt;/p&gt;

&lt;p&gt;You build within a system.&lt;/p&gt;

&lt;p&gt;That’s what the web is missing.&lt;/p&gt;


&lt;h2&gt;
  
  
  Frameworks vs Engines
&lt;/h2&gt;

&lt;p&gt;Frameworks give you tools.&lt;/p&gt;

&lt;p&gt;Engines give you rules, structure, and guarantees.&lt;/p&gt;

&lt;p&gt;A framework says:&lt;/p&gt;

&lt;p&gt;“Here’s how you can do it.”&lt;/p&gt;

&lt;p&gt;An engine says:&lt;/p&gt;

&lt;p&gt;“Here’s how it will be done.”&lt;/p&gt;

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

&lt;p&gt;Consistency is what allows systems to scale.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Philosophy: Contract-First Everything
&lt;/h2&gt;

&lt;p&gt;The core idea is simple:&lt;/p&gt;

&lt;p&gt;Every layer should be defined by a contract before it is implemented.&lt;/p&gt;

&lt;p&gt;Not after. Not loosely. Not guessed.&lt;/p&gt;


&lt;h3&gt;
  
  
  UI Contract
&lt;/h3&gt;

&lt;p&gt;Instead of scattered styles and component sprawl:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI follows predictable structure&lt;/li&gt;
&lt;li&gt;Styling is expressive but controlled&lt;/li&gt;
&lt;li&gt;Components are declarative&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  API Contract
&lt;/h3&gt;

&lt;p&gt;Instead of writing endpoints ad hoc:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APIs are defined in configuration&lt;/li&gt;
&lt;li&gt;Inputs and outputs are explicit&lt;/li&gt;
&lt;li&gt;Validation is built-in&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&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;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;GetUserById&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$param.id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Data Contract
&lt;/h3&gt;

&lt;p&gt;Instead of implicit assumptions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data models are defined centrally&lt;/li&gt;
&lt;li&gt;Queries are structured&lt;/li&gt;
&lt;li&gt;Transformations are controlled&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Infrastructure Contract
&lt;/h3&gt;

&lt;p&gt;Instead of dashboards and manual setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Infrastructure is declared&lt;/li&gt;
&lt;li&gt;Environments are reproducible&lt;/li&gt;
&lt;li&gt;Deployments are predictable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&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;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;digitalocean&lt;/span&gt;

&lt;span class="na"&gt;droplet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-server&lt;/span&gt;
  &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;s-2vcpu-4gb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why Contract-First Matters
&lt;/h2&gt;

&lt;p&gt;Without contracts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logic becomes implicit&lt;/li&gt;
&lt;li&gt;Bugs are harder to trace&lt;/li&gt;
&lt;li&gt;Systems drift over time&lt;/li&gt;
&lt;li&gt;Refactoring becomes risky&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With contracts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Systems are self-documenting&lt;/li&gt;
&lt;li&gt;Validation happens early&lt;/li&gt;
&lt;li&gt;Teams move faster&lt;/li&gt;
&lt;li&gt;Code reflects intent instead of guesswork&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pipelines Over Hooks
&lt;/h2&gt;

&lt;p&gt;One of the biggest shifts I made:&lt;/p&gt;

&lt;p&gt;I stopped relying on hooks.&lt;/p&gt;

&lt;p&gt;Hooks are flexible, but they introduce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hidden execution order&lt;/li&gt;
&lt;li&gt;Implicit dependencies&lt;/li&gt;
&lt;li&gt;Debugging complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, I use pipelines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request → Validate → Transform → Execute → Respond
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each step is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicit&lt;/li&gt;
&lt;li&gt;Ordered&lt;/li&gt;
&lt;li&gt;Observable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t inject behavior into the system.&lt;/p&gt;

&lt;p&gt;You move through it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Configuration as a First-Class Citizen
&lt;/h2&gt;

&lt;p&gt;Most systems treat configuration as secondary.&lt;/p&gt;

&lt;p&gt;A web engine treats configuration as the source of truth.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;YAML or TOML define behavior&lt;/li&gt;
&lt;li&gt;Code executes the contract&lt;/li&gt;
&lt;li&gt;Systems are assembled, not improvised&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This doesn’t remove code.&lt;/p&gt;

&lt;p&gt;It disciplines it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Goal: Reduce Reinvention
&lt;/h2&gt;

&lt;p&gt;Right now, building apps looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick a framework&lt;/li&gt;
&lt;li&gt;Pick a backend&lt;/li&gt;
&lt;li&gt;Pick a database&lt;/li&gt;
&lt;li&gt;Pick deployment&lt;/li&gt;
&lt;li&gt;Glue everything together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every project is a new puzzle.&lt;/p&gt;

&lt;p&gt;A web engine changes that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The system already exists&lt;/li&gt;
&lt;li&gt;The rules are already defined&lt;/li&gt;
&lt;li&gt;You build within constraints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And constraints are what enable speed.&lt;/p&gt;




&lt;h2&gt;
  
  
  This Isn’t About Control
&lt;/h2&gt;

&lt;p&gt;This isn’t about locking developers in.&lt;/p&gt;

&lt;p&gt;It’s about giving them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Predictability&lt;/li&gt;
&lt;li&gt;Stability&lt;/li&gt;
&lt;li&gt;Confidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Freedom without structure leads to chaos.&lt;/p&gt;

&lt;p&gt;Structure without flexibility leads to stagnation.&lt;/p&gt;

&lt;p&gt;A web engine aims for the balance.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where This Is Going
&lt;/h2&gt;

&lt;p&gt;What started as a UI experiment grew into something bigger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI layer&lt;/li&gt;
&lt;li&gt;Rendering layer&lt;/li&gt;
&lt;li&gt;API and data system&lt;/li&gt;
&lt;li&gt;HTTP pipeline&lt;/li&gt;
&lt;li&gt;Infrastructure layer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not separate tools.&lt;/p&gt;

&lt;p&gt;Parts of the same system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;The web doesn’t need more ways to build things.&lt;/p&gt;

&lt;p&gt;It needs a better foundation for building them.&lt;/p&gt;

&lt;p&gt;Not just faster.&lt;/p&gt;

&lt;p&gt;Better.&lt;/p&gt;

&lt;p&gt;More predictable.&lt;/p&gt;

&lt;p&gt;More stable.&lt;/p&gt;

&lt;p&gt;More intentional.&lt;/p&gt;

&lt;p&gt;That’s what I mean when I say:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The web needs an engine.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Headless WordPress Isn’t Enough (Here’s What’s Missing)</title>
      <dc:creator>Drew Marshall</dc:creator>
      <pubDate>Fri, 01 May 2026 18:30:00 +0000</pubDate>
      <link>https://forem.com/stinklewinks/headless-wordpress-isnt-enough-heres-whats-missing-70j</link>
      <guid>https://forem.com/stinklewinks/headless-wordpress-isnt-enough-heres-whats-missing-70j</guid>
      <description>&lt;p&gt;When I first moved to headless WordPress, it felt like a huge upgrade.&lt;/p&gt;

&lt;p&gt;No more theme constraints.&lt;br&gt;
No more mixing PHP templates with business logic.&lt;br&gt;
A clean separation between frontend and backend.&lt;/p&gt;

&lt;p&gt;It worked.&lt;/p&gt;

&lt;p&gt;But after a few projects, I started noticing a new problem.&lt;/p&gt;


&lt;h2&gt;
  
  
  The New Problem
&lt;/h2&gt;

&lt;p&gt;Headless WordPress removes one layer of complexity…&lt;/p&gt;

&lt;p&gt;…but it shifts that complexity somewhere else.&lt;/p&gt;

&lt;p&gt;Now your frontend is responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fetching data&lt;/li&gt;
&lt;li&gt;shaping responses&lt;/li&gt;
&lt;li&gt;handling auth&lt;/li&gt;
&lt;li&gt;managing consistency across endpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if you build multiple frontends?&lt;/p&gt;

&lt;p&gt;You repeat that logic.&lt;/p&gt;

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


&lt;h2&gt;
  
  
  What Headless Actually Solves
&lt;/h2&gt;

&lt;p&gt;Headless WordPress is great at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;decoupling the UI&lt;/li&gt;
&lt;li&gt;improving performance (especially with SSG)&lt;/li&gt;
&lt;li&gt;giving frontend flexibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s all real value.&lt;/p&gt;

&lt;p&gt;But it doesn’t solve:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Where does application logic live?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  The Missing Layer
&lt;/h2&gt;

&lt;p&gt;Most setups look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend → WordPress REST API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple.&lt;/p&gt;

&lt;p&gt;But also…&lt;/p&gt;

&lt;p&gt;fragile.&lt;/p&gt;

&lt;p&gt;Because the frontend becomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;data layer&lt;/li&gt;
&lt;li&gt;logic layer&lt;/li&gt;
&lt;li&gt;presentation layer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All at once.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Started Doing Instead
&lt;/h2&gt;

&lt;p&gt;I introduced a middle layer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend → Application Layer → WordPress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That layer is where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;data access is standardized&lt;/li&gt;
&lt;li&gt;logic is centralized&lt;/li&gt;
&lt;li&gt;behavior becomes reusable&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Enter KiwiPress
&lt;/h2&gt;

&lt;p&gt;KiwiPress is my attempt to define that missing layer.&lt;/p&gt;

&lt;p&gt;Instead of every frontend talking directly to WordPress…&lt;/p&gt;

&lt;p&gt;They talk to structured services like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;WPRead&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WPCreate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WPUpdate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WPDelete&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each one has a clear responsibility.&lt;/p&gt;

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

&lt;p&gt;No guessing where logic lives.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Changes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;every frontend reimplements logic&lt;/li&gt;
&lt;li&gt;inconsistent data handling&lt;/li&gt;
&lt;li&gt;harder to scale across projects&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;one source of truth for behavior&lt;/li&gt;
&lt;li&gt;cleaner frontends&lt;/li&gt;
&lt;li&gt;easier to swap rendering strategies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now I can move between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;static builds&lt;/li&gt;
&lt;li&gt;SPAs&lt;/li&gt;
&lt;li&gt;server-rendered apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…without rewriting core logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Static Site Generators Fit
&lt;/h2&gt;

&lt;p&gt;This doesn’t replace SSG frameworks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js&lt;/li&gt;
&lt;li&gt;Astro&lt;/li&gt;
&lt;li&gt;Gatsby&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If anything, it complements them.&lt;/p&gt;

&lt;p&gt;SSGs handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rendering&lt;/li&gt;
&lt;li&gt;performance&lt;/li&gt;
&lt;li&gt;delivery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;KiwiPress handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;structure&lt;/li&gt;
&lt;li&gt;logic&lt;/li&gt;
&lt;li&gt;consistency&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Bigger Idea
&lt;/h2&gt;

&lt;p&gt;Headless WordPress is a step forward.&lt;/p&gt;

&lt;p&gt;But it’s not the final step.&lt;/p&gt;

&lt;p&gt;If WordPress becomes the &lt;strong&gt;data layer&lt;/strong&gt;…&lt;/p&gt;

&lt;p&gt;Then we still need something to define the &lt;strong&gt;application layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That’s what I’m building toward.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Headless solves separation.&lt;/p&gt;

&lt;p&gt;But structure is still your responsibility.&lt;/p&gt;

&lt;p&gt;And that’s where things usually fall apart.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>wordpress</category>
      <category>opensource</category>
      <category>development</category>
    </item>
    <item>
      <title>I Stopped Fighting WordPress… So I Rebuilt How I Use It</title>
      <dc:creator>Drew Marshall</dc:creator>
      <pubDate>Tue, 28 Apr 2026 01:19:29 +0000</pubDate>
      <link>https://forem.com/stinklewinks/i-stopped-fighting-wordpress-so-i-rebuilt-how-i-use-it-6p0</link>
      <guid>https://forem.com/stinklewinks/i-stopped-fighting-wordpress-so-i-rebuilt-how-i-use-it-6p0</guid>
      <description>&lt;p&gt;I’ve built enough WordPress projects to notice a pattern.&lt;/p&gt;

&lt;p&gt;They all start clean.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;plugins pile up&lt;/li&gt;
&lt;li&gt;logic creeps into templates&lt;/li&gt;
&lt;li&gt;APIs get scattered&lt;/li&gt;
&lt;li&gt;and “just make it work” becomes the architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At some point, you’re not building a system anymore—you’re managing chaos.&lt;/p&gt;

&lt;p&gt;And the frustrating part?&lt;/p&gt;

&lt;p&gt;It’s not really WordPress’ fault.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Problem
&lt;/h2&gt;

&lt;p&gt;WordPress tries to be everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CMS&lt;/li&gt;
&lt;li&gt;backend&lt;/li&gt;
&lt;li&gt;frontend&lt;/li&gt;
&lt;li&gt;plugin system&lt;/li&gt;
&lt;li&gt;templating engine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So naturally, everything ends up mixed together.&lt;/p&gt;

&lt;p&gt;Routes know too much.&lt;br&gt;
Templates do too much.&lt;br&gt;
Plugins patch too much.&lt;/p&gt;

&lt;p&gt;There’s no clear boundary between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;data&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;behavior&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;execution&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s where things break down.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Shift That Changed Everything
&lt;/h2&gt;

&lt;p&gt;Instead of treating WordPress like the application…&lt;/p&gt;

&lt;p&gt;I started treating it like a &lt;strong&gt;data source&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That single shift changes everything.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;WordPress manages content&lt;/li&gt;
&lt;li&gt;My system manages behavior&lt;/li&gt;
&lt;li&gt;The frontend becomes fully flexible&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Introducing KiwiPress
&lt;/h2&gt;

&lt;p&gt;KiwiPress is an application layer on top of WordPress.&lt;/p&gt;

&lt;p&gt;It doesn’t replace WordPress.&lt;/p&gt;

&lt;p&gt;It organizes how you use it.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Separate &lt;em&gt;what&lt;/em&gt; WordPress stores from &lt;em&gt;how&lt;/em&gt; your app behaves.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  How It’s Structured
&lt;/h2&gt;

&lt;p&gt;KiwiPress sits between your app and WordPress and splits responsibilities clearly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Seltzer&lt;/strong&gt; → handles routes and request lifecycle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nectarine&lt;/strong&gt; → parses config and API structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KiwiPress&lt;/strong&gt; → owns WordPress-specific behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside KiwiPress, everything is broken into focused services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;WPCore&lt;/code&gt; → handles communication with WordPress&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WPRead&lt;/code&gt; → fetches data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WPCreate&lt;/code&gt; → creates data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WPUpdate&lt;/code&gt; → updates data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WPDelete&lt;/code&gt; → deletes data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WPAuth&lt;/code&gt; → handles authentication&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WPSync&lt;/code&gt; → handles migration, backup, and syncing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each part has one job.&lt;/p&gt;

&lt;p&gt;Nothing leaks.&lt;/p&gt;


&lt;h2&gt;
  
  
  What This Looks Like in Practice
&lt;/h2&gt;

&lt;p&gt;Instead of stuffing logic into routes or templates…&lt;/p&gt;

&lt;p&gt;You delegate.&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;wpread&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;WPRead&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/users/:email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;wpread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUserByEmail&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 route doesn’t know &lt;em&gt;how&lt;/em&gt; WordPress works.&lt;/p&gt;

&lt;p&gt;It just asks for data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;This approach gives you:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Clarity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You always know where logic lives.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Flexibility&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Your frontend can be anything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;custom UI&lt;/li&gt;
&lt;li&gt;SPA&lt;/li&gt;
&lt;li&gt;static site&lt;/li&gt;
&lt;li&gt;hybrid&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Portability&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you ever move away from WordPress, your app doesn’t collapse.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Maintainability&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;No more hunting through plugins and templates to understand behavior.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Better Way to Use WordPress
&lt;/h2&gt;

&lt;p&gt;I’m not trying to replace WordPress.&lt;/p&gt;

&lt;p&gt;I’m trying to use it &lt;em&gt;correctly&lt;/em&gt; in modern systems.&lt;/p&gt;

&lt;p&gt;WordPress is still great at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;content management&lt;/li&gt;
&lt;li&gt;admin workflows&lt;/li&gt;
&lt;li&gt;ecosystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But your &lt;strong&gt;application logic&lt;/strong&gt; shouldn’t live inside it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where This Is Going
&lt;/h2&gt;

&lt;p&gt;KiwiPress is part of a larger system I’m building focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;contract-driven architecture&lt;/li&gt;
&lt;li&gt;modular app engines&lt;/li&gt;
&lt;li&gt;vendor-neutral systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is just one piece.&lt;/p&gt;

&lt;p&gt;But it’s the first one that feels like a real product.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;WordPress isn’t broken.&lt;/p&gt;

&lt;p&gt;We just keep asking it to do too much.&lt;/p&gt;

&lt;p&gt;Split the responsibilities…&lt;/p&gt;

&lt;p&gt;…and suddenly everything gets a lot simpler.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>wordpress</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Got Tired of Class-Heavy UI Code — So I Kept Going (Juice Part 4)</title>
      <dc:creator>Drew Marshall</dc:creator>
      <pubDate>Wed, 22 Apr 2026 01:05:28 +0000</pubDate>
      <link>https://forem.com/stinklewinks/i-got-tired-of-class-heavy-ui-code-so-i-kept-going-juice-part-4-4jf2</link>
      <guid>https://forem.com/stinklewinks/i-got-tired-of-class-heavy-ui-code-so-i-kept-going-juice-part-4-4jf2</guid>
      <description>&lt;p&gt;In Part 1, I talked about the frustration.&lt;/p&gt;

&lt;p&gt;In Part 2, I showed the direction.&lt;/p&gt;

&lt;p&gt;In Part 3, I explained the shift toward a system.&lt;/p&gt;

&lt;p&gt;Now in Part 4, I want to talk about the part that matters most:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;rules.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because a UI system is not just made useful by how expressive it is.&lt;/p&gt;

&lt;p&gt;It is made useful by how well it avoids turning into chaos.&lt;/p&gt;




&lt;h2&gt;
  
  
  A System Cannot Be “Anything You Want”
&lt;/h2&gt;

&lt;p&gt;This is the trap a lot of systems fall into.&lt;/p&gt;

&lt;p&gt;They give you a lot of power, but not enough structure.&lt;/p&gt;

&lt;p&gt;So over time, the same idea gets written five different ways.&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;div&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"2rem"&lt;/span&gt; &lt;span class="na"&gt;bgColor=&lt;/span&gt;&lt;span class="s"&gt;"blue-500"&lt;/span&gt; &lt;span class="na"&gt;fontColor=&lt;/span&gt;&lt;span class="s"&gt;"white-100"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Content
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;div&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"32px"&lt;/span&gt; &lt;span class="na"&gt;bgColor=&lt;/span&gt;&lt;span class="s"&gt;"blue-500"&lt;/span&gt; &lt;span class="na"&gt;fontColor=&lt;/span&gt;&lt;span class="s"&gt;"white-100"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Content
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-8 bg-blue-500 text-white"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Content
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different syntax. Same outcome.&lt;/p&gt;

&lt;p&gt;That might seem harmless at first, but over time it creates drift.&lt;/p&gt;

&lt;p&gt;And drift is what breaks systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Juice Needs More Than Attributes
&lt;/h2&gt;

&lt;p&gt;This is one of the biggest things I have realized while building Juice:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Attributes alone do not make a system.&lt;br&gt;
Rules make a system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The attributes are just the interface.&lt;/p&gt;

&lt;p&gt;The rules are what make the interface reliable.&lt;/p&gt;

&lt;p&gt;Without rules, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;naming drift&lt;/li&gt;
&lt;li&gt;inconsistent spacing&lt;/li&gt;
&lt;li&gt;duplicated patterns&lt;/li&gt;
&lt;li&gt;unpredictable components&lt;/li&gt;
&lt;li&gt;weird one-off markup decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With rules, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repeatability&lt;/li&gt;
&lt;li&gt;consistency&lt;/li&gt;
&lt;li&gt;cleaner templates&lt;/li&gt;
&lt;li&gt;stronger defaults&lt;/li&gt;
&lt;li&gt;better long-term scale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the real difference.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rule 004: One Concern Per Attribute
&lt;/h2&gt;

&lt;p&gt;One of the most important rules I have written for Juice is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One concern per attribute.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That means an attribute should do one job.&lt;/p&gt;

&lt;p&gt;Not three jobs.&lt;br&gt;
Not five jobs.&lt;br&gt;
One.&lt;/p&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;div&lt;/span&gt; &lt;span class="na"&gt;box=&lt;/span&gt;&lt;span class="s"&gt;"primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Content
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why is that bad?&lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;box="primary"&lt;/code&gt; is too vague.&lt;/p&gt;

&lt;p&gt;Does it control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;background color?&lt;/li&gt;
&lt;li&gt;padding?&lt;/li&gt;
&lt;li&gt;border?&lt;/li&gt;
&lt;li&gt;radius?&lt;/li&gt;
&lt;li&gt;shadow?&lt;/li&gt;
&lt;li&gt;text color?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Probably several of those.&lt;/p&gt;

&lt;p&gt;That means one attribute is hiding multiple concerns.&lt;/p&gt;

&lt;p&gt;And once that starts happening, the system gets harder to reason about.&lt;/p&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;div&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"2rem"&lt;/span&gt; &lt;span class="na"&gt;bgColor=&lt;/span&gt;&lt;span class="s"&gt;"blue-500"&lt;/span&gt; &lt;span class="na"&gt;radius=&lt;/span&gt;&lt;span class="s"&gt;"md"&lt;/span&gt; &lt;span class="na"&gt;shadow=&lt;/span&gt;&lt;span class="s"&gt;"gray-400"&lt;/span&gt; &lt;span class="na"&gt;depth=&lt;/span&gt;&lt;span class="s"&gt;"sm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Content
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now each attribute has a clear responsibility.&lt;/p&gt;

&lt;p&gt;That makes the system easier to learn, easier to document, and easier to extend.&lt;/p&gt;




&lt;h2&gt;
  
  
  Explicit Beats Clever
&lt;/h2&gt;

&lt;p&gt;A lot of frontend tooling tries to be clever.&lt;/p&gt;

&lt;p&gt;I want Juice to be clear.&lt;/p&gt;

&lt;p&gt;I would rather have markup that is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;readable&lt;/li&gt;
&lt;li&gt;direct&lt;/li&gt;
&lt;li&gt;predictable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;than markup that is “smart” but unclear.&lt;/p&gt;

&lt;p&gt;That is part of why I keep leaning into attributes.&lt;/p&gt;

&lt;p&gt;They let the markup say what is happening in a way that feels close to the element itself.&lt;/p&gt;

&lt;p&gt;But that only works if the attribute language stays disciplined.&lt;/p&gt;

&lt;p&gt;If the language gets sloppy, then all I have done is reinvent confusion with different syntax.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rules Protect the System From Drift
&lt;/h2&gt;

&lt;p&gt;This is especially important in a growing project.&lt;/p&gt;

&lt;p&gt;Once you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cards&lt;/li&gt;
&lt;li&gt;forms&lt;/li&gt;
&lt;li&gt;nav&lt;/li&gt;
&lt;li&gt;themes&lt;/li&gt;
&lt;li&gt;layout primitives&lt;/li&gt;
&lt;li&gt;responsive behavior&lt;/li&gt;
&lt;li&gt;surface ideas&lt;/li&gt;
&lt;li&gt;templates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;you are no longer just experimenting.&lt;/p&gt;

&lt;p&gt;You are defining a language.&lt;/p&gt;

&lt;p&gt;And languages break down fast when the same thing can be expressed too many different ways.&lt;/p&gt;

&lt;p&gt;That is why rules matter.&lt;/p&gt;

&lt;p&gt;They protect the system from becoming a pile of “kind of similar” patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  Constraints Are Not the Enemy
&lt;/h2&gt;

&lt;p&gt;This is something I think more developers should hear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;constraints are not what kill creativity.&lt;br&gt;
bad constraints kill creativity.&lt;br&gt;
good constraints make creativity faster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If spacing is already consistent, I do not have to think about spacing every five seconds.&lt;/p&gt;

&lt;p&gt;If responsiveness is already baked into the system, I do not have to keep writing breakpoint logic into the markup.&lt;/p&gt;

&lt;p&gt;If a card has a known structure, I can focus on the actual content and presentation.&lt;/p&gt;

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

&lt;p&gt;Not the freedom to do anything.&lt;/p&gt;

&lt;p&gt;The freedom to move faster without lowering quality.&lt;/p&gt;




&lt;h2&gt;
  
  
  Juice Is Trying To Be a Language
&lt;/h2&gt;

&lt;p&gt;That is the deeper idea behind all of this.&lt;/p&gt;

&lt;p&gt;I am not trying to build a bag of styling tricks.&lt;/p&gt;

&lt;p&gt;I am trying to build a language for UI.&lt;/p&gt;

&lt;p&gt;A language needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;vocabulary&lt;/li&gt;
&lt;li&gt;syntax&lt;/li&gt;
&lt;li&gt;constraints&lt;/li&gt;
&lt;li&gt;consistency&lt;/li&gt;
&lt;li&gt;meaning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Juice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;attributes are the vocabulary&lt;/li&gt;
&lt;li&gt;markup patterns are the syntax&lt;/li&gt;
&lt;li&gt;rules are the constraints&lt;/li&gt;
&lt;li&gt;docs are the grammar&lt;/li&gt;
&lt;li&gt;templates are the stress test&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is how it starts becoming more than a styling library.&lt;/p&gt;

&lt;p&gt;That is how it starts becoming a system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters for the Future
&lt;/h2&gt;

&lt;p&gt;The more I work on Juice, the more I believe this:&lt;/p&gt;

&lt;p&gt;frontend development has too much repeated decision-making in it.&lt;/p&gt;

&lt;p&gt;Too much repetition.&lt;br&gt;
Too much breakpoint choreography.&lt;br&gt;
Too much restating intent.&lt;br&gt;
Too much low-level noise in markup.&lt;/p&gt;

&lt;p&gt;I think future-thinking UI systems should take more responsibility.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;understand layout better&lt;/li&gt;
&lt;li&gt;handle responsiveness better&lt;/li&gt;
&lt;li&gt;provide stronger structure&lt;/li&gt;
&lt;li&gt;reduce repeated authoring work&lt;/li&gt;
&lt;li&gt;let developers think more about pages and products&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the direction I want Juice to move in.&lt;/p&gt;

&lt;p&gt;Not less control.&lt;/p&gt;

&lt;p&gt;Better defaults.&lt;br&gt;
Better structure.&lt;br&gt;
Better language.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Goal
&lt;/h2&gt;

&lt;p&gt;The goal is not to remove thought from UI development.&lt;/p&gt;

&lt;p&gt;The goal is to remove unnecessary thought.&lt;/p&gt;

&lt;p&gt;I should be thinking about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the page&lt;/li&gt;
&lt;li&gt;the product&lt;/li&gt;
&lt;li&gt;the experience&lt;/li&gt;
&lt;li&gt;the content&lt;/li&gt;
&lt;li&gt;the flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I should not have to keep fighting the markup just to maintain consistency.&lt;/p&gt;

&lt;p&gt;That is what the rules are for.&lt;/p&gt;

&lt;p&gt;They make the language trustworthy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Juice does not get stronger by adding endless attributes.&lt;/p&gt;

&lt;p&gt;It gets stronger by making the attribute language more disciplined.&lt;/p&gt;

&lt;p&gt;Because the real power of a UI system is not how much it can do.&lt;/p&gt;

&lt;p&gt;It is how consistently it helps people do the same things well.&lt;/p&gt;

&lt;p&gt;That is where I am pushing Juice next.&lt;/p&gt;

&lt;p&gt;Not just toward more features.&lt;/p&gt;

&lt;p&gt;Toward stronger rules.&lt;/p&gt;




&lt;p&gt;Part 5 will go deeper into themes, surfaces, and how Juice starts moving from a styling system into something that feels more like an engine.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>opensource</category>
      <category>css</category>
    </item>
    <item>
      <title>I Got Tired of Class-Heavy UI Code — So I Kept Going (Juice Part 3)</title>
      <dc:creator>Drew Marshall</dc:creator>
      <pubDate>Mon, 20 Apr 2026 22:40:42 +0000</pubDate>
      <link>https://forem.com/stinklewinks/i-got-tired-of-class-heavy-ui-code-so-i-kept-going-juice-part-3-1ah0</link>
      <guid>https://forem.com/stinklewinks/i-got-tired-of-class-heavy-ui-code-so-i-kept-going-juice-part-3-1ah0</guid>
      <description>&lt;p&gt;In Part 1, I talked about the frustration.&lt;/p&gt;

&lt;p&gt;In Part 2, I showed the direction.&lt;/p&gt;

&lt;p&gt;Now in Part 3, we’re going deeper into what Juice is actually becoming.&lt;/p&gt;

&lt;p&gt;Because at this point…&lt;/p&gt;

&lt;p&gt;This isn’t just about styling anymore.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Problem Was Never Classes
&lt;/h2&gt;

&lt;p&gt;Classes were just the symptom.&lt;/p&gt;

&lt;p&gt;The real problem?&lt;/p&gt;

&lt;p&gt;We’ve been writing UI in a way that separates &lt;em&gt;what something is&lt;/em&gt; from &lt;em&gt;how it behaves&lt;/em&gt;.&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center justify-between p-4 bg-gray-900 text-white rounded-lg shadow-md"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This doesn’t describe intent.&lt;/p&gt;

&lt;p&gt;It describes implementation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Juice Is About Intent
&lt;/h2&gt;

&lt;p&gt;With Juice, I’m not trying to replace Tailwind.&lt;/p&gt;

&lt;p&gt;I’m trying to replace how we &lt;em&gt;think&lt;/em&gt; about UI.&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;div&lt;/span&gt; &lt;span class="na"&gt;layout=&lt;/span&gt;&lt;span class="s"&gt;"row space-between center"&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt; &lt;span class="na"&gt;surface=&lt;/span&gt;&lt;span class="s"&gt;"dark"&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"white"&lt;/span&gt; &lt;span class="na"&gt;radius=&lt;/span&gt;&lt;span class="s"&gt;"lg"&lt;/span&gt; &lt;span class="na"&gt;elevation=&lt;/span&gt;&lt;span class="s"&gt;"md"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we’re talking.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;layout&lt;/code&gt; → structure&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;padding&lt;/code&gt; → spacing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;surface&lt;/code&gt; → semantic background&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;text&lt;/code&gt; → semantic color&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;radius&lt;/code&gt; → shape&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;elevation&lt;/code&gt; → depth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is no longer a pile of utilities.&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;language&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  From Styling → System Design
&lt;/h2&gt;

&lt;p&gt;Here’s the shift that changed everything for me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Juice isn’t a CSS library. It’s a UI protocol.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defined attributes&lt;/li&gt;
&lt;li&gt;Predictable behavior&lt;/li&gt;
&lt;li&gt;Shared contracts across components&lt;/li&gt;
&lt;li&gt;Extensible rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sound familiar?&lt;/p&gt;

&lt;p&gt;That’s because it mirrors how we already think about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;Schemas&lt;/li&gt;
&lt;li&gt;Infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So why doesn’t UI get the same treatment?&lt;/p&gt;




&lt;h2&gt;
  
  
  The Missing Layer in Frontend
&lt;/h2&gt;

&lt;p&gt;We have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frameworks (React, Vue, etc.)&lt;/li&gt;
&lt;li&gt;Styling systems (Tailwind, CSS Modules)&lt;/li&gt;
&lt;li&gt;Component libraries (MUI, Chakra)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But we don’t have a &lt;strong&gt;standardized way to describe UI itself&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Juice is aiming to sit right there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ App Logic ]
      ↓
[ UI Description Layer (Juice) ]
      ↓
[ Render Layer (DOM / Canvas / WebGL) ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That middle layer?&lt;/p&gt;

&lt;p&gt;That’s the gap.&lt;/p&gt;




&lt;h2&gt;
  
  
  Attributes &amp;gt; Classes Isn’t the Point
&lt;/h2&gt;

&lt;p&gt;Let’s be clear:&lt;/p&gt;

&lt;p&gt;This isn’t about:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“attributes are better than classes”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s shallow.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Attributes let you define rules and contracts more naturally.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example:&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;button&lt;/span&gt; &lt;span class="na"&gt;variant=&lt;/span&gt;&lt;span class="s"&gt;"primary"&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;"lg"&lt;/span&gt; &lt;span class="na"&gt;state=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now imagine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;variant&lt;/code&gt; ties into your design system&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;size&lt;/code&gt; scales consistently everywhere&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;state&lt;/code&gt; drives behavior + visuals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This becomes a &lt;em&gt;shared interface&lt;/em&gt;, not just styling.&lt;/p&gt;




&lt;h2&gt;
  
  
  Composability Without Chaos
&lt;/h2&gt;

&lt;p&gt;One of the biggest issues with utility-first systems:&lt;/p&gt;

&lt;p&gt;They scale &lt;em&gt;visually&lt;/em&gt; but not &lt;em&gt;conceptually&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You end up with:&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex gap-2 p-3 sm:p-4 md:p-6 bg-neutral-800 hover:bg-neutral-700 transition-all duration-200"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multiply that across an app…&lt;/p&gt;

&lt;p&gt;Now try to refactor it.&lt;/p&gt;

&lt;p&gt;Good luck.&lt;/p&gt;

&lt;p&gt;With Juice:&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;div&lt;/span&gt; &lt;span class="na"&gt;layout=&lt;/span&gt;&lt;span class="s"&gt;"row gap-2"&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"responsive"&lt;/span&gt; &lt;span class="na"&gt;surface=&lt;/span&gt;&lt;span class="s"&gt;"neutral-800"&lt;/span&gt; &lt;span class="na"&gt;interaction=&lt;/span&gt;&lt;span class="s"&gt;"hover-surface"&lt;/span&gt; &lt;span class="na"&gt;transition=&lt;/span&gt;&lt;span class="s"&gt;"fast"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Behavior is abstracted&lt;/li&gt;
&lt;li&gt;Patterns are reusable&lt;/li&gt;
&lt;li&gt;Refactoring becomes &lt;em&gt;changing rules&lt;/em&gt;, not hunting classes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  This Is Where It Gets Interesting
&lt;/h2&gt;

&lt;p&gt;Once UI becomes declarative like this…&lt;/p&gt;

&lt;p&gt;You unlock things like:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Theming at a System Level
&lt;/h3&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;app&lt;/span&gt; &lt;span class="na"&gt;theme=&lt;/span&gt;&lt;span class="s"&gt;"corporate-dark"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/app&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything adapts.&lt;/p&gt;

&lt;p&gt;No class overrides.&lt;br&gt;
No specificity wars.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Dynamic UI Generation
&lt;/h3&gt;

&lt;p&gt;Now your UI can be generated from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON&lt;/li&gt;
&lt;li&gt;YAML&lt;/li&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;AI (👀)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because it's structured.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Cross-Platform Rendering
&lt;/h3&gt;

&lt;p&gt;Same UI definition could target:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DOM&lt;/li&gt;
&lt;li&gt;Canvas&lt;/li&gt;
&lt;li&gt;WebGL&lt;/li&gt;
&lt;li&gt;Native&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because Juice isn’t tied to one renderer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Juice + The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;This is where Juice connects to everything else I’m building.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sig&lt;/strong&gt; → rendering &amp;amp; reactivity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nectarine&lt;/strong&gt; → data &amp;amp; APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seltzer&lt;/strong&gt; → HTTP layer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GrapeVine&lt;/strong&gt; → infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Juice becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The way UI is &lt;em&gt;defined&lt;/em&gt; across the entire system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not just styled.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where This Is Going
&lt;/h2&gt;

&lt;p&gt;Right now, Juice is still evolving.&lt;/p&gt;

&lt;p&gt;I’m documenting rules.&lt;br&gt;
Defining protocols.&lt;br&gt;
Figuring out where flexibility ends and standards begin.&lt;/p&gt;

&lt;p&gt;But the direction is clear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;UI should be declarative, structured, and system-driven.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not just styled with strings.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;I didn’t start building Juice because I hated CSS.&lt;/p&gt;

&lt;p&gt;I started building it because I realized:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We’ve been missing a layer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And once you see it…&lt;/p&gt;

&lt;p&gt;You can’t unsee it.&lt;/p&gt;




&lt;p&gt;Part 4 is where things start getting real.&lt;/p&gt;

&lt;p&gt;We’ll talk about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rules &amp;amp; constraints&lt;/li&gt;
&lt;li&gt;How Juice avoids becoming chaos&lt;/li&gt;
&lt;li&gt;And how this turns into an actual engine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>css</category>
      <category>frontend</category>
    </item>
    <item>
      <title>I Got Tired of Class-Heavy UI Code… So I Kept Going (Juice Part 2)</title>
      <dc:creator>Drew Marshall</dc:creator>
      <pubDate>Sun, 19 Apr 2026 11:54:00 +0000</pubDate>
      <link>https://forem.com/stinklewinks/i-got-tired-of-class-heavy-ui-code-so-i-kept-going-juice-part-2-2nk2</link>
      <guid>https://forem.com/stinklewinks/i-got-tired-of-class-heavy-ui-code-so-i-kept-going-juice-part-2-2nk2</guid>
      <description>&lt;p&gt;In my last post, I talked about why I started building Juice—mainly out of frustration with class-heavy UI code and how messy things can get as projects scale.&lt;/p&gt;

&lt;p&gt;If you haven’t read that yet, here it is:&lt;br&gt;
👉 &lt;a href="https://dev.to/stinklewinks/i-got-tired-of-class-heavy-ui-code-so-i-started-building-juice-4ocg"&gt;https://dev.to/stinklewinks/i-got-tired-of-class-heavy-ui-code-so-i-started-building-juice-4ocg&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post is about what came next.&lt;/p&gt;

&lt;p&gt;Not just &lt;em&gt;what Juice is&lt;/em&gt;, but what I’m actually trying to build with it.&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚠️ The Problem Isn’t Just Classes
&lt;/h2&gt;

&lt;p&gt;After stepping back, I realized something:&lt;/p&gt;

&lt;p&gt;The issue wasn’t just Tailwind-style class overload.&lt;/p&gt;

&lt;p&gt;It was bigger than that.&lt;/p&gt;

&lt;p&gt;Most UI systems today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Push styling into long class strings&lt;/li&gt;
&lt;li&gt;Mix structure, intent, and design into one place&lt;/li&gt;
&lt;li&gt;Become harder to read as complexity increases&lt;/li&gt;
&lt;li&gt;Don’t feel like they scale &lt;em&gt;conceptually&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can make them work—but you’re constantly managing them.&lt;/p&gt;

&lt;p&gt;And that’s where things started to feel off to me.&lt;/p&gt;


&lt;h2&gt;
  
  
  💡 What If UI Was More Declarative?
&lt;/h2&gt;

&lt;p&gt;Instead of this:&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center justify-between p-4 bg-white rounded-lg shadow-md"&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;What if you could express intent more directly?&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;div&lt;/span&gt; &lt;span class="na"&gt;row&lt;/span&gt; &lt;span class="na"&gt;centered&lt;/span&gt; &lt;span class="na"&gt;gap=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"4rem"&lt;/span&gt; &lt;span class="na"&gt;card&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;Not just shorter—but more meaningful.&lt;/p&gt;

&lt;p&gt;That’s the direction Juice is going.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧃 The Core Idea Behind Juice
&lt;/h2&gt;

&lt;p&gt;Juice is built around one simple idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;UI should describe intent, not implementation.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing long class lists&lt;/li&gt;
&lt;li&gt;Remembering utility combinations&lt;/li&gt;
&lt;li&gt;Repeating patterns across files&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Layout&lt;/li&gt;
&lt;li&gt;Spacing&lt;/li&gt;
&lt;li&gt;Surfaces&lt;/li&gt;
&lt;li&gt;Behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using &lt;strong&gt;attributes that map to a design system&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧱 Attributes Over Classes
&lt;/h2&gt;

&lt;p&gt;Classes are flexible, but they come with trade-offs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No structure&lt;/li&gt;
&lt;li&gt;Easy to overuse&lt;/li&gt;
&lt;li&gt;Hard to standardize across teams&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Attributes, on the other hand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encourage consistency&lt;/li&gt;
&lt;li&gt;Create a natural design language&lt;/li&gt;
&lt;li&gt;Are easier to read at a glance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&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;div&lt;/span&gt; &lt;span class="na"&gt;grid=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt; &lt;span class="na"&gt;gap=&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;card&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;A&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;card&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;B&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You immediately understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Layout: grid with 2 columns&lt;/li&gt;
&lt;li&gt;Spacing: gap of 4&lt;/li&gt;
&lt;li&gt;Surface: reusable card style&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No mental decoding required.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Not Just Styling — A System
&lt;/h2&gt;

&lt;p&gt;Juice isn’t just about styling elements.&lt;/p&gt;

&lt;p&gt;It’s about creating a &lt;strong&gt;cohesive UI system&lt;/strong&gt; that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🎨 Design tokens (colors, spacing, typography)&lt;/li&gt;
&lt;li&gt;🧩 Components (cards, nav, sections)&lt;/li&gt;
&lt;li&gt;⚡ Interactions (animations, states)&lt;/li&gt;
&lt;li&gt;📱 Responsiveness (built-in, not bolted on)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to make UI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster to build&lt;/li&gt;
&lt;li&gt;Easier to read&lt;/li&gt;
&lt;li&gt;More consistent&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚡ Where This Is Going
&lt;/h2&gt;

&lt;p&gt;Right now, Juice is still early.&lt;/p&gt;

&lt;p&gt;But the direction is clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;fully expressive attribute-based UI system&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Designed to work standalone or alongside other frameworks&lt;/li&gt;
&lt;li&gt;Built to integrate directly into WebEngine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And eventually:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A system where developers and non-developers can both build interfaces without fighting the code.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧠 What I’m Exploring Next
&lt;/h2&gt;

&lt;p&gt;Some of the things I’m actively thinking through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How far can attributes go before they become noisy?&lt;/li&gt;
&lt;li&gt;How should responsiveness be handled without clutter?&lt;/li&gt;
&lt;li&gt;What’s the right balance between flexibility and structure?&lt;/li&gt;
&lt;li&gt;How can this integrate with things like WebGL and dynamic UI?&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Why This Matters (To Me)
&lt;/h2&gt;

&lt;p&gt;At the end of the day, this isn’t just about CSS.&lt;/p&gt;

&lt;p&gt;It’s about reducing friction when building ideas.&lt;/p&gt;

&lt;p&gt;Because when UI becomes easier to reason about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You build faster&lt;/li&gt;
&lt;li&gt;You experiment more&lt;/li&gt;
&lt;li&gt;You ship more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that’s the real goal.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤝 Let’s Build This Together
&lt;/h2&gt;

&lt;p&gt;This is still evolving, and I’m learning as I go.&lt;/p&gt;

&lt;p&gt;If you’ve run into similar frustrations—or have thoughts on this approach—I’d love to hear them.&lt;/p&gt;

&lt;p&gt;Repo here:&lt;br&gt;
👉 &lt;a href="https://github.com/citrusworx/webengine/tree/master/libraries/juice" rel="noopener noreferrer"&gt;https://github.com/citrusworx/webengine/tree/master/libraries/juice&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Next up, I’ll probably dive deeper into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How Juice handles responsiveness&lt;/li&gt;
&lt;li&gt;Or how it compares directly to existing frameworks in real-world use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Appreciate you reading 🙏&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>frontend</category>
      <category>css</category>
    </item>
    <item>
      <title>I got tired of class-heavy UI code, so I started building Juice</title>
      <dc:creator>Drew Marshall</dc:creator>
      <pubDate>Tue, 14 Apr 2026 22:34:31 +0000</pubDate>
      <link>https://forem.com/stinklewinks/i-got-tired-of-class-heavy-ui-code-so-i-started-building-juice-4ocg</link>
      <guid>https://forem.com/stinklewinks/i-got-tired-of-class-heavy-ui-code-so-i-started-building-juice-4ocg</guid>
      <description>&lt;p&gt;At some point, my markup started feeling… heavy.&lt;/p&gt;

&lt;p&gt;Not slow. Not broken. Just hard to &lt;em&gt;look at&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;At some point, it stopped feeling like I was writing UI…&lt;br&gt;
and started feeling like I was managing class strings.&lt;/p&gt;


&lt;h1&gt;
  
  
  The Problem
&lt;/h1&gt;

&lt;p&gt;Modern CSS tooling solves a lot of problems.&lt;/p&gt;

&lt;p&gt;But it also introduces some friction—especially at scale.&lt;/p&gt;
&lt;h3&gt;
  
  
  Verbosity
&lt;/h3&gt;

&lt;p&gt;You end up stacking utilities:&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center justify-center h-screen bg-gradient-to-r from-purple-400 to-pink-500"&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;It works. It’s powerful. But it’s a lot to parse.&lt;/p&gt;




&lt;h3&gt;
  
  
  Readability
&lt;/h3&gt;

&lt;p&gt;When everything is a class:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;layout&lt;/li&gt;
&lt;li&gt;spacing&lt;/li&gt;
&lt;li&gt;color&lt;/li&gt;
&lt;li&gt;behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…it all blends together.&lt;/p&gt;

&lt;p&gt;You stop seeing &lt;em&gt;intent&lt;/em&gt; and start reading &lt;em&gt;implementation&lt;/em&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Scaling UI Systems
&lt;/h3&gt;

&lt;p&gt;As projects grow, this turns into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;long, unreadable markup&lt;/li&gt;
&lt;li&gt;repeated patterns everywhere&lt;/li&gt;
&lt;li&gt;small changes requiring multiple class edits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It works—but it starts to feel messy.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Idea
&lt;/h1&gt;

&lt;p&gt;What if UI wasn’t driven by long class strings?&lt;/p&gt;

&lt;p&gt;What if it looked more like this:&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;div&lt;/span&gt; &lt;span class="na"&gt;flex=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"full"&lt;/span&gt; &lt;span class="na"&gt;grad=&lt;/span&gt;&lt;span class="s"&gt;"candy-grape"&lt;/span&gt; &lt;span class="na"&gt;centered&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;Instead of stacking utilities, each attribute describes intent directly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;flex="col" centered&lt;/code&gt; → layout&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;height="full"&lt;/code&gt; → sizing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;grad="candy-grape"&lt;/code&gt; → styling&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Example
&lt;/h1&gt;

&lt;p&gt;Here’s a simple comparison.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tailwind-style
&lt;/h3&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center justify-center h-screen bg-gradient-to-r from-purple-400 to-pink-500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-2xl font-bold text-white"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-4 px-4 py-2 bg-black text-white rounded-md"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click me&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Juice
&lt;/h3&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;div&lt;/span&gt; &lt;span class="na"&gt;flex=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"full"&lt;/span&gt; &lt;span class="na"&gt;grad=&lt;/span&gt;&lt;span class="s"&gt;"candy-grape"&lt;/span&gt; &lt;span class="na"&gt;centered&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;fontSize=&lt;/span&gt;&lt;span class="s"&gt;"xl"&lt;/span&gt; &lt;span class="na"&gt;fontColor=&lt;/span&gt;&lt;span class="s"&gt;"white"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;margin-top=&lt;/span&gt;&lt;span class="s"&gt;"4rem"&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"x-4 y-2"&lt;/span&gt; &lt;span class="na"&gt;bgColor=&lt;/span&gt;&lt;span class="s"&gt;"black"&lt;/span&gt; &lt;span class="na"&gt;fontColor=&lt;/span&gt;&lt;span class="s"&gt;"white"&lt;/span&gt; &lt;span class="na"&gt;rounded=&lt;/span&gt;&lt;span class="s"&gt;"md"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Click me
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;The difference isn’t just shorter code.&lt;/p&gt;

&lt;p&gt;Each attribute expresses &lt;em&gt;intent&lt;/em&gt; directly, instead of stacking utilities together.&lt;/p&gt;




&lt;h1&gt;
  
  
  Interactions &amp;amp; Animations
&lt;/h1&gt;

&lt;p&gt;This pattern extends beyond layout and styling.&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;button&lt;/span&gt; &lt;span class="na"&gt;hover=&lt;/span&gt;&lt;span class="s"&gt;"scale-up"&lt;/span&gt; &lt;span class="na"&gt;motion=&lt;/span&gt;&lt;span class="s"&gt;"fade-in"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Click me
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interactions and animations follow the same idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;attributes describe behavior&lt;/li&gt;
&lt;li&gt;not just appearance&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  What Juice Is
&lt;/h1&gt;

&lt;p&gt;Juice is an &lt;strong&gt;attribute-based UI system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s designed to make UI code more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;expressive&lt;/li&gt;
&lt;li&gt;readable&lt;/li&gt;
&lt;li&gt;scalable&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Core Ideas
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Layout via attributes&lt;/li&gt;
&lt;li&gt;Styling via attributes&lt;/li&gt;
&lt;li&gt;Animations via attributes&lt;/li&gt;
&lt;li&gt;Works standalone or with frameworks&lt;/li&gt;
&lt;li&gt;Optional JS control when needed&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Why I Built It
&lt;/h1&gt;

&lt;p&gt;I wasn’t trying to replace existing tools.&lt;/p&gt;

&lt;p&gt;I was trying to solve a personal problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I wanted my UI code to feel as clean as my logic.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I like systems.&lt;br&gt;
I like consistency.&lt;/p&gt;

&lt;p&gt;And I didn’t like how styling started to feel like a wall of strings.&lt;/p&gt;

&lt;p&gt;So I started experimenting with attributes.&lt;/p&gt;

&lt;p&gt;That turned into patterns.&lt;br&gt;
Then conventions.&lt;br&gt;
Then a system.&lt;/p&gt;




&lt;h1&gt;
  
  
  Who This Is For
&lt;/h1&gt;

&lt;p&gt;Juice is probably a good fit if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build apps or dashboards&lt;/li&gt;
&lt;li&gt;use Tailwind (or similar) but feel the verbosity&lt;/li&gt;
&lt;li&gt;care about readability as your project grows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s probably not for you if you prefer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;strict class-based systems&lt;/li&gt;
&lt;li&gt;or fully abstracted component libraries&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Current State
&lt;/h1&gt;

&lt;p&gt;Juice is currently in &lt;strong&gt;alpha&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;things will change&lt;/li&gt;
&lt;li&gt;APIs may evolve&lt;/li&gt;
&lt;li&gt;ideas are still being refined&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the core concept is solid enough to start sharing.&lt;/p&gt;




&lt;h1&gt;
  
  
  Try It / Feedback
&lt;/h1&gt;

&lt;p&gt;This is still early, and I’m actively shaping it.&lt;/p&gt;

&lt;p&gt;If you’ve ever felt the pain of class-heavy UI code, I’d love your feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this feel clearer or just different?&lt;/li&gt;
&lt;li&gt;Would you actually use this in a project?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repo:&lt;br&gt;
👉 &lt;a href="https://github.com/citrusworx/webengine/tree/master/libraries/juice" rel="noopener noreferrer"&gt;Juice&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This isn’t meant to replace everything.&lt;/p&gt;

&lt;p&gt;It’s just another way to think about UI—and I’m curious if it clicks for anyone else the way it did for me.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>frontend</category>
      <category>opensource</category>
    </item>
    <item>
      <title>📚 Reading With Intention as a Builder</title>
      <dc:creator>Drew Marshall</dc:creator>
      <pubDate>Sun, 12 Apr 2026 12:52:10 +0000</pubDate>
      <link>https://forem.com/stinklewinks/reading-with-intention-as-a-builder-1hkm</link>
      <guid>https://forem.com/stinklewinks/reading-with-intention-as-a-builder-1hkm</guid>
      <description>&lt;p&gt;Lately I’ve been trying to be more intentional about what I read—not just consuming information, but actually learning things I can apply while building.&lt;/p&gt;

&lt;p&gt;Here’s the current list I’ve been working through:&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Finished
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Zero to One&lt;/li&gt;
&lt;li&gt;The Cold Start Problem&lt;/li&gt;
&lt;li&gt;The Lean Startup&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📖 In Progress / Up Next
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;High Output Management&lt;/li&gt;
&lt;li&gt;Platform Revolution&lt;/li&gt;
&lt;li&gt;Obviously Awesome&lt;/li&gt;
&lt;li&gt;Redeeming Science&lt;/li&gt;
&lt;li&gt;Financial Intelligence for Entrepreneurs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 What I’m Starting to Notice
&lt;/h2&gt;

&lt;p&gt;Even though these books come from different angles—startups, product, management, finance—they keep pointing to the same ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building something “cool” isn’t enough&lt;/li&gt;
&lt;li&gt;Growth is designed, not accidental&lt;/li&gt;
&lt;li&gt;Positioning determines whether people care&lt;/li&gt;
&lt;li&gt;Simplicity and clarity win over complexity&lt;/li&gt;
&lt;li&gt;And understanding business is just as important as writing code&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚙️ Applying This in Real Time
&lt;/h2&gt;

&lt;p&gt;I’m not reading these passively—I’m trying to apply them across the things I’m building right now.&lt;/p&gt;

&lt;p&gt;Whether that’s:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thinking about distribution before development&lt;/li&gt;
&lt;li&gt;Designing systems instead of one-off solutions&lt;/li&gt;
&lt;li&gt;Or being more intentional about how ideas are positioned&lt;/li&gt;
&lt;/ul&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Build things that actually work in the real world—not just in theory.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🤝 Always Learning
&lt;/h2&gt;

&lt;p&gt;If you’ve read any of these, I’d love to hear what stuck with you—or what I should add next.&lt;/p&gt;

&lt;p&gt;I’m always looking to sharpen both the technical &lt;em&gt;and&lt;/em&gt; business side of building.&lt;/p&gt;

</description>
      <category>books</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
