<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Luciano Federico Pereira</title>
    <description>The latest articles on DEV Community by Luciano Federico Pereira (@lucianofedericopereira).</description>
    <link>https://dev.to/lucianofedericopereira</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%2F3727055%2Fc21728ea-2492-4d86-84dc-40f44cafe8ec.png</url>
      <title>DEV Community: Luciano Federico Pereira</title>
      <link>https://dev.to/lucianofedericopereira</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lucianofedericopereira"/>
    <language>en</language>
    <item>
      <title>Run WordPress on SQLite: A Zero-Server Local Development Revolution</title>
      <dc:creator>Luciano Federico Pereira</dc:creator>
      <pubDate>Wed, 18 Mar 2026 07:41:32 +0000</pubDate>
      <link>https://dev.to/lucianofedericopereira/run-wordpress-on-sqlite-a-zero-server-local-development-revolution-nd9</link>
      <guid>https://dev.to/lucianofedericopereira/run-wordpress-on-sqlite-a-zero-server-local-development-revolution-nd9</guid>
      <description>&lt;p&gt;For years, the "Local WordPress" experience has been synonymous with overhead. Whether you use Docker, XAMPP, or dedicated local server apps, you are essentially running a miniature data center just to edit a theme or manage content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lucianofedericopereira/mysqlite" rel="noopener noreferrer"&gt;mysqlite&lt;/a&gt; changes the paradigm. It allows you to run WordPress locally using &lt;strong&gt;SQLite&lt;/strong&gt;, meaning no MariaDB, no containers, and no background services. Just PHP and a single database file.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Vision: WordPress as a Portable Folder
&lt;/h2&gt;

&lt;p&gt;The goal of this project isn't necessarily to replace MySQL on high-traffic production servers. Instead, it’s about making WordPress &lt;strong&gt;local-first&lt;/strong&gt; and &lt;strong&gt;ultra-portable&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;This is the perfect setup for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Headless WordPress:&lt;/strong&gt; Use WP as a content API for your local Next.js or Astro dev environment without spinning up a database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static Site Generation (SSG):&lt;/strong&gt; Build your site locally, generate the static HTML, and deploy to GitHub Pages or Netlify.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instant Sandboxing:&lt;/strong&gt; Since the entire site (files + DB) lives in one folder, you can Move, Zip, or Git-commit the entire state of the project instantly.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Technical Achievement: The Nim Translator
&lt;/h2&gt;

&lt;p&gt;Most previous attempts to bring SQLite to WordPress relied on a &lt;code&gt;db.php&lt;/code&gt; drop-in that used PHP's &lt;code&gt;preg_replace&lt;/code&gt; to try and rewrite SQL queries on the fly. These were notoriously fragile because MySQL and SQLite speak very different dialects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;mysqlite&lt;/strong&gt; takes a much more sophisticated, low-level approach using &lt;strong&gt;Nim&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the Nim code actually achieves:
&lt;/h3&gt;

&lt;p&gt;The core of this project is a compiled library written in Nim that acts as a &lt;strong&gt;structural translator&lt;/strong&gt;. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Binary-Level Interception:&lt;/strong&gt; Instead of just swapping text in PHP, it handles the translation at a high-performance level. Nim compiles to C, allowing it to interface directly with system libraries with near-zero latency.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Dialect Mapping:&lt;/strong&gt; MySQL and SQLite handle things like &lt;code&gt;AUTO_INCREMENT&lt;/code&gt;, date formats, and specific index types differently. The Nim logic acts as a "Universal Translator," taking complex MySQL queries and reframing them into valid SQLite logic before they ever touch the disk.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The "Fake" Client:&lt;/strong&gt; It effectively tricks the WordPress core into thinking it is talking to a full-blown MySQL server, while secretly writing everything to a highly optimized local &lt;code&gt;.sqlite&lt;/code&gt; file.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why Nim?&lt;/strong&gt; Using Nim was a strategic choice. It offers the performance of C (required for database-level tasks) but with a much safer, modern syntax that makes complex string manipulation and logic mapping manageable.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why This Beats Containers for Local Dev
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Traditional (Docker/MariaDB)&lt;/th&gt;
&lt;th&gt;mysqlite (Local SQLite)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RAM Usage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Significant (Background services)&lt;/td&gt;
&lt;td&gt;Negligible (PHP only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Start-up Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;10–30 seconds&lt;/td&gt;
&lt;td&gt;Instant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hidden in Volumes/DB Servers&lt;/td&gt;
&lt;td&gt;A single &lt;code&gt;.sqlite&lt;/code&gt; file in your folder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Portability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires Export/Import&lt;/td&gt;
&lt;td&gt;Copy/Paste the folder&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How to Get Started
&lt;/h2&gt;

&lt;p&gt;Since you don't need a database server, the setup is incredibly lean:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Clone the Repo:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/lucianofedericopereira/mysqlite
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start the PHP Server:&lt;/strong&gt;&lt;br&gt;
Navigate to the directory and run:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-S&lt;/span&gt; localhost:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install:&lt;/strong&gt; Open your browser. The installation will proceed normally, but you’ll notice you don't need to create a database or a user in a separate management tool.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;By decoupling WordPress from the requirement of a dedicated database server, we turn the world’s most popular CMS into a lightweight, file-based tool. It bridges the gap between the power of WordPress and the simplicity of flat-file systems.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>sql</category>
      <category>mysql</category>
      <category>nim</category>
    </item>
    <item>
      <title>Vapor Chamber: A Command Bus Built for Vue Vapor</title>
      <dc:creator>Luciano Federico Pereira</dc:creator>
      <pubDate>Mon, 16 Mar 2026 19:53:21 +0000</pubDate>
      <link>https://dev.to/lucianofedericopereira/vapor-chamber-a-command-bus-built-for-vue-vapor-41i</link>
      <guid>https://dev.to/lucianofedericopereira/vapor-chamber-a-command-bus-built-for-vue-vapor-41i</guid>
      <description>&lt;h2&gt;
  
  
  Vapor Chamber: A Command Bus Built for Vue Vapor
&lt;/h2&gt;

&lt;p&gt;Vue Vapor is changing how Vue apps compile. By ditching the Virtual DOM in favor of direct DOM updates using signals, Vapor opens the door for leaner, faster reactivity. &lt;strong&gt;Vapor Chamber&lt;/strong&gt; is a ~2KB command bus designed to match that philosophy: minimal abstraction, predictable data flow, one place to look, debug, and test.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem With Events
&lt;/h2&gt;

&lt;p&gt;The traditional Vue pattern — &lt;code&gt;emit&lt;/code&gt;, &lt;code&gt;v-on&lt;/code&gt;, scattered handlers — works fine for small apps. But as complexity grows, logic fragments across components and tracing a single user action becomes a hunt.&lt;/p&gt;

&lt;p&gt;With events you ask: &lt;em&gt;where did this get handled?&lt;/em&gt;&lt;br&gt;
With a command bus you ask: &lt;em&gt;what does this do?&lt;/em&gt; — and the answer is always one function.&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="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart.add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One semantic action. One handler. One result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;vapor-chamber
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Requires Node &amp;gt;=18 and Vue &amp;gt;=3.5 (peer dependency, optional).&lt;/p&gt;




&lt;h2&gt;
  
  
  Core Concepts
&lt;/h2&gt;

&lt;p&gt;Every command has three parts:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;action&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What to do&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'cart.add'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;target&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What to act on&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;product&lt;/code&gt; object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;payload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Optional extra data&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ quantity: 2 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Results always return a consistent shape:&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="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No exceptions leaking out. No ambiguous returns.&lt;/p&gt;




&lt;h2&gt;
  
  
  Registering Handlers
&lt;/h2&gt;

&lt;p&gt;One action → one handler. That's the contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createCommandBus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vapor-chamber&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCommandBus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart.add&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="nx"&gt;cmd&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="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart.add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cart updated:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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;h2&gt;
  
  
  Plugin System
&lt;/h2&gt;

&lt;p&gt;Plugins are middleware that wrap every dispatch. They run in &lt;strong&gt;priority order&lt;/strong&gt; (highest first), making it easy to compose cross-cutting concerns without touching handler logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;validator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;history&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vapor-chamber&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Validate before execution&lt;/span&gt;
&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;validator&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart.add&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="nx"&gt;cmd&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;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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="kc"&gt;null&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 product ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}))&lt;/span&gt;

