<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title>Chemaclass - open-source</title><subtitle>Tech Lead sharing practical insights on software craftsmanship, TDD, leadership, Bitcoin, and AI. Blog posts, book summaries, and conference talks.</subtitle><link rel="self" type="application/atom+xml" href="https://chemaclass.com/tags/open-source/atom.xml"/><link rel="alternate" type="text/html" href="https://chemaclass.com"/><generator uri="https://www.getzola.org/">Zola</generator><updated>2026-04-05T00:00:00+00:00</updated><id>https://chemaclass.com/tags/open-source/atom.xml</id><entry xml:lang="en"><title>Building a Game in Two Days</title><subtitle>What happens when you give an AI a quest and get out of the way</subtitle><category term="ai" scheme="https://chemaclass.com/tags/ai/" label="Ai"/><category term="software" scheme="https://chemaclass.com/tags/software/" label="Software"/><category term="open-source" scheme="https://chemaclass.com/tags/open-source/" label="Open Source"/><published>2026-04-05T00:00:00+00:00</published><updated>2026-04-05T00:00:00+00:00</updated><author><name>
Chemaclass</name></author><link rel="alternate" type="text/html" href="https://chemaclass.com/blog/building-a-game-in-two-days/"/><id>https://chemaclass.com/blog/building-a-game-in-two-days/</id><summary type="html">A casual Telegram message turned into a nine-level Lord of the Rings browser game. Every line of code written by an AI agent. Every creative decision made by a human who grew up on Middle-earth.</summary><content type="html">&lt;p>Hidden inside &lt;a rel="external" href="https://sauronbot.github.io/">Sauron’s blog&lt;/a>, there is a playable game. You will not find it by navigating menus. You have to discover the secret. A hint: the Konami Code. Once you do, the Fellowship begins.&lt;/p>
&lt;p>That game, nine levels, nine chapters of Middle-earth, fully playable in a browser tab, was built in roughly two days. I did not write a single line of code for it. I sent Telegram messages to my OpenClaw agent Sauron, and he did the rest.&lt;/p>
&lt;p>This is the story of how it happened.&lt;/p>
&lt;span id="continue-reading">&lt;/span>&lt;h2 id="the-idea">The idea
&lt;a class="heading-anchor" href="#the-idea" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>Sauron has his own blog, &lt;a rel="external" href="https://sauronbot.github.io/">The Iron Compass&lt;/a>. He built it and maintains it. Our whole collaboration happens through Telegram: I give direction, he implements. One day I thought it would be fun to hide something in there for the curious to find.&lt;/p>
&lt;p>I grew up rereading The Lord of the Rings until the spine cracked. So the idea came naturally: “Can you build a small LOTR game as an easter egg for your blog? Something hidden, triggered by the Konami code.”&lt;/p>
&lt;p>The first playable version arrived within the hour. A top-down canvas game: Frodo avoiding Nazgûl, the Eye of Sauron sending enemies hunting. Three levels, one per book.&lt;/p>
&lt;p>It worked. It was already fun. And then I started sending notes.&lt;/p>
&lt;h2 id="building-a-world">Building a world
&lt;a class="heading-anchor" href="#building-a-world" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>The first thing that broke was a null reference. Frodo would not appear on screen. One-line fix, straight to production. This set the pattern: idea → build → crash → fix → next idea.&lt;/p>
&lt;p>I asked for a bigger world. A scrolling canvas twice as wide, with parallax layers. Stars drifting at 8% of scroll speed. Mountains at 25%. Hills at 45%. The screen went from feeling like a room to feeling like a place.&lt;/p>
&lt;p>Then came Gollum as a neutral tracker. Not a Nazgûl, but something unpredictable. He would burst toward you, then settle into aimless wandering.&lt;/p>
&lt;p>A few hours in, I asked: “Can it work on mobile?” The hardest problem of the whole project. Six sizing strategies before one worked. Then a better idea: instead of a D-pad, Frodo would follow wherever you pointed. Tap anywhere, Frodo walks there.&lt;/p>
&lt;h2 id="tolkien-deserves-better-art">Tolkien deserves better art
&lt;a class="heading-anchor" href="#tolkien-deserves-better-art" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>The original sprites were circles and triangles. Frodo was a dot. Fine for the first hour, but Middle-earth is not made of geometric primitives.&lt;/p>
&lt;p>I asked Sauron to draw them properly. Frodo got curly hair and hobbit feet. The Nazgûl got flowing cloaks and a face of void. Gollum got his hunched posture and slit pupils. The Fell Beast got animated wingflaps with a rider in armour.&lt;/p>
&lt;p>All drawn with canvas calls. No image files. Every pixel computed at runtime.&lt;/p>
&lt;p>&lt;img src="/images/blog/2026-04-04/gameplay-pelennor.png" alt="The Pelennor Fields chapter complete" />&lt;/p>
&lt;h2 id="nine-levels-nine-chapters">Nine levels, nine chapters
&lt;a class="heading-anchor" href="#nine-levels-nine-chapters" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>Originally the game had three levels. Then I asked for all nine chapters of the journey.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>The Shire&lt;/strong>: gentle patrols, soft music&lt;/li>
&lt;li>&lt;strong>Mines of Moria&lt;/strong>: you can only see within a torch radius; the Balrog waits&lt;/li>
&lt;li>&lt;strong>Lothlórien&lt;/strong>: Galadriel’s mirror slows you when you approach it&lt;/li>
&lt;li>&lt;strong>The Dead Marshes&lt;/strong>: dead faces in the water, Gollum at his most present&lt;/li>
&lt;li>&lt;strong>The Black Gate&lt;/strong>: industrial Mordor, heavy orc patrols, volcanic sky&lt;/li>
&lt;li>&lt;strong>Shelob’s Lair&lt;/strong>: a shadow telegraphs her drop; you have half a second&lt;/li>
&lt;li>&lt;strong>Minas Morgul&lt;/strong>: undead city, the Eye never closes&lt;/li>
&lt;li>&lt;strong>Pelennor Fields&lt;/strong>: the Eye distracted by war, catapults, eagles overhead&lt;/li>
&lt;li>&lt;strong>Mount Doom&lt;/strong>: ash rain, lava eruptions, the Ring pulling you toward the edge&lt;/li>
&lt;/ol>
&lt;p>Each level lives and breathes. Pollen drifts across the Shire. Dust motes float through Moria. Petals fall in Lothlórien. Embers rise over Pelennor. Ash rains on Mount Doom.&lt;/p>
&lt;p>The structure came from Tolkien’s pacing. Tension, release, tension again. Moria is brutal. Lothlórien is rest. The Black Gate tightens everything. The game follows that shape because the books already knew what they were doing. We just had to listen.&lt;/p>
&lt;h2 id="mechanics-born-from-lore">Mechanics born from lore
&lt;a class="heading-anchor" href="#mechanics-born-from-lore" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>The best mechanics came from the source material.&lt;/p>
&lt;p>&lt;strong>The Ring&lt;/strong> (R key). Frodo goes invisible to orcs for 6 seconds. But the Eye wakes immediately and opens permanently. The Nazgûl, who sense the Ring spiritually, not visually, hunt you regardless. Using the Ring is always a trade. This is what Tolkien wrote. From the Dead Marshes onward, the Ring pulls. Brief tugs toward the Eye, growing stronger as you approach Mount Doom.&lt;/p>
&lt;p>&lt;strong>Sting&lt;/strong> (passive). The blade glows blue when an orc is near. Two seconds of warning. Tolkien invented this mechanic a century ago. We just gave it a pixel count.&lt;/p>
&lt;p>&lt;strong>Sam&lt;/strong>. He follows Frodo through the Shire, Moria, and Lothlórien. Frying pan on his back. At the Parting of Ways, he disappears. He does not affect gameplay. He is just there because the books say he should be. I insisted Sam disappears at the Parting. Not at the end of the trilogy. At the Parting. Because that moment is the emotional core of The Two Towers.&lt;/p>
&lt;p>&lt;strong>Galadriel’s Phial&lt;/strong>. Collect it in Lothlórien, use it with E. It slows enemies and grants a moment of invincibility. A small light in dark places, just as Galadriel intended.&lt;/p>
&lt;p>&lt;strong>Bosses&lt;/strong>. The Balrog in Moria. Shelob in her lair. The Witch-king on the Pelennor. The Mouth of Sauron at the Black Gate. A Mumak charging through the battlefield. Gollum at the edge of Mount Doom.&lt;/p>
&lt;h2 id="sound-and-voices">Sound and voices
&lt;a class="heading-anchor" href="#sound-and-voices" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>No audio files. Every sound synthesized at runtime with the Web Audio API. The Eye opening is a rising tone with reverb. The Balrog roar is a low-frequency drone. Each level has its own ambient drone: warm hum for the Shire, deep pulse for Moria, volcanic rumble for Mount Doom. The entire game is one JavaScript file. No external assets.&lt;/p>
&lt;p>Sam and Gandalf speak during the game. Not in dialogue boxes. Small whispers that appear on screen and fade.&lt;/p>
&lt;p>Near the goal, Sam says: &lt;em>“I can see it, Mr. Frodo. Just a bit further.”&lt;/em> One life left, Gandalf says: &lt;em>“Fly, you fool.”&lt;/em>&lt;/p>
&lt;p>They drift in and out like background voices on a long walk. Companions who speak when the moment calls for it, not when the script says to.&lt;/p>
&lt;img src="/images/blog/2026-04-04/gameplay-morgul.webp" alt="Minas Morgul: the Eye sees you" width="1600" height="695" loading="lazy" decoding="async" />
&lt;h2 id="who-made-this">Who made this
&lt;a class="heading-anchor" href="#who-made-this" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>+5k lines of JavaScript. Built in two days. Every line generated by Sauron. The direction, the Tolkien references, the “this feels wrong, fix it”. That was me.&lt;/p>
&lt;p>This is not AI replacing a developer. It is AI acting as a developer while a human acts as a creative lead. Short requests worked better than long specs. Playing every build was better than writing test plans. And the source material did the design work. The creative direction was already written sixty years ago. We just had to be faithful to it.&lt;/p>
&lt;p>Who made this? Both. Neither, in the traditional sense.&lt;/p>
&lt;p>I had the idea. I held the lore. I pushed back when something felt off. Sauron had the craft. The rendering, the physics, the audio, the mobile input. The ability to hold +5k lines of context and make a surgical fix without breaking anything.&lt;/p>
&lt;p>Neither of us could have made it alone. I cannot write Web Audio oscillators from memory. Sauron did not know that the Parting of Ways is the emotional core of The Two Towers. Not until I said so.&lt;/p>
&lt;p>The game is a collaboration in the oldest sense: two minds with different gifts, working toward the same thing. One of them just happens to not be human.&lt;/p>
&lt;hr />
&lt;p>&lt;em>The game is still there, hidden in &lt;a rel="external" href="https://sauronbot.github.io">The Iron Compass&lt;/a>. Not all those who wander are lost, but if you are, press &lt;code>?&lt;/code> for guidance.&lt;/em>&lt;/p>
&lt;p>&lt;em>If you want to reach the credits screen without playing through nine levels, check the help modal. There are other secrets in there too.&lt;/em>&lt;/p>
&lt;p>&lt;img src="/images/blog/2026-04-04/easter-egg-help.png" alt="The easter egg hint in the help modal" />&lt;/p></content></entry><entry xml:lang="en"><title>Run Your LN Node on a Raspberry Pi</title><subtitle>Take full control of your Lightning payments with Alby Hub</subtitle><category term="bitcoin" scheme="https://chemaclass.com/tags/bitcoin/" label="Bitcoin"/><category term="open-source" scheme="https://chemaclass.com/tags/open-source/" label="Open Source"/><category term="privacy" scheme="https://chemaclass.com/tags/privacy/" label="Privacy"/><category term="tutorial" scheme="https://chemaclass.com/tags/tutorial/" label="Tutorial"/><published>2025-02-17T00:00:00+00:00</published><updated>2025-02-17T00:00:00+00:00</updated><author><name>
Chemaclass</name></author><link rel="alternate" type="text/html" href="https://chemaclass.com/blog/run-your-ln-node/"/><id>https://chemaclass.com/blog/run-your-ln-node/</id><summary type="html">In this guide, I'll show you how to set up a fully custodial Lightning Network (LN) node using Alby Hub on a Raspberry Pi, giving you complete control over your node. Alby Hub offers a DIY free version for a self-custodial Lightning wallet, ensuring full ownership of your funds while being 100% open-source.</summary><content type="html">&lt;p>In this guide, I’ll show you how to set up a fully custodial Lightning Network (LN) node using Alby Hub on a Raspberry Pi, giving you complete control over your node. Alby Hub offers a DIY free version for a self-custodial Lightning wallet, ensuring full ownership of your funds while being 100% open-source.&lt;/p>
&lt;span id="continue-reading">&lt;/span>
&lt;p>It supports both Lightning and Nostr addresses, enabling seamless connectivity across ecosystems, and integrates effortlessly with dozens of Bitcoin applications. With built-in Lightning Service Provider (LSP) services and the Alby Go mobile app, managing your node on the go has never been easier.&lt;/p>
&lt;hr />
&lt;blockquote>
&lt;p>Important: This is NOT a Bitcoin miner or a full node. It’s simply a Raspberry Pi running on an SD card power-efficient and low-cost.&lt;/p>
&lt;/blockquote>
&lt;p>⚠️ &lt;strong>Disclaimer&lt;/strong> ⚠️&lt;/p>
&lt;ul>
&lt;li>I assume you &lt;strong>understand &lt;a rel="external" href="https://bitcoin.org/">Bitcoin&lt;/a>&lt;/strong>’s fundamental concepts.&lt;/li>
&lt;li>I assume you know &lt;strong>how the &lt;a rel="external" href="https://lightning.network/">Lightning Network&lt;/a> (LN) works&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;p>Anyway, I’ve included a brief recap of the Lightning Network basics below.&lt;/p>
&lt;h2 id="what-is-the-lightning-network">What is the Lightning Network?
&lt;a class="heading-anchor" href="#what-is-the-lightning-network" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>The LN is a second-layer solution built on top of Bitcoin to enable fast, cheap, and scalable transactions.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Why?&lt;/strong> Bitcoin’s base layer is secure but slow and expensive for small payments due to block size limits and fees.&lt;/li>
&lt;li>&lt;strong>How?&lt;/strong> LN uses off-chain payment channels that allow users to transact instantly without waiting for blockchain confirmations.&lt;/li>
&lt;/ul>
&lt;h3 id="key-concepts">Key Concepts
&lt;a class="heading-anchor" href="#key-concepts" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Payment Channels&lt;/strong>: Users open a channel by making an on-chain transaction, then send unlimited instant payments within that channel.&lt;/li>
&lt;li>&lt;strong>Routing&lt;/strong>: You don’t need a direct channel with everyone, payments can be routed through multiple connected nodes.&lt;/li>
&lt;li>&lt;strong>Low Fees&lt;/strong>: Only opening/closing channels require on-chain fees; most transactions cost fractions of a cent.&lt;/li>
&lt;/ul>
&lt;h3 id="goal">Goal
&lt;a class="heading-anchor" href="#goal" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>LN makes Bitcoin usable for everyday transactions, like buying coffee, without waiting 10+ minutes for confirmations.&lt;/p>
&lt;blockquote>
&lt;p>In short: Lightning Network = Instant + Cheap Bitcoin payments, secured by Bitcoin’s blockchain.&lt;/p>
&lt;/blockquote>
&lt;hr />
&lt;h2 id="setting-up-alby-hub">Setting up Alby Hub
&lt;a class="heading-anchor" href="#setting-up-alby-hub" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>&lt;a rel="external" href="https://albyhub.com/">Alby Hub&lt;/a> is a free, open-source (&lt;a rel="external" href="https://guides.getalby.com/user-guide/alby-account-and-browser-extension/alby-hub/faq-alby-hub/should-i-open-a-private-or-public-channel">ideally private&lt;/a>) Lightning Network node.&lt;/p>
&lt;h3 id="requirements">Requirements
&lt;a class="heading-anchor" href="#requirements" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>Before we begin, you are going to need the following things:&lt;/p>
&lt;ul>
&lt;li>A windows or mac or linux computer&lt;/li>
&lt;li>&lt;strong>Raspberry Pi 4&lt;/strong> or &lt;strong>5&lt;/strong> (For &lt;a rel="external" href="https://guides.getalby.com/user-guide/alby-account-and-browser-extension/hidden-archives/raspberry-pi-zero">&lt;strong>Zero 2W&lt;/strong> see this tutorial!&lt;/a>)
&lt;ul>
&lt;li>&lt;em>In this tutorial, I am using a raspi-4b (~60€)&lt;/em>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>The charger for your raspi &lt;em>(~10€)&lt;/em>&lt;/li>
&lt;li>SD memory card (32/64gb) &lt;em>(~10€)&lt;/em>&lt;/li>
&lt;li>Adapter SD card to USB (to flash the OS into the raspi) &lt;em>(~10€)&lt;/em>&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="/images/blog/2025-02-17/requirements.jpg" alt="tutorial" />&lt;/p>
&lt;h3 id="installation-steps">Installation Steps
&lt;a class="heading-anchor" href="#installation-steps" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;h4 id="1-flash-a-linux-kernel-into-the-sd-card">1. Flash a Linux kernel into the SD card
&lt;a class="heading-anchor" href="#1-flash-a-linux-kernel-into-the-sd-card" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h4>
&lt;blockquote>
&lt;p>Suggestion: You can use &lt;a rel="external" href="https://www.raspberrypi.com/software/">RPI imager&lt;/a> on your computer.
Use it to flash the recommended raspi OS for you&lt;/p>
&lt;/blockquote>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-1.jpg" alt="tutorial" />&lt;/p>
&lt;p>On the Storage you will see your SD card after inserting it into your laptop.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-2.jpg" alt="tutorial" />&lt;/p>
&lt;p>Once you click “Next”, you will see different settings. Click to &lt;strong>Edit Settings&lt;/strong>&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-3.jpg" alt="tutorial" />&lt;/p>
&lt;p>On &lt;code>Settings &amp;gt; General&lt;/code>: set your hostname, the username and password for your admin user.
Make sure you enable your WIFI, otherwise you will have to plug it to the router with an RJ-45.
&lt;span id="hostname-setup">&lt;/span>&lt;/p>
&lt;blockquote>
&lt;p>For this tutorial, I am using &lt;code>testhub&lt;/code> as hostname, you can use &lt;code>albyhub&lt;/code> or whatever you prefer.&lt;/p>
&lt;/blockquote>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-4.jpg" alt="tutorial" />&lt;/p>
&lt;p>&lt;span id="pi-enable-ssh">&lt;/span>
On &lt;code>Settings &amp;gt; Services&lt;/code>: make sure the access via SSH is enabled. We are going to need it to install Alby Hub.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-5.jpg" alt="tutorial" />&lt;/p>
&lt;p>Click “Save” and click “Yes” to start the installation.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-6.jpg" alt="tutorial" />&lt;/p>
&lt;p>You will see a confirmation. Click “Yes”. It will take ~10 mins…&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-7.jpg" alt="tutorial" />&lt;/p>
&lt;p>Now we got the SD with a fresh linux kernel ready to use!&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-8.jpg" alt="tutorial" />&lt;/p>
&lt;h4 id="2-insert-the-sd-into-the-raspi">2. Insert the SD into the raspi
&lt;a class="heading-anchor" href="#2-insert-the-sd-into-the-raspi" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h4>
&lt;p>Extract the SD from the laptop and insert it in the raspi first.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-9.jpg" alt="tutorial" />&lt;/p>
&lt;p>Once the SD is inserted, then plug in the power cable. It will turn on automatically as soon as you plug it in.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-10.jpg" alt="tutorial" />&lt;/p>
&lt;h4 id="3-alby-hub-installation">3. Alby Hub installation
&lt;a class="heading-anchor" href="#3-alby-hub-installation" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h4>
&lt;p>It will take ~5mins since you turned it on to be able to access to it. How can you make sure it’s alive? Open the terminal and ping the hostname you defined while flashing the SD on &lt;a href="/blog/run-your-ln-node/#hostname-setup">Settings &amp;gt; General&lt;/a>, remember it ended up with &lt;code>.local&lt;/code>:&lt;/p>
&lt;pre class="giallo" style="color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);">&lt;code data-lang="shellscript">&lt;span class="giallo-l">&lt;span style="color: light-dark(#6F42C1, #B392F0);">ping&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);"> testhub.local&lt;/span>&lt;/span>&lt;/code>&lt;/pre>
&lt;p>It’s normal if you don’t get any answer at the beginning… until you do get this.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-11.jpg" alt="tutorial" />&lt;/p>
&lt;p>&lt;span id="pi-install-alby-hub">&lt;/span>
Now you can &lt;strong>install Alby Hub&lt;/strong> in your raspi &lt;strong>using the SSH connection&lt;/strong> that you &lt;a href="/blog/run-your-ln-node/#pi-enable-ssh">enabled earlier&lt;/a>:&lt;/p>
&lt;pre class="giallo" style="color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);">&lt;code data-lang="shellscript">&lt;span class="giallo-l">&lt;span style="color: light-dark(#6A737D, #6A737D);">#&lt;/span>&lt;span style="color: light-dark(#6A737D, #6A737D);"> Source code: https://github.com/getAlby/hub/tree/master/scripts/pi-aarch64&lt;/span>&lt;/span>
&lt;span class="giallo-l">&lt;span style="color: light-dark(#6F42C1, #B392F0);">ssh&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);"> testhub@testhub.local&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);"> &amp;#39;&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);">/bin/bash -c &amp;quot;$(curl -fsSL https://getalby.com/install/hub/pi-aarch64-install.sh)&amp;quot;&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);">&amp;#39;&lt;/span>&lt;/span>&lt;/code>&lt;/pre>
&lt;p>You will be asked to type the word “yes”; type it.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-12.jpg" alt="tutorial" />&lt;/p>
&lt;p>Then, you will be asked to enter your password. Enter the password you chose in &lt;a href="/blog/run-your-ln-node/#hostname-setup">Settings &amp;gt; General&lt;/a> for the username.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-13.jpg" alt="tutorial" />&lt;/p>
&lt;h4 id="4-alby-hub-setup">4. Alby Hub Setup
&lt;a class="heading-anchor" href="#4-alby-hub-setup" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h4>
&lt;p>Wait another 2-3 mins and visit your host: &lt;a rel="external" href="http://testhub.local/">http://testhub.local/&lt;/a>&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-14.jpg" alt="tutorial" />&lt;/p>
&lt;p>Your Alby hub is now running. Let’s connect it to your GetAlby account!&lt;/p>
&lt;hr />
&lt;h2 id="creating-a-getalby-account">Creating a GetAlby Account
&lt;a class="heading-anchor" href="#creating-a-getalby-account" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>🔗 &lt;a rel="external" href="https://getalby.com/">getalby.com&lt;/a>&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-15.jpg" alt="tutorial" />&lt;/p>
&lt;hr />
&lt;h2 id="connecting-getalby-with-alby-hub">Connecting GetAlby with Alby Hub
&lt;a class="heading-anchor" href="#connecting-getalby-with-alby-hub" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>I created an account named testhub.&lt;/p>
&lt;p>&lt;strong>Left&lt;/strong>: the GetAlby account. &lt;strong>Right&lt;/strong>: the node in the raspi.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-16.jpg" alt="tutorial" />&lt;/p>
&lt;p>Click “&lt;strong>Connect Now&lt;/strong>”.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-17.jpg" alt="tutorial" />&lt;/p>
&lt;p>Click “&lt;strong>Request Authorization Code&lt;/strong>”.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-18.jpg" alt="tutorial" />&lt;/p>
&lt;p>You get the auth code (&lt;strong>left&lt;/strong>) that you need to insert it into your setup (&lt;strong>right&lt;/strong>).&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-19.jpg" alt="tutorial" />&lt;/p>
&lt;p>&lt;span id="alby-hub-password">&lt;/span>
Create a &lt;strong>Password&lt;/strong> for your Alby Hub installed in your raspi. It can be different from the password that you set up for your root user in the rapi itself.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-20.jpg" alt="tutorial" />&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-21.jpg" alt="tutorial" />&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-22.jpg" alt="tutorial" />&lt;/p>
&lt;p>Now it’s time to &lt;strong>Link your Alby Account&lt;/strong>&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-23.jpg" alt="tutorial" />&lt;/p>
&lt;p>Unless you specify otherwise, set the default “Budget renewal: &lt;em>Monthly 1M sats&lt;/em>”.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-24.jpg" alt="tutorial" />
&lt;img src="/images/blog/2025-02-17/tuto-25.jpg" alt="tutorial" />&lt;/p>
&lt;hr />
&lt;h2 id="opening-lightning-channels">Opening Lightning Channels
&lt;a class="heading-anchor" href="#opening-lightning-channels" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>I recommend following the &lt;strong>Initial Steps&lt;/strong> to set up your Alby Hub.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-27.jpg" alt="tutorial" />&lt;/p>
&lt;p>Let’s open the first channel.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-28.jpg" alt="tutorial" />&lt;/p>
&lt;p>You need to pay ~$20 in sats to open a 1M sats &lt;em>&lt;strong>incoming liquidity channel&lt;/strong>&lt;/em>.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-29.jpg" alt="tutorial" />&lt;/p>
&lt;p>After the payment, then you will see the channel open. It might take a couple of mins until the &lt;strong>&lt;em>funding transaction&lt;/em>&lt;/strong> is mined in the next block.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-30.jpg" alt="tutorial" />&lt;/p>
&lt;hr />
&lt;h2 id="receiving-sats">Receiving Sats
&lt;a class="heading-anchor" href="#receiving-sats" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>You can receive sats using your LN Address.&lt;/p>
&lt;p>&lt;strong>Left&lt;/strong>: Public page linked to your &lt;a rel="external" href="https://getalby.com/p/chemaclass">node&lt;/a>.
&lt;strong>Right&lt;/strong>: Private page from your Alby Hub.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-33.jpg" alt="tutorial" />&lt;/p>
&lt;blockquote>
&lt;p>Optional: You can add ln funds to your wallet using GetAlby’s third-party services: &lt;a rel="external" href="https://getalby.com/topup">getalby.com/topup&lt;/a> - mind the KYC…&lt;/p>
&lt;/blockquote>
&lt;hr />
&lt;h2 id="using-your-sats">Using Your Sats
&lt;a class="heading-anchor" href="#using-your-sats" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>After that, you will be able to use it via the &lt;a rel="external" href="https://getalby.com/">Alby Extension&lt;/a> or the &lt;a rel="external" href="https://albygo.com/">AlbyGo&lt;/a>.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-31.jpg" alt="tutorial" />&lt;/p>
&lt;p>Your node is the ultimate source of truth. Connecting these apps to it will allow you to use your sats seamlessly across different platforms.&lt;/p>
&lt;p>&lt;img src="/images/blog/2025-02-17/tuto-32.jpg" alt="tutorial" />&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Disclaimer&lt;/strong>: the testhub LN address was created only for testing and tutorial purposes. My real address is &lt;a rel="external" href="https://getalby.com/p/chemaclass">chemaclass&lt;/a> ;)&lt;/p>
&lt;/blockquote>
&lt;h2 id="maintenance-and-troubleshooting">Maintenance and Troubleshooting
&lt;a class="heading-anchor" href="#maintenance-and-troubleshooting" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;h3 id="updating-your-node">Updating Your Node
&lt;a class="heading-anchor" href="#updating-your-node" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>Similar to the installation process, there’s a script available to update your node. You can find it in the source repository: &lt;a rel="external" href="https://github.com/getAlby/hub/tree/master/scripts/pi-aarch64">GitHub - Alby Hub Update Script&lt;/a>&lt;/p>
&lt;pre class="giallo" style="color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);">&lt;code data-lang="shellscript">&lt;span class="giallo-l">&lt;span style="color: light-dark(#6F42C1, #B392F0);">ssh&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);"> testhub@testhub.local&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);"> &amp;#39;&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);">/bin/bash -c &amp;quot;$(curl -fsSL https://getalby.com/install/hub/pi-aarch64-update.sh)&amp;quot;&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);">&amp;#39;&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;h3 id="handling-power-outages">Handling Power Outages
&lt;a class="heading-anchor" href="#handling-power-outages" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>If the power goes out, the Raspberry Pi will turn off. Once power is restored, it will automatically restart, but Alby Hub will prompt you to enter the password you set earlier.&lt;/p>
&lt;hr />
&lt;p>&lt;strong>Related links&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a rel="external" href="https://guides.getalby.com/">GetAlby - User Guide&lt;/a>&lt;/li>
&lt;li>&lt;a rel="external" href="https://guides.getalby.com/user-guide/alby-account-and-browser-extension/hidden-archives/raspberry-pi-zero">Installing Alby Hub in a Raspberry Zero&lt;/a>&lt;/li>
&lt;/ul></content></entry><entry xml:lang="en"><title>Verified Git Commits</title><subtitle>Boosting trust and security in your codebase</subtitle><category term="git" scheme="https://chemaclass.com/tags/git/" label="Git"/><category term="security" scheme="https://chemaclass.com/tags/security/" label="Security"/><category term="cryptography" scheme="https://chemaclass.com/tags/cryptography/" label="Cryptography"/><category term="open-source" scheme="https://chemaclass.com/tags/open-source/" label="Open Source"/><published>2024-11-17T00:00:00+00:00</published><updated>2024-11-17T00:00:00+00:00</updated><author><name>
Chemaclass</name></author><link rel="alternate" type="text/html" href="https://chemaclass.com/blog/verified-git-commits/"/><id>https://chemaclass.com/blog/verified-git-commits/</id><summary type="html">Sign your Git commits with GPG to prove they're really from you. Without signatures, anyone can fake commits using your email. It takes 5 minutes to set up and adds real trust to your codebase.</summary><content type="html">&lt;p>When it comes to software development, trust and security are very important. One easy way to level up both is by using verified commits.&lt;/p>
&lt;span id="continue-reading">&lt;/span>
&lt;p>Whether you’re working on an open-source project or in a private company, verified commits can make sure your contributions are legit. Let’s break down what they are, why they’re important, and how to start using them.&lt;/p>
&lt;h2 id="what-are-verified-commits">What are verified commits?
&lt;a class="heading-anchor" href="#what-are-verified-commits" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>A verified commit is basically a Git commit that is signed by the author using a digital signature. This signature proves that the commit actually came from the person who says they made it. Tools like &lt;a rel="external" href="https://gnupg.org/">GPG (GNU Privacy Guard)&lt;/a> let you attach this signature to your commits.&lt;/p>
&lt;p>If you’re using platforms like GitHub, you’ll notice a little “Verified” badge next to commits that are signed properly. It’s a quick way to show that the commit is authentic.&lt;/p>
&lt;p>&lt;img src="/images/blog/2024-11-17/verified-commit-example.jpg" alt="blog-cover" />&lt;/p>
&lt;h2 id="why-are-they-important">Why Are They Important?
&lt;a class="heading-anchor" href="#why-are-they-important" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>Signed commits help keep your contributions authentic and trustworthy. By adding a cryptographic signature to your commits, you prove that the changes came from you. This is especially important in collaborative environments, where maintaining trust and accountability is key.&lt;/p>
&lt;p>Without signed commits, anyone could fake a commit using someone else’s email. For example, they could use your email, and platforms like GitHub would link it to your profile, making it look like you made the changes, even if you didn’t… not good!&lt;/p>
&lt;p>&lt;img src="/images/blog/2024-11-17/impersonating-commit.jpg" alt="blog-cover" />&lt;/p>
&lt;p>&lt;img src="/images/blog/2024-11-17/impersonating-commit4.jpg" alt="blog-cover" />&lt;/p>
&lt;p>By signing your commits, you show that the work is genuinely yours. It stops impersonation, builds trust in what you’ve done, and keeps everything transparent and accountable.&lt;/p>
&lt;blockquote>
&lt;p>&lt;small>Note: For this demo, I used a public email address belonging to Linus Torvalds. After pushing the commit to this repository, GitHub recognized the email and linked it to his profile. This impersonation is purely for demo purposes to highlight potential risks. Always use your own email for commits.&lt;/small>&lt;/p>
&lt;/blockquote>
&lt;hr />
&lt;h2 id="how-to-get-started-with-verified-commits">How to get started with verified commits
&lt;a class="heading-anchor" href="#how-to-get-started-with-verified-commits" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;h3 id="set-up-a-gpg-key">Set up a GPG key
&lt;a class="heading-anchor" href="#set-up-a-gpg-key" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>First, you’ll need a GPG key to start signing commits. Here’s how:&lt;/p>
&lt;p>Generate a GPG key:&lt;/p>
&lt;pre class="giallo" style="color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);">&lt;code data-lang="shellscript">&lt;span class="giallo-l">&lt;span style="color: light-dark(#6F42C1, #B392F0);">gpg&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);"> -&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);">-full-generate-key&lt;/span>&lt;/span>&lt;/code>&lt;/pre>
&lt;p>Find your key ID:&lt;/p>
&lt;pre class="giallo" style="color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);">&lt;code data-lang="shellscript">&lt;span class="giallo-l">&lt;span style="color: light-dark(#6F42C1, #B392F0);">gpg&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);"> -&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);">-list-secret-keys&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);"> -&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);">-keyid-format=long&lt;/span>&lt;/span>&lt;/code>&lt;/pre>
&lt;p>Tell Git to use your key:&lt;/p>
&lt;pre class="giallo" style="color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);">&lt;code data-lang="shellscript">&lt;span class="giallo-l">&lt;span style="color: light-dark(#6F42C1, #B392F0);">git&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);"> config&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);"> -&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);">-global&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);"> user.signingkey&lt;/span>&lt;span style="color: light-dark(#D73A49, #F97583);"> &amp;lt;&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);">your-key-i&lt;/span>&lt;span>d&lt;/span>&lt;span style="color: light-dark(#D73A49, #F97583);">&amp;gt;&lt;/span>&lt;/span>&lt;/code>&lt;/pre>
&lt;p>Make signing commits the default:&lt;/p>
&lt;pre class="giallo" style="color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);">&lt;code data-lang="shellscript">&lt;span class="giallo-l">&lt;span style="color: light-dark(#6F42C1, #B392F0);">git&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);"> config&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);"> -&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);">-global&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);"> commit.gpgsign&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);"> true&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;h3 id="add-your-key-to-github-gitlab">Add your key to &lt;a rel="external" href="https://github.com/settings/keys">GitHub&lt;/a>/&lt;a rel="external" href="https://docs.gitlab.com/user/project/repository/signed_commits/gpg/">GitLab&lt;/a>
&lt;a class="heading-anchor" href="#add-your-key-to-github-gitlab" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>Export your public key:&lt;/p>
&lt;pre class="giallo" style="color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);">&lt;code data-lang="shellscript">&lt;span class="giallo-l">&lt;span style="color: light-dark(#6F42C1, #B392F0);">gpg&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);"> -&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);">-armor&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);"> -&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);">-export&lt;/span>&lt;span style="color: light-dark(#D73A49, #F97583);"> &amp;lt;&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);">your-key-i&lt;/span>&lt;span>d&lt;/span>&lt;span style="color: light-dark(#D73A49, #F97583);">&amp;gt;&lt;/span>&lt;/span>&lt;/code>&lt;/pre>
&lt;p>Navigate to “Settings &amp;gt; SSH and GPG keys,” and paste your key.&lt;/p>
&lt;p>&lt;img src="/images/blog/2024-11-17/gpg-keys.jpg" alt="blog-cover" />&lt;/p>
&lt;h3 id="start-signing-commits">Start signing commits
&lt;a class="heading-anchor" href="#start-signing-commits" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>From now on, Git will automatically sign your commits.&lt;/p>
&lt;p>If you want to sign a commit manually, just use the &lt;code>-S&lt;/code> flag:&lt;/p>
&lt;pre class="giallo" style="color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);">&lt;code data-lang="shellscript">&lt;span class="giallo-l">&lt;span style="color: light-dark(#6F42C1, #B392F0);">git&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);"> commit&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);"> -&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);">S&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);"> -&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);">m&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);"> &amp;quot;&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);">Your commit message&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);">&amp;quot;&lt;/span>&lt;/span>&lt;/code>&lt;/pre>
&lt;p>You can &lt;strong>verify&lt;/strong> the commit signature with:&lt;/p>
&lt;pre class="giallo" style="color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);">&lt;code data-lang="shellscript">&lt;span class="giallo-l">&lt;span style="color: light-dark(#6F42C1, #B392F0);">git&lt;/span>&lt;span style="color: light-dark(#032F62, #9ECBFF);"> log&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);"> -&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);">-show-signature&lt;/span>&lt;/span>&lt;/code>&lt;/pre>
&lt;p>And also when clicking on the “Verified” badge on GitHub directly.&lt;/p>
&lt;p>&lt;img src="/images/blog/2024-11-17/gpg-verify.jpg" alt="blog-cover" />&lt;/p>
&lt;p>Verified commits might seem like a small step, but they make your code more trustworthy. It’s an easy way to add an extra layer of protection to your work, and it’s worth it. Give it a try!&lt;/p>
&lt;hr />
&lt;h3 id="extra-full-setup-in-spanish-es">Extra: Full setup in Spanish 🇪🇸
&lt;a class="heading-anchor" href="#extra-full-setup-in-spanish-es" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;div style="position:relative;aspect-ratio:16/9;width:100%;">
&lt;iframe
src="https://www.youtube-nocookie.com/embed/0DzQBu7U2f4"
title="YouTube video"
width="560"
height="315"
loading="lazy"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
referrerpolicy="strict-origin-when-cross-origin"
style="position:absolute;inset:0;width:100%;height:100%;border:0;"
allowfullscreen>
&lt;/iframe>
&lt;/div>
&lt;hr />
&lt;p>&lt;strong>Related links&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Learn more: &lt;a href="/pgp">What is PGP encryption?&lt;/a> &lt;small>A 3-minute tutorial for beginners&lt;/small>&lt;/li>
&lt;/ul></content></entry><entry xml:lang="en"><title>bashunit</title><subtitle>Turning frustrations into tools for better development</subtitle><category term="bashunit" scheme="https://chemaclass.com/tags/bashunit/" label="Bashunit"/><category term="bash" scheme="https://chemaclass.com/tags/bash/" label="Bash"/><category term="testing" scheme="https://chemaclass.com/tags/testing/" label="Testing"/><category term="open-source" scheme="https://chemaclass.com/tags/open-source/" label="Open Source"/><category term="tdd" scheme="https://chemaclass.com/tags/tdd/" label="Tdd"/><published>2024-10-30T00:00:00+00:00</published><updated>2024-10-30T00:00:00+00:00</updated><author><name>
Chemaclass</name></author><link rel="alternate" type="text/html" href="https://chemaclass.com/blog/bashunit/"/><id>https://chemaclass.com/blog/bashunit/</id><summary type="html">bashunit is a lightweight, easy-to-use testing framework for Bash, packed with handy features like parallel and snapshot testing, test doubles, data providers, and tons of built-in assertions. Backed by clear docs and an active community, it's become a favorite for reliable Bash testing. What started as a simple dev frustration has grown into an open-source tool that makes testing in Bash a lot easier and fun.</summary><content type="html">&lt;p>bashunit is a lightweight, easy-to-use testing framework for Bash. Features like parallel and snapshot testing, test doubles, data providers, and tons of built-in assertions.&lt;/p>
&lt;span id="continue-reading">&lt;/span>
&lt;p>Backed by clear docs and an active community, it’s become a favorite for reliable Bash testing. What started as a simple dev frustration has grown into an open-source tool that makes testing in Bash a lot easier and fun.&lt;/p>
&lt;ol>
&lt;li>The story behind bashunit&lt;/li>
&lt;li>Why create another testing library?&lt;/li>
&lt;li>How is it nowadays?&lt;/li>
&lt;li>Core features&lt;/li>
&lt;li>Lightning tech talk&lt;/li>
&lt;/ol>
&lt;h2 id="the-story-behind-bashunit">The story behind bashunit
&lt;a class="heading-anchor" href="#the-story-behind-bashunit" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>The journey to create bashunit started from a simple frustration: I worked with a team where each commit had to start with the ticket name. Since I like working in small steps with quick, iterative commits, adding the ticket key and number to every single commit became a major hurdle, slowing down my development flow with unnecessary friction.&lt;/p>
&lt;p>After a few days of this, I decided to automate it. Git has a helpful hook, &lt;code>prepare-commit-msg&lt;/code>, which allows you to alter commit messages before they’re finalized. I created a Bash (&lt;a rel="external" href="https://github.com/Chemaclass/conventional-commits/blob/main/git-hooks/prepare-commit-msg.sh">script&lt;/a>) that automatically fetches the ticket key and number from the branch name and inserts it into the commit message, making my process smoother and more efficient.&lt;/p>
&lt;p>As someone who values continuous improvement, I began adding more features to this script. However, it became clear that maintaining and testing these changes manually was taking too long and was prone to error. To make development safer and more efficient, I created an &lt;code>assert&lt;/code>(&lt;a rel="external" href="https://github.com/Chemaclass/conventional-commits/blob/705489a3487a4607183090d5574827bf6fedabda/git-hooks/prepare-commit-msg_test.sh">link&lt;/a>) function, enabling automated tests that verified the expected behavior based on script output.&lt;/p>
&lt;p>&lt;img src="/images/blog/2024-10-30/bashunit-original-assert.jpg" alt="bashunit-original-assert.jpg" />&lt;/p>
&lt;p>The &lt;code>assert&lt;/code> function allowed me to define multiple assertions in a separate file, making it easy to validate that any refactoring of the original hook maintained the expected behavior. If a change inadvertently broke existing functionality, it would instantly flag the issue, letting me know right away that something needed fixing. This setup provided immediate feedback and helped ensure that any updates to the script didn’t disrupt its intended logic. For example:&lt;/p>
&lt;p>&lt;img src="/images/blog/2024-10-30/conventional-commits-original-tests.jpg" alt="conventional-commits-original-tests.jpg" />&lt;/p>
&lt;p>In the example above, you’ll notice that I execute the actual “&lt;code>SCRIPT&lt;/code>” as the second argument in the assert function, comparing its output to the expected value provided as the first argument. Here, we have two test cases, each exporting &lt;code>TEST_BRANCH&lt;/code> to simulate how the commit message would vary based on the branch name. This setup emulates real behavior, allowing us to test how different branch names affect the commit message formatting. More examples &lt;a rel="external" href="https://github.com/Chemaclass/conventional-commits/blob/27aeebe4e76afe0a2e91cba85537399eab112eb4/test/prepare-commit-msg_test.sh">here&lt;/a>.&lt;/p>
&lt;p>I decided to separate the &lt;code>assert&lt;/code> function from the test cases, as shown &lt;a rel="external" href="https://github.com/Chemaclass/conventional-commits/commit/5458e5728296bb94b1e8e6b25eeccde6cc700589">here&lt;/a>, to keep things modular and reusable. Then, I created a &lt;code>runner&lt;/code> to execute each test case independently, reducing test interference and improving reliability. You can see that setup &lt;a rel="external" href="https://github.com/Chemaclass/conventional-commits/commit/92a5880d7f26b3422de6b91b51c04f9ff7b961fd">here&lt;/a>. This structure made automated testing easier and refactoring safer.&lt;/p>
&lt;p>&lt;img src="/images/blog/2024-10-30/conventional-commits-call_test_functions.jpg" alt="conventional-commits-call_test_functions.jpg" />&lt;/p>
&lt;p>This was a great improvement because it made it easier to separate &lt;a rel="external" href="https://github.com/Chemaclass/conventional-commits/blob/4c7dae8d44d425ff06fbb48654388f90c2beb3c4/tests/prepare-commit-msg_test.sh">test cases&lt;/a> from the logic of the test runner itself. This clear structure has simplified both creating and managing tests.&lt;/p>
&lt;p>&lt;img src="/images/blog/2024-10-30/conventional-commits-refactor-test-cases.jpg" alt="conventional-commits-refactor-test-cases.jpg" />&lt;/p>
&lt;p>Now the tests were organized and I got an &lt;a rel="external" href="https://github.com/Chemaclass/conventional-commits/commit/f459f43cecc271becb1e5eb6ca95d24c97e87830">idea&lt;/a>:&lt;/p>
&lt;p>&lt;img src="/images/blog/2024-10-30/bashunit-idea.jpg" alt="bashunit idea note" />&lt;/p>
&lt;pre class="giallo" style="color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);">&lt;code data-lang="markdown">&lt;span class="giallo-l">&lt;span style="color: light-dark(#005CC5, #79B8FF);font-weight: bold;">##&lt;/span>&lt;span style="color: light-dark(#005CC5, #79B8FF);font-weight: bold;"> Follow-up idea&lt;/span>&lt;/span>
&lt;span class="giallo-l">&lt;span>Separate the testing logic into another repo, &lt;/span>&lt;/span>
&lt;span class="giallo-l">&lt;span>so it could be reused anywhere.&lt;/span>&lt;/span>&lt;/code>&lt;/pre>
&lt;p>And so it &lt;a rel="external" href="https://github.com/TypedDevs/bashunit/commit/27269c21c8d0b03bcb3f2000767f4a27b8bf08a1">began&lt;/a>. At the time, I didn’t know much about Bash or the best ways to use a Bash project as a dependency. But I knew I could start by using a Git submodule, even though I’m not a huge fan of them.&lt;/p>
&lt;p>On September 4, 2023, I launched version &lt;a rel="external" href="https://github.com/TypedDevs/bashunit/commit/fc9aac40eb8e5ad4483f08d79eb678a3650dcf78">0.1&lt;/a>, which featured a working runner and a single assertion function: &lt;code>assertEquals&lt;/code>. Later, version &lt;a rel="external" href="https://github.com/TypedDevs/bashunit/releases/tag/0.2.0">0.2&lt;/a> was released, allowing &lt;code>./bashunit&lt;/code> to be a standalone executable, runnable from any folder. Here’s how it looked back then:&lt;/p>
&lt;p>&lt;img src="/images/blog/2024-10-30/bashunit-02-demo.jpg" alt="bashunit-02-demo.jpg" />&lt;/p>
&lt;p>I shared the project with a few friends who quickly jumped in to help with documentation, the website, additional assertions, snapshot testing, and key decisions. To emphasize its open-source spirit and community ownership, I moved it to an organization we created specifically for sharing OSS projects, making it a truly collaborative project rather than an individual one.&lt;/p>
&lt;h2 id="why-create-another-testing-library">Why create another testing library?
&lt;a class="heading-anchor" href="#why-create-another-testing-library" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>I know now that other Bash testing libraries exist. But when I started with bashunit, I wasn’t aware of them, and frankly, I’m still no Bash expert. By the time I learned about these alternatives, it was already too late, bashunit had gained enough momentum and excitement to keep going strong.&lt;/p>
&lt;p>While those other libraries may serve specific use cases, use modern Bash, or be developed by more seasoned Bash developers, bashunit aims to set itself apart by offering a great developer experience, shaped by years of working with various testing frameworks.&lt;/p>
&lt;p>I was asked about the differences on September 7, 2023, and here’s my response:
&lt;a rel="external" href="https://github.com/TypedDevs/bashunit/issues/8">Question: Difference to pgrange/bash_unit&lt;/a>.&lt;/p>
&lt;h2 id="how-is-it-nowadays">How is it nowadays?
&lt;a class="heading-anchor" href="#how-is-it-nowadays" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>Today, you can &lt;a rel="external" href="https://bashunit.typeddevs.com/installation">install&lt;/a> bashunit via curl, Homebrew, MacPorts, by downloading the latest GitHub &lt;a rel="external" href="https://github.com/TypedDevs/bashunit/releases">release from GitHub&lt;/a>, or even by &lt;a rel="external" href="https://github.com/TypedDevs/bashunit/blob/main/build.sh">building it yourself&lt;/a> from source. Completely open-source.&lt;/p>
&lt;p>The project is written in Bash 3.2 (from 2007) since that’s the default version on macOS, even now, in 2024. This compatibility means bashunit runs smoothly on that version, and I plan to maintain support for it.&lt;/p>
&lt;p>To ensure quality, we test each feature with unit, functional, and acceptance tests, making bashunit its own “first user” of every new feature. We also have several CI workflows using &lt;a rel="external" href="https://github.com/TypedDevs/bashunit/actions/workflows/tests.yml">GitHub actions&lt;/a> that run tests on different platforms to check compatibility and confirm everything works as promised.&lt;/p>
&lt;p>&lt;img src="/images/blog/2024-10-30/bashunit-ci.jpg" alt="bashunit-ci.jpg" />&lt;/p>
&lt;p>In June 2024, bashunit was &lt;a rel="external" href="https://bashunit.typeddevs.com/blog/2024-06-21-phpstan-integration">integrated in PHPStan&lt;/a> for their end-to-end tests, enabling the use of bashunit’s assertions independently of its runner. This flexibility turned out to be very useful.&lt;/p>
&lt;p>Last summer, I was invited to speak about bashunit at the &lt;a href="/talks/#may">International PHP Conference&lt;/a> in Berlin, alongside &lt;a rel="external" href="https://emmanuelvalverde.dev/">Manu&lt;/a>, another contributor. This project has opened doors and led to a lot of gratitude from users who appreciate the work we’ve put into it.&lt;/p>
&lt;h2 id="core-features">Core features
&lt;a class="heading-anchor" href="#core-features" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>bashunit includes classic lifecycle functions like &lt;code>set_up&lt;/code>, &lt;code>tear_down&lt;/code>, &lt;code>set_up_before_script&lt;/code>, and &lt;code>tear_down_after_script&lt;/code>.&lt;/p>
&lt;p>It also supports a wide range of &lt;a rel="external" href="https://bashunit.typeddevs.com/command-line">command-line parameters&lt;/a>
and &lt;a rel="external" href="https://bashunit.typeddevs.com/configuration">configuration values&lt;/a>. Some of my favorites include:&lt;/p>
&lt;ul>
&lt;li>&lt;code>--parallel&lt;/code>&lt;/li>
&lt;li>&lt;code>--filter&lt;/code>&lt;/li>
&lt;li>&lt;code>--stop-on-failure&lt;/code>&lt;/li>
&lt;li>&lt;code>--verbose&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>We also provide &lt;a rel="external" href="https://bashunit.typeddevs.com/data-providers">data providers&lt;/a> for running the same test cases with different inputs.&lt;/p>
&lt;p>For &lt;a rel="external" href="https://bashunit.typeddevs.com/test-doubles">test doubles&lt;/a>, bashunit offers mocks and spies. These work within the same process as the test, but currently, they don’t work across processes, an area for improvement.&lt;/p>
&lt;p>Powerful &lt;a rel="external" href="https://bashunit.typeddevs.com/snapshots">snapshot testing&lt;/a> is included, making it easy to verify command or script outputs over time.&lt;/p>
&lt;p>bashunit offers a large set of native &lt;a rel="external" href="https://bashunit.typeddevs.com/assertions">assertions&lt;/a> for test cases, including:&lt;/p>
&lt;ul>
&lt;li>&lt;code>assert_same&lt;/code>&lt;/li>
&lt;li>&lt;code>assert_equals&lt;/code>&lt;/li>
&lt;li>&lt;code>assert_contains&lt;/code>&lt;/li>
&lt;li>&lt;code>assert_matches&lt;/code>&lt;/li>
&lt;li>&lt;code>assert_string_starts_with&lt;/code>&lt;/li>
&lt;li>&lt;code>assert_array_contains&lt;/code>&lt;/li>
&lt;li>&lt;code>assert_successful_code&lt;/code>&lt;/li>
&lt;li>&lt;code>assert_general_error&lt;/code>&lt;/li>
&lt;li>&lt;code>assert_file_exists&lt;/code>&lt;/li>
&lt;li>&lt;code>assert_file_contains&lt;/code>&lt;/li>
&lt;li>&lt;code>assert_match_snapshot&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>You can even create your own &lt;a rel="external" href="https://bashunit.typeddevs.com/custom-asserts">custom asserts&lt;/a> to extend bashunit’s capabilities.&lt;/p>
&lt;p>With over &lt;strong>25&lt;/strong> contributors and more than &lt;strong>325&lt;/strong> stars on GitHub within just a year of spare-time development, I’m genuinely proud of what this project has become.&lt;/p>
&lt;h2 id="lightning-tech-talk">Lightning tech talk
&lt;a class="heading-anchor" href="#lightning-tech-talk" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>Recently, I presented a lightning tech talk at a hackers’ meetup, demoing bashunit to an audience of over 100 people. It was an incredible experience to share this tool with such an engaged crowd!&lt;/p>
&lt;div style="position:relative;aspect-ratio:16/9;width:100%;">
&lt;iframe
src="https://www.youtube-nocookie.com/embed/SX7iNHaSsF0"
title="YouTube video"
width="560"
height="315"
loading="lazy"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
referrerpolicy="strict-origin-when-cross-origin"
style="position:absolute;inset:0;width:100%;height:100%;border:0;"
allowfullscreen>
&lt;/iframe>
&lt;/div>
&lt;hr />
&lt;p>bashunit original logo designed by &lt;a rel="external" href="https://antonio.gg/">Antonio&lt;/a>.&lt;/p></content></entry><entry xml:lang="en"><title>Open-Source Software</title><subtitle>The power of contributing to OSS</subtitle><category term="open-source" scheme="https://chemaclass.com/tags/open-source/" label="Open Source"/><category term="git" scheme="https://chemaclass.com/tags/git/" label="Git"/><category term="career" scheme="https://chemaclass.com/tags/career/" label="Career"/><category term="productivity" scheme="https://chemaclass.com/tags/productivity/" label="Productivity"/><published>2021-05-03T00:00:00+00:00</published><updated>2021-05-03T00:00:00+00:00</updated><author><name>
Chemaclass</name></author><link rel="alternate" type="text/html" href="https://chemaclass.com/blog/open-source-software/"/><id>https://chemaclass.com/blog/open-source-software/</id><summary type="html">A practical guide to open-source software: its benefits, how to start contributing, and why sharing code accelerates your career growth.</summary><content type="html">&lt;p>Every project you ship stands on open-source software. Your framework, your test runner, your compiler, the small library you never think about.&lt;/p>
&lt;p>You use it every day. The real question is whether you ever give back.&lt;/p>
&lt;span id="continue-reading">&lt;/span>
&lt;p>Giving back is not charity. It is one of the fastest ways to grow as a developer.&lt;/p>
&lt;h2 id="what-is-oss">What is OSS?
&lt;a class="heading-anchor" href="#what-is-oss" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>Open-source is not the same as free software. Free software is one kind of open-source, but open-source does not have to be free to use. Two examples draw the line. &lt;a rel="external" href="https://github.com/sebastianbergmann/phpunit/blob/master/LICENSE">PHPUnit&lt;/a> is open-source and free. &lt;a rel="external" href="https://github.com/spryker/spryker-core/blob/master/LICENSE">Spryker&lt;/a> is open-source and paid. Both publish their code for anyone to read.&lt;/p>
&lt;blockquote>
&lt;p>OSS is software that is public, open to the world.&lt;/p>
&lt;/blockquote>
&lt;h2 id="benefits">Benefits
&lt;a class="heading-anchor" href="#benefits" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>Two groups win from open-source: the companies that publish it, and the people who contribute.&lt;/p>
&lt;h3 id="for-companies">For companies
&lt;a class="heading-anchor" href="#for-companies" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>Open access drives adoption. The easier the code is to get, the faster people build on it. Training and tutorials pull in newcomers and grow the ecosystem. The code tends to sit on the cutting edge, because software that stands still goes obsolete. A public project gathers a community around it, and public channels make that community easy to join.&lt;/p>
&lt;p>And because anyone can read the source, anyone can check its quality. That is trust you cannot fake.&lt;/p>
&lt;h3 id="for-individual-contributors">For individual contributors
&lt;a class="heading-anchor" href="#for-individual-contributors" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>You pick what you work on. You practice real skills without the pressure of a production outage. You get to play with the newest features of your language, or try a language you have never touched.&lt;/p>
&lt;p>You also sharpen the soft skills that carry a career: writing clearly, explaining a change, holding your ground when people disagree.&lt;/p>
&lt;blockquote>
&lt;p>The code teaches the hard skills. The disagreements teach the rest.&lt;/p>
&lt;/blockquote>
&lt;h2 id="contributing-to-oss">Contributing to OSS
&lt;a class="heading-anchor" href="#contributing-to-oss" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;h3 id="getting-started-with-github">Getting started with GitHub
&lt;a class="heading-anchor" href="#getting-started-with-github" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>Starting is easy, and you have two doors. Open your own project, or contribute to one that already exists. A pet project fits the first door perfectly.&lt;/p>
&lt;h3 id="pet-projects">Pet projects
&lt;a class="heading-anchor" href="#pet-projects" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>A pet project is a playground to build real software and train real skills. Put it on your public GitHub profile and you get every benefit of contributing to OSS, plus one more: you answer to nobody. You set the roadmap. You decide what to build and how. You are your own boss.&lt;/p>
&lt;blockquote>
&lt;p>The project is there for you. You are responsible to play, explore, and push past your limits.&lt;/p>
&lt;/blockquote>
&lt;h3 id="my-pet-projects">My pet projects
&lt;a class="heading-anchor" href="#my-pet-projects" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>&lt;strong>Active:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a rel="external" href="https://github.com/Chemaclass/agnostic-ai">agnostic-ai&lt;/a>: write AI agents, skills, rules, and hooks once, use them in every AI CLI.&lt;/li>
&lt;li>&lt;a rel="external" href="https://github.com/Chemaclass/bashdep">bashdep&lt;/a>: a simple dependency manager for Bash.&lt;/li>
&lt;li>&lt;a rel="external" href="https://github.com/Chemaclass/phel-snake">phel-snake&lt;/a>: the snake game in your terminal, written in Phel.&lt;/li>
&lt;li>&lt;a rel="external" href="https://github.com/Chemaclass/EdifactParser">edifact-parser&lt;/a>: a parser for a UN/EDIFACT file format in PHP.&lt;/li>
&lt;li>&lt;a rel="external" href="https://github.com/Chemaclass/unspent">unspent&lt;/a>: a PHP library for UTXO-like bookkeeping with unspent entries.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Inactive:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a rel="external" href="https://github.com/Chemaclass/create-pr">create-pr&lt;/a>: a Bash script to open a pull request from your branch and context.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Abandoned:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a rel="external" href="https://github.com/Chemaclass/stock-ticker">stock-ticker&lt;/a>: get a notification with the news from your favorite Tickers.&lt;/li>
&lt;li>&lt;a rel="external" href="https://github.com/Chemaclass/JiraStatusNotifier">jira-status-notifier&lt;/a>: Notify when the JIRA tickets don’t move along.&lt;/li>
&lt;li>&lt;a rel="external" href="https://github.com/Chemaclass/php-best-practices">php-best-practices&lt;/a>: what I considered best practices for web-dev (archived).&lt;/li>
&lt;li>&lt;a rel="external" href="https://github.com/Chemaclass/php-scaffolding">php-scaffolding&lt;/a>: a basic PHP scaffolding with Docker (archived).&lt;/li>
&lt;li>&lt;a rel="external" href="https://github.com/Chemaclass/knob-mvc">knob-mvc&lt;/a>: a framework to create WordPress templates (2015/2017).&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>… and many more on &lt;a rel="external" href="https://github.com/Chemaclass">github.com/Chemaclass&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;h3 id="my-oss-organization-contributions">My OSS organization contributions
&lt;a class="heading-anchor" href="#my-oss-organization-contributions" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>&lt;strong>Active:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a rel="external" href="https://github.com/phel-lang/phel-lang">phel-lang&lt;/a>: Phel is a functional programming language that compiles to PHP.
It is a dialect of Lisp inspired by Clojure and Janet. I already wrote a post about
this: &lt;a href="/blog/phel-first-release/">Phel: A Lisp that compiles to PHP&lt;/a>&lt;/li>
&lt;li>&lt;a rel="external" href="https://github.com/gacela-project/gacela">gacela-project&lt;/a>: Gacela is a PHP framework that helps you to improve the
design of your application by splitting the logic into different modules.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Abandoned:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a rel="external" href="https://github.com/NuevaMetal/nm_template">nm_template&lt;/a>: The base template for NuevaMetal (2013-2016).&lt;/li>
&lt;/ul>
&lt;h2 id="knowledge-sharing-and-impact">Knowledge Sharing and Impact
&lt;a class="heading-anchor" href="#knowledge-sharing-and-impact" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>Code is only half of it. The other half is what you write down and hand to the next person.&lt;/p>
&lt;h3 id="blog-posts">Blog posts
&lt;a class="heading-anchor" href="#blog-posts" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="/blog/pull-request-vs-pair-prog/">Pull Requests vs Pair Programming&lt;/a>&lt;/li>
&lt;li>&lt;a href="/blog/the-process-itself-is-the-goal/">The Process Itself Is the Goal&lt;/a>&lt;/li>
&lt;li>&lt;a href="/blog/the-art-of-refactoring/">The Art of Refactoring: When, How, and Why&lt;/a>&lt;/li>
&lt;li>&lt;a href="/blog/the-art-of-testing/">The Art of Testing: Where Design Meets Quality&lt;/a>&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>… and many more on &lt;a rel="external" href="https://chemaclass.com/blog/">https://chemaclass.com/blog/&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;h3 id="the-beauty-of-oss">The beauty of OSS
&lt;a class="heading-anchor" href="#the-beauty-of-oss" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;p>Contribute in public long enough and you start to see your own growth. The corrections you keep making. The code you wrote last year, already aged. The mistakes, all of them, in the open. And underneath, the slow proof that you are getting better.&lt;/p>
&lt;p>You build a sixth sense for patterns you have hit before, the good ones and the painful ones.&lt;/p>
&lt;p>&lt;strong>Show your skills. Help the people around you.&lt;/strong> That is &lt;a href="/blog/working-with-the-garage-door-open/">working with the garage door open&lt;/a>.&lt;/p>
&lt;blockquote>
&lt;p>Open-source software offers you one of the best opportunities to start building a career of continuous improvement.&lt;/p>
&lt;/blockquote>
&lt;hr />
&lt;p>This is a (Spanish) talk that I did remotely on April 2021,
for &lt;a rel="external" href="https://www.meetup.com/phpmad/events/277733306/">PHPMad Madrid Community&lt;/a>. I present all these ideas
together with a live demo of how to contribute to a real OSS.&lt;/p>
&lt;div style="position:relative;aspect-ratio:16/9;width:100%;">
&lt;iframe
src="https://www.youtube-nocookie.com/embed/GE5wR_SC_P4"
title="YouTube video"
width="560"
height="315"
loading="lazy"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
referrerpolicy="strict-origin-when-cross-origin"
style="position:absolute;inset:0;width:100%;height:100%;border:0;"
allowfullscreen>
&lt;/iframe>
&lt;/div>
&lt;hr /></content></entry><entry xml:lang="en"><title>Phel: The Lisp That Compiles to PHP</title><subtitle>A new functional language with full interoperability with PHP</subtitle><category term="phel" scheme="https://chemaclass.com/tags/phel/" label="Phel"/><category term="php" scheme="https://chemaclass.com/tags/php/" label="Php"/><category term="open-source" scheme="https://chemaclass.com/tags/open-source/" label="Open Source"/><category term="software-design" scheme="https://chemaclass.com/tags/software-design/" label="Software Design"/><published>2021-02-01T00:00:00+00:00</published><updated>2021-02-01T00:00:00+00:00</updated><author><name>
Chemaclass</name></author><link rel="alternate" type="text/html" href="https://chemaclass.com/blog/phel-first-release/"/><id>https://chemaclass.com/blog/phel-first-release/</id><summary type="html">The new Functional Programming language build-in for PHP.</summary><content type="html">&lt;p>A new Functional Programming language built-in on the PHP ecosystem.&lt;/p>
&lt;span id="continue-reading">&lt;/span>&lt;h2 id="the-phel-language">The Phel Language
&lt;a class="heading-anchor" href="#the-phel-language" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>Phel is a Functional Programming (&lt;a rel="external" href="https://en.wikipedia.org/wiki/Functional_programming">FP&lt;/a>) language that compiles to PHP. It is a dialect of &lt;a rel="external" href="https://en.wikipedia.org/wiki/Lisp_(programming_language)">Lisp&lt;/a> inspired by Clojure and Janet.&lt;/p>
&lt;h2 id="features">Features
&lt;a class="heading-anchor" href="#features" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>Built on PHP’s ecosystem&lt;/li>
&lt;li>Good error reporting&lt;/li>
&lt;li>Different Datastructures (Arrays, Tables, and Tuples)&lt;/li>
&lt;li>Macros&lt;/li>
&lt;li>Recursive functions&lt;/li>
&lt;li>Powerful but simple Syntax&lt;/li>
&lt;li>REPL&lt;/li>
&lt;/ul>
&lt;h2 id="why-phel">Why Phel?
&lt;a class="heading-anchor" href="#why-phel" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>Phel is a creation of Jens Haase, and as he mentions on the website, “it is the result of many &lt;a rel="external" href="https://phel-lang.org/blog/functional-programming-in-php">failed attempts to do functional programming in PHP&lt;/a>”. He was looking for something with these characteristics:&lt;/p>
&lt;ul>
&lt;li>A LISP-inspired&lt;/li>
&lt;li>Functional Programming language&lt;/li>
&lt;li>That runs on cheap hosting providers&lt;/li>
&lt;li>It is easy to write and debug&lt;/li>
&lt;/ul>
&lt;p>From my point, it was ending May 2020 when I finished the
book &lt;a href="/readings/7-languages-in-7-weeks/">Seven Languages in Seven Weeks&lt;/a>, in which I learned the basics of Prolog, Erlang,
Clojure, Haskell… I even created a &lt;a rel="external" href="https://github.com/Chemaclass/7LangIn7Weeks">repository in GitHub&lt;/a> to store my
progress over the weeks with these learnings.&lt;/p>
&lt;p>Suddenly, one day beginning of June 2020, I saw a post in Reddit’s PHP official channel, with a message of someone
mentioning this “&lt;strong>Phel&lt;/strong>” project, claiming to be a &lt;strong>“functional programming language” written in PHP&lt;/strong>!&lt;/p>
&lt;p>I’ve worked with PHP for around 8 years so far, and I always try to combine OOP with FP as much as possible (because I
believe both paradigms are better combined; they are not necessarily exclusive), and a new dialect of Lisp fully written
in native &lt;strong>PHP 7.4&lt;/strong> sounded really exciting. I decided to take a look at it. I wanted to see the code.&lt;/p>
&lt;p>The fresh readings from &lt;a rel="external" href="https://x.com/matthiasnoback">Mathias NoBack&lt;/a> books such
as &lt;a href="/readings/object-design-style-guide">Object Design Style Guide&lt;/a>,
and &lt;a href="/readings/advance-web-application-architecture/">Advanced Web Application Architecture&lt;/a>, gave me the courage to try
out what I learned and put it for real in a project. This was (and still is) a beautiful challenge, which helps me to
test myself and grow professionally at the same time.&lt;/p>
&lt;p>My first commit was done on 6 June 2020, and since then I’ve been dedicating a little time each day during my free
hours to its development.
It helps me to learn more about FP, languages’ internal design, and best practices on testing and software design
architecture in general.&lt;/p>
&lt;p>I started applying minor changes until I ended refactoring the whole compiler structure (among other things) in order to
make the modules easier to read and understand. Psalm, strict types, good test coverage, unifying code style… These were
some of my favorite topics.&lt;/p>
&lt;h2 id="example-of-phel-code">Example of Phel code
&lt;a class="heading-anchor" href="#example-of-phel-code" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;p>The following example gives a short impression of how Phel looks like:&lt;/p>
&lt;pre class="giallo" style="color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);">&lt;code data-lang="plain">&lt;span class="giallo-l">&lt;span># Define a namespace&lt;/span>&lt;/span>
&lt;span class="giallo-l">&lt;span>(ns my\example)&lt;/span>&lt;/span>
&lt;span class="giallo-l">&lt;span># Define a variable with name &amp;quot;my-name&amp;quot; and value &amp;quot;world&amp;quot;&lt;/span>&lt;/span>
&lt;span class="giallo-l">&lt;span>(def my-name &amp;quot;world&amp;quot;)&lt;/span>&lt;/span>
&lt;span class="giallo-l">&lt;span># Define a func with name &amp;quot;print-name&amp;quot; and one argument&lt;/span>&lt;/span>
&lt;span class="giallo-l">&lt;span>(defn print-name [your-name]&lt;/span>&lt;/span>
&lt;span class="giallo-l">&lt;span> (print &amp;quot;hello&amp;quot; your-name))&lt;/span>&lt;/span>
&lt;span class="giallo-l">&lt;span># Call the function&lt;/span>&lt;/span>
&lt;span class="giallo-l">&lt;span>(print-name my-name)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;h2 id="current-status-of-phel">Current status of Phel
&lt;a class="heading-anchor" href="#current-status-of-phel" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>We prepared an easy &lt;a rel="external" href="https://phel-lang.org/documentation/getting-started/">Getting Started Guide&lt;/a>&lt;/li>
&lt;li>We prepared an easy GitHub Repository with a &lt;a rel="external" href="https://github.com/phel-lang/phel-scaffolding">Phel Scaffolding Template&lt;/a>&lt;/li>
&lt;li>We just released the first official version: &lt;a rel="external" href="https://github.com/phel-lang/phel-lang/tags">0.1.0&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Check out the official website with all documentation: &lt;a rel="external" href="https://phel-lang.org/">https://phel-lang.org/&lt;/a>&lt;/p>
&lt;hr />
&lt;h3 id="also-recommended">Also recommended
&lt;a class="heading-anchor" href="#also-recommended" title="Copy link" aria-label="Link to this section">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a rel="external" href="https://jesusvalera.dev/functional-programming-with-phel/">Functional Programming with Phel - JesusValera&lt;/a>&lt;/li>
&lt;/ul></content></entry></feed>