&lt;span class="c1"&gt;// Log everything (lowest priority, runs last)&lt;/span&gt;
&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Track undo/redo history&lt;/span&gt;
&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;history&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Built-in Plugins
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plugin&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;logger&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Console logging with action filtering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validator&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pre-execution validation rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;history&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Undo/redo tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;debounce&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delay until activity stops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;throttle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limit execution frequency&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Async Support
&lt;/h2&gt;

&lt;p&gt;Need to hit an API? Use the async bus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createAsyncCommandBus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vapor-chamber&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAsyncCommandBus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.fetch&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;cmd&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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="s2"&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;data&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="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&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;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.fetch&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Batch Dispatching
&lt;/h2&gt;

&lt;p&gt;Run multiple commands as a unit. Stops on the first failure.&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;result&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;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchBatch&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart.clear&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cart&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;order.create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;orderData&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email.send&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&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;h2&gt;
  
  
  Vue Vapor Composables
&lt;/h2&gt;

&lt;p&gt;Vapor Chamber ships with composables built for Vue Vapor's signal-based reactivity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCommandBus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCommandState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCommandHistory&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vapor-chamber&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Access the shared bus (tree-shakeable)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCommandBus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Dispatch with reactive loading/error signals&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;dispatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart.add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// State management via commands&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;state&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCommandState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Undo/redo&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;undo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;canUndo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;canRedo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCommandHistory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Dead Letter Handling
&lt;/h2&gt;

&lt;p&gt;Configure what happens when an unregistered action is dispatched:&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;bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCommandBus&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;onMissing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;    &lt;span class="c1"&gt;// 'error' | 'throw' | 'ignore' | (cmd) =&amp;gt; {}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;createTestBus()&lt;/code&gt; records dispatches without executing handlers — perfect for unit tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createTestBus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vapor-chamber&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTestBus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart.add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatched&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart.add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatched&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  DevTools Integration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setupDevtools&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vapor-chamber&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;setupDevtools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adds a command timeline and inspector panel to Vue DevTools.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Vapor Chamber?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;~2KB gzipped&lt;/strong&gt; — practically free&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full TypeScript support&lt;/strong&gt; out of the box&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework-optional&lt;/strong&gt; — works without Vue too&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predictable&lt;/strong&gt; — consistent result shape everywhere&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testable&lt;/strong&gt; — first-class testing utilities&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;vapor-chamber
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/lucianofedericopereira/vapor-chamber" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/vapor-chamber" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building with Vue Vapor and want your data flow as direct as your DOM updates, give Vapor Chamber a try.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>In Praise of “Hobbyist Languages”: The Unsung Heroes of Software Development</title>
      <dc:creator>Luciano Federico Pereira</dc:creator>
      <pubDate>Thu, 19 Feb 2026 00:38:42 +0000</pubDate>
      <link>https://dev.to/lucianofedericopereira/in-praise-of-hobbyist-languages-the-unsung-heroes-of-software-development-k2c</link>
      <guid>https://dev.to/lucianofedericopereira/in-praise-of-hobbyist-languages-the-unsung-heroes-of-software-development-k2c</guid>
      <description>&lt;p&gt;First published on &lt;a href="https://lucianofedericopereira.github.io/codecraft/code/in-praise-of-hobbyist-languages-the-unsung-heroes-of-software-development/" rel="noopener noreferrer"&gt;design﹢code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It started with a simple message posted to a Usenet group in 1991:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“I’m doing a (free) operating system (just a hobby, won’t be big and professional like GNU) for 386(486) AT clones.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That hobby, of course, was Linux. And its author was Linus Torvalds.&lt;/p&gt;

&lt;p&gt;For decades, some of the most significant and foundational technologies in computing originated in much the same way: as hobbyist projects. In an industry that often glorifies enterprise-scale and corporate backing, it’s easy to forget that the spirit of tinkering—coding for the sheer joy of it—is the true engine of innovation.&lt;/p&gt;

&lt;p&gt;At the same time, you’ve probably heard the phrase &lt;em&gt;“hobbyist language”&lt;/em&gt; tossed around as an insult. The implication is clear: not serious, not professional, not &lt;em&gt;“enterprise‑grade”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;But what if that dismissal gets things completely backward? What if the qualities that make a language beloved by hobbyists are the very signs of a healthy, innovative, and resilient technology?&lt;/p&gt;

&lt;p&gt;Here’s why the hobbyist developer isn’t just a quaint figure of the past, but a vital force for the future of tech.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hobbyists Drive Early Adoption
&lt;/h2&gt;

&lt;p&gt;Before a language or framework becomes &lt;em&gt;“enterprise‑ready”&lt;/em&gt;, hobbyists are already exploring it, pushing its limits, and writing the first tutorials. They adopt new tools not because a manager told them to, but because they’re curious.&lt;/p&gt;

&lt;p&gt;Python, Ruby, and many others grew first through communities of self‑taught developers drawn to their elegance and simplicity. Without production deadlines or corporate constraints, hobbyists provide crucial early feedback and help build the initial momentum that later leads to mainstream adoption.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hobbyists Expand the Talent Pipeline
&lt;/h2&gt;

&lt;p&gt;Where do professional developers come from? Almost always from hobbyists.&lt;/p&gt;

&lt;p&gt;GitHub surveys consistently show that most developers started coding as a hobby. That “side project” on a resume often says more about a person’s potential than any certification. It demonstrates passion, self‑direction, and the ability to learn independently.&lt;/p&gt;

&lt;p&gt;The person who spends their weekend building a Discord bot or automating their home is the same person who will later solve complex problems on a professional team.&lt;/p&gt;

&lt;p&gt;Not every hobbyist becomes a professional developer, and that’s perfectly fine. The kid who spends their weekend running a Minecraft server or coding a 4 K intro doesn’t automatically become a professional DevOps engineer or graphics specialist. But the curiosity, experimentation, and problem‑solving behind those projects are the same traits that often grow into professional skills later on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hobbyists Strengthen Ecosystems
&lt;/h2&gt;

&lt;p&gt;Most of the bug fixes, documentation updates, and useful utilities that professionals use daily come from people coding in their spare time.&lt;/p&gt;

&lt;p&gt;Think about the last time you used npm, pip, or cargo. The vast universe of open‑source libraries you rely on every day is built substantially by people coding in their spare time.&lt;/p&gt;

&lt;p&gt;Bug fixes, documentation updates, small utilities—these contributions form the connective tissue of modern software. They fill the gaps that corporations overlook, and keep ecosystems vibrant, flexible, and resilient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hobbyists Keep Languages Relevant
&lt;/h2&gt;

&lt;p&gt;Why do some platforms or languages thrive for decades while others fade into obscurity? A vibrant hobbyist community is a key differentiator (some as die-hard as the Amiga scene). Languages with a low barrier to entry, like Python and JavaScript, attract a steady stream of newcomers. This creates a virtuous cycle: more beginners lead to more tutorials, more forum questions (and answers), and more community-built tools. This activity keeps a language feeling fresh and relevant, preventing it from becoming a niche tool locked away in an enterprise silo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hobbyists Create Real Innovation
&lt;/h2&gt;

&lt;p&gt;“Serious innovation,” the kind that truly changes the industry, rarely comes from a corporate R&amp;amp;D department. The history of software is a history of side projects that changed the world. The evidence is undeniable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linux&lt;/strong&gt;: Started by Linus Torvald “just for fun.” It now powers the majority of the world’s servers, Android phones, and countless other devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python&lt;/strong&gt;: Created by Guido van Rossum as a project to keep him occupied during a Christmas break.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git&lt;/strong&gt;: Also created by Linus Torvalds to solve his personal problem of managing the Linux kernel source code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ruby on Rails&lt;/strong&gt;: Extracted by David Heinemeier Hansson from the codebase of Basecamp. He open-sourced the framework that would go on to power thousands of startups.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hobbyists Increase Language Visibility
&lt;/h2&gt;

&lt;p&gt;Who writes the tutorials, records the YouTube videos, and answers questions on Stack Overflow? Overwhelmingly, hobbyists.&lt;/p&gt;

&lt;p&gt;This decentralized network of educators and enthusiasts makes new technologies approachable. Their content often matters more for long‑term adoption than any official marketing campaign.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Every time you git push, run a Python script, or spin up a Linux server, you’re standing on the shoulders of hobbyists—past and present.&lt;/p&gt;

&lt;p&gt;So keep your side projects alive. That little script you’re writing to automate a boring task? That weird web app you’re building just because it amused you? Or the impulse to see if you can get Doom running on a kitchen thermometer, a smart toaster, or whatever strange gadget you found in a drawer last weekend—that’s the tradition. That’s the vibe. That’s the whole point.&lt;/p&gt;

&lt;p&gt;Even if your project never becomes the next Linux, it still matters. You’re part of the lineage that built this industry-and the lineage that will keep it moving.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>community</category>
      <category>motivation</category>
      <category>career</category>
    </item>
    <item>
      <title>Code Quality: CQ Risk‑Weighted Assessment Mode</title>
      <dc:creator>Luciano Federico Pereira</dc:creator>
      <pubDate>Wed, 11 Feb 2026 06:00:06 +0000</pubDate>
      <link>https://dev.to/lucianofedericopereira/code-quality-cq-risk-weighted-assessment-mode-4p72</link>
      <guid>https://dev.to/lucianofedericopereira/code-quality-cq-risk-weighted-assessment-mode-4p72</guid>
      <description>&lt;h3&gt;
  
  
  1. The Philosophy: Reality vs. Compliance
&lt;/h3&gt;

&lt;p&gt;In a regulated payment environment, &lt;strong&gt;Code Quality (CQ)&lt;/strong&gt; is often a tug-of-war between two worlds: the &lt;strong&gt;Engineering Reality&lt;/strong&gt; (the daily developer experience) and &lt;strong&gt;KPI Governance&lt;/strong&gt; (the metrics required by regulators like PCI-DSS, PSD2, or ISO 27001).&lt;/p&gt;

&lt;p&gt;My approach is to bridge this gap. I do not view quality as a "one-size-fits-all" metric. Instead, I use a &lt;strong&gt;Risk-Weighted Scoring Model&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This model acknowledges a hard truth: in payments, a security breach is an existential threat, while a latency spike is merely a degraded experience. Therefore, we do not chase "clean code" in a vacuum; we prioritize the metrics that protect the business license and the user’s funds.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Core Thesis:&lt;/strong&gt; "Speed is a feature; Security is a prerequisite. We can scale to fix performance, but we cannot scale to fix a data breach."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. The Strategy: Risk-Based Weighting
&lt;/h3&gt;

&lt;p&gt;We align our engineering standards with our regulatory environment. The following weighting model ensures that a system cannot achieve a "Passing" grade if it is fast but insecure.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Weight (PCI-DSS Context)&lt;/th&gt;
&lt;th&gt;Why this weight?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;40% - 45%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Highest Risk.&lt;/strong&gt; Non-negotiable for ISO 27001/PCI-DSS. Vulnerabilities here end the business.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Integrity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;20% - 25%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Financial Risk.&lt;/strong&gt; Prevents fraud, double-spending, and data tampering.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reliability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15% - 20%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Operational Risk.&lt;/strong&gt; Uptime and error handling must be deterministic.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5% - 10%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;User Experience.&lt;/strong&gt; Important, but secondary to the safety of funds.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Refined Scoring Formula
&lt;/h3&gt;

&lt;p&gt;To avoid arbitrary grading, each metric is &lt;strong&gt;normalized&lt;/strong&gt; onto a shared 0–100 scale. This lets us compare apples to oranges—latency, error rates, security findings—without smuggling in hidden biases.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Normalization Model&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For any metric where &lt;strong&gt;lower is better&lt;/strong&gt; (latency, error count, etc.):&lt;br&gt;
$$&lt;br&gt;
[ \text{Score} = \max\left(0,; 100 \cdot \left(1 - \frac{\text{Actual} - \text{Target}}{\text{Target}}\right)\right) ]&lt;br&gt;
$$&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hitting the target → &lt;strong&gt;100&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Missing the target by 10% → &lt;strong&gt;90&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Missing the target by 50% → &lt;strong&gt;50&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Catastrophic misses bottom out at &lt;strong&gt;0&lt;/strong&gt;, not negative values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps the scoring intuitive and prevents a single bad metric from dominating the entire risk profile.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Example&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A service has a &lt;strong&gt;P95 latency target of 150ms&lt;/strong&gt; but is currently at &lt;strong&gt;220ms&lt;/strong&gt;.&lt;br&gt;
$$&lt;br&gt;
[ \text{Score} = 100 \cdot \left(1 - \frac{220 - 150}{150}\right) = 100 \cdot (1 - 0.4667) = 53.3 ]&lt;br&gt;
$$&lt;br&gt;
Rounded → &lt;strong&gt;53&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If this metric carries a &lt;strong&gt;5% weight&lt;/strong&gt;, its contribution to the overall score is:&lt;br&gt;
$$&lt;br&gt;
[ 53 \times 0.05 = 2.65 ]&lt;br&gt;
$$&lt;br&gt;
&lt;strong&gt;This keeps the signal honest&lt;/strong&gt;: the service &lt;strong&gt;i*s slow&lt;/strong&gt;&lt;em&gt;, but the risk impact is proportionate—*unless&lt;/em&gt; high‑weight categories like &lt;strong&gt;Security&lt;/strong&gt; or &lt;strong&gt;Availability&lt;/strong&gt; are also degraded.&lt;/p&gt;

&lt;p&gt;To avoid arbitrary grading, we use &lt;strong&gt;Normalization&lt;/strong&gt;. We convert diverse metrics (&lt;em&gt;milliseconds, vulnerability counts, percentages&lt;/em&gt;) into a shared &lt;strong&gt;0–100&lt;/strong&gt; scale using the formula:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; If a service has a P95 Latency target of &lt;strong&gt;150ms&lt;/strong&gt; but is hitting &lt;strong&gt;220ms&lt;/strong&gt;, the score is &lt;strong&gt;68&lt;/strong&gt;. However, at a &lt;strong&gt;5% weight&lt;/strong&gt;, this impacts the final score by only &lt;strong&gt;3.4 points&lt;/strong&gt;. This allows us to be honest about technical debt without panicking stakeholders, &lt;em&gt;provided&lt;/em&gt; the Security score remains high.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Balance: SLAs, Reality, and Error Budgets
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;SLA&lt;/strong&gt; is a promise to the customer; &lt;strong&gt;Telemetry&lt;/strong&gt; is the engineering truth. We manage the gap between them using &lt;strong&gt;Error Budgets&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Innovation Phase:&lt;/strong&gt; If &lt;strong&gt;Reality &amp;gt; SLA&lt;/strong&gt;, the team has the "budget" to ship features fast and experiment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stabilization Phase:&lt;/strong&gt; If telemetry shows we are drifting near the &lt;strong&gt;SLA Floor&lt;/strong&gt;, the model triggers a pivot. We stop feature work and move engineering effort to debt reduction and hardening.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4. Implementation: Multi-Stack Consistency
&lt;/h3&gt;

&lt;p&gt;In a microservices environment utilizing &lt;strong&gt;Go&lt;/strong&gt;, &lt;strong&gt;FastAPI (Python)&lt;/strong&gt;, and &lt;strong&gt;Symfony/Laravel (PHP)&lt;/strong&gt; on &lt;strong&gt;AWS&lt;/strong&gt;, language consistency is secondary to &lt;strong&gt;Telemetry Consistency&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Stack Strategy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Go (Microservices):&lt;/strong&gt; Focused on high-concurrency throughput.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Quality Gate:&lt;/em&gt; &lt;code&gt;govulncheck&lt;/code&gt; for security, strict &lt;code&gt;context&lt;/code&gt; propagation for tracing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;FastAPI (Data/ML):&lt;/strong&gt; Focused on schema integrity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Quality Gate:&lt;/em&gt; &lt;strong&gt;Pydantic&lt;/strong&gt; for strict input/output validation (Integrity Score).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Symfony/Laravel (BFF/Legacy):&lt;/strong&gt; Focused on business logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Quality Gate:&lt;/em&gt; &lt;strong&gt;PHPStan&lt;/strong&gt; (Level 8+) and structured logging for audit trails.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWS Infrastructure:&lt;/strong&gt; The Unifying Layer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Observability:&lt;/em&gt; &lt;strong&gt;CloudWatch&lt;/strong&gt; and &lt;strong&gt;X-Ray&lt;/strong&gt; ingest normalized JSON logs and Trace IDs from all three languages, providing a single "pane of glass" for system health.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Telemetry: Compliance-Ready Observability
&lt;/h3&gt;

&lt;p&gt;We move beyond "vanity metrics" (like simple uptime) to a maturity model that satisfies &lt;strong&gt;PCI-DSS Requirement 10&lt;/strong&gt; and &lt;strong&gt;PSD2 Auditability&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Telemetry Checklist
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Traceability:&lt;/strong&gt; Every request generates a &lt;strong&gt;Correlation ID&lt;/strong&gt; at the edge, propagated through every Go routine, PHP process, and Python async task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auditability:&lt;/strong&gt; Logs are structured (JSON), immutable, and contain User IDs/Context (without logging PII/Secrets).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrity:&lt;/strong&gt; We monitor for log-tampering and missing telemetry signals.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sample Quality Report: &lt;code&gt;payment-gateway-svc&lt;/code&gt; (Go)
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;This is an example of the model’s output for a production service.&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Metric (Target vs. Actual)&lt;/th&gt;
&lt;th&gt;Score (0-100)&lt;/th&gt;
&lt;th&gt;Weight&lt;/th&gt;
&lt;th&gt;Weighted Contribution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0 Critical Vulns&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;45%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;45.0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Integrity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100% Schema Validation&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;20%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;20.0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reliability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;99.9% Uptime (Actual 99.8%)&lt;/td&gt;
&lt;td&gt;99&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;14.8&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;P95: 150ms (Actual 220ms)&lt;/td&gt;
&lt;td&gt;68&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.4&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Auditability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100% Trace ID Propagation&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15.0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TOTAL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;98.2 / 100 (PASS)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Analysis:&lt;/strong&gt; The service passes because it is secure and auditable. The performance drift (220ms) is noted as technical debt but does not block deployment, as it sits within the Error Budget.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Conclusion
&lt;/h3&gt;

&lt;p&gt;This work shows that Code Quality is a measurable control surface, not an ideal. By weighting Security and Integrity above all else, we align engineering effort with real risk. Telemetry becomes the verification layer that proves our engineering state matches our business commitments.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>security</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Vapor Chamber — A Tiny Command Bus for Vue Vapor (~1KB)</title>
      <dc:creator>Luciano Federico Pereira</dc:creator>
      <pubDate>Thu, 29 Jan 2026 00:12:07 +0000</pubDate>
      <link>https://dev.to/lucianofedericopereira/vapor-chamber-a-tiny-command-bus-for-vue-vapor-1kb-5eeo</link>
      <guid>https://dev.to/lucianofedericopereira/vapor-chamber-a-tiny-command-bus-for-vue-vapor-1kb-5eeo</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fool74q4q8vt2dzuypbty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fool74q4q8vt2dzuypbty.png" alt="Vapor Chamber Logo inspired in Vue" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/lucianofedericopereira/vapor-chamber" rel="noopener noreferrer"&gt;github.com&lt;/a&gt; Package: &lt;a href="https://www.npmjs.com/package/vapor-chamber" rel="noopener noreferrer"&gt;npmjs.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vapor Chamber is a lightweight command bus built for Vue Vapor, Vue’s upcoming compilation mode that removes the Virtual DOM. Vapor compiles templates into direct DOM operations powered by signals, updating only what actually changed.&lt;/p&gt;

&lt;p&gt;Vapor Chamber follows the same philosophy: minimal abstraction, direct updates, signal‑native reactivity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimal Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createCommandBus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vapor-chamber&lt;/span&gt;&lt;span class="dl"&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;bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCommandBus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart.add&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="nx"&gt;cmd&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="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart.add&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Book&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why a Command Bus?
&lt;/h2&gt;

&lt;p&gt;Traditional event systems scatter logic across components. A command bus centralizes it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Event-driven&lt;/strong&gt;: components emit → others listen → logic spreads everywhere&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Command bus&lt;/strong&gt;: dispatch('cart.add', product) → one handler → plugins wrap behavior&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Clear, semantic actions (cart.add &amp;gt; emit('add'))&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One handler per action → easier debugging &amp;amp; testing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plugin pipeline for logging, validation, analytics, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Natural undo/redo via command history&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vue</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>vapor</category>
    </item>
    <item>
      <title>Jinja2TT2: Jinja2 to Template Toolkit Transpiler</title>
      <dc:creator>Luciano Federico Pereira</dc:creator>
      <pubDate>Wed, 28 Jan 2026 05:59:15 +0000</pubDate>
      <link>https://dev.to/lucianofedericopereira/jinja2tt2-jinja2-to-template-toolkit-transpiler-4ge8</link>
      <guid>https://dev.to/lucianofedericopereira/jinja2tt2-jinja2-to-template-toolkit-transpiler-4ge8</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjv5460kzfh490dqi6fx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjv5460kzfh490dqi6fx.png" alt="jinja2tt2 logo a tori and a camel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Perl transpiler that converts Jinja2 templates to Template Toolkit 2 (TT2) syntax.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/lucianofedericopereira/jinja2tt2" rel="noopener noreferrer"&gt;https://github.com/lucianofedericopereira/jinja2tt2&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Description
&lt;/h2&gt;

&lt;p&gt;Jinja2 is deeply integrated with Python, making a direct port impractical. However, since TT2 and Jinja2 share similar concepts and syntax patterns, this transpiler performs a &lt;strong&gt;mechanical translation&lt;/strong&gt; between the two template languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why TT2?
&lt;/h3&gt;

&lt;p&gt;TT2 and Jinja2 share:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Variable interpolation: &lt;code&gt;{{ var }}&lt;/code&gt; maps to &lt;code&gt;[% var %]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Control structures: &lt;code&gt;{% if %}&lt;/code&gt; / &lt;code&gt;{% for %}&lt;/code&gt; map to &lt;code&gt;[% IF %]&lt;/code&gt; / &lt;code&gt;[% FOREACH %]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Filters: &lt;code&gt;{{ name|upper }}&lt;/code&gt; maps to &lt;code&gt;[% name | upper %]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Includes, blocks, and inheritance (conceptually similar)&lt;/li&gt;
&lt;li&gt;Expression grammar close enough to map mechanically&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;No external dependencies beyond core Perl 5.20+.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/lucianofedericopereira/jinja2tt2
&lt;span class="nb"&gt;cd &lt;/span&gt;jinja2tt2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Command Line
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Transpile a file to stdout&lt;/span&gt;
./bin/jinja2tt2 template.j2

&lt;span class="c"&gt;# Transpile with output to file&lt;/span&gt;
./bin/jinja2tt2 template.j2 &lt;span class="nt"&gt;-o&lt;/span&gt; template.tt

&lt;span class="c"&gt;# Transpile in-place (creates .tt file)&lt;/span&gt;
./bin/jinja2tt2 &lt;span class="nt"&gt;-i&lt;/span&gt; template.j2

&lt;span class="c"&gt;# From stdin&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{{ name|upper }}'&lt;/span&gt; | ./bin/jinja2tt2

&lt;span class="c"&gt;# Debug mode (shows tokens and AST)&lt;/span&gt;
./bin/jinja2tt2 &lt;span class="nt"&gt;--debug&lt;/span&gt; template.j2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Programmatic Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Jinja2::&lt;/span&gt;&lt;span class="nv"&gt;TT2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$transpiler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Jinja2::&lt;/span&gt;&lt;span class="nv"&gt;TT2&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;# From string&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$tt2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$transpiler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;transpile&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;{{ user.name|upper }}&lt;/span&gt;&lt;span class="p"&gt;');&lt;/span&gt;
&lt;span class="c1"&gt;# Result: [% user.name.upper %]&lt;/span&gt;

&lt;span class="c1"&gt;# From file&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$tt2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$transpiler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;transpile_file&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;template.j2&lt;/span&gt;&lt;span class="p"&gt;');&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Supported Constructs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Variables
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ foo }}           →  [% foo %]
{{ user.name }}     →  [% user.name %]
{{ items[0] }}      →  [% items.0 %]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Filters
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ name|upper }}              →  [% name.upper %]
{{ name|lower|trim }}         →  [% name.lower.trim %]
{{ items|join(", ") }}        →  [% items.join(', ') %]
{{ name|default("Guest") }}   →  [% (name || 'Guest') %]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conditionals
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% if user %}          →  [% IF user %]
{% elif admin %}       →  [% ELSIF admin %]
{% else %}             →  [% ELSE %]
{% endif %}            →  [% END %]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Loops
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% for item in items %}    →  [% FOREACH item IN items %]
{{ loop.index }}           →  [% loop.count %]
{{ loop.first }}           →  [% loop.first %]
{{ loop.last }}            →  [% loop.last %]
{% endfor %}               →  [% END %]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Blocks and Macros
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% block content %}        →  [% BLOCK content %]
{% endblock %}             →  [% END %]

{% macro btn(text) %}      →  [% MACRO btn(text) BLOCK %]
{% endmacro %}             →  [% END %]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comments
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{# This is a comment #}    →  [%# This is a comment %]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Whitespace Control
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{- name -}}               →  [%- name -%]
{%- if x -%}               →  [%- IF x -%]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Other Constructs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{% include "file.html" %}&lt;/code&gt; → &lt;code&gt;[% INCLUDE file.html %]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{% set x = 42 %}&lt;/code&gt; → &lt;code&gt;[% x = 42 %]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ternary: &lt;code&gt;{{ x if cond else y }}&lt;/code&gt; → &lt;code&gt;[% (cond ? x : y) %]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Boolean literals: &lt;code&gt;true&lt;/code&gt;/&lt;code&gt;false&lt;/code&gt; → &lt;code&gt;1&lt;/code&gt;/&lt;code&gt;0&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Filter Mapping
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Jinja2&lt;/th&gt;
&lt;th&gt;TT2 Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upper&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.upper&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lower&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.lower&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;trim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.trim&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;first&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.first&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;last&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.last&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;length&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.size&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;join&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.join&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reverse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.reverse&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sort&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.sort&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;escape&lt;/code&gt; / &lt;code&gt;e&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;`\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;{% raw %}&lt;code&gt;default&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;`\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;{% raw %}&lt;code&gt;replace&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.replace&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Some filters require TT2 plugins (e.g., &lt;code&gt;tojson&lt;/code&gt; needs &lt;code&gt;Template::Plugin::JSON&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Loop Variable Mapping
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Jinja2&lt;/th&gt;
&lt;th&gt;TT2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;loop.index&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;loop.count&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;loop.index0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;loop.index&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;loop.first&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;loop.first&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;loop.last&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;loop.last&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;loop.length&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;loop.size&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Template inheritance&lt;/strong&gt; (&lt;code&gt;{% extends %}&lt;/code&gt;) requires manual adjustment for TT2's &lt;code&gt;WRAPPER&lt;/code&gt; pattern&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autoescape&lt;/strong&gt; is not directly supported in TT2&lt;/li&gt;
&lt;li&gt;Some filters need custom TT2 plugins or vmethods&lt;/li&gt;
&lt;li&gt;Complex Python expressions may need review&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Running Tests
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prove &lt;span class="nt"&gt;-l&lt;/span&gt; t/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Tokenizer&lt;/strong&gt;: Splits Jinja2 source into tokens (text, variables, statements, comments)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parser&lt;/strong&gt;: Builds an Abstract Syntax Tree (AST) from the token stream&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emitter&lt;/strong&gt;: Walks the AST and generates equivalent TT2 code&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Luciano Federico Pereira&lt;/strong&gt; - Author&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  License
&lt;/h2&gt;

&lt;p&gt;This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) version 2.1 as published by the Free Software Foundation.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>python</category>
    </item>
    <item>
      <title>The Joy Division Effect: How I Learned Programming by Making Waves</title>
      <dc:creator>Luciano Federico Pereira</dc:creator>
      <pubDate>Mon, 26 Jan 2026 22:56:31 +0000</pubDate>
      <link>https://dev.to/lucianofedericopereira/the-joy-division-effect-how-i-learned-programming-by-making-waves-2b6d</link>
      <guid>https://dev.to/lucianofedericopereira/the-joy-division-effect-how-i-learned-programming-by-making-waves-2b6d</guid>
      <description>&lt;p&gt;Exploring how a static pulsar plot from 1970 became the spark that led me to understand Perlin noise, animation, and the beauty of coherent randomness. Turning Unknown Pleasures into moving waves taught me more about programming than any textbook ever did.&lt;/p&gt;

&lt;p&gt;Original Posted on: &lt;br&gt;
&lt;a href="https://lucianofedericopereira.github.io/codecraft/design/the-joy-division-effect-how-i-learned-programming-by-making-waves/" rel="noopener noreferrer"&gt;Codecraft blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The original image is a plot of radio pulses from the pulsar CP1919, first published in The Cambridge Encyclopaedia of Astronomy.&lt;/p&gt;

&lt;h2&gt;
  
  
  4K Before 4K
&lt;/h2&gt;

&lt;p&gt;Back then, “4K” didn’t mean ultra‑HD — it meant 4 kilobytes. Tiny intros that somehow squeezed whole worlds of motion, color, and attitude into the space of a modern emoji pack. And somewhere in that neon‑washed universe of pixels pretending to be ultra‑HD, with synth lines stretching into cosmic gradients, one image kept resurfacing in my mind: the waveform from Joy Division’s Unknown Pleasures.&lt;/p&gt;

&lt;p&gt;That stark, minimalist cover showed something I couldn’t unsee — a still image that wanted to move. Those parallel mountain ranges weren’t Perlin noise at all, but stacked plots of radio pulses from the pulsar CP1919. Still, to my kid‑programmer brain, they looked like frozen waves begging to be animated, pulsing, breathing.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Stillness to Motion
&lt;/h2&gt;

&lt;p&gt;On my Commodore 64, armed with assembly language and pre‑calculated prime numbers (because true randomness was too expensive), I tried to animate what I saw. Sine waves came first: too perfect, too predictable. Then I tried more complex LFOs, but they still lacked that organic wobble I was chasing.&lt;/p&gt;

&lt;p&gt;Just to be clear, the original CP1919 pulsar plot — the one used on &lt;em&gt;Unknown Pleasures&lt;/em&gt; — does not move. It’s a stack of 80 separate recordings, each one a single rotation of the pulsar. Think of it like 80 screenshots of a repeating signal.&lt;/p&gt;

&lt;p&gt;But what I wanted wasn’t the science — it was the &lt;em&gt;feeling&lt;/em&gt; of those lines coming alive. And to get that, I needed something the real data couldn’t give me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Perlin noise: So 80s.
&lt;/h2&gt;

&lt;p&gt;Years later, I realized I’d been trying to reinvent Perlin noise without knowing it existed. Ken Perlin’s 1983 algorithm for generating natural‑looking textures was exactly what I’d been reaching for: coherent randomness, smooth transitions — the mathematical equivalent of something alive.&lt;/p&gt;

&lt;p&gt;Perlin created his noise function while working on Tron, trying to avoid the rigid, grid‑like look that early CGI couldn’t escape. He later described the method in a paper called An Image Synthesizer, which remains one of the most accurate names ever given to a graphics technique. Between Tron, synth aesthetics, vector graphics, and that title, the only thing missing is The Breakfast Club and you’ve basically assembled the entire 80s in one algorithm.&lt;/p&gt;

&lt;p&gt;The core idea behind Perlin noise is simple: generate variation that isn’t repetitive like a sine wave and isn’t chaotic like pure randomness. It produces values that drift smoothly — exactly the behavior I could never coax out of lookup tables, LFOs, or prime‑indexed hacks. &lt;/p&gt;

&lt;h2&gt;
  
  
  How 1D Perlin Noise Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The one‑dimensional version goes like this:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;take the two integer positions around your input&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;assign each a pseudo‑random gradient&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;compute each gradient’s influence&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;blend the results using a smooth interpolation curve&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That interpolation step is what removes the mechanical edges and creates the “organic” motion the Unknown Pleasures cover hints at.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you understand that, animating the lines becomes straightforward. Each horizontal line samples a slightly different position in the noise field. Each x‑coordinate marches forward through noise space. A height table shapes the silhouette so the lines rise and fall like the original plot. Everything else is just drawing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s Bring in JavaScript
&lt;/h2&gt;

&lt;p&gt;The JavaScript version below keeps only the essentials: a permutation table for repeatable pseudo‑random values, a precomputed fade curve for smooth transitions, and a compact 1D noise function. A height table controls how much each point can move, creating the familiar rise in the center and fall at the edges. Each line reads from a slightly different position in the noise field, and each x‑coordinate steps forward to preserve the tiny spikes and irregularities that make the motion feel alive. Relevant Parts of the Code&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Permutation table&lt;/strong&gt; (perm): &lt;em&gt;A 512‑entry table used to generate repeatable pseudo‑random gradients — the backbone of classic Perlin noise&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fade table (fadeTable): A precomputed smoothing curve. Instead of calculating the fade function every frame, the code looks it up, which is faster and avoids unnecessary floating‑point work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Height table (hTable): _ Defines how tall each line can be at each x‑coordinate. This creates the “mountain” profile: low at the edges, high in the center._&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Noise function (noise(x)): A compact 1D Perlin implementation that: finds the integer cell around x, computes the fractional part, blends the two gradient contributions using the fade curve.The result is a smooth value between 0 and 1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Animation loop (animate()) : _Draws stacked horizontal lines. Each line: samples the noise field with a different offset (this.t + idx * this.step), uses the height table to scale the displacement, and fills and strokes the shape to create the solid Unknown Pleasures look.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key detail is the idx++ inside the inner loop. That increment ensures each x‑coordinate samples a unique position in the noise field, preserving the tiny spikes and irregularities that make the waveform feel alive.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Code Is Doing, Conceptually
&lt;/h2&gt;

&lt;p&gt;In practical terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Initialize noise tables&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build the permutation table, fade curve, and height profile.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For each animation frame: 1) clear the canvas 2) loop over horizontal lines 3)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;for each x‑coordinate, compute a Perlin noise value: 1) multiply it by the height table 2) subtract it from the baseline y‑position 3) draw the resulting shape&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Advance time (this.t += 0.01) This shifts the sampling position in the noise field, creating motion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Request the next frame&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And the animation continues.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s all the algorithm needs: a smooth noise source, a height profile, and a stack of lines sampling the noise field at different offsets.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://lucianofedericopereira.github.io/codecraft/design/the-joy-division-effect-how-i-learned-programming-by-making-waves/" rel="noopener noreferrer"&gt;https://lucianofedericopereira.github.io/codecraft/design/the-joy-division-effect-how-i-learned-programming-by-making-waves/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>🚀 sqltool: A Lightweight Local MySQL/MariaDB Instance Manager (No Containers Needed)</title>
      <dc:creator>Luciano Federico Pereira</dc:creator>
      <pubDate>Thu, 22 Jan 2026 20:49:49 +0000</pubDate>
      <link>https://dev.to/lucianofedericopereira/sqltool-a-lightweight-local-mysqlmariadb-instance-manager-no-containers-needed-203i</link>
      <guid>https://dev.to/lucianofedericopereira/sqltool-a-lightweight-local-mysqlmariadb-instance-manager-no-containers-needed-203i</guid>
      <description>&lt;h2&gt;
  
  
  👉 GitHub repo: &lt;a href="https://github.com/lucianofedericopereira/sqltool" rel="noopener noreferrer"&gt;sqltool&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;If you’ve ever spun up a MySQL or MariaDB database for local development, you’ve probably gone through one of these:&lt;/p&gt;

&lt;p&gt;Pull a heavy Docker image&lt;/p&gt;

&lt;p&gt;Run a container that stays running even when you don’t need it&lt;/p&gt;

&lt;p&gt;Install a system‑wide service that auto‑starts on boot&lt;/p&gt;

&lt;p&gt;Fight with conflicting ports, configs, or leftover data&lt;/p&gt;

&lt;p&gt;For something as simple as “I need a database for this project,” that’s a lot of overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  sqltool takes a different approach.
&lt;/h2&gt;

&lt;p&gt;It’s a tiny, single‑file CLI tool that creates isolated MySQL/MariaDB instances on your machine — without containers, without systemd services, and without touching your global database installation.&lt;/p&gt;

&lt;p&gt;Each project gets its own clean, isolated environment that runs only when you explicitly start it.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧩 What is sqltool?
&lt;/h2&gt;

&lt;p&gt;sqltool is a local MySQL/MariaDB instance manager designed specifically for development workflows. It:&lt;/p&gt;

&lt;p&gt;Runs mysqld directly as your user&lt;/p&gt;

&lt;p&gt;Creates isolated per‑project instances&lt;/p&gt;

&lt;p&gt;Avoids global configuration changes&lt;/p&gt;

&lt;p&gt;Keeps everything inside ~/sql/&lt;/p&gt;

&lt;p&gt;Works on almost any Linux distribution&lt;/p&gt;

&lt;p&gt;Requires no dependencies beyond Perl and MariaDB&lt;/p&gt;

&lt;p&gt;It’s ideal for developers working on multiple projects, microservices, or experiments where each environment needs its own database.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨ Key Features
&lt;/h2&gt;

&lt;p&gt;No containers — no Docker, no Podman, no images to pull&lt;/p&gt;

&lt;p&gt;No system services — nothing auto‑starts, nothing runs in the background&lt;/p&gt;

&lt;p&gt;Isolated instances — each project gets its own data directory, socket, port, and logs&lt;/p&gt;

&lt;p&gt;Simple workflow — add, start, stop, backup, restore, clone&lt;/p&gt;

&lt;p&gt;Multi‑distro support — Debian, Ubuntu, Fedora, Arch, SUSE, Alpine, Void, and more&lt;/p&gt;

&lt;p&gt;Single‑file tool — just copy it and run&lt;/p&gt;

&lt;h2&gt;
  
  
  📦 Requirements
&lt;/h2&gt;

&lt;p&gt;Perl 5 (preinstalled on almost every Linux distro)&lt;/p&gt;

&lt;p&gt;MariaDB or MySQL (auto‑installed if missing)&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Commands Overview
&lt;/h2&gt;

&lt;p&gt;Command Description&lt;br&gt;
add Create new instance&lt;br&gt;
remove  Delete instance + data&lt;br&gt;
start   Start instance&lt;br&gt;
stop    Stop instance&lt;br&gt;
list    List all instances&lt;br&gt;
info    Show details&lt;br&gt;
port    Show port&lt;br&gt;
logs    Show recent logs&lt;br&gt;
backup  Create SQL backup&lt;br&gt;
restore Restore backup&lt;br&gt;
clone   Clone instance&lt;br&gt;
status  Quick status&lt;br&gt;
help    Show help&lt;/p&gt;

&lt;h2&gt;
  
  
  🐧 Supported Linux Distributions
&lt;/h2&gt;

&lt;p&gt;Auto‑detection + auto‑installation works on:&lt;/p&gt;

&lt;p&gt;Debian, Ubuntu, Linux Mint, Pop!_OS, elementary OS&lt;br&gt;
Fedora, RHEL, CentOS, Rocky, AlmaLinux&lt;br&gt;
Arch Linux, Manjaro&lt;br&gt;
openSUSE, SUSE&lt;br&gt;
Alpine Linux&lt;br&gt;
Void Linux&lt;/p&gt;

&lt;p&gt;For other distros, just install MariaDB manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐪 Why Perl?
&lt;/h2&gt;

&lt;p&gt;Because for this kind of tool, Perl hits the sweet spot:&lt;br&gt;
Preinstalled everywhere&lt;br&gt;
No dependency hell&lt;br&gt;
Uses only core modules&lt;br&gt;
Fast startup&lt;br&gt;
Perfect for system tasks&lt;br&gt;
Single‑file distribution&lt;br&gt;
Stable across decades&lt;/p&gt;

&lt;p&gt;Many classic Linux tools are still written in Perl or shell for a reason — they’re reliable, portable, and easy to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  📜 License
&lt;/h2&gt;

&lt;p&gt;LGPL‑2.1 — see source file for details.&lt;/p&gt;

&lt;h2&gt;
  
  
  👤 Author
&lt;/h2&gt;

&lt;p&gt;Luciano Federico Pereira  &lt;/p&gt;

</description>
      <category>mysql</category>
      <category>tooling</category>
      <category>perl</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
