<?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: Mihai Farcas</title>
    <description>The latest articles on DEV Community by Mihai Farcas (@mihailtd).</description>
    <link>https://dev.to/mihailtd</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%2F142282%2F3789fb4b-f94d-4d22-9546-ffc5576a73ee.png</url>
      <title>DEV Community: Mihai Farcas</title>
      <link>https://dev.to/mihailtd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mihailtd"/>
    <language>en</language>
    <item>
      <title>The $3/Month Enterprise-Ready Automation Stack: Zero-Trust n8n With One Command (n8n, Cloudflare, UpCloud, Pulumi)</title>
      <dc:creator>Mihai Farcas</dc:creator>
      <pubDate>Tue, 07 Apr 2026 17:44:04 +0000</pubDate>
      <link>https://dev.to/mihailtd/the-3month-enterprise-ready-automation-stack-zero-trust-n8n-with-one-command-n8n-cloudflare-556g</link>
      <guid>https://dev.to/mihailtd/the-3month-enterprise-ready-automation-stack-zero-trust-n8n-with-one-command-n8n-cloudflare-556g</guid>
      <description>&lt;p&gt;I run one command and get a fully working n8n instance — HTTPS, zero-trust tunnel, PostgreSQL, the works. One more command and it's all gone. Total cost: $3/month.&lt;/p&gt;

&lt;p&gt;No SSH. No open ports. No clicking around in dashboards.&lt;/p&gt;

&lt;p&gt;Here's exactly how it works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1vykmxq9qm2ni4p4d368.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%2F1vykmxq9qm2ni4p4d368.png" alt=" " width="800" height="121"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem With Self-Hosted Automation
&lt;/h2&gt;

&lt;p&gt;Every self-hosting tutorial I find tells me to do the same thing: open ports 80 and 443, set up Nginx, wrestle with Let's Encrypt, and pray nobody scans my server before I've hardened it.&lt;/p&gt;

&lt;p&gt;Then there's the database. Most n8n guides default to SQLite. It works — until two workflows fire at the same time and the whole thing locks up.&lt;/p&gt;

&lt;p&gt;I don't want to babysit a server. I want to deploy, use it, and tear it down when I'm done. No manual steps. No leftover infrastructure.&lt;/p&gt;

&lt;p&gt;So I built exactly that.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You Get
&lt;/h2&gt;

&lt;p&gt;One &lt;code&gt;pulumi up&lt;/code&gt; command creates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;$3/month UpCloud server&lt;/strong&gt; (1 CPU, 1 GB RAM, 10 GB storage, Ubuntu 24.04)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Cloudflare Tunnel&lt;/strong&gt; — zero-trust, outbound-only connection. No open ports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic HTTPS&lt;/strong&gt; and DDoS protection via Cloudflare's edge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL 18&lt;/strong&gt; for concurrent workflow execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt; running behind the tunnel, accessible at your custom domain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS records&lt;/strong&gt; pointed at the tunnel automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One &lt;code&gt;pulumi destroy&lt;/code&gt; removes everything. Server, tunnel, DNS — gone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0q2ww1w5o606juonx7dd.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%2F0q2ww1w5o606juonx7dd.png" alt=" " width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Zero-Trust Matters Here
&lt;/h2&gt;

&lt;p&gt;Traditional setups expose your server to the internet. You open ports, configure firewalls, manage certificates. Every open port is an attack surface.&lt;/p&gt;

&lt;p&gt;Cloudflare Tunnels flip this model. The &lt;code&gt;cloudflared&lt;/code&gt; daemon on your server creates an outbound-only connection to Cloudflare's network. Traffic flows in reverse:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User → Cloudflare (HTTPS + DDoS) → Tunnel → n8n container&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your server has zero open inbound ports. No firewall rules to manage. No certificates to renew. Cloudflare handles all of it at the edge.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 6-Pillar Stack
&lt;/h2&gt;

&lt;p&gt;Each tool has one job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pulumi&lt;/strong&gt; — Infrastructure as Code. Provisions everything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UpCloud&lt;/strong&gt; — $3/month compute (Frankfurt, DE).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare&lt;/strong&gt; — Zero-trust tunnel + HTTPS + DDoS protection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker&lt;/strong&gt; — Container runtime via Docker Compose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt; — Workflow automation engine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL 18&lt;/strong&gt; — Production database for concurrent execution.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How It Wires Together
&lt;/h2&gt;

&lt;p&gt;The entire deployment is 180 lines of TypeScript. Here's what happens when you run &lt;code&gt;pulumi up&lt;/code&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Pulumi Creates the Cloudflare Tunnel
&lt;/h3&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;tunnel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cloudflare&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ZeroTrustTunnelCloudflared&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;n8n-tunnel&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;accountId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cfAccountId&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="s2"&gt;n8n-tunnel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;configSrc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cloudflare&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tunnelSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base64&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 32-byte random secret gets generated. The tunnel routes traffic from your domain to &lt;code&gt;http://n8n:5678&lt;/code&gt; inside the Docker network.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Tunnel Token Gets Fetched via API
&lt;/h3&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;tunnelToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cloudflare&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getZeroTrustTunnelCloudflaredTokenOutput&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cfAccountId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tunnelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tunnel&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the key trick. Instead of SSHing into the server after boot to inject the token, Pulumi fetches it directly from Cloudflare's API. The token gets baked into the cloud-init script — zero post-deploy steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. DNS Points to the Tunnel
&lt;/h3&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;dnsRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cloudflare&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DnsRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;n8n-dns&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;zoneId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cfZoneId&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="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CNAME&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interpolate&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tunnel&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;.cfargotunnel.com`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;proxied&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A proxied CNAME record. Cloudflare's edge handles TLS termination and DDoS filtering before traffic ever reaches your server.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Cloud-Init Bootstraps the Server
&lt;/h3&gt;

&lt;p&gt;Pulumi builds a cloud-init script that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Installs Docker Engine&lt;/li&gt;
&lt;li&gt;Writes &lt;code&gt;docker-compose.yml&lt;/code&gt; with all secrets baked in&lt;/li&gt;
&lt;li&gt;Writes the tunnel token to &lt;code&gt;.env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Runs &lt;code&gt;docker compose up -d&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The server boots, runs this script, and 60 seconds later n8n is live. No SSH required.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Three Containers, One Compose File
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:18-alpine&lt;/span&gt;
    &lt;span class="c1"&gt;# Health check ensures n8n waits for DB&lt;/span&gt;

  &lt;span class="na"&gt;n8n&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8nio/n8n:latest&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
    &lt;span class="c1"&gt;# Full PostgreSQL config, HTTPS via tunnel&lt;/span&gt;

  &lt;span class="na"&gt;cloudflared&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cloudflare/cloudflared:latest&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tunnel run&lt;/span&gt;
    &lt;span class="c1"&gt;# Token from .env file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PostgreSQL starts first. n8n waits for the health check. &lt;code&gt;cloudflared&lt;/code&gt; connects the tunnel. The Docker network handles service discovery — &lt;code&gt;n8n:5678&lt;/code&gt; just works.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Setup (5 Minutes)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;a href="https://upcloud.com" rel="noopener noreferrer"&gt;UpCloud&lt;/a&gt; account (API credentials)&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://cloudflare.com" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt; account with a domain (API token with Zone:DNS:Edit + Account:Tunnels:Edit)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.pulumi.com/docs/install/" rel="noopener noreferrer"&gt;Pulumi CLI&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;Node.js 18+&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deploy
&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;# Clone and install&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;infra &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Create .env from the template (in the project root)&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; ../.env.example ../.env
&lt;span class="c"&gt;# Edit .env — fill in your API tokens, domain, and Cloudflare IDs&lt;/span&gt;
&lt;span class="c"&gt;# SSH key is auto-detected from ~/.ssh/ (no config needed)&lt;/span&gt;

&lt;span class="c"&gt;# Load env vars and set secrets&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; ../.env &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; +a
pulumi config &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;--secret&lt;/span&gt; postgresPassword &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 16&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
pulumi config &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;--secret&lt;/span&gt; n8nBasicAuthUser &lt;span class="s2"&gt;"admin"&lt;/span&gt;
pulumi config &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;--secret&lt;/span&gt; n8nBasicAuthPassword &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 16&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
pulumi config &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;--secret&lt;/span&gt; n8nEncryptionKey &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 32&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Deploy everything&lt;/span&gt;
pulumi up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Visit &lt;code&gt;https://n8n.yourdomain.com&lt;/code&gt; and log in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tear Down
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pulumi destroy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Server, tunnel, DNS — all removed. Nothing left running. Nothing left billing.&lt;/p&gt;




&lt;h2&gt;
  
  
  What About Persistence?
&lt;/h2&gt;

&lt;p&gt;PostgreSQL data is saved as a Docker volume on the server itself. Your workflows, credentials, and execution history survive container restarts and &lt;code&gt;docker compose down&lt;/code&gt; / &lt;code&gt;up&lt;/code&gt; cycles.&lt;/p&gt;

&lt;p&gt;What they don't survive is &lt;code&gt;pulumi destroy&lt;/code&gt; — that deletes the server and everything on it.&lt;/p&gt;

&lt;p&gt;For production, consider switching to a managed PostgreSQL service (UpCloud, Aiven, Neon) or mounting resilient block storage for the database volume. Either option decouples your data from the server lifecycle.&lt;/p&gt;




&lt;h2&gt;
  
  
  What About n8n Cloud?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://n8n.partnerlinks.io/700yejiez8he" rel="noopener noreferrer"&gt;n8n Cloud&lt;/a&gt; is the easiest way to get started. Managed hosting, automatic updates, built-in auth, and zero infrastructure to think about. If you don't want to manage servers, it's the right choice.&lt;/p&gt;

&lt;p&gt;This self-hosted stack is a different tradeoff. You get full control over the environment — custom domains, your own database, and the ability to spin up or tear down the whole thing in seconds. You also manage the infrastructure.&lt;/p&gt;

&lt;p&gt;Both are valid paths. Pick the one that fits how you work.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Full Lifecycle
&lt;/h2&gt;

&lt;p&gt;Here's the entire flow, start to finish:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You (one-time):&lt;/strong&gt; Fill in a &lt;code&gt;.env&lt;/code&gt; file (API tokens, domain, Cloudflare IDs). Run 4 secret config commands. SSH key is auto-detected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pulumi (automated):&lt;/strong&gt; Creates tunnel → fetches token → configures routes → creates DNS → builds cloud-init → provisions server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server (automated):&lt;/strong&gt; Boots → installs Docker → writes configs → starts containers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; n8n live at your domain with HTTPS, zero-trust networking, and PostgreSQL. No SSH. No open ports. $3/month.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Done?&lt;/strong&gt; &lt;code&gt;pulumi destroy&lt;/code&gt;. Everything gone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvt595qpqhuxayjno9u3.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%2Fkvt595qpqhuxayjno9u3.png" alt=" " width="748" height="1285"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Want to try it?&lt;/strong&gt; The full source code is on &lt;a href="https://github.com/mihailtd/iac-deploy-n8n-upcloud-cloudflare-pulumi" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Clone the repo, set your API keys, and deploy in 5 minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need help with your setup?&lt;/strong&gt; I build and consult on automation infrastructure professionally. Reach out and let's talk about your use case.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>devops</category>
      <category>infrastructureascode</category>
    </item>
    <item>
      <title>Automate Your Homelab Like a Pro with Ansible!</title>
      <dc:creator>Mihai Farcas</dc:creator>
      <pubDate>Wed, 02 Apr 2025 07:02:04 +0000</pubDate>
      <link>https://dev.to/mihailtd/automate-your-homelab-like-a-pro-with-ansible-1f7i</link>
      <guid>https://dev.to/mihailtd/automate-your-homelab-like-a-pro-with-ansible-1f7i</guid>
      <description>&lt;p&gt;Spending too much time manually configuring servers in your homelab? Wish you could automate setup, updates, and deployments reliably? Ansible is a powerful yet simple, agentless automation tool that can tame your infrastructure, whether it's a personal lab or a production environment.&lt;/p&gt;

&lt;p&gt;This article walks through practical examples directly from my latest YouTube video, showing you how to automate Proxmox updates, VM setups, PostgreSQL configuration, and even handle secrets securely with Ansible Vault.&lt;/p&gt;

&lt;p&gt;If you'd rather watch a youtube video than read:&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/NMSCOhK2rqY"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If not, let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Ansible for Your Homelab (and Beyond)?
&lt;/h2&gt;

&lt;p&gt;So, why choose Ansible over manual configurations or complex scripts? Here are a few compelling reasons:&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplicity &amp;amp; Readability
&lt;/h3&gt;

&lt;p&gt;Ansible uses YAML for its playbooks, which is incredibly easy for humans to read and write. You describe the &lt;em&gt;state&lt;/em&gt; you want your systems to be in, rather than scripting every single step. This makes your automation understandable and maintainable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agentless Architecture
&lt;/h3&gt;

&lt;p&gt;This is a huge advantage! You don't need to install or manage special agent software on your servers (nodes). Ansible communicates primarily over standard SSH for Linux/Unix systems (or WinRM for Windows), using Python on the remote end (which is usually already there). This means less setup, less resource overhead, and a smaller attack surface.&lt;/p&gt;

&lt;h3&gt;
  
  
  Idempotency: The Automation Superpower
&lt;/h3&gt;

&lt;p&gt;As highlighted in the video, Ansible operations are typically &lt;em&gt;idempotent&lt;/em&gt;. This means you can run a playbook multiple times, and it will only make changes if needed to reach the desired state. Running it again won't break things or cause unintended side effects. This is absolutely crucial for reliable and predictable automation – run your updates, and only the nodes that need updating get touched!&lt;/p&gt;

&lt;h3&gt;
  
  
  Power &amp;amp; Flexibility ("Batteries Included")
&lt;/h3&gt;

&lt;p&gt;Don't let the simplicity fool you. Ansible comes with a vast library of built-in modules that handle thousands of common tasks – installing packages (&lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;yum&lt;/code&gt;), managing services (&lt;code&gt;service&lt;/code&gt;, &lt;code&gt;systemd&lt;/code&gt;), copying files (&lt;code&gt;copy&lt;/code&gt;), generating configs from templates (&lt;code&gt;template&lt;/code&gt;), managing users (&lt;code&gt;user&lt;/code&gt;), interacting with cloud providers, configuring databases (like PostgreSQL!), and much more. You describe &lt;em&gt;what&lt;/em&gt; you want done, and the module handles the &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started: Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you start automating, you need a couple of things set up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. On Your Control Machine (Where you run Ansible):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Python 3:&lt;/strong&gt; Ansible is built with Python. Make sure you have Python 3 installed. You can check with:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ansible:&lt;/strong&gt; Install Ansible itself. Using &lt;code&gt;pip&lt;/code&gt; (Python's package manager) is often recommended for getting the latest version: &lt;code&gt;pip3 install ansible&lt;/code&gt;. Alternatively, use your OS package manager (like &lt;code&gt;apt&lt;/code&gt; or &lt;code&gt;brew&lt;/code&gt;). Check your installation with:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;(Optional) Ansible VS Code Extension:&lt;/strong&gt; If you use Visual Studio Code, the official Ansible extension by Red Hat provides excellent syntax highlighting and autocompletion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ansible Packages&lt;/strong&gt;: Some Ansible community collections might need to be installed separately using commands like &lt;code&gt;ansible-galaxy collection install community.postgresql&lt;/code&gt; for example.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Access to Your Target Nodes (Your Homelab Servers):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SSH Access:&lt;/strong&gt; Since Ansible is agentless for Linux/Unix, it relies on SSH to connect and execute commands. You need SSH access from your control machine to your homelab servers.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SSH Key Authentication (Recommended):&lt;/strong&gt; For seamless automation, set up SSH key-based authentication so Ansible doesn't need to ask for passwords. The easiest way is to copy your public SSH key (e.g., &lt;code&gt;~/.ssh/id_ed25519.pub&lt;/code&gt;) to your target nodes using &lt;code&gt;ssh-copy-id&lt;/code&gt;. Replace &lt;code&gt;root@&amp;lt;server_ip&amp;gt;&lt;/code&gt; with the appropriate user and IP for each server:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-copy-id &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/id_ed25519.pub root@&amp;lt;your_homelab_server_ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;em&gt;(Note: For Windows targets, Ansible uses WinRM instead of SSH, which requires different setup steps not covered in detail here.)&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Understanding Your Ansible Project: Structure &amp;amp; Core Concepts
&lt;/h2&gt;

&lt;p&gt;A well-structured Ansible project makes automation easier to manage and scale. Here's a typical layout, incorporating the core concepts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your-ansible-project/
├── ansible.cfg         # Project-specific Ansible configuration
├── inventory/          # Defines WHAT servers Ansible manages
│   └── hosts.ini       # Your inventory file(s)
├── playbooks/          # Contains your automation instructions (playbooks)
│   ├── proxmox.yml
│   ├── postgres.yml
│   └── ...
├── vars/               # Stores variables, including secrets
│   ├── common_vars.yml
│   └── secrets.yml     # Encrypted secrets using Ansible Vault
└── roles/              # (Optional) Reusable units of automation (Not covered in detail here)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;[Image: Simple diagram showing this directory structure]&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's break down each part:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;inventory/&lt;/code&gt; (The "What"):&lt;/strong&gt; This directory holds your &lt;strong&gt;Inventory&lt;/strong&gt; file(s) (often &lt;code&gt;hosts.ini&lt;/code&gt; or &lt;code&gt;inventory.yml&lt;/code&gt;). This tells Ansible &lt;em&gt;which&lt;/em&gt; servers (nodes) it should manage. You can list servers individually or group them logically (like &lt;code&gt;[proxmox_nodes]&lt;/code&gt; or &lt;code&gt;[webservers]&lt;/code&gt;). Your script showed an example &lt;code&gt;inventory.ini&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[proxmox_nodes]&lt;/span&gt;
&lt;span class="err"&gt;pve&lt;/span&gt; &lt;span class="py"&gt;ansible_host&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;192.168.31.100&lt;/span&gt;
&lt;span class="err"&gt;srv-1&lt;/span&gt; &lt;span class="py"&gt;ansible_host&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;192.168.31.101&lt;/span&gt;
&lt;span class="err"&gt;srv-2&lt;/span&gt; &lt;span class="py"&gt;ansible_host&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;192.168.31.110 # The new node&lt;/span&gt;

&lt;span class="nn"&gt;[k3s_nodes]&lt;/span&gt;
&lt;span class="err"&gt;k3s-master-1&lt;/span&gt; &lt;span class="py"&gt;ansible_host&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;192.168.31.50 ansible_user=k3s ansible_become_password="{{ k3s_password }}"&lt;/span&gt;
&lt;span class="c"&gt;# ... other nodes ...
&lt;/span&gt;
&lt;span class="nn"&gt;[all:vars]&lt;/span&gt;
&lt;span class="c"&gt;# Global variables can go here
&lt;/span&gt;&lt;span class="py"&gt;ansible_user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;root # Default user if not specified per host/group&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;em&gt;[Note: Variables like &lt;code&gt;ansible_host&lt;/code&gt;, &lt;code&gt;ansible_user&lt;/code&gt;, and group variables (&lt;code&gt;[all:vars]&lt;/code&gt;) can also be defined here.]&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;playbooks/&lt;/code&gt; (The "How"):&lt;/strong&gt; This is where your &lt;strong&gt;Playbooks&lt;/strong&gt; live. Playbooks are written in YAML and define a series of &lt;strong&gt;Tasks&lt;/strong&gt; to be executed on hosts defined in your inventory. Each task typically uses an Ansible &lt;strong&gt;Module&lt;/strong&gt; (the building blocks like &lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;service&lt;/code&gt;, &lt;code&gt;template&lt;/code&gt;, &lt;code&gt;command&lt;/code&gt;, &lt;code&gt;postgresql_user&lt;/code&gt;) to perform a specific action. Remember, good modules are &lt;em&gt;idempotent&lt;/em&gt;. A basic task structure looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Example Play&lt;/span&gt; &lt;span class="c1"&gt;# Descriptive name for the whole play&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;proxmox_nodes&lt;/span&gt; &lt;span class="c1"&gt;# Which group(s) from inventory to target&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# Execute tasks with root privileges (like sudo)&lt;/span&gt;

  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update Proxmox&lt;/span&gt; &lt;span class="c1"&gt;# Descriptive name for this task&lt;/span&gt;
      &lt;span class="na"&gt;apt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# The module being used&lt;/span&gt;
        &lt;span class="na"&gt;update_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt; &lt;span class="c1"&gt;# Module parameters&lt;/span&gt;
        &lt;span class="na"&gt;upgrade&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dist&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;vars/&lt;/code&gt; (The Data &amp;amp; Secrets):&lt;/strong&gt; Store your variables here, separating them from your playbooks for better organization. You can have files for common variables (&lt;code&gt;common_vars.yml&lt;/code&gt;) and crucially, for secrets (&lt;code&gt;secrets.yml&lt;/code&gt;). Never commit plain-text passwords! Use &lt;strong&gt;Ansible Vault&lt;/strong&gt; to encrypt sensitive files:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a new encrypted file&lt;/span&gt;
ansible-vault create vars/secrets.yml

&lt;span class="c"&gt;# Edit an existing encrypted file&lt;/span&gt;
ansible-vault edit vars/secrets.yml

&lt;span class="c"&gt;# Run playbook asking for password&lt;/span&gt;
&lt;span class="c"&gt;# ansible-playbook my_playbook.yml --ask-vault-pass&lt;/span&gt;

&lt;span class="c"&gt;# Or better, use a password file (add vault.pass to .gitignore!)&lt;/span&gt;
ansible-playbook my_playbook.yml &lt;span class="nt"&gt;--vault-password-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./vault.pass
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Your &lt;code&gt;secrets.yml&lt;/code&gt; might contain things like &lt;code&gt;db_password: your_secret_password&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you run &lt;code&gt;ansible-vault create&lt;/code&gt; or &lt;code&gt;edit&lt;/code&gt;, Ansible opens your default text editor (&lt;code&gt;$EDITOR&lt;/code&gt;). Inside the editor, you just write standard YAML key-value pairs with your secrets, like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```yaml
# vars/secrets.yml
# --- This is just plain YAML while you edit! ---
k3s_password: "your_k3s_sudo_password"
app1_db_password: "supersafepassword123"
some_api_key: "xyz789abc123"
some_secret_value: 1234
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once you save and close the editor, Ansible encrypts the content. The actual file on disk becomes unreadable text, which &lt;em&gt;is&lt;/em&gt; safe to commit to version control. This file is encrypted and can be decrypted with the password you picked when creating the vault!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ansible.cfg&lt;/code&gt; (The Settings):&lt;/strong&gt; This optional file defines project-specific Ansible settings, overriding system defaults. Your script mentioned useful settings:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[defaults]&lt;/span&gt;
&lt;span class="py"&gt;inventory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;./inventory/hosts.ini  # Default inventory file location&lt;/span&gt;
&lt;span class="py"&gt;remote_user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;root              # Default user to connect as&lt;/span&gt;
&lt;span class="py"&gt;private_key_file&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;~/.ssh/id_ed25519 # Default SSH key&lt;/span&gt;
&lt;span class="py"&gt;host_key_checking&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;False       # Disable host key checking (use with caution!). Acceptable in trusted homelabs, but avoid in production - Disabling key checking skips verification of the remote host's identity, making you vulnerable to man-in-the-middle attacks.&lt;/span&gt;

&lt;span class="nn"&gt;[privilege_escalation]&lt;/span&gt;
&lt;span class="py"&gt;become&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;True                   # Run tasks with privileges by default&lt;/span&gt;
&lt;span class="py"&gt;become_method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;sudo            # How to gain privileges&lt;/span&gt;
&lt;span class="py"&gt;become_user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;root              # Which user to become&lt;/span&gt;
&lt;span class="py"&gt;become_ask_pass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;False         # Don't ask for sudo password (assumes NOPASSWD)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Organizing your project this way keeps things tidy and makes your automation easier to understand, maintain, and share.&lt;/p&gt;
&lt;h2&gt;
  
  
  Homelab Automation in Action: Examples
&lt;/h2&gt;

&lt;p&gt;Theory is great, but let's see Ansible solve real homelab problems, based on the examples from the YouTube video.&lt;/p&gt;

&lt;p&gt;Before we look at example, do me a solid favor and check out my YouTube Channel, Let's Talk Dev&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.youtube.com/channel/UC_tS0kNJZXkMZn2mRJRTA_g/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyt3.googleusercontent.com%2FRIzr-0Smkmg3dcAmBedb7FDoofVtML0mW5AtG8ixVmh9EDh9E8zPq7toYW243x3PChxCztcSxg%3Ds900-c-k-c0x00ffffff-no-rj" height="900" class="m-0" width="900"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.youtube.com/channel/UC_tS0kNJZXkMZn2mRJRTA_g/" rel="noopener noreferrer" class="c-link"&gt;
            Let's Talk Dev - YouTube
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            I share my insights and tips on software engineering topics such as web development, databases, cloud computing, and more.
Hi, I'm Mihai and I'm a full-stack software engineer with a passion for creating innovative and user-friendly solutions using web and cloud technologies. I have a home lab where I like to experiment with Kubernetes and other cutting-edge technologies. I'm also a big fan of open-source software.
When I'm not coding, I enjoy photography, reading books, learning about finance and entrepreneurship, and watching movies.

          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.youtube.com%2Fs%2Fdesktop%2F5d82a8bc%2Fimg%2Ffavicon.ico" width="16" height="16"&gt;
          youtube.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Who knows, you might find those videos helpful and even &lt;strong&gt;subscribe&lt;/strong&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Fixing Proxmox Subscription Error by Adding the Non-Subscription Repositories
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Dealing with the Proxmox "no subscription" warnings by switching repositories, and keeping all Proxmox nodes consistently updated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; Use Ansible's dedicated &lt;code&gt;apt_repository&lt;/code&gt; module to manage APT sources correctly, and the &lt;code&gt;apt&lt;/code&gt; module for updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Fixing Repositories (using &lt;code&gt;apt_repository&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# playbooks/proxmox_config.yml (Example Snippet)&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Fix Proxmox repository errors by adding the no-subscription repository&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;proxmox_nodes&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;gather_facts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;# Facts not strictly needed for this part&lt;/span&gt;
  &lt;span class="c1"&gt;# vars_files: # Only needed if secrets were used here&lt;/span&gt;
  &lt;span class="c1"&gt;#  - ../vars/secrets.yml&lt;/span&gt;

  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Disable Proxmox enterprise repository&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.apt_repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deb&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[https://enterprise.proxmox.com/debian/pve](https://enterprise.proxmox.com/debian/pve)&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bookworm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pve-enterprise"&lt;/span&gt; &lt;span class="c1"&gt;# Adjust 'bookworm' for your PVE version&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;absent&lt;/span&gt;
        &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pve-enterprise&lt;/span&gt; &lt;span class="c1"&gt;# Explicitly target the correct file&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Add Proxmox no-subscription repository&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.apt_repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deb&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[http://download.proxmox.com/debian/pve](http://download.proxmox.com/debian/pve)&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bookworm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pve-no-subscription"&lt;/span&gt; &lt;span class="c1"&gt;# Adjust 'bookworm'&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;present&lt;/span&gt;
        &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pve-no-subscription&lt;/span&gt; &lt;span class="c1"&gt;# Use a distinct filename&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Disable Proxmox enterprise ceph repository (if applicable)&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.apt_repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deb&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[https://enterprise.proxmox.com/debian/ceph-quincy](https://enterprise.proxmox.com/debian/ceph-quincy)&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bookworm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;enterprise"&lt;/span&gt; &lt;span class="c1"&gt;# Adjust 'quincy'/'bookworm'&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;absent&lt;/span&gt;
        &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ceph-enterprise&lt;/span&gt; &lt;span class="c1"&gt;# Explicitly target the correct file&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Add Proxmox no-subscription ceph repository (if applicable)&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.apt_repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deb&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[http://download.proxmox.com/debian/ceph-quincy](http://download.proxmox.com/debian/ceph-quincy)&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bookworm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;no-subscription"&lt;/span&gt; &lt;span class="c1"&gt;# Adjust 'quincy'/'bookworm'&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;present&lt;/span&gt;
        &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ceph-no-subscription&lt;/span&gt; &lt;span class="c1"&gt;# Use a distinct filename&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update apt cache after repo changes&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.apt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;update_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Explanation:&lt;/em&gt; This automation uses the &lt;code&gt;ansible.builtin.apt_repository&lt;/code&gt; module, which is the idiomatic way to manage APT repositories. &lt;code&gt;state: absent&lt;/code&gt; ensures the enterprise repositories are removed or commented out in their respective files (specified by &lt;code&gt;filename&lt;/code&gt;), while &lt;code&gt;state: present&lt;/code&gt; ensures the no-subscription repositories are added correctly. Finally, &lt;code&gt;apt update_cache: true&lt;/code&gt; refreshes the package list.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Keeping Proxmox up to date!
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Upgrading Proxmox Nodes (&lt;code&gt;upgrade-proxmox.yml&lt;/code&gt; logic):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# playbooks/proxmox_upgrade.yml (Example Snippet)&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upgrade Proxmox Nodes&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;proxmox_nodes&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update apt cache and perform dist-upgrade&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.apt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;update_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt; &lt;span class="c1"&gt;# Good practice before upgrade&lt;/span&gt;
        &lt;span class="na"&gt;upgrade&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dist&lt;/span&gt; &lt;span class="c1"&gt;# Handles kernel/PVE upgrades correctly&lt;/span&gt;
        &lt;span class="na"&gt;autoclean&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt; &lt;span class="c1"&gt;# Clean up downloaded package files&lt;/span&gt;
        &lt;span class="na"&gt;autoremove&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt; &lt;span class="c1"&gt;# Remove unused dependencies&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check if reboot is required&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.stat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/run/reboot-required&lt;/span&gt;
      &lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reboot_required_file&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Reboot the server if required&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.reboot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reboot&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;initiated&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;by&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Ansible&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;due&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;OS&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;updates"&lt;/span&gt;
        &lt;span class="na"&gt;connect_timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
        &lt;span class="na"&gt;reboot_timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600&lt;/span&gt; &lt;span class="c1"&gt;# Wait up to 10 mins for reboot&lt;/span&gt;
        &lt;span class="na"&gt;pre_reboot_delay&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
        &lt;span class="na"&gt;post_reboot_delay&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="c1"&gt;# Wait 30s after reboot before continuing&lt;/span&gt;
        &lt;span class="na"&gt;test_command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;uptime&lt;/span&gt; &lt;span class="c1"&gt;# Command to test if server is back up&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reboot_required_file.stat.exists&lt;/span&gt; &lt;span class="c1"&gt;# Only reboot if flag file exists&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Explanation:&lt;/em&gt; This automation uses the &lt;code&gt;apt&lt;/code&gt; module for the upgrade process (&lt;code&gt;upgrade: dist&lt;/code&gt; is important for Proxmox). Crucially, it checks if the system flagged a required reboot (&lt;code&gt;stat&lt;/code&gt; module) and then uses the &lt;code&gt;reboot&lt;/code&gt; module &lt;em&gt;only when&lt;/em&gt; that flag exists (&lt;code&gt;when&lt;/code&gt; condition). Idempotency ensures nodes already up-to-date are simply skipped by the &lt;code&gt;apt&lt;/code&gt; module.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Managing VMs Consistently
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Ensuring all your VMs (e.g., Ubuntu servers running Docker or k3s) have essential tools like Python and specific libraries installed.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Target a group of VMs in your inventory and use the &lt;code&gt;apt&lt;/code&gt; module.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# playbooks/vm_setup.yml (Example Snippet)&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Base Packages on VMs&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k3s_nodes&lt;/span&gt; &lt;span class="c1"&gt;# Or a group like [all_vms]&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# Needs sudo/root privileges&lt;/span&gt;
  &lt;span class="c1"&gt;# Assumes ansible_become_password might be needed (defined in inventory/vault)&lt;/span&gt;

  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Python, Pip, and other required packages&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.apt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;python3&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;python3-pip&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;python3-psycopg2&lt;/span&gt; &lt;span class="c1"&gt;# For PostgreSQL interaction later&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;python3-docker&lt;/span&gt;   &lt;span class="c1"&gt;# For Docker interaction later&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;present&lt;/span&gt;
        &lt;span class="na"&gt;update_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;em&gt;Explanation:&lt;/em&gt; This playbook targets a specific group (&lt;code&gt;k3s_nodes&lt;/code&gt;). The &lt;code&gt;apt&lt;/code&gt; module ensures the listed packages are installed (&lt;code&gt;state: present&lt;/code&gt;). If a package is already installed, Ansible makes no changes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Automating PostgreSQL Initialization and Configuration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Manually creating database users and databases for different applications is repetitive and error-prone.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Use service-specific Ansible modules for more complex tasks.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# playbooks/postgres_setup.yml (Example Snippet)&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure PostgreSQL Users and Databases&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;database_servers&lt;/span&gt; &lt;span class="c1"&gt;# Assuming a group for your DB server(s)&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;become_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt; &lt;span class="c1"&gt;# Run postgres tasks as the 'postgres' OS user, alternatively if postgres runs as root, keep using root.&lt;/span&gt;

  &lt;span class="na"&gt;vars_files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;../vars/secrets.yml&lt;/span&gt; &lt;span class="c1"&gt;# Load sensitive variables like passwords&lt;/span&gt;

  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ensure database user exists for App1&lt;/span&gt;
      &lt;span class="na"&gt;community.postgresql.postgresql_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app1_user&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;app1_db_password&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt; &lt;span class="c1"&gt;# Password from vault&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;present&lt;/span&gt;
      &lt;span class="c1"&gt;# This module handles creating the user idempotently&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ensure database exists for App1&lt;/span&gt;
      &lt;span class="na"&gt;community.postgresql.postgresql_db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app1_db&lt;/span&gt;
        &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app1_user&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;present&lt;/span&gt;
      &lt;span class="c1"&gt;# This module handles creating the database idempotently&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;em&gt;Explanation:&lt;/em&gt; This example uses modules from the &lt;code&gt;community.postgresql&lt;/code&gt; collection (&lt;code&gt;postgresql_user&lt;/code&gt;, &lt;code&gt;postgresql_db&lt;/code&gt;). It runs tasks as the &lt;code&gt;postgres&lt;/code&gt; system user (&lt;code&gt;become_user&lt;/code&gt;) and pulls the password from an Ansible Vault encrypted file (&lt;code&gt;vars_files&lt;/code&gt; and &lt;code&gt;{{ app1_db_password }}&lt;/code&gt;). These modules are designed to be idempotent.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These examples show how Ansible moves beyond simple commands to reliably manage configurations, updates, and service setups across your homelab infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As we've seen, Ansible is a fantastic tool for bringing order and efficiency to your homelab (and potentially your day job!). By defining your infrastructure as code, you reduce tedious manual work, ensure configurations are consistent across machines, and gain confidence through idempotent operations. The examples here – fixing Proxmox repos, updating nodes, setting up VMs, and configuring PostgreSQL – are just the beginning. Think about initial server setups, Docker container deployments, or keeping k3s clusters up-to-date; Ansible can handle it all.&lt;/p&gt;

&lt;p&gt;Remember, the key concept is &lt;strong&gt;idempotency&lt;/strong&gt;: run your playbooks as often as you need, knowing they'll only make changes necessary to reach your desired state.&lt;/p&gt;

&lt;p&gt;I hope this gives you a solid starting point! For the full walkthrough and live demos, make sure to check out the companion &lt;a href="https://youtu.be/NMSCOhK2rqY" rel="noopener noreferrer"&gt;Ansible Automation YouTube video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What's the first thing &lt;em&gt;you&lt;/em&gt; plan to automate in your homelab using Ansible? Let me know in the comments below!&lt;/p&gt;

&lt;p&gt;If you found this article and the video helpful, consider subscribing to &lt;a href="https://youtube.com/@letstalkdev" rel="noopener noreferrer"&gt;Let's Talk Dev on YouTube&lt;/a&gt; for more software engineering and DevOps content, and follow me here on Dev.to! Happy automating!&lt;/p&gt;

&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;I'm Mihai Farcas, a software architect with over a decade of experience under my belt. I'm passionate about writing code and love sharing knowledge with fellow developers.&lt;/p&gt;

&lt;p&gt;My YouTube channel, "Let's Talk Dev," is where I break down complex concepts, share my experiences (both the good and the face-palm moments).&lt;/p&gt;

&lt;p&gt;Connect with me:&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://mihai.ltd" rel="noopener noreferrer"&gt;https://mihai.ltd&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@letstalkdev" rel="noopener noreferrer"&gt;https://www.youtube.com/@letstalkdev&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/mihailtd" rel="noopener noreferrer"&gt;https://github.com/mihailtd&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/mihai-farcas-ltd/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/mihai-farcas-ltd/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>ansible</category>
      <category>devops</category>
      <category>homelab</category>
    </item>
    <item>
      <title>Functional Programming Face-Off: Python vs JavaScript vs Go!</title>
      <dc:creator>Mihai Farcas</dc:creator>
      <pubDate>Wed, 05 Mar 2025 20:50:20 +0000</pubDate>
      <link>https://dev.to/mihailtd/functional-programming-face-off-python-vs-javascript-vs-go-3bmj</link>
      <guid>https://dev.to/mihailtd/functional-programming-face-off-python-vs-javascript-vs-go-3bmj</guid>
      <description>&lt;p&gt;Functional programming has been gaining popularity in recent years, and for good reason. It offers a number of benefits over traditional imperative programming, such as improved code readability, testability, and maintainability.&lt;/p&gt;

&lt;p&gt;In this article, we'll compare and contrast how three popular programming languages - Python, JavaScript, and Go - handle functional programming concepts. We'll explore how each language supports features like higher-order functions, immutability, and function composition, and discuss their strengths and weaknesses.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you'd rather watch than read:
&lt;/h2&gt;

&lt;p&gt;Check out the accompanying YouTube video!&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/56i63VPtZGY"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Defining and Calling Functions
&lt;/h2&gt;

&lt;p&gt;At the heart of functional programming lies, unsurprisingly, the function. The way functions are defined and invoked can significantly impact a language's suitability for functional programming paradigms. We'll examine how Python, JavaScript, and Go handle function definitions, looking at syntax, typing, and overall structure, setting the stage for more advanced functional concepts. Specifically how similar (or different) the syntax is, and the implications of different approaches to type systems (static, dynamic, type hints).&lt;/p&gt;

&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In Python, functions are defined using the &lt;code&gt;def&lt;/code&gt; keyword followed by the function name, parentheses for parameters, and a colon. The code block within the function is indented. Type hints can be optionally added to specify the expected types of parameters and return values.&lt;/p&gt;
&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;i&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="nf"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;JavaScript offers a more compact syntax for defining functions, particularly with arrow functions. Arrow functions use the &lt;code&gt;=&amp;gt;&lt;/code&gt; operator, providing a concise way to express a function's logic.&lt;/p&gt;
&lt;h3&gt;
  
  
  Go
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Go, a statically-typed language, requires explicit type declarations for both function parameters and return values. Functions are defined using the func keyword, followed by the function name, a parenthesized list of parameters (with their types), and the return type. The function body is enclosed in curly braces &lt;code&gt;{}&lt;/code&gt;.  Go's syntax is very similar to python in that it uses a keyword, followed by the name, followed by parameters. However, Go's strict typing and the need for explicit imports, even for basic operations like printing to the console (using the fmt package), introduce a slightly higher level of formality compared to Python and JavaScript. The Go example defines a function that, like the Python and JavaScript counterparts, takes an integer and returns its square.&lt;/p&gt;

&lt;p&gt;However, Go differs significantly in its overall structure. Every Go file belongs to a package, and the &lt;code&gt;package main&lt;/code&gt; declaration is special. It signifies that the file is part of the main package, which is the entry point for executable programs.  Without &lt;code&gt;package main&lt;/code&gt; and the &lt;code&gt;func main()&lt;/code&gt; within it, Go wouldn't know where to begin executing your code. It's a fundamental difference from Python and JavaScript, where you don't need such explicit entry point declarations for simple scripts. Another key distinction is Go's requirement for explicit imports, even for basic functionalities like printing to the console.  In the provided example, &lt;code&gt;fmt.Println&lt;/code&gt; is used, requiring an import of the &lt;code&gt;fmt&lt;/code&gt; (format) package.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Higher-Order Functions
&lt;/h2&gt;

&lt;p&gt;This section delves into a cornerstone of functional programming: &lt;strong&gt;treating functions as first-class citizens&lt;/strong&gt;. This means functions can be passed as arguments to other functions, returned as values from functions, and generally treated like any other variable.  A direct consequence of this is the ability to create higher-order functions – functions that either take other functions as arguments or return them (or both).  This allows for highly flexible and reusable code. We will also be touching on Closures, though the dedicated section for them comes later.&lt;/p&gt;
&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;applyOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;


&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;applyOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Output: 15
&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;applyOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Output: 5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Python supports higher-order functions elegantly. In the Python snippet, &lt;code&gt;applyOperation&lt;/code&gt; is a higher-order function because it takes another function (&lt;code&gt;operation&lt;/code&gt;) as an argument.  &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;subtract&lt;/code&gt; are regular functions that perform addition and subtraction, respectively.  &lt;code&gt;applyOperation&lt;/code&gt; then calls the passed-in function (&lt;code&gt;operation&lt;/code&gt;) with the provided arguments (a and b).  Notice that the type hints are optional in Python. While the example does use type hints for clarity (specifying that operation should be a function taking two integers and returning an integer, and that a and b are integers), they are not enforced at runtime by default. This makes the Python code concise and similar in that aspect to JavaScript.&lt;/p&gt;
&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;applyOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;applyOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: 15&lt;/span&gt;

&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;applyOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: 5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;JavaScript, like Python, treats functions as first-class citizens and readily supports higher-order functions. The JavaScript snippet demonstrates the same &lt;code&gt;applyOperation&lt;/code&gt;, &lt;code&gt;add&lt;/code&gt;, and &lt;code&gt;subtract&lt;/code&gt; structure as the Python example. &lt;code&gt;applyOperation&lt;/code&gt; accepts a function (&lt;code&gt;operation&lt;/code&gt;) and calls it with arguments &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;. Because JavaScript is dynamically typed, there are no type annotations.  The code is very concise and mirrors the Python example in its functional approach.&lt;/p&gt;
&lt;h3&gt;
  
  
  Go
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;applyOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;applyOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Output: 15&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;applyOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Output: 5&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Go also supports higher-order functions, although with its characteristic explicitness due to static typing. In the Go snippet, &lt;code&gt;applyOperation&lt;/code&gt; is again the higher-order function. However, the type of the operation parameter is explicitly declared: &lt;code&gt;func(int, int) int&lt;/code&gt;. This signifies that operation must be a function that takes two int arguments and returns an int.  This explicit type declaration is a key difference from Python (with optional type hints) and JavaScript (dynamically typed). The &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;subtract&lt;/code&gt; functions are defined with their types, and &lt;code&gt;applyOperation&lt;/code&gt; calls the provided function just like in the other languages. While all three languages achieve the same result, Go's static typing makes the function signatures more verbose. This reinforces Go's emphasis on explicitness and compile-time type safety.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Closures
&lt;/h2&gt;

&lt;p&gt;Closures are a powerful feature often used in conjunction with higher-order functions. A closure is a function that "remembers" its surrounding environment (its lexical scope) even after the outer function that created it has finished executing.  This means the inner function can access and modify variables defined in the outer function's scope, even if the outer function has returned. This ability to "capture" state is crucial for many functional programming patterns.&lt;/p&gt;
&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;createCounter&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;nonlocal&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;  &lt;span class="c1"&gt;# count is not a local variable,
&lt;/span&gt;        &lt;span class="c1"&gt;# it refers to the count variable in the outer scope
&lt;/span&gt;        &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;


&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The Python snippet demonstrates a classic closure example with &lt;code&gt;createCounter&lt;/code&gt;.  &lt;code&gt;createCounter&lt;/code&gt; is a function that returns another function, &lt;code&gt;counter&lt;/code&gt;.  The key here is the &lt;code&gt;nonlocal count&lt;/code&gt; declaration within &lt;code&gt;counter&lt;/code&gt;.  Because Python has stricter scoping rules, you need to explicitly tell the inner function (&lt;code&gt;counter&lt;/code&gt;) that &lt;code&gt;count&lt;/code&gt; is not a local variable within counter itself, but rather refers to the count variable in the &lt;strong&gt;enclosing *&lt;em&gt;scope of &lt;code&gt;createCounter&lt;/code&gt;. Without &lt;code&gt;nonlocal&lt;/code&gt;, Python would create a new, local &lt;code&gt;count&lt;/code&gt; variable inside &lt;code&gt;counter&lt;/code&gt;, and the outer count would remain unchanged. The returned &lt;code&gt;counter&lt;/code&gt; function *&lt;/em&gt;"closes over"&lt;/strong&gt; the count variable, maintaining its state between calls.&lt;/p&gt;
&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createCounter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return &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;count&lt;/span&gt;&lt;span class="o"&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;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCounter&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="nf"&gt;counter&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="nf"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;JavaScript handles closures very naturally.  In the JavaScript snippet, &lt;code&gt;createCounter&lt;/code&gt; also returns an anonymous function (the closure). This inner function increments and returns the &lt;code&gt;count&lt;/code&gt; variable.  Crucially, JavaScript's scoping rules automatically allow the inner function to access and modify the count variable from the &lt;code&gt;createCounter&lt;/code&gt; scope, even after &lt;code&gt;createCounter&lt;/code&gt; has completed.  There's no need for a special keyword like Python's &lt;code&gt;nonlocal&lt;/code&gt;; the closure behavior is &lt;strong&gt;implicit&lt;/strong&gt;. This makes the JavaScript code very concise.&lt;/p&gt;
&lt;h3&gt;
  
  
  Go
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;createCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Go's closure mechanism is similar to JavaScript's.  The Go snippet defines &lt;code&gt;createCounter&lt;/code&gt;, which returns an anonymous function that increments and returns the count variable.  Like JavaScript, and unlike Python, there's no need for any special declaration to indicate that &lt;code&gt;count&lt;/code&gt; is from the outer scope. The inner function automatically has access to and can modify &lt;code&gt;count&lt;/code&gt;.  The returned function &lt;strong&gt;"closes over"&lt;/strong&gt; the count variable, preserving its state between invocations.  Go's approach, like JavaScript's, is straightforward and doesn't require extra keywords for closure behavior. The syntax, returning a &lt;code&gt;func() int&lt;/code&gt;, clearly expresses that &lt;code&gt;createCounter&lt;/code&gt; returns a function that takes no arguments and returns an integer.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Partial Application
&lt;/h2&gt;

&lt;p&gt;Partial application is a technique for creating new functions from existing ones by pre-filling some of their arguments.  It's a way to specialize a general function into a more specific one.  Instead of calling a function with all its arguments at once, you "fix" some of the arguments, creating a new function that expects only the remaining arguments. This can lead to more reusable and readable code.&lt;/p&gt;
&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;createGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greetingFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;greetingFn&lt;/span&gt;


&lt;span class="n"&gt;firstGreeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Well, hello there &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;secondGreeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hola &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;firstGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Remi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;secondGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ana&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the Python snippet, &lt;code&gt;createGreeting&lt;/code&gt; is a function that demonstrates partial application. It takes a &lt;code&gt;greeting&lt;/code&gt; string as input and returns a new function (&lt;code&gt;greetingFn&lt;/code&gt;). This returned function takes a name string and combines it with the pre-filled greeting.  When you call &lt;code&gt;createGreeting("Well, hello there ")&lt;/code&gt;, you're not getting the final greeting string; you're getting a new function (&lt;code&gt;firstGreeting&lt;/code&gt;) that has the "Well, hello there " greeting already "baked in."  You can then call &lt;code&gt;firstGreeting&lt;/code&gt; with different names to get the complete greeting. The same principle applies to &lt;code&gt;secondGreeting&lt;/code&gt;, prefilling a different initial greeting. The type hints help show the flow: &lt;code&gt;createGreeting&lt;/code&gt; takes a string and returns a function that takes a string and returns a string.&lt;/p&gt;
&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createGreeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greeting&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;greeting&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="nx"&gt;name&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="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;firstGreeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Well, hello there &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;secondGreeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola &lt;/span&gt;&lt;span class="dl"&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="nf"&gt;firstGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Remi&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;secondGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ana&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The JavaScript snippet achieves the same result using a concise arrow function syntax. &lt;code&gt;createGreeting&lt;/code&gt; takes a greeting and returns another arrow function that takes a name.  This inner function uses template literals (backticks) to create the final greeting string.  Like the Python example, calling &lt;code&gt;createGreeting&lt;/code&gt; with a greeting creates a new, specialized function (&lt;code&gt;firstGreeting&lt;/code&gt;, &lt;code&gt;secondGreeting&lt;/code&gt;) with that greeting pre-applied. The nested arrow functions clearly illustrate the process of creating a function that returns another function.&lt;/p&gt;
&lt;h3&gt;
  
  
  Go
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;


&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;firstGreeting&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;createGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Well, hello there "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;secondGreeting&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;createGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hola "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Remi"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secondGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ana"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The Go snippet implements partial application in a similar manner.  &lt;code&gt;createGreeting&lt;/code&gt; takes a greeting string and returns a function that takes a name string and returns the combined string.  Go's explicit type signature, &lt;code&gt;func(string) string&lt;/code&gt;, clearly indicates that &lt;code&gt;createGreeting&lt;/code&gt; returns a function. The use of &lt;code&gt;fmt.Sprintf&lt;/code&gt; is Go's way of formatting strings, analogous to Python's f-strings and JavaScript's template literals.  The result is the same: &lt;code&gt;firstGreeting&lt;/code&gt; and &lt;code&gt;secondGreeting&lt;/code&gt; become specialized functions with their respective greetings pre-filled.  Go's syntax, while slightly more verbose due to type declarations, achieves the same functional goal.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. Currying
&lt;/h2&gt;

&lt;p&gt;Currying is a technique closely related to partial application, but with a subtle, yet &lt;strong&gt;important&lt;/strong&gt;, difference.  While partial application allows you to pre-fill any number of arguments, &lt;strong&gt;currying transforms a function that takes multiple arguments into a sequence of functions, each taking a single argument&lt;/strong&gt;. Each function in the sequence returns the next function in the sequence, until all arguments have been supplied, at which point the final result is returned. Currying isn't built-in to any of these languages; we need to implement a curry function ourselves.&lt;/p&gt;
&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;curry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;curried&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__code__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;co_argcount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;curried&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;args2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;curried&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;


&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;curry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Output: 6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The Python snippet implements a general-purpose &lt;code&gt;curry&lt;/code&gt; function. This function is more complex than the previous examples because it needs to handle functions with an arbitrary number of arguments. It uses &lt;code&gt;fn.__code__.co_argcount&lt;/code&gt; to determine the number of arguments the original function (&lt;code&gt;fn&lt;/code&gt;) expects.  The inner curried function uses &lt;code&gt;*args&lt;/code&gt; to collect arguments.  If enough arguments have been collected (the length of args is greater or equal to the number of arguments that &lt;code&gt;fn&lt;/code&gt; expects), it calls the original function fn with those arguments.  Otherwise, it returns a new lambda function that takes more arguments (&lt;code&gt;*args2&lt;/code&gt;), combines them with the existing arguments (&lt;code&gt;args + args2&lt;/code&gt;), and recursively calls &lt;code&gt;curried&lt;/code&gt; again. This recursive process continues until all arguments are provided. The add function, which takes three arguments, is then curried and called with one argument at a time: &lt;code&gt;curry(add)(1)(2)(3)&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;curry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;curried&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args2&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;curried&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;c&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="nf"&gt;curry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;add&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="mi"&gt;3&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The JavaScript snippet provides a similar curry function implementation. It uses &lt;code&gt;fn.length&lt;/code&gt; to get the number of arguments the original function expects.  The curried function uses the rest parameter syntax (&lt;code&gt;...args&lt;/code&gt;) to gather arguments.  If enough arguments are present, it calls the original function &lt;code&gt;fn&lt;/code&gt; using &lt;code&gt;apply&lt;/code&gt; (to handle the &lt;code&gt;this&lt;/code&gt; context correctly). Otherwise, it returns a new function that takes more arguments (&lt;code&gt;...args2&lt;/code&gt;), concatenates them with the existing arguments using &lt;code&gt;concat&lt;/code&gt;, and recursively calls &lt;code&gt;curried&lt;/code&gt;.  Like the Python version, this allows us to call a curried function with one argument at a time, as shown with &lt;code&gt;curry(add)(1)(2)(3)&lt;/code&gt;. The Javascript and Python versions are strikingly similar.&lt;/p&gt;
&lt;h3&gt;
  
  
  Go
&lt;/h3&gt;

&lt;p&gt;The Go snippet presents a significantly more complex implementation of curry. This is where the differences between Go's static typing and the dynamic typing of Python and JavaScript become most apparent.  Because Go is statically typed, creating a generic curry function that works with functions of any arity (number of arguments) and any type requires using the &lt;code&gt;reflect&lt;/code&gt; package. &lt;strong&gt;Reflection allows us to inspect and manipulate types at runtime, which is necessary because the curry function doesn't know the types of the function it's currying beforehand.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"reflect"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;curry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ft&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"curry: argument must be a function"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;numArgs&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NumIn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;curried&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;curried&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;numArgs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interface&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;curried&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;curried&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;curriedAdd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;curry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;add1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;curriedAdd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})(&lt;/span&gt;&lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;add12&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;add1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})(&lt;/span&gt;&lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;add12&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})(&lt;/span&gt;&lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Output: 6&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;curry&lt;/code&gt; function first checks if the input f is actually a function using &lt;code&gt;reflect.TypeOf(f).Kind() != reflect.Func&lt;/code&gt;.  It then determines the number of expected arguments using &lt;code&gt;ft.NumIn()&lt;/code&gt;.  It uses a slice args (of type &lt;code&gt;reflect.Value&lt;/code&gt;) to store the accumulated arguments. The curried function (a closure) is defined recursively. When called with an argument x, it appends x to args. If enough arguments have been collected, it calls the original function using &lt;code&gt;reflect.ValueOf(f).Call(args)[0].Interface()&lt;/code&gt;.  This line is crucial: it converts the function &lt;code&gt;f&lt;/code&gt; to a &lt;code&gt;reflect.Value&lt;/code&gt;, calls it with the collected arguments, extracts the result (which is also a &lt;code&gt;reflect.Value&lt;/code&gt;), and then converts it back to a regular Go &lt;code&gt;interface{}&lt;/code&gt; using &lt;code&gt;.Interface()&lt;/code&gt;. If not enough arguments have been collected, it returns itself (curried), continuing the currying process.&lt;/p&gt;

&lt;p&gt;The main function shows how to use the curried function.  Because the curry function returns the most generic type &lt;code&gt;interface{}&lt;/code&gt;, we need multiple type assertions (e.g., .&lt;code&gt;(func(reflect.Value) interface{})&lt;/code&gt;) to convert the intermediate curried functions to their correct types before we can call them. This is much more verbose than the Python and JavaScript examples, highlighting the added complexity of implementing currying in a statically-typed language without generics (prior to Go 1.18). The final result is retrieved and printed, demonstrating that the currying works, but at the cost of significantly more complex code. This example clearly shows that functional programming patterns like currying, while possible in Go, are often more natural and concise in dynamically typed languages.&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Immutability
&lt;/h2&gt;

&lt;p&gt;Immutability is a core principle of functional programming.  An immutable object is one whose state cannot be changed after it's created.  This contrasts with mutable objects, which can be modified in place.  Immutability simplifies reasoning about code, prevents unintended side effects, and is crucial for concurrent programming (as immutable data is inherently thread-safe).  Different languages have varying levels of built-in support for immutability.&lt;/p&gt;
&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;

&lt;span class="n"&gt;points1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="sh"&gt;"&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="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;

&lt;span class="c1"&gt;# Shallow Copy
&lt;/span&gt;&lt;span class="n"&gt;points2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;points2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;  &lt;span class="c1"&gt;# Modifies only points2
&lt;/span&gt;&lt;span class="n"&gt;points2&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;  &lt;span class="c1"&gt;# Modifies the object in both lists
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Output: [{'x': 10, 'y': 2}, {'x': 3, 'y': 4}] (affected!)
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Output: [{'x': 10, 'y': 2}, {'x': 3, 'y': 4}, {'x': 5, 'y': 6}]
&lt;/span&gt;
&lt;span class="c1"&gt;# Deep Copy
&lt;/span&gt;&lt;span class="n"&gt;points3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deepcopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;points3&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;  &lt;span class="c1"&gt;# Modifies only points3
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Output: [{'x': 10, 'y': 2}, {'x': 3, 'y': 4}] (unaffected)
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Output: [{'x': 20, 'y': 2}, {'x': 3, 'y': 4}]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Python's built-in data structures, like lists and dictionaries, are mutable.  This means you can modify them directly after creation. The Python snippet highlights the importance of understanding the difference between shallow and deep copies when working with nested mutable objects.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Shallow Copy (&lt;code&gt;copy.copy()&lt;/code&gt;): A shallow copy creates a new top-level object, but the elements within that object are still references to the original objects.  So, if you have a list of dictionaries, a shallow copy will create a new list, but the dictionaries inside the new list will be the same dictionaries as in the original list.  Modifying a nested object in the shallow copy will affect the original object as well. As shown, appending to &lt;code&gt;points2&lt;/code&gt; affects only the copy because append creates a new array, but modifying &lt;code&gt;points2[0]["x"]&lt;/code&gt; modifies the underlying object referenced by both &lt;code&gt;points1&lt;/code&gt; and &lt;code&gt;points2&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deep Copy (&lt;code&gt;copy.deepcopy()&lt;/code&gt;): A deep copy recursively creates new copies of all objects, including nested ones.  This means modifying a nested object in a deep copy will not affect the original object. As shown, after a deep copy, modifying &lt;code&gt;points3[0]["x"]&lt;/code&gt; only affects &lt;code&gt;points3&lt;/code&gt;, leaving &lt;code&gt;points1&lt;/code&gt; unchanged. You need to explicitly use &lt;code&gt;copy.deepcopy()&lt;/code&gt; to achieve true immutability with nested mutable objects in Python.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;points1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;x&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;y&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&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;points2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;points1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// Creates a shallow copy&lt;/span&gt;

&lt;span class="nx"&gt;points2&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="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// Modifies only points2&lt;/span&gt;
&lt;span class="nx"&gt;points2&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;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Modifies the object in both arrays&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="nx"&gt;points1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: [{ x: 10, y: 2 }, { x: 3, y: 4 }] (affected!)&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="nx"&gt;points2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: [{ x: 10, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 }]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;JavaScript, like Python, has mutable objects (arrays and objects) by default.  The JavaScript snippet uses the spread operator (&lt;code&gt;...&lt;/code&gt;) to create a shallow copy of an array of objects.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Spread Operator for Arrays:  The spread operator, when used with an array, creates a &lt;strong&gt;shallow copy&lt;/strong&gt;.  Similar to Python's &lt;code&gt;copy.copy()&lt;/code&gt;, it creates a new array, but the objects within the array are still references to the same objects in the original array.  Appending to &lt;code&gt;points2&lt;/code&gt; doesn't modify &lt;code&gt;points1&lt;/code&gt;, as a new array instance is created, but changing &lt;code&gt;points2[0].x&lt;/code&gt; does modify the corresponding object in &lt;code&gt;points1&lt;/code&gt; because it's a &lt;strong&gt;shared reference&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deep Copying in JavaScript: JavaScript doesn't have a built-in deep copy function like Python's &lt;code&gt;copy.deepcopy()&lt;/code&gt;.  You typically need to use a custom function or a library (like Lodash's &lt;code&gt;_.cloneDeep&lt;/code&gt;) to perform a deep copy. One common (but potentially problematic) approach is to use &lt;code&gt;JSON.parse(JSON.stringify(object))&lt;/code&gt;, but this only works for objects that can be safely serialized to JSON (no functions, circular references, etc.). The lack of a standard, built-in deep copy mechanism is a notable weakness of JavaScript in terms of supporting immutability.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Go
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Point&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;points1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="n"&gt;points2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;points1&lt;/span&gt; &lt;span class="c"&gt;// Creates a copy of the slice header and underlying array&lt;/span&gt;

    &lt;span class="c"&gt;// Appending creates a new slice, doesn't modify points1&lt;/span&gt;
    &lt;span class="n"&gt;points2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c"&gt;// Modifying an element in points2 creates a copy of that element.&lt;/span&gt;
    &lt;span class="n"&gt;points2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Output: [{1 2} {3 4}] (original unaffected)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Output: [{10 2} {3 4} {5 6}]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Go takes a different approach to immutability.  Go's structs are value types. When you assign a struct to a new variable or pass it to a function, a copy of the struct is created. This promotes immutability by default.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Value Types: In the Go snippet, Point is a struct.  When &lt;code&gt;points2 := points1&lt;/code&gt; is executed, &lt;code&gt;points2&lt;/code&gt; receives a copy of the slice header.  Importantly, in this case, the underlying array elements (the Point structs) are also copied because they are value types.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;append&lt;/code&gt;: The &lt;code&gt;append&lt;/code&gt; function in Go is designed to work well with immutability. When you append to a slice, Go might create a new underlying array if the existing array doesn't have enough capacity. This means that &lt;code&gt;append&lt;/code&gt; often returns a new slice, leaving the original slice untouched. As demonstrated, p&lt;code&gt;oints2 = append(points2, Point{5, 6})&lt;/code&gt; creates a new slice for &lt;code&gt;points2&lt;/code&gt;, leaving &lt;code&gt;points1&lt;/code&gt; unmodified.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Modifying Struct Fields: Because of the value semantics of structs, changing a field within the struct inside a slice in Go doesn't change the value of the struct in another.&lt;br&gt;
In the example provided, modifying &lt;code&gt;points2&lt;/code&gt;, does not affect &lt;code&gt;points1&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Go's design, with its emphasis on value types for structs and the behavior of &lt;code&gt;append&lt;/code&gt;, encourages immutability. While you can use pointers to create mutable behavior in Go, the language's default behavior for structs promotes immutability, making it easier to write code with fewer side effects.  This is a significant advantage of Go for functional programming.&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Map, Filter, Reduce
&lt;/h2&gt;

&lt;p&gt;Map, filter, and reduce are fundamental higher-order functions in functional programming that operate on collections of data (like lists or arrays). They provide a concise and declarative way to transform and process data without using explicit loops.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;Map&lt;/strong&gt;: Applies a given function to each element of a collection, producing a new collection with the transformed elements. The original collection remains unchanged.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Filter&lt;/strong&gt;: Creates a new collection containing only the elements from the original collection that satisfy a given condition (a predicate function).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Reduce&lt;/strong&gt;: Combines all elements of a collection into a single value using a specified function. This function takes an accumulator and the current element, updating the accumulator with each iteration.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nb"&gt;reduce&lt;/span&gt;

&lt;span class="c1"&gt;# Map: Square each number
&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;squares&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Squares:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;squares&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Filter: Get even numbers
&lt;/span&gt;&lt;span class="n"&gt;evens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Evens:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;evens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Reduce: Sum all numbers
&lt;/span&gt;&lt;span class="n"&gt;sum_of_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numbers&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;# 0 is the initial value
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sum:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sum_of_numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Python has built-in support for &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, and &lt;code&gt;reduce&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;map&lt;/strong&gt;: The &lt;code&gt;map&lt;/code&gt; function takes a function and an iterable (like a list) as arguments.  In the example, &lt;code&gt;lambda n: n * n&lt;/code&gt; is an anonymous function (a &lt;code&gt;lambda&lt;/code&gt;) that squares a number.  map applies this function to each element of the numbers list. The result of &lt;code&gt;map&lt;/code&gt; is an &lt;code&gt;iterator&lt;/code&gt;, so we use &lt;code&gt;list()&lt;/code&gt; to convert it to a list for printing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;filter&lt;/strong&gt;: The &lt;code&gt;filter&lt;/code&gt; function also takes a function and an iterable.  The function (&lt;code&gt;lambda n: n % 2 == 0&lt;/code&gt;) acts as a predicate, returning &lt;code&gt;True&lt;/code&gt; for even numbers and &lt;code&gt;False&lt;/code&gt; otherwise. &lt;code&gt;filter&lt;/code&gt; returns an iterator containing only the elements for which the predicate returns &lt;code&gt;True&lt;/code&gt;. Again, we use &lt;code&gt;list()&lt;/code&gt; to convert it to a list.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;reduce&lt;/strong&gt;:  &lt;code&gt;reduce&lt;/code&gt; is not directly built-in; it's part of the &lt;code&gt;functools&lt;/code&gt; module.  It takes a function, an iterable, and an optional initial value.  The function (&lt;code&gt;lambda acc, n: acc + n&lt;/code&gt;) takes the accumulator (&lt;code&gt;acc&lt;/code&gt;) and the current element (&lt;code&gt;n&lt;/code&gt;), returning the updated accumulator. reduce applies this function cumulatively to the items of the sequence, from left to right, so as to reduce the sequence to a single value. In the snippet, it calculates the sum of all numbers in the list.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Map: Square each number&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&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;squares&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;n&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="s2"&gt;Squares:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;squares&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Filter: Get even numbers&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;evens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&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;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="s2"&gt;Evens:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;evens&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Reduce: Sum all numbers&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&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;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;n&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;// 0 is the initial value&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="s2"&gt;Sum:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;JavaScript also provides &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, and &lt;code&gt;reduce&lt;/code&gt; as built-in methods on arrays. This makes the syntax very concise and readable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;map&lt;/strong&gt;: The &lt;code&gt;map&lt;/code&gt; method is called directly on the numbers array. It takes a callback function (&lt;code&gt;n =&amp;gt; n * n&lt;/code&gt;) that's applied to each element, creating a new array (&lt;code&gt;squares&lt;/code&gt;) with the results.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;filter&lt;/strong&gt;: The &lt;code&gt;filter&lt;/code&gt; method, similarly, is called on the array. It takes a predicate function (&lt;code&gt;n =&amp;gt; n % 2 === 0&lt;/code&gt;) and returns a new array (&lt;code&gt;evens&lt;/code&gt;) containing only the elements that satisfy the predicate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;reduce&lt;/strong&gt;: The &lt;code&gt;reduce&lt;/code&gt; method is also called on the array.  It takes a callback function (&lt;code&gt;(acc, n) =&amp;gt; acc + n&lt;/code&gt;) and an initial value (&lt;code&gt;0&lt;/code&gt;). The callback function takes the accumulator (&lt;code&gt;acc&lt;/code&gt;) and the current element (&lt;code&gt;n&lt;/code&gt;), returning the updated accumulator. &lt;code&gt;reduce&lt;/code&gt; iterates through the array, accumulating the result into the &lt;code&gt;sum&lt;/code&gt; variable. The JavaScript syntax for these operations is very clean and directly integrated into the array object.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Go
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Reduce&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;initial&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Map: Square each number&lt;/span&gt;
    &lt;span class="n"&gt;squares&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Squares:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;squares&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Filter: Get even numbers&lt;/span&gt;
    &lt;span class="n"&gt;evens&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Evens:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;evens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Reduce: Sum all numbers&lt;/span&gt;
    &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sum:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Go, unlike Python and JavaScript, does not have built-in &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, and &lt;code&gt;reduce&lt;/code&gt; functions. However, you can easily implement them using Go's &lt;code&gt;for...range&lt;/code&gt; loops and functions. The Go snippet shows generic implementations of &lt;code&gt;Map&lt;/code&gt;, &lt;code&gt;Filter&lt;/code&gt;, and &lt;code&gt;Reduce&lt;/code&gt; using Go 1.18+ &lt;strong&gt;generics&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Map&lt;/strong&gt;: The provided &lt;code&gt;Map&lt;/code&gt; function takes a slice of type &lt;code&gt;T&lt;/code&gt;, a function that transforms a &lt;code&gt;T&lt;/code&gt; to a &lt;code&gt;U&lt;/code&gt;, and it returns a slice of type &lt;code&gt;U&lt;/code&gt;. The types &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;U&lt;/code&gt; can be any types. It iterates through the input slice, applies the provided function &lt;code&gt;f&lt;/code&gt; to each element, and stores the result in a new slice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Filter&lt;/strong&gt;: The &lt;code&gt;Filter&lt;/code&gt; function takes a slice of type &lt;code&gt;T&lt;/code&gt; and a predicate function (a function that returns a boolean). It iterates through the slice, and for each element where the predicate function returns &lt;code&gt;true&lt;/code&gt;, it appends the element to a new slice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduce&lt;/strong&gt;: The &lt;code&gt;Reduce&lt;/code&gt; function takes a slice of type &lt;code&gt;T&lt;/code&gt;, an initial value of type &lt;code&gt;U&lt;/code&gt;, and a function which takes a value of type &lt;code&gt;U&lt;/code&gt; and a value of type &lt;code&gt;T&lt;/code&gt;, returning another &lt;code&gt;U&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While Go requires more code to achieve the same functionality as Python and JavaScript's built-ins, &lt;strong&gt;the generic implementations provide flexibility and type safety.&lt;/strong&gt; The use of anonymous functions (like &lt;code&gt;func(n int) int { return n * n }&lt;/code&gt;) makes the code resemble the lambda expressions used in Python and JavaScript.&lt;/p&gt;
&lt;h2&gt;
  
  
  8. Function Composition
&lt;/h2&gt;

&lt;p&gt;Function composition is the process of combining two or more functions to create a new function. The output of one function becomes the input of the next, forming a pipeline of operations. This is a powerful way to build complex logic from simpler, reusable building blocks, enhancing code modularity and readability. It avoids creating intermediate variables and nested function calls.&lt;/p&gt;
&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nb"&gt;reduce&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;funcs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;funcs&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;multiply_by_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;


&lt;span class="n"&gt;composed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;multiply_by_two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Order is correct
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;composed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# ((5 + 1) * 2)^2 = 144
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Composed result:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The Python snippet defines a compose function that takes a variable number of functions (&lt;code&gt;*funcs&lt;/code&gt;) as arguments. It returns a new function (a lambda) that takes an initial value &lt;code&gt;x&lt;/code&gt;. Inside the lambda, it uses &lt;code&gt;reduce&lt;/code&gt; to apply the functions in sequence. The trick here is &lt;code&gt;reversed(funcs)&lt;/code&gt;. reduce normally applies functions from left to right, but in function composition, we usually want the rightmost function to be applied first. &lt;code&gt;reversed(funcs)&lt;/code&gt; reverses the order of functions, so reduce effectively applies them from right to left. The functions &lt;code&gt;add_one&lt;/code&gt;, &lt;code&gt;square&lt;/code&gt;, &lt;code&gt;multiply_by_two&lt;/code&gt; demonstrates what functions can be composed. The order matters in composition. The comment ((5 + 1) * 2)^2 = 144 shows how the functions are applied step by step, starting with &lt;code&gt;add_one&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;compose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;funcs&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;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;funcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduceRight&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;x&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;addOne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;x&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;multiplyByTwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&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;composed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;square&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;multiplyByTwo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;addOne&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Order is correct&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="nf"&gt;composed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ((5 + 1) * 2)^2 = 144&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="s2"&gt;Composed result:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The JavaScript snippet defines a compose function using arrow function syntax. It's very concise. &lt;code&gt;...funcs&lt;/code&gt; collects all function arguments into an array. The returned function takes an initial value &lt;code&gt;x&lt;/code&gt; and uses &lt;code&gt;funcs.reduceRight((acc, f) =&amp;gt; f(acc), x)&lt;/code&gt;. The &lt;code&gt;reduceRight&lt;/code&gt; method is the key here; it's a built-in array method that applies a function against an accumulator and each element of the array (&lt;strong&gt;from right to left&lt;/strong&gt;), reducing it to a single value. This achieves the correct order of function application directly, without needing to reverse the function list like in Python.&lt;/p&gt;
&lt;h3&gt;
  
  
  Go
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;funcs&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;funcs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;addOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;multiplyByTwo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;composed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addOne&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;multiplyByTwo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;composed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// ((5 + 1) * 2)^2 = 144&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Composed result:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The go snippet defines a &lt;code&gt;compose&lt;/code&gt; function takes advantage of Go 1.18+ generics.&lt;br&gt;
It is defined to take a variadic number of functions (&lt;code&gt;funcs ...func(T) T&lt;/code&gt;). The &lt;code&gt;T&lt;/code&gt; represents any data type. The key difference is in how the functions are applied. It uses a simple &lt;code&gt;for...range&lt;/code&gt; loop to iterate through the funcs slice &lt;strong&gt;in the order they were provided&lt;/strong&gt;. Unlike Python and JavaScript, this Go compose function applies functions from left to right. This is a deliberate choice to make the code simpler, and in the provided &lt;code&gt;main()&lt;/code&gt; function, this is accounted for. The composed variable receives the composition, but the functions are listed in the reverse order (&lt;code&gt;addOne&lt;/code&gt;, &lt;code&gt;multiplyByTwo&lt;/code&gt;, &lt;code&gt;square&lt;/code&gt;) compared to what would be mathematically expected. The final call to &lt;code&gt;composed(5)&lt;/code&gt; produces correct results.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Each of these three languages brings its own unique approach to functional programming. Python and JavaScript, with their dynamic typing and built-in support for many functional features, offer a relatively lower barrier to entry. Go, on the other hand, while requiring a bit more effort to implement some functional concepts, provides strong immutability support and explicitness, which can be advantageous in certain scenarios.&lt;/p&gt;
&lt;h2&gt;
  
  
  Subscribe for More!
&lt;/h2&gt;

&lt;p&gt;If you enjoyed this comparison, be sure to subscribe to my YouTube channel for more content on programming languages, software development, and other tech topics.&lt;/p&gt;

&lt;p&gt;Let me know in the comments which language you prefer for functional programming and why!&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.youtube.com/channel/UC_tS0kNJZXkMZn2mRJRTA_g/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyt3.googleusercontent.com%2FRIzr-0Smkmg3dcAmBedb7FDoofVtML0mW5AtG8ixVmh9EDh9E8zPq7toYW243x3PChxCztcSxg%3Ds900-c-k-c0x00ffffff-no-rj" height="900" class="m-0" width="900"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.youtube.com/channel/UC_tS0kNJZXkMZn2mRJRTA_g/" rel="noopener noreferrer" class="c-link"&gt;
            Let's Talk Dev - YouTube
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            I share my insights and tips on software engineering topics such as web development, databases, cloud computing, and more.
Hi, I'm Mihai and I'm a full-stack software engineer with a passion for creating innovative and user-friendly solutions using web and cloud technologies. I have a home lab where I like to experiment with Kubernetes and other cutting-edge technologies. I'm also a big fan of open-source software.
When I'm not coding, I enjoy photography, reading books, learning about finance and entrepreneurship, and watching movies.

          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.youtube.com%2Fs%2Fdesktop%2F5d82a8bc%2Fimg%2Ffavicon.ico" width="16" height="16"&gt;
          youtube.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;I'm Mihai Farcas, a software engineer with a few years of experience under my belt. I'm passionate about writing code and love sharing knowledge with fellow developers.&lt;/p&gt;

&lt;p&gt;My YouTube channel, "Let's Talk Dev," is where I break down complex concepts, share my experiences (both the good and the face-palm moments).&lt;/p&gt;

&lt;p&gt;Connect with me:&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://mihai.ltd" rel="noopener noreferrer"&gt;https://mihai.ltd&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@letstalkdev" rel="noopener noreferrer"&gt;https://www.youtube.com/@letstalkdev&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/mihailtd" rel="noopener noreferrer"&gt;https://github.com/mihailtd&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/mihai-farcas-ltd/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/mihai-farcas-ltd/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>python</category>
      <category>javascript</category>
      <category>functional</category>
    </item>
    <item>
      <title>Secure Self-Hosting with Cloudflare Tunnels and Docker: Zero Trust Security</title>
      <dc:creator>Mihai Farcas</dc:creator>
      <pubDate>Wed, 08 Jan 2025 11:07:20 +0000</pubDate>
      <link>https://dev.to/mihailtd/secure-self-hosting-with-cloudflare-tunnels-and-docker-zero-trust-security-5bbn</link>
      <guid>https://dev.to/mihailtd/secure-self-hosting-with-cloudflare-tunnels-and-docker-zero-trust-security-5bbn</guid>
      <description>&lt;p&gt;For many software engineers, the allure of self-hosting is undeniable. It represents autonomy, a playground for experimentation and helps you learn about the infrastructure that makes the internet work.&lt;/p&gt;

&lt;p&gt;However, the freedom of self-hosting comes with a critical responsibility: security. Exposing your home network to the internet is like opening your front door to everyone. Without proper protection, your home setup can quickly become a target.&lt;/p&gt;

&lt;p&gt;This article explains the key methods and tools for securing your self-hosted applications, changing it from a weak spot into a secure setup. We'll go through DNS, look at the threat of DDoS attacks, and show how Cloudflare Tunnels, especially with Docker, provide a strong solution for achieving zero-trust security for your self-hosted environment.&lt;/p&gt;

&lt;p&gt;To complement this written guide, I've created two accompanying YouTube videos:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/q4IXxTg-nCc"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This video delves into the underlying concepts of DNS, DDoS attacks, reverse proxies, and how Cloudflare's infrastructure works to mitigate these threats.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/SivE_EfUNd8"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This video provides a hands-on walkthrough, demonstrating how to set up Cloudflare Tunnels with Docker, securing a sample web application step-by-step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Self-Hosting Needs Special Attention
&lt;/h2&gt;

&lt;p&gt;When you self-host a website, you're essentially making your home network a part of the public internet. This drastically increases your attack surface. Let's look at some key implications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Your Public IP Address: This is your home network's "address" on the internet. Traditionally, to make your website accessible, you'd point your domain's DNS records to this IP. This direct association creates a clear target for malicious actors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open Ports: To serve web traffic, you typically need to open ports 80 (HTTP) and 443 (HTTPS) on your router, forwarding them to your web server. Open ports are like open doors, inviting potential intruders to probe your network for weaknesses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dynamic IP Addresses: Most residential ISPs assign dynamic IP addresses, which change periodically. This makes self-hosting less reliable because your website's DNS records need to be updated constantly to point to the correct IP. If they're not, your site can become unreachable. We'll see how to solve this problem later on.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is DNS and how does it work?
&lt;/h2&gt;

&lt;p&gt;Domain Name System (DNS) is like the internet's phone book. It's the technology that translates human-friendly website names (like &lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt;) into the numerical IP addresses that computers use to communicate. Without DNS, browsing the web would be incredibly difficult.&lt;/p&gt;

&lt;p&gt;However, for self-hosting, the traditional DNS system has a weakness: it can expose your home IP address. When someone looks up your domain, the DNS lookup process eventually leads back to your home's IP address, if you are using a basic self hosting setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  DDoS Attacks: The Digital Siege
&lt;/h2&gt;

&lt;p&gt;Once a malicious actor gets hold of your home IP address, which as we saw, can be exposed through the DNS resolution process, they can launch a Distributed Denial of Service (DDoS) attack.&lt;/p&gt;

&lt;p&gt;DDoS attacks are a major threat to self-hosted websites. In a DDoS attack, attackers use a network of infected computers (called a "botnet") to flood your server with traffic. This overwhelms your server's resources, making your website slow or completely inaccessible to legitimate users.&lt;/p&gt;

&lt;p&gt;For self-hosted sites, a DDoS attack can be devastating. Not only can it take your website offline, but the flood of traffic can also disrupt your entire home network, affecting other services and even your household's internet access.&lt;/p&gt;

&lt;p&gt;If you're interested in diving deeper into topics like this, including software engineering, self-hosting, home labs, Docker, Kubernetes, and other DevOps practices, head over to the Let's Talk Dev YouTube channel.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.youtube.com/channel/UC_tS0kNJZXkMZn2mRJRTA_g/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyt3.googleusercontent.com%2FRIzr-0Smkmg3dcAmBedb7FDoofVtML0mW5AtG8ixVmh9EDh9E8zPq7toYW243x3PChxCztcSxg%3Ds900-c-k-c0x00ffffff-no-rj" height="900" class="m-0" width="900"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.youtube.com/channel/UC_tS0kNJZXkMZn2mRJRTA_g/" rel="noopener noreferrer" class="c-link"&gt;
            Let's Talk Dev - YouTube
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            I share my insights and tips on software engineering topics such as web development, databases, cloud computing, and more.
Hi, I'm Mihai and I'm a full-stack software engineer with a passion for creating innovative and user-friendly solutions using web and cloud technologies. I have a home lab where I like to experiment with Kubernetes and other cutting-edge technologies. I'm also a big fan of open-source software.
When I'm not coding, I enjoy photography, reading books, learning about finance and entrepreneurship, and watching movies.

          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.youtube.com%2Fs%2Fdesktop%2F5d82a8bc%2Fimg%2Ffavicon.ico" width="16" height="16"&gt;
          youtube.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Cloudflare: Your First Line of Defense
&lt;/h2&gt;

&lt;p&gt;Cloudflare, at its core, is a Content Delivery Network (CDN) with a strong focus on security. It acts as an intermediary between your users and your origin server, providing numerous benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reverse Proxy: Cloudflare operates as a reverse proxy, meaning all traffic to your website flows through its network first. This masks your origin server's IP address, shielding it from direct exposure.&lt;/li&gt;
&lt;li&gt;DNS Resolution Through Cloudflare: When you use Cloudflare's DNS services, the resolution process is handled by their vast network of globally distributed DNS servers. This not only improves performance but also adds another layer of obfuscation, preventing attackers from easily discovering your home IP through DNS queries.&lt;/li&gt;
&lt;li&gt;Basic DDoS Mitigation: Cloudflare's network is designed to absorb and filter malicious traffic. Their anycast network distributes traffic across numerous data centers, making it difficult for attackers to overwhelm a single point. It also identifies and blocks known malicious traffic patterns, preventing them from reaching your server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations of Traditional Cloudflare Protection for Self-Hosting
&lt;/h2&gt;

&lt;p&gt;While Cloudflare's basic DNS and DDoS protection offer a substantial improvement, they are not a complete solution for self-hosting scenarios. Here's why:&lt;/p&gt;

&lt;p&gt;To allow Cloudflare to communicate with your web server, you still need to open ports 80 and 443 on your router and forward them to your server. This keeps a potential vulnerability open. Attackers can directly target those open ports, attempting to exploit any weaknesses in your web server (i.e. Nginx) or other services running on your network.&lt;/p&gt;

&lt;p&gt;This also doesn't get rid of the dynamic IP address issue. If your home IP address changes, your website becomes inaccessible until you manually update your DNS records on Cloudflare. This manual intervention is prone to errors and can lead to downtime. There are more automated solutions out there, however they all rely on making the change on a schedule dinterval, which still leads to downtime.&lt;/p&gt;

&lt;p&gt;Also, while Cloudflare hides your IP from direct DNS queries, determined attackers might still uncover it through other means, such as examining email headers or exploiting vulnerabilities in third-party services you use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloudflare Tunnels: The Zero Trust Solution
&lt;/h2&gt;

&lt;p&gt;Cloudflare Tunnels provide a paradigm shift in how you expose self-hosted services to the internet. Instead of opening inbound ports and relying on traditional DNS pointing to your home IP, Tunnels create a secure, outbound-only connection from your server to the Cloudflare network. This fundamentally changes the security model to one of "zero trust."&lt;/p&gt;

&lt;h2&gt;
  
  
  How Cloudflare Tunnels Work: A Deep Dive
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;cloudflared Daemon: You install a lightweight agent called cloudflared on your server (or within a Docker container, as we'll see later). This daemon is responsible for establishing and maintaining the secure tunnel.&lt;/li&gt;
&lt;li&gt;Outbound-Only Connection: cloudflared initiates an outbound connection to Cloudflare's edge network. This is crucial because it eliminates the need to open any inbound ports on your router, drastically reducing your attack surface.&lt;/li&gt;
&lt;li&gt;Tunnel Creation: You create a tunnel in the Cloudflare dashboard, giving it a unique name.&lt;/li&gt;
&lt;li&gt;Service Configuration: You configure the tunnel to route traffic to specific services running on your local network. For instance, you can specify that traffic for &lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt; should be routed to your web server running on port 80. So you can choose which services are accessible through the tunnel and which aren't.&lt;/li&gt;
&lt;li&gt;DNS Integration: Finally, when creating the tunnel, DNS records in Cloudflare are automatically configured to point to the Cloudflare network, specifying the tunnel to be used for each service. So even if your home IP changes, the tunnel will still be opened and connected to Cloudflare's network.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To recap, the benefits of using Cloudflare Tunnels are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not reliant on opened ports&lt;/li&gt;
&lt;li&gt;Dynamic IP resilience&lt;/li&gt;
&lt;li&gt;Granular access control&lt;/li&gt;
&lt;li&gt;Better security&lt;/li&gt;
&lt;li&gt;Simplified management&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Docker and Cloudflare Tunnels
&lt;/h2&gt;

&lt;p&gt;You can run the &lt;code&gt;cloudflared&lt;/code&gt; daemon within a separate Docker container alongside your application containers.&lt;/p&gt;

&lt;p&gt;You can also use &lt;code&gt;cloudflared&lt;/code&gt; in a &lt;code&gt;docker-compose.yml&lt;/code&gt;. Docker Compose simplifies the process of defining and managing multi-container applications. You can define your web application, database, and cloudflared container in a single docker-compose.yml file, ensuring they call all communicate between each other easily through Docker's internal DNS.&lt;/p&gt;

&lt;p&gt;Refer to my accompanying YouTube video for a detailed &lt;a href="https://youtu.be/SivE_EfUNd8" rel="noopener noreferrer"&gt;step-by-step guide on setting up Cloudflare Tunnels with Docker&lt;/a&gt;. The video covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating and managing tunnels through the Cloudflare dashboard&lt;/li&gt;
&lt;li&gt;Installing and configuring cloudflared within a Docker container&lt;/li&gt;
&lt;li&gt;Using docker compose (and Portainer) to expose a self hosted service to the internet!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tldr; is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cloudflared&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cloudflare/cloudflared:latest&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tunnel --no-autoupdate run&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TUNNEL_TOKEN=${TUNNEL_TOKEN}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Embracing Secure Self-Hosting
&lt;/h2&gt;

&lt;p&gt;Self-hosting offers a unique blend of control, flexibility, and learning opportunities. However, security should always be paramount. Cloudflare Tunnels, provide a robust and elegant solution for securing your self-hosted environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;I'm Mihai Farcas, a software engineer with a few years of experience under my belt. I'm passionate about writing code and love sharing knowledge with fellow developers.&lt;/p&gt;

&lt;p&gt;My YouTube channel, "Let's Talk Dev," is where I break down complex concepts, share my experiences (both the good and the face-palm moments).&lt;/p&gt;

&lt;p&gt;Connect with me:&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://mihai.ltd" rel="noopener noreferrer"&gt;https://mihai.ltd&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@letstalkdev" rel="noopener noreferrer"&gt;https://www.youtube.com/@letstalkdev&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/mihailtd" rel="noopener noreferrer"&gt;https://github.com/mihailtd&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/mihai-farcas-ltd/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/mihai-farcas-ltd/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cloudflare</category>
      <category>networking</category>
      <category>security</category>
      <category>selfhosting</category>
    </item>
    <item>
      <title>Kubernetes Debugging Made Easy with mirrord</title>
      <dc:creator>Mihai Farcas</dc:creator>
      <pubDate>Fri, 25 Oct 2024 18:04:46 +0000</pubDate>
      <link>https://dev.to/mihailtd/kubernetes-debugging-made-easy-with-mirrord-105d</link>
      <guid>https://dev.to/mihailtd/kubernetes-debugging-made-easy-with-mirrord-105d</guid>
      <description>&lt;p&gt;Developing and debugging applications in a Kubernetes cluster can be complex. However, mirrord, an open-source project by MetalBear, offers a solution to simplify this process.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Use Case
&lt;/h2&gt;

&lt;p&gt;Imagine you're a software engineer working on a complex project involving multiple interconnected microservices. You encounter a bug that only occurs in the staging environment. Reproducing this bug locally is a nightmare for two main reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Running the application locally requires a complex setup with multiple microservices, making it difficult to replicate the staging environment accurately.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The bug may be data-dependent, and you lack the specific data present in the staging environment. Downloading this data from the staging database is a convoluted process.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is where mirrord comes in!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is mirrord?
&lt;/h2&gt;

&lt;p&gt;mirrord is an open-source tool designed to simplify the development and debugging of applications running in Kubernetes clusters. It achieves this by enabling developers to work on their code directly within the cluster, eliminating the need for extensive local setups or continuous deployments to staging environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;mirrord operates as a "mirror" (hence the name) between your local development environment and the Kubernetes cluster. It intercepts requests destined for your application pods in the cluster and duplicates them, sending a copy to your local machine.    &lt;/p&gt;

&lt;p&gt;This allows you to run and debug your code locally while interacting with real production data and services within the cluster. In essence, it's like having a magic portal that connects your local machine to the live Kubernetes environment without affecting actual users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Debugging a Production-Only Bug
&lt;/h2&gt;

&lt;p&gt;The video demonstrates how mirrord can help debug an upper-environment-only bug. The application, written in Go, runs fine locally but displays an error in the production Kubernetes cluster. In the following video I show how to use the mirrord along with it's VS Code extension to debug the application. mirrord allows you to select a target to mirror (pod or deployment) and provides access to the same resources and environment variables as the remote application.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/KJpEebC1tNE"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Keep in mind you have to have &lt;code&gt;kubectl&lt;/code&gt; access to the Kubernetes cluster you want to target pods in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is Mirrord for?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Developers Tired of the "Push-and-Pray" Development Cycle
&lt;/h3&gt;

&lt;p&gt;If you're tired of the constant cycle of pushing code to a staging environment and praying it works, Mirrord is for you. With mirrord, you can see your code running in a near-production environment instantly, without waiting for deployments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Teams Struggling with Complex Local Setups
&lt;/h3&gt;

&lt;p&gt;Setting up a local environment that accurately mirrors a production Kubernetes cluster can be a real headache, especially in microservice architectures. mirrord eliminates this pain by allowing you to develop and debug directly in the cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Developers Who Need to Debug with Production-Like Data
&lt;/h3&gt;

&lt;p&gt;Debugging with real-world data is crucial for finding and fixing those tricky bugs that only show up in upper environments. mirrord lets you do this safely, without impacting your live application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anyone Facing Challenges in Reproducing and Fixing Environment-Specific Bugs
&lt;/h3&gt;

&lt;p&gt;Some bugs just won't show up in your local environment, no matter how hard you try to replicate it. mirrord makes it easy to reproduce and fix these environment-specific bugs by giving you direct access to the target environment.&lt;/p&gt;

&lt;p&gt;TLDR; mirrord is for any developer who wants to simplify Kubernetes development and debugging, improve their workflow, and ship higher-quality code faster.&lt;/p&gt;

&lt;p&gt;For more details check out the documentation on the &lt;a href="https://mirrord.dev/" rel="noopener noreferrer"&gt;mirrord website&lt;/a&gt; along with the &lt;a href="https://github.com/mihailtd/mirrord-demo" rel="noopener noreferrer"&gt;code repository I created to demonstrate mirrod's features&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;I'm Mihai Farcas, a software engineer with a few years of experience under my belt. I'm passionate about writing code and love sharing knowledge with fellow developers. &lt;/p&gt;

&lt;p&gt;My YouTube channel, "Let's Talk Dev," is where I break down complex concepts, share my experiences (both the good and the face-palm moments).&lt;/p&gt;

&lt;p&gt;Connect with me:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Website&lt;/strong&gt;: &lt;a href="https://mihai.ltd" rel="noopener noreferrer"&gt;https://mihai.ltd&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;YouTube&lt;/strong&gt;: &lt;a href="https://www.youtube.com/@letstalkdev" rel="noopener noreferrer"&gt;https://www.youtube.com/@letstalkdev&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/mihailtd" rel="noopener noreferrer"&gt;https://github.com/mihailtd&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;LinkedIn&lt;/strong&gt;: &lt;a href="https://www.linkedin.com/in/mihai-farcas-ltd/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/mihai-farcas-ltd/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>opensource</category>
      <category>tooling</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Why Go is Popular Right Now and Why I Started Learning Go as a Node.js Developer</title>
      <dc:creator>Mihai Farcas</dc:creator>
      <pubDate>Tue, 22 Oct 2024 07:28:06 +0000</pubDate>
      <link>https://dev.to/mihailtd/why-go-is-popular-right-now-and-how-and-why-i-started-learning-go-as-a-nodejs-developer-2jcg</link>
      <guid>https://dev.to/mihailtd/why-go-is-popular-right-now-and-how-and-why-i-started-learning-go-as-a-nodejs-developer-2jcg</guid>
      <description>&lt;p&gt;As a Node.js developer for over a decade, I've built countless web applications, APIs, and microservices. Node.js has been my go-to language for its versatility and vast ecosystem. However, I've recently become increasingly interested in Go, particularly its performance, concurrency model, and growing popularity in the cloud-native space. This interest led me to start learning Go, and I'm thrilled to share my experiences and insights with you all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reasons for Go's Popularity
&lt;/h2&gt;

&lt;p&gt;Go has been steadily gaining popularity among developers, and for good reason. It offers a unique blend of features that make it a compelling choice for building modern, high-performance applications.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; Go's compiled nature and efficient garbage collection result in impressive execution speed, often outperforming interpreted languages like Node.js and Python.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency:&lt;/strong&gt; Go's built-in concurrency features, through goroutines and channels, make it easier to write concurrent code, which is essential for building scalable applications.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity:&lt;/strong&gt; Go's syntax is clean, minimal, and easy to learn, reducing cognitive overhead and promoting code readability.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type Safety:&lt;/strong&gt; Go's static typing helps catch errors during compilation, reducing runtime surprises and improving code reliability.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tooling:&lt;/strong&gt; Go's comprehensive standard library and rich ecosystem of third-party tools provide developers with the necessary resources to build and maintain robust applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Go's sweet spot lies in its ability to balance performance, concurrency, and simplicity. It's a language that allows you to write efficient, scalable code without sacrificing readability or ease of development.&lt;/p&gt;

&lt;p&gt;Go's popularity has also been fueled by the rise of Kubernetes. As Kubernetes has become the de facto standard for container orchestration, Go has benefited from its close association. Kubernetes is written in Go, and many of its components and extensions are also built using Go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Started Learning Go
&lt;/h2&gt;

&lt;p&gt;Beyond the technical benefits, I was drawn to Go's simplicity and elegance. Coming from the world of JavaScript with its occasional quirks and complexities, Go's minimalist syntax and clear design principles were a breath of fresh air. The language's focus on readability and maintainability aligned with my belief in writing clean, understandable code.&lt;/p&gt;

&lt;p&gt;I've been writing code in a functional-lite style in Node.js, and Go allows me to continue with that as it has many of the traits that make this possible in JS. Go's support for first-class functions, closures, and immutability makes it well-suited for functional programming paradigms. This was a significant advantage, as I could leverage my existing functional programming skills while exploring Go's unique features. Check out my &lt;a href="https://youtu.be/q1aNVIq3K7c" rel="noopener noreferrer"&gt;video about functional programming in JavaScript&lt;/a&gt; - many of the concepts apply to Go as well.&lt;/p&gt;

&lt;p&gt;I was particularly interested in Kubernetes and the possibility of writing Kubernetes extensions and operators in Go. Kubernetes has become the de facto standard for container orchestration, and Go's close association with Kubernetes made it a natural choice for extending its functionality. The prospect of building custom Kubernetes tools and controllers in Go further fueled my interest in learning the language. &lt;/p&gt;

&lt;p&gt;If you're interested in similar topics, check out my YouTube channel, where I share content about Kubernetes, functional programming, and many other software development topics:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.youtube.com/channel/UC_tS0kNJZXkMZn2mRJRTA_g" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyt3.googleusercontent.com%2FRIzr-0Smkmg3dcAmBedb7FDoofVtML0mW5AtG8ixVmh9EDh9E8zPq7toYW243x3PChxCztcSxg%3Ds900-c-k-c0x00ffffff-no-rj" height="900" class="m-0" width="900"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.youtube.com/channel/UC_tS0kNJZXkMZn2mRJRTA_g" rel="noopener noreferrer" class="c-link"&gt;
            Let's Talk Dev - YouTube
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            I share my insights and tips on software engineering topics such as web development, databases, cloud computing, and more.
Hi, I'm Mihai and I'm a full-stack software engineer with a passion for creating innovative and user-friendly solutions using web and cloud technologies. I have a home lab where I like to experiment with Kubernetes and other cutting-edge technologies. I'm also a big fan of open-source software.
When I'm not coding, I enjoy photography, reading books, learning about finance and entrepreneurship, and watching movies.

          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.youtube.com%2Fs%2Fdesktop%2F5d82a8bc%2Fimg%2Ffavicon.ico" width="16" height="16"&gt;
          youtube.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Transitioning from Node.js to Go:
&lt;/h2&gt;

&lt;p&gt;While I found several similarities between Go and Node.js, particularly in their approach to concurrency and support for functional programming paradigms, there are also some notable differences that shaped my transition experience. Initially, I felt a bit disoriented switching between the two languages, but as I gained more experience with Go, the transition became smoother.&lt;/p&gt;

&lt;p&gt;Go's strict type system and compilation process were significant changes from Node.js with TypeScript.  While TypeScript introduces static typing to JavaScript, Go's type system is more strict and enforced during compilation.  This stricter approach reduces runtime errors and improves code reliability.  Go's compilation process also differs from TypeScript's transpilation process.  Go compiles directly to machine code, resulting in faster execution speeds compared to TypeScript, which is transpiled to JavaScript that then runs on a JavaScript engine.&lt;/p&gt;

&lt;p&gt;A big difference was Go's minimalist approach to error handling. Unlike Node.js's reliance on exceptions, Go treats errors as values, requiring explicit handling. This approach, while initially surprising, encouraged me to write more robust and error-aware code. It also made me realize the importance of carefully considering error handling strategies in my Node.js projects. I must say that I much prefer Go’s approach to error handling!&lt;/p&gt;

&lt;p&gt;Go's built-in support for concurrency through goroutines and channels was a significant advantage over Node.js's single-threaded model with its event loop and asynchronous callbacks. Goroutines, Go's lightweight concurrency units, allowed me to write concurrent code without the overhead of managing threads manually.  They are managed by the Go runtime, and multiple goroutines can be multiplexed onto a smaller number of OS threads.  This is unlike Node.js, where the developer has to make use of the event loop and manage asynchronous code and callbacks.  Channels, the communication mechanism between goroutines, provided a safe and efficient way to synchronize data between concurrent processes.  They can be used to pass data and also to signal that a certain task is done.&lt;/p&gt;

&lt;p&gt;For other Node.js developers looking to learn Go, I recommend embracing the type system, understanding the concurrency model, and adopting Go’s error handling approach. There are plenty of resources available online, including tutorials, documentation, and community forums, to help you get started with Go. You can also check out my video about how I started learning Go:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Wv-vgKk-3ds"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of Learning Go
&lt;/h2&gt;

&lt;p&gt;Learning Go has been a rewarding experience, and I encourage other Node.js developers to explore this powerful language. By taking this step, you'll be investing in your own growth and development as a software engineer. Here are some of the benefits I've gained from learning Go:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improved performance and scalability of applications&lt;/strong&gt;: Go's compiled nature and efficient memory management translate to faster execution speeds and reduced resource consumption. This can lead to significant improvements in application performance, especially for high-traffic web services and data-intensive applications.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced understanding of concurrency and parallelism&lt;/strong&gt;: Go's built-in concurrency features, using goroutines and channels, provide an elegant and efficient way to handle concurrent operations. Learning Go can deepen your understanding of concurrency concepts.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased productivity and code maintainability&lt;/strong&gt;: Go's simplicity, strong typing, and tooling contribute to increased developer productivity. The language's focus on readability and clarity makes it easier to write, understand, and maintain code, even in large and complex projects.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exposure to a new programming language and its community&lt;/strong&gt;: Learning a new language like Go exposes you to new ideas, paradigms, and approaches to problem-solving. It also opens doors to a vibrant and supportive community of Go developers, where you can learn, collaborate, and contribute.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion:
&lt;/h2&gt;

&lt;p&gt;Go's popularity is a testament to its ability to address the challenges of building modern, high-performance applications. Its performance, concurrency model, simplicity, and tooling have made it a compelling choice for developers across various domains.&lt;/p&gt;

&lt;p&gt;My journey into Go as a Node.js developer has been a rewarding experience. The transition, while initially challenging, has broadened my perspective and enhanced my skill set. I encourage other Node.js developers to consider learning Go and explore its potential for building robust and scalable applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;I'm Mihai Farcas, a software engineer with a few years of experience under my belt. I'm passionate about writing code and love sharing knowledge with fellow developers. &lt;/p&gt;

&lt;p&gt;My YouTube channel, "Let's Talk Dev," is where I break down complex concepts, share my experiences (both the good and the face-palm moments).&lt;/p&gt;

&lt;p&gt;Connect with me:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Website&lt;/strong&gt;: &lt;a href="https://mihai.ltd" rel="noopener noreferrer"&gt;https://mihai.ltd&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;YouTube&lt;/strong&gt;: &lt;a href="https://www.youtube.com/@letstalkdev" rel="noopener noreferrer"&gt;https://www.youtube.com/@letstalkdev&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/mihailtd" rel="noopener noreferrer"&gt;https://github.com/mihailtd&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;LinkedIn&lt;/strong&gt;: &lt;a href="https://www.linkedin.com/in/mihai-farcas-ltd/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/mihai-farcas-ltd/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Prompt Engineering and Other Bullshit Jobs in Tech</title>
      <dc:creator>Mihai Farcas</dc:creator>
      <pubDate>Wed, 28 Aug 2024 20:31:22 +0000</pubDate>
      <link>https://dev.to/mihailtd/prompt-engineering-and-other-bullshit-jobs-in-tech-4lk4</link>
      <guid>https://dev.to/mihailtd/prompt-engineering-and-other-bullshit-jobs-in-tech-4lk4</guid>
      <description>&lt;p&gt;In the tech industry, we love our buzzwords. "Prompt engineering" is the latest buzzword, a shiny new term for a role that shouldn’t and probably doesn’t exist. As usual, the internet and tech companies have latched onto this buzzword and are now creating entire "prompt engineering" teams.&lt;/p&gt;

&lt;p&gt;I'm calling BS. Sure, there's a skill to getting chatbots to spit out what you want, but it's not that hard to do, nor does it deserve its own “role” in a company. It's more like knowing how to sweet-talk or clearly define what you want. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Bullshit Job Phenomenon in Tech
&lt;/h2&gt;

&lt;p&gt;Bullshit jobs are not a new phenomenon in tech. Long before "prompt engineer" became a thing, the tech world was already a breeding ground for pointless positions.&lt;/p&gt;

&lt;p&gt;The Compliance Officer Who Clicks "Approve": In the wake of scandals and regulations, companies hired hordes of compliance officers. Many of them spent their days rubber-stamping documents, ensuring the illusion of oversight rather than actual scrutiny.&lt;/p&gt;

&lt;p&gt;The "Innovation Strategist" Who Never Innovates: With titles like "Chief Innovation Officer" or "VP of Disruption," these folks were paid handsomely to brainstorm ideas that rarely see the light of day. Their real job? To make the company look forward-thinking.&lt;/p&gt;

&lt;p&gt;The "Customer Experience Manager" Who Doesn't Talk to Customers: Tasked with improving the customer experience, these employees often have little contact with actual customers. Instead, they focused on internal metrics and reports, creating the illusion of progress without actually making a difference.&lt;/p&gt;

&lt;p&gt;In David Graeber's book Bullshit Jobs, he describes the phenomenon of pointless jobs that exist only to make companies or individuals appear busy and important. Think of all those endless meetings that could've been an email. He argues that these jobs are not only useless but also soul-crushing for the people who hold them.&lt;/p&gt;

&lt;p&gt;The rise of "prompt engineering" seems to fit Graeber's definition of a bullshit job perfectly. It's a job that exists solely because of the hype surrounding AI, not because there's any real need for it. It exists because it sounds cutting-edge and cool, not because it solves real problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "Prompt Engineers" Actually Do (or Don't Do)
&lt;/h2&gt;

&lt;p&gt;So, you're probably wondering, what do these so-called "prompt engineers" actually do all day? Well, the truth is, it's not as glamorous as it sounds. The reality is that much of what's touted as "prompt engineering" is just the same old stuff dressed up in fancy new tech jargon.&lt;/p&gt;

&lt;p&gt;The fundamental skills remain the same. If you were a marketer before, you still need marketing expertise to craft effective prompts for AI. If you were a coder, you still need coding knowledge to guide the AI in generating functional code. AI is a tool, not a replacement for domain knowledge.&lt;/p&gt;

&lt;p&gt;It boils down to crafting clear and specific instructions for AI models. Think of it like giving directions to a particularly literal-minded friend. You need to be explicit, avoid ambiguity, and anticipate potential misunderstandings. It's less about engineering and more about effective communication.&lt;/p&gt;

&lt;p&gt;Of course, there are some nuances involved. Prompt engineers might experiment with different phrasing, iterate on instructions, and fine-tune parameters to optimize the AI's output. But let's be honest, it's not exactly rocket science. If you can write a clear email or follow a recipe, you've got the basic skills down.&lt;/p&gt;

&lt;p&gt;You can confidently dismiss the "prompt engineer" fad. Prompting LLMs or AI is not a job; it's a skill, and a basic one at that. It certainly won't be a key differentiator in the job market.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain Expertise vs. Prompt Engineering: What Employers Really Want?
&lt;/h2&gt;

&lt;p&gt;Let's cut through the BS. The real value in today's AI-driven world isn't in "prompt engineering" – it's in good old-fashioned domain expertise. AI is a tool, and like any tool, it's only as good as the person wielding it. You can give a monkey a paintbrush, but it won't create a masterpiece - actually never mind, that would probably sell for millions. Similarly, you can give someone with zero marketing experience the ability to prompt an AI, but they won't generate a winning campaign.&lt;/p&gt;

&lt;p&gt;The hype around "prompt engineering" might be driven by the same factors that create bullshit jobs. It's a shiny new title that creates an illusion of specialized knowledge and importance, masking the reality that the core tasks remain unchanged. Companies might be tempted to hire "prompt engineers" to project an image of being at the forefront of AI innovation, even if the role itself adds little genuine value.&lt;/p&gt;

&lt;p&gt;Employers ultimately care about results. They might think they need people with AI prompting skills, but what they really need is someone who can deliver. And delivering results requires experience, expertise, and intelligence. AI can assist in the process, but it can't replace the human element that drives success.&lt;/p&gt;

&lt;p&gt;The future of work isn't about becoming a "prompt engineer." It's about becoming an expert in your field and learning how to leverage AI to enhance your skills and productivity. AI can automate mundane tasks, generate ideas, and provide insights, but it can't replace the critical thinking, creativity, and problem-solving skills that come with true expertise.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future of Work in the Age of AI
&lt;/h2&gt;

&lt;p&gt;The future belongs to those who can adapt and evolve, not those who chase fleeting trends. Instead, invest in yourself and your skills. Focus on building your knowledge in your chosen field. The real winners in the age of AI will be those who combine their domain expertise, with their unique set of skills and experience and use AI as a tool to enhance these.&lt;/p&gt;

&lt;p&gt;"Prompt engineering" is largely a myth. Don't be fooled by the hype. Focus on what you're good at, and let the AI tools help you where they actually can. The essence of meaningful work lies in its ability to create value, solve problems, and contribute to the world. AI can be a powerful ally in this endeavor, but it's the human element - our knowledge, creativity, and passion - that will ultimately define the future of work.&lt;/p&gt;

&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;I'm Mihai Farcas, a software engineer with a few years of experience under my belt. I'm passionate about writing code and love sharing knowledge with fellow developers. &lt;/p&gt;

&lt;p&gt;My YouTube channel, "Let's Talk Dev," is where I break down complex concepts, share my experiences (both the good and the face-palm moments).&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.youtube.com/@letstalkdev" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyt3.googleusercontent.com%2FRIzr-0Smkmg3dcAmBedb7FDoofVtML0mW5AtG8ixVmh9EDh9E8zPq7toYW243x3PChxCztcSxg%3Ds900-c-k-c0x00ffffff-no-rj" height="900" class="m-0" width="900"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.youtube.com/@letstalkdev" rel="noopener noreferrer" class="c-link"&gt;
            Let's Talk Dev - YouTube
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            I share my insights and tips on software engineering topics such as web development, databases, cloud computing, and more.
Hi, I'm Mihai and I'm a full-stack software engineer with a passion for creating innovative and user-friendly solutions using web and cloud technologies. I have a home lab where I like to experiment with Kubernetes and other cutting-edge technologies. I'm also a big fan of open-source software.
When I'm not coding, I enjoy photography, reading books, learning about finance and entrepreneurship, and watching movies.

          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.youtube.com%2Fs%2Fdesktop%2F5d82a8bc%2Fimg%2Ffavicon.ico" width="16" height="16"&gt;
          youtube.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Connect with me:&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://mihai.ltd" rel="noopener noreferrer"&gt;https://mihai.ltd&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@letstalkdev" rel="noopener noreferrer"&gt;https://www.youtube.com/@letstalkdev&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/mihailtd" rel="noopener noreferrer"&gt;https://github.com/mihailtd&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/mihai-farcas-ltd/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/mihai-farcas-ltd/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>promptengineering</category>
      <category>career</category>
    </item>
    <item>
      <title>Simplify PostgreSQL Deployments with Kubernetes &amp; GitOps (with Crunchy Data Operator)</title>
      <dc:creator>Mihai Farcas</dc:creator>
      <pubDate>Mon, 22 Jul 2024 21:17:15 +0000</pubDate>
      <link>https://dev.to/mihailtd/simplify-postgresql-deployments-with-kubernetes-gitops-with-crunchy-data-operator-4hca</link>
      <guid>https://dev.to/mihailtd/simplify-postgresql-deployments-with-kubernetes-gitops-with-crunchy-data-operator-4hca</guid>
      <description>&lt;p&gt;Ever felt frustrated with the complexity of running PostgreSQL on Kubernetes? Manually setting up data volumes, services, deployments, managing backups, managing secrets holding credentials, not to mention high availability... There is a lot of complexity in running stateful applications in Kubernetes. This is especially true if you're aiming to achieve this in a declarative GitOps way.&lt;/p&gt;

&lt;p&gt;There is a way to simplify this process, to deploy PostgreSQL declaratively, and have a production-ready setup with just a few lines of declarative yaml.&lt;/p&gt;

&lt;p&gt;That's where the Crunchy Data Postgres Operator comes in.&lt;br&gt;
In this article, let's deploy PostgreSQL declaratively, creating a production-ready setup on Kubernetes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you'd rather watch than read:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Y2V5HqCqx34"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Crunchy Data Postgres Operator
&lt;/h2&gt;

&lt;p&gt;To follow along, you need to have a kubernetes cluster running. On my local machine I will be using Rancher Desktop - see my video on that topic. Or you can do so in the cloud or even in your own homelab, and wouldn’t you know, I have a video on how to easily set up a kubernetes homelab as well.&lt;/p&gt;

&lt;p&gt;Let’s get back to the task at hand. Installing PGO is not that complicated, however it presented a few challenges when I initially started out, especially since I was a beginner in Kubernetes back then. So I am aiming to simplify this process for you.&lt;/p&gt;

&lt;p&gt;To help us out Crunchy has prepared a &lt;a href="https://github.com/CrunchyData/postgres-operator-examples" rel="noopener noreferrer"&gt;github repo with code examples&lt;/a&gt;. You can find that in the &lt;a href="https://access.crunchydata.com/documentation/postgres-operator/latest" rel="noopener noreferrer"&gt;quick start guide&lt;/a&gt; from the documentation.&lt;/p&gt;

&lt;p&gt;Let’s clone that repo locally and see what’s inside.&lt;/p&gt;

&lt;p&gt;There are a couple of ways to install PGO, or actually most things in kubernetes. One is through Helm and one is through Kustomize.&lt;/p&gt;

&lt;p&gt;I will use Kustomize, it is the closest thing to native kubernetes manifests and I believe the easiest to figure out what exactly is being installed.&lt;/p&gt;

&lt;p&gt;You'll want to check out the folder conveniently named &lt;code&gt;install&lt;/code&gt;. And yet again, there are a couple of ways of installing it. One is the single namespace install, where PGO will manage Postgres instances in, well, a single namespace, and the other one is a cluster-wide installation where PGO can manage postgres instances in any namespace in the cluster. The main difference is in the permissions you give PGO within your cluster. &lt;/p&gt;

&lt;p&gt;This type of cluster-wide operator is important and we will see that later on we'll talk about the interesting topic of Platform Development.&lt;/p&gt;

&lt;p&gt;The cluster-wide installation manifests can be found in the &lt;code&gt;default&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Here we can check the manifest file, it references other manifests, but we can understand what it’s trying to do: install a CRD or a custom resource definition, which is how you extend the kubernetes API, it applies some role based access controls (RBAC), and some thing called “manager” which is just a deployment, a pod that will run an image with the code that makes all of this possible.&lt;/p&gt;

&lt;p&gt;OK let’s try to apply these manifests, &lt;code&gt;kubectl apply -k ./kustomize/install/default&lt;/code&gt; and here we get the first error. The annotation is too long. To fix it you just need server-side apply. I added the --force-conflicts flag as well but that’s optional. Here is the final command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -k ./kustomize/install/default --server-side --force-conflicts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And that’s it, we now have the Crunchy Data Postgres Operator installed!&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying PostgreSQL using PGO
&lt;/h2&gt;

&lt;p&gt;In the examples repository you can find manifests that showcase the options you have when deploying PostgreSQL. Let's take a look at &lt;code&gt;/kustomize/postgres/postgres.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With PGO installed we can now create a custom resource of kind &lt;code&gt;PostgresCluster&lt;/code&gt;.&lt;br&gt;
In the manifest we can define the Postgres image and version to use, in this case version 16.&lt;br&gt;
We can have multiple instances in the same manifest and each instance can be a replica set with multiple replicas.&lt;br&gt;
For example here there is a single instance named &lt;code&gt;instance1&lt;/code&gt;.&lt;br&gt;
We need to allocate some storage - 1 gb should be enough.&lt;/p&gt;

&lt;p&gt;Another required field to have a minimal postgres cluster is the &lt;code&gt;backup&lt;/code&gt; configuration. It’s nice that they "force" you to have at least a minimal backup configuration. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In a production scenario the backups should be stored at least on a separate drive or even better, offsite or in the cloud.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are a bunch of options you can configure here, and after we apply the manifest, PGO will take care of backups automatically.&lt;/p&gt;

&lt;p&gt;As you can see there are a few pods that started, you can see one pod for that postgres instance. There is also a backup job that ran immediately and now it’s stopped. It also created some kubernetes services so you can connect to this postgres instance.&lt;/p&gt;

&lt;p&gt;Speaking of connecting to postgres, one of the best things about this operator is that it manages credentials in kubernetes secrets automatically!&lt;/p&gt;

&lt;p&gt;You should see a secret for each user configured for the database. Let’s check one of these secrets out to see what’s in there: a few properties, basically everything you need to successfully connect to the database!&lt;/p&gt;

&lt;p&gt;No need to manually configure secrets, this is all done for us!&lt;/p&gt;

&lt;p&gt;Actually let me show you how easy it is to just create a user and a new database.&lt;br&gt;
There is a &lt;code&gt;users&lt;/code&gt; key in the manifest, and we can give it a name, we can specify the databases this new user has access to. The nice thing is that if the database doesn’t exist PGO will create it. Let’s call it testdb. And we can give this new user SUPERUSER access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
      &lt;span class="na"&gt;databases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;testdb&lt;/span&gt;
      &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SUPERUSER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now it’s as simple as applying this new manifest and there we go, a new secret has been created for this new user with all the credentials. &lt;br&gt;
More importantly behind the scene, all the required operations were done for us, creating the database, creating the user and so on. And the beauty of it all is that it’s all declarative!&lt;/p&gt;
&lt;h3&gt;
  
  
  Deploying PGAdmin
&lt;/h3&gt;

&lt;p&gt;I’d really love to test all of this in a visual way, if only there was a UI interface to see what’s going on in a Postgres database. Oh wait, PGO can also manage a PGAdmin installation for us! Let’s check out the manifest for that: &lt;code&gt;./kustomize/pgadmin/pgadmin.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As you can see the other custom resource that this operator installed is of kind &lt;code&gt;PGAdmin&lt;/code&gt;.&lt;br&gt;
Let’s just apply this example manifest. We can see a pod PGAdmin was created, let’s port forward and open it in a browser.&lt;/p&gt;

&lt;p&gt;Credentials for the PGAdmin web interface are also stored in a kubernetes secret automatically.&lt;/p&gt;
&lt;h3&gt;
  
  
  High Availability
&lt;/h3&gt;

&lt;p&gt;Scaling a PostgreSQL instance with PGO is as easy as flipping an integer:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-operator.crunchydata.com/v1beta1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PostgresCluster&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hippo-ha&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.3-1&lt;/span&gt;
  &lt;span class="na"&gt;postgresVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;
  &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pgha1&lt;/span&gt;
      &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Just change the number of replicas to whatever you need, and PGO will take care of it. See &lt;code&gt;./kustomize/high-availability/ha-postgres.yaml&lt;/code&gt; for a more complete example that also includes &lt;code&gt;pgbouncer&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is a Kubernetes Operator?
&lt;/h2&gt;

&lt;p&gt;Kubernetes is great at managing stateless applications, it has everything you need out of the box. But stateful applications like PostgreSQL, which store persistent data and require special care and procedures to run, that’s a bit more tricky. This is where Kubernetes Operators come in. They are software extensions that enhance Kubernetes' capabilities, specifically designed to automate the management of complex, stateful applications like PostgreSQL databases.&lt;/p&gt;

&lt;p&gt;Like we saw earlier, operators extend the kubernetes API with new types of resources, in this case we had the &lt;code&gt;PostgresCluster&lt;/code&gt; and the &lt;code&gt;PGAdmin&lt;/code&gt; resource types.&lt;/p&gt;

&lt;p&gt;The operators usually also run a container in the background and can handle certain administrative tasks for you, for example they can scale Postgres instances, automate backup and restores, disaster recovery etc.&lt;/p&gt;

&lt;p&gt;And most importantly they can do so in a declarative way!&lt;/p&gt;
&lt;h2&gt;
  
  
  Platform Development
&lt;/h2&gt;

&lt;p&gt;This leads me to the other topic I wanted to cover in the video and that is &lt;strong&gt;Platform Development&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is a concept where you have a platform team that manages a Kubernetes cluster that has all of these operators installed.&lt;/p&gt;

&lt;p&gt;This platform then enables self-provisioning and managing of resources without complex scripting, manual actions - it’s all done through declarative configuration!&lt;/p&gt;

&lt;p&gt;This is especially important for a few use cases, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spinning up new environments like staging or test environments&lt;/li&gt;
&lt;li&gt;Accelerating development cycles and productivity&lt;/li&gt;
&lt;li&gt;Faster iteration on new ideas&lt;/li&gt;
&lt;li&gt;Implementing GitOps principles ensuring consistency, repeatability and auditability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So there you have it! The Crunchy Data Postgres Operator takes the complexity out of running PostgreSQL on Kubernetes. Head over to their GitHub page and give it a try. I'd love to hear about your experiences in the comments below!&lt;/p&gt;

&lt;p&gt;Don't forget to subscribe to my youtube channel for more content like this!&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.youtube.com/@letstalkdev" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyt3.googleusercontent.com%2FRIzr-0Smkmg3dcAmBedb7FDoofVtML0mW5AtG8ixVmh9EDh9E8zPq7toYW243x3PChxCztcSxg%3Ds900-c-k-c0x00ffffff-no-rj" height="900" class="m-0" width="900"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.youtube.com/@letstalkdev" rel="noopener noreferrer" class="c-link"&gt;
            Let's Talk Dev - YouTube
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            I share my insights and tips on software engineering topics such as web development, databases, cloud computing, and more.
Hi, I'm Mihai and I'm a full-stack software engineer with a passion for creating innovative and user-friendly solutions using web and cloud technologies. I have a home lab where I like to experiment with Kubernetes and other cutting-edge technologies. I'm also a big fan of open-source software.
When I'm not coding, I enjoy photography, reading books, learning about finance and entrepreneurship, and watching movies.

          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.youtube.com%2Fs%2Fdesktop%2F5d82a8bc%2Fimg%2Ffavicon.ico" width="16" height="16"&gt;
          youtube.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>kubernetes</category>
      <category>postgres</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Hosting for Web Apps: Cloud vs. Homelab vs. Hybrid – Which Saves You Money?</title>
      <dc:creator>Mihai Farcas</dc:creator>
      <pubDate>Sun, 14 Apr 2024 13:42:07 +0000</pubDate>
      <link>https://dev.to/mihailtd/hosting-for-web-apps-cloud-vs-homelab-vs-hybrid-which-saves-you-money-4h85</link>
      <guid>https://dev.to/mihailtd/hosting-for-web-apps-cloud-vs-homelab-vs-hybrid-which-saves-you-money-4h85</guid>
      <description>&lt;p&gt;Cloud providers love to promise cheap, scalable web app hosting. The reality is often far more complex. Let's cut through the marketing jargon and uncover the true cost of cloud solutions, the potential savings of a homelab, and when a hybrid approach might be your smartest move.&lt;/p&gt;

&lt;h2&gt;
  
  
  When "Simple" Gets Costly
&lt;/h2&gt;

&lt;p&gt;Building a solid online presence is crucial in today's world, and a strong portfolio website can open doors to new opportunities. That's why I decided to create my own &lt;a href="https://mihai.ltd" rel="noopener noreferrer"&gt;"Mihai @ Let's Talk Dev" portfolio website&lt;/a&gt;, opting for a stack using Nuxt.js, Directus CMS, and PostgreSQL. While the development went smoothly, finding the right hosting solution proved far more complicated than I anticipated.&lt;/p&gt;

&lt;p&gt;If you'd rather watch than read, check out my video on this topic here:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/NoRr4uNSu7s"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://vercel.com/pricing" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;: The Maze of Pricing
&lt;/h3&gt;

&lt;p&gt;Initially, Vercel seemed like a great choice for the frontend. Their promises of "unlimited this" and "free that" are enticing... until you try to decipher their pricing structure. Even with experience, I found it overwhelming, and it's easy to imagine how intimidating this would be for newcomers.&lt;/p&gt;

&lt;p&gt;One particularly obscure detail was the PostgreSQL compute time limit on their "Hobby" tier. While 60 hours per month sound generous, there's no clear definition of what constitutes a "compute hour." This lack of transparency makes it incredibly difficult to estimate your real-world costs for a web app.&lt;/p&gt;

&lt;p&gt;Let's consider two scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Low-Traffic Backend: If your web app powers a small portfolio site or a simple API with infrequent queries, you might stay within the free tier.&lt;/li&gt;
&lt;li&gt;A Real-Time Dashboard: Now, picture a dashboard constantly polling for updates. These frequent requests, even if simple, could blow past those 60 hours in no time, landing you with a bill for each additional hour.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...And here's where I want you to think honestly: Looking at this price table, would you be able, right now, to predict with certainty how quickly your project might outgrow Vercel's free tier? Can you really say for sure which of those limits you'll hit first – the storage, the requests, or that mysterious "compute time"? Or, even, how much will your first month’s invoice be?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9oy4wkqlzvu6sytgyis.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%2Fk9oy4wkqlzvu6sytgyis.png" alt="Image: Screenshot of Vercel's pricing page" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Cost of Convenience: &lt;a href="https://supabase.com/pricing" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Seeking a simpler solution, I considered Supabase. Their free tier looked promising at first. But then I hit a major snag: they sleep inactive databases, and you have to manually wake them up from the dashboard.&lt;/p&gt;

&lt;p&gt;Now, my web app wouldn't get a ton of traffic. I could realistically see a week with no visitors. Could I really guarantee at least some activity to keep my database awake? Should I resort to automated scripts as a workaround? That seems like a hack, and suddenly, even basic availability jumps you into paid tiers.&lt;/p&gt;

&lt;p&gt;And then there's the storage issue. Their free storage is tiny – maybe enough for a simple portfolio, but a slightly more complex project would easily exceed that limit. It seems like this would be the first hurdle forcing you into a paid tier, even if everything else about your project is small-scale. And then that next tier likely over-provisions the database to something you don't really need – the jump is just too drastic.&lt;/p&gt;

&lt;p&gt;This made me question whether these supposedly simpler services are really as straightforward as they seem.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.digitalocean.com/pricing" rel="noopener noreferrer"&gt;Digital Ocean&lt;/a&gt;: Better
&lt;/h3&gt;

&lt;p&gt;Unlike Vercel and Supabase, which are Platform-as-a-Service (PaaS) providers, Digital Ocean takes an Infrastructure-as-a-Service (IaaS) approach. This means they focus on renting you raw resources like virtual machines ("droplets"), instead of pre-packaged web app solutions. This offers more granular control over costs compared to the often opaque tiered pricing of PaaS solutions.&lt;/p&gt;

&lt;p&gt;So, at least with platforms like Digital Ocean, the pricing is transparent. However, their managed database options start off affordable but quickly become expensive as you need more resources. Even a modest performance boost can easily double your bill.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furfpqs1goop1itksdzrt.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%2Furfpqs1goop1itksdzrt.png" alt="Image: Digital Ocean Managed PostgreSQL pricing" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's important to note that 1GB of RAM and 1 CPU core isn't really a performant database setup, especially for anything beyond a small project. And this price is just for a single node, not a cluster. On the plus side, they do include free daily backups for 7 days, which is a nice touch.&lt;/p&gt;

&lt;p&gt;I would also need one or two droplets where I could host the Nuxt page itself and the Directus CMS. So you’re looking at upwards of $20 for a simple website like this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Cloud Costs Cause Headaches
&lt;/h2&gt;

&lt;p&gt;Before diving into specific pitfalls, let's understand the root of the problem with cloud hosting for many web apps:&lt;/p&gt;

&lt;h3&gt;
  
  
  Complexity Overload
&lt;/h3&gt;

&lt;p&gt;Cloud providers offer a dizzying array of services designed for massive enterprises. For most of us, this is overkill. Think of AWS: you start needing a host (EC2), then storage (S3), a database (RDS), maybe a CDN... It's like an onion, layer upon layer of services, each with its own pricing model. This makes accurately budgeting for your web app almost impossible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hidden Fees
&lt;/h3&gt;

&lt;p&gt;Data transfer, egress charges... ever tried to calculate the cost of moving your data off a cloud platform? It'll make you question your tech choices (and maybe consider investing in a fast SSD instead!). The nickel-and-diming is rampant, and thankfully, the European Union is taking action. Their new Data Act aims to force transparency around these fees, but it highlights how insidious the problem has become.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vendor Lock-In
&lt;/h3&gt;

&lt;p&gt;Those shiny, cloud-exclusive tools are tempting. But good luck migrating if your costs suddenly skyrocket! You might end up feeling trapped, with the cloud feeling more like a mortgage than a flexible solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security and Surprise Invoices
&lt;/h3&gt;

&lt;p&gt;As Web Dev Cody showed in his &lt;a href="https://www.youtube.com/watch?v=-lNpF0ACe1Y" rel="noopener noreferrer"&gt;video&lt;/a&gt;, cloud security isn't a "set it and forget it" deal. Protection during attacks can get incredibly expensive. Planning is key! If your self-hosted server gets DDoS'ed, downtime is likely. But, if your cloud service gets hit, you might face a shocking bill. The right choice depends on your web app's needs: can you tolerate downtime, or is an unexpected invoice worse?&lt;/p&gt;

&lt;h2&gt;
  
  
  Pitfalls
&lt;/h2&gt;

&lt;p&gt;Understanding pitfalls like these is crucial for avoiding unexpected costs. Here are five of the most common ones I've encountered:&lt;/p&gt;

&lt;h3&gt;
  
  
  Pitfall 1: The Illusion of "Per Request" Pricing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Charges by Rows Fetched&lt;/strong&gt;: Let's say your shiny cloud database charges per row fetched. Sounds reasonable, right? But one unoptimized query without an index? Suddenly, you're scanning thousands of rows to find that single piece of data you need ...and now your 'cheap' database query just bankrupted you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Charges per Requests&lt;/strong&gt;: Requests are not users. My simple portfolio sees about 1500 requests for 50 unique users. That's because every image, CSS file, and JavaScript snippet that is sent in chunks is a request. And that’s for my simple portfolio, for a more dynamic website, and the bill stacks up fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unpredictability&lt;/strong&gt;: Unless you can predict exactly how every user will interact with your site, estimating your true cost at the end of the month is next to impossible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pitfall 2: The "Generosity" Trap
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Bait&lt;/strong&gt;: Ample free storage, bandwidth, etc., lure you in. But that one crucial feature you really need? Strangely limited...forcing a paid upgrade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overprovisioning&lt;/strong&gt;: And of course, that upgrade tier forces you into a package with way more resources than you need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the Fine Print&lt;/strong&gt;: Try to understand what each item on the pricing page means, before you get hooked!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pitfall 3: The Cost of Escape
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Egress&lt;/strong&gt;: Extracting your data out of the cloud? You'll often pay steep fees for the privilege, especially at scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool Lock-in&lt;/strong&gt;: Proprietary cloud tools may seem amazing at first, but are designed to make switching a nightmare, potentially costing you a small fortune in development time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pitfall 4: Dangerous Ignorance
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Abstraction Blindness&lt;/strong&gt;: Many devs treat cloud services as magic black boxes. They don't realize the underlying tech (PostgreSQL, Nginx, etc.) and how that impacts cost. Imagine unknowingly deploying a database configuration that costs ten times more than a perfectly suitable alternative!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "Just Pay" Mentality&lt;/strong&gt;: Without understanding the fundamentals, devs easily accept inflated prices, assuming "this is just how the cloud works." But cloud pricing is often arbitrary. Understanding and questioning those costs is important!
And this perfectly sets us up for the next pitfall:&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pitfall 5: The "Managed" Illusion
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Managed Doesn't Mean Problem-Free&lt;/strong&gt;: Managed databases and automatic backups are fantastic tools. However some developers confuse them with a set-it-and-forget-it solution, but they often lure developers into a false sense of security.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What You Still Need to Do:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Performance Tuning: Managed services don't optimize your queries for you. Indexing, database design are still your responsibility. Not understanding this leads to unnecessary costs through inefficient setup or over-reliance on auto-scaling – both of which cloud providers happily profit from.&lt;/li&gt;
&lt;li&gt;Backup Strategy: Automatic backups are great, but what's your disaster recovery plan? How often do you test restores?&lt;/li&gt;
&lt;li&gt;Cost Control and Monitoring: Managed services can scale automatically, often without you fully realizing it. You still need to monitor usage. Cloud providers DO offer monitoring tools, but they often come with their own costs or limitations. Don't assume you're getting accurate oversight for free!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Solutions for my portfolio website
&lt;/h2&gt;

&lt;p&gt;So, does this mean cloud computing is evil? Absolutely not! I don’t even think the services I outlined here are bad, they just helped me illustrate some points and misconceptions. But, you need to be armed with knowledge. Here’s what ended up working for my portfolio website:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl5tq5y9g5cdekazgdglt.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%2Fl5tq5y9g5cdekazgdglt.png" alt="Mihai @ Let's Talk Dev portfolio website infrastructure diagram" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Finding the Right Fit&lt;/strong&gt;: I used &lt;a href="https://workers.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare Workers&lt;/a&gt; for the Nuxt frontend application. It is simple to use and has a generous free tier. Cloudflare also acts as your DNS manager, and offers performance optimizations and DDOS protection for free! This seems like a smart strategy on their part – support smaller projects with potential to grow, and they get word of mouth recommendations, case and point, I’m mentioning their services in this video!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Homelab Love&lt;/strong&gt;: For the CMS, my trusty homelab server stepped up. This is where I host Directus and PostgreSQL. To see some more information on how I built my homelab server, check out this video! Yes, electricity costs a bit, but at least my server isn't sending me surprise invoices. It’s a predictable cost and I'm in total control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be Strategic about Self-Hosting&lt;/strong&gt;: Choose what goes on your servers for example, non mission critical services, staging environments and so on. and what goes in the cloud or on managed services. For example, I self-host multiple services that use the same database instance, sharing the costs. Plus, I can use the same Directus instance to manage content for multiple websites. And for securely exposing the services from my home network, I use &lt;a href="https://www.cloudflare.com/products/tunnel/" rel="noopener noreferrer"&gt;Cloudflare Tunnels&lt;/a&gt; – a great option for controlled exposure of self-hosted services. This was again, free, if you can believe it! So all in all I am only paying for electricity to host my website.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Price Conscious Architecting&lt;/strong&gt;: When I do use the cloud, I scrutinize every component's cost. Open-source tools help break free of vendor lock-in and give me more flexibility in the long run.&lt;/li&gt;
&lt;li&gt;But beyond that, I'm &lt;strong&gt;investing time into learning the underlying technologies&lt;/strong&gt; – things like Kubernetes and cloud-native applications. This means that if I need to, I can move these workloads between cloud providers, or even bring them to my homelab without major headaches.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take time to understand what you actually NEED and shop smartly. Don’t be afraid to do it yourself, and learn the hard things, trust me it pays off!&lt;/p&gt;

&lt;p&gt;Let's keep this conversation going. Drop your cloud pricing horror stories in the comments, and let's learn from each other. Maybe your story will help someone else avoid a nasty cloud invoice.&lt;/p&gt;

&lt;p&gt;Or maybe you think my criticism is unfair - write me a comment about that, I read all of them!&lt;/p&gt;

&lt;p&gt;And before you go, we’re getting very close to 1000 subscribers!&lt;br&gt;
Please consider subscribing to the Let's Talk Dev YouTube channel:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.youtube.com/channel/UC_tS0kNJZXkMZn2mRJRTA_g" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyt3.googleusercontent.com%2FRIzr-0Smkmg3dcAmBedb7FDoofVtML0mW5AtG8ixVmh9EDh9E8zPq7toYW243x3PChxCztcSxg%3Ds900-c-k-c0x00ffffff-no-rj" height="900" class="m-0" width="900"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.youtube.com/channel/UC_tS0kNJZXkMZn2mRJRTA_g" rel="noopener noreferrer" class="c-link"&gt;
            Let's Talk Dev - YouTube
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            I share my insights and tips on software engineering topics such as web development, databases, cloud computing, and more.
Hi, I'm Mihai and I'm a full-stack software engineer with a passion for creating innovative and user-friendly solutions using web and cloud technologies. I have a home lab where I like to experiment with Kubernetes and other cutting-edge technologies. I'm also a big fan of open-source software.
When I'm not coding, I enjoy photography, reading books, learning about finance and entrepreneurship, and watching movies.

          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.youtube.com%2Fs%2Fdesktop%2F5d82a8bc%2Fimg%2Ffavicon.ico" width="16" height="16"&gt;
          youtube.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Here is a video of how I built the UI for the landing page of my portfolio website I talked about in this article:&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/-DnuAVn1eB8"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>selfhosting</category>
      <category>homelab</category>
    </item>
    <item>
      <title>Better Postgres Database Migrations and Testing by Ditching Bloated ORMs</title>
      <dc:creator>Mihai Farcas</dc:creator>
      <pubDate>Sat, 02 Mar 2024 10:21:35 +0000</pubDate>
      <link>https://dev.to/mihailtd/better-postgres-database-migrations-and-testing-by-ditching-bloated-orms-1fln</link>
      <guid>https://dev.to/mihailtd/better-postgres-database-migrations-and-testing-by-ditching-bloated-orms-1fln</guid>
      <description>&lt;p&gt;Managing PostgresSQL schema can be a challenging task, especially when dealing with bloated ORMs. Learning new syntaxes that eventually translate to SQL but are almost always worse than writing pure SQL can be frustrating. In this blog post, we will explore a better approach to managing Postgres database migrations and testing, using a tool called &lt;a href="https://github.com/graphile/migrate" rel="noopener noreferrer"&gt;Graphile Migrate&lt;/a&gt;. We will discuss the important principles to follow and how Graphile Migrate simplifies the workflow. So, let's jump right in!&lt;/p&gt;

&lt;p&gt;Before I continue, a couple of useful links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The GitHub code repository containing an &lt;a href="https://github.com/mihailtd/database-migrations-and-testing" rel="noopener noreferrer"&gt;example of a database migration and integration test&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The video version of this article which contains additional practical examples.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/vf7hDdYJQoA"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Principle #1: Writing Schema Migrations in the Language of Your Database:
&lt;/h2&gt;

&lt;p&gt;The best way to write schema migrations is in the native language of your database, which is SQL. Graphile Migrate allows you to write migrations in pure SQL, freeing you from being tied to a particular tech stack. By using SQL, you can easily switch between different migration tools without rewriting your migration scripts.&lt;/p&gt;

&lt;p&gt;Embracing the native language of your database — SQL — and harnessing its robust features will empower you as a software engineer. SQL is the key to querying, manipulating, and optimizing data efficiently. Whether you’re writing complex queries or designing efficient indexes, SQL proficiency is essential for successful database management.&lt;br&gt;
So dive into SQL tutorials, practice writing queries, and explore the intricacies of database design.&lt;/p&gt;
&lt;h2&gt;
  
  
  Principle #2: Idempotency
&lt;/h2&gt;

&lt;p&gt;Graphile Migrate emphasizes the important concept of idempotency in database migrations. An idempotent operation can be run multiple times without altering the results. This means that if a migration script is run multiple times, it will always produce the same outcome. In other words an operation is considered idempotent if it can be executed multiple times without altering the final state.&lt;br&gt;
This property ensures predictability and stability during the migration process. &lt;/p&gt;
&lt;h2&gt;
  
  
  Getting Started with Graphile Migrate:
&lt;/h2&gt;

&lt;p&gt;To get started with Graphile Migrate, you'll need to install it and run the initialization script (I'm using Bun, feel free to use NodeJS &amp;amp; npm / pnpm / yarn):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun add graphile-migrate
bun graphile-migrate init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will set up the basic folder structure and configuration file. The configuration file contains connection strings for your Postgres database, and you can customize it to suit your needs. Graphile Migrate also provides features like setting placeholders which are special strings (i.e. &lt;code&gt;:DATABASE_NAME&lt;/code&gt; or &lt;code&gt;:DATABASE_USER&lt;/code&gt;) that will evaluate to a value in the final migration. This value can be evaluated from env variables for example. You can also define hooks for executing custom commands during or after the migration process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fast and Seamless Migration Workflow:
&lt;/h3&gt;

&lt;p&gt;One of the key advantages of Graphile Migrate is its speed. It runs migrations extremely fast, making the development workflow seamless. The watch mode allows you to continuously run the migration command, automatically executing the migration whenever there are changes in the SQL file. This immediate feedback enables quick iteration and boosts developer confidence that the migration scripts are correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Principle #3: Roll Forward Migrations
&lt;/h2&gt;

&lt;p&gt;Graphile Migrate exclusively supports roll forward migrations. Unlike rollbacks, which revert changes, roll forward migrations only move forward in the migration history. Here’s why this approach is beneficial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No Need for Rollbacks: By focusing solely on forward progress, developers avoid the complexity of managing backward migrations. This simplifies the schema evolution process.&lt;/li&gt;
&lt;li&gt;Consistently Reproducible Schema: Roll forward migrations maintain a clean and reproducible schema, making it easier to collaborate and deploy changes across development, staging, and production environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Principle #4: Testing Database Migrations:
&lt;/h2&gt;

&lt;p&gt;By writing integration tests for your migrations, you can ensure their correctness and catch any issues early. Testing also plays a crucial role in maintaining a consistently reproducible chain of events, which leads to the same final state every time.&lt;br&gt;
An example of a database integration test would be:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;spawn a new test database&lt;/li&gt;
&lt;li&gt;run migrations&lt;/li&gt;
&lt;li&gt;seed test data for different scenarios&lt;/li&gt;
&lt;li&gt;execute functions, triggers etc.&lt;/li&gt;
&lt;li&gt;make assertions&lt;/li&gt;
&lt;li&gt;clean up the data&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Ditching bloated ORMs and adopting a better approach to Postgres database migrations can greatly enhance your development workflow. By following the principles of writing migrations in SQL, ensuring idempotency, and leveraging the power of tools like Graphile Migrate, you can simplify the process and achieve a cleaner, consistently reproducible schema. So why not give it a try and level up your database migration game?&lt;/p&gt;

&lt;p&gt;Remember, Your mastery of SQL will elevate your development skills and enable you to build robust, scalable applications. Happy migrating!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: To learn more about the advantages of PostgreSQL and why it's a strong choice even for non-relational data, check out this video:&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/AlYHUNQQVGg"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;p&gt;Don't forget to subscribe to the &lt;a href="https://www.youtube.com/channel/UC_tS0kNJZXkMZn2mRJRTA_g/" rel="noopener noreferrer"&gt;Let's Talk Dev YouTube channel&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>sql</category>
    </item>
    <item>
      <title>Set up a Kubernetes cluster in under 5 minutes with Proxmox and k3s</title>
      <dc:creator>Mihai Farcas</dc:creator>
      <pubDate>Tue, 30 Jan 2024 16:02:18 +0000</pubDate>
      <link>https://dev.to/mihailtd/set-up-a-kubernetes-cluster-in-under-5-minutes-with-proxmox-and-k3s-2987</link>
      <guid>https://dev.to/mihailtd/set-up-a-kubernetes-cluster-in-under-5-minutes-with-proxmox-and-k3s-2987</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this blog post, we will explore how to quickly and easily add a new node to your Kubernetes cluster in under 5 minutes. I'll walk you through the process of setting up a compact mini PC and demonstrate how to integrate it seamlessly into your existing Kubernetes cluster. By following this guide, you'll be able to expand the capabilities of your cluster and gain valuable insights into the inner workings of cloud computing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Video Version
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/PtQ8FOepn94"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Compact Mini PCs: A Cost-Effective Solution
&lt;/h2&gt;

&lt;p&gt;First, let's take a look at the compact mini PC that I'll be using for this setup. These machines are not only affordable but also powerful enough to perform complex computing tasks. With their 8th Gen Core i7 processors, 16GB of RAM, and fast NVMe storage, these mini PCs offer exceptional performance while consuming minimal power. In fact, they draw only about 10 to 30 watts of power (depending on load), making them a budget-friendly alternative to cloud computing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PRO Tip: There are a lot of great deals to be found on second hand Mini PCs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffc6esweqzyn6bl64aqwc.jpg" 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%2Ffc6esweqzyn6bl64aqwc.jpg" alt="ASUS Mini PC Chromebox" width="678" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Choose Kubernetes?
&lt;/h2&gt;

&lt;p&gt;Before I dive into the setup process, let's briefly discuss why Kubernetes is the platform of choice for building scalable and efficient applications. Kubernetes has gained immense popularity, especially in the enterprise world, due to its ability to streamline containerized application deployment and management. By learning Kubernetes, you can open up new career opportunities and gain a better understanding of the services cloud vendors provide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Your New Node
&lt;/h2&gt;

&lt;p&gt;To add a new node to your Kubernetes cluster, I'll utilize Proxmox, a powerful tool for managing clusters of servers. Installing Proxmox is a straightforward process that can be completed by booting from a USB with the Proxmox ISO file. Once the installation is complete, you can go to the IP address that was assigned to the machine during installation on the port 8006 and you will be greeted by the Proxmox web UI. &lt;br&gt;
If this is the first node, then you instead need to click on "Create Cluster".&lt;br&gt;
Since I already have a cluster, I'll join this new machine to it. This is as simple as going to to the existing cluster's Proxmox web UI, click on Datacenter -&amp;gt; Cluster -&amp;gt; Join Information. Copy the join information, go back to the new node's Proxmox web UI, click "Join Cluster" paste the information, input the cluster's password, and click join. Wait for a few seconds until the join is successful. From now on, you only use the cluster's web UI.&lt;/p&gt;

&lt;p&gt;Check out the official &lt;a href="https://www.proxmox.com/en/proxmox-virtual-environment/get-started" rel="noopener noreferrer"&gt;quick start guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating a Virtual Machine in Proxmox
&lt;/h2&gt;

&lt;p&gt;Now that our new machine is part of the cluster, it's time to create a virtual machine (VM) that will serve as our new Kubernetes worker node. I'll use Ubuntu Server as the base operating system for this VM, as it provides a solid foundation for running Kubernetes. In Proxmox, creating the VM is as simple as giving it a name, allocating resources such as storage, CPU cores, and RAM, and then booting it up.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installing Kubernetes with K3S
&lt;/h2&gt;

&lt;p&gt;Once the VM is up and running with Ubuntu Server, we're ready to install Kubernetes. To keep things lightweight and beginner-friendly, we'll use K3S, a minimalistic version of Kubernetes developed by the Rancher team. By following a quick start guide, setting up K3S on our Ubuntu server becomes a breeze. We'll ensure that the environment variables "K3S_URL" and "K3S_TOKEN" are set correctly to enable the worker node to join the existing cluster.&lt;br&gt;
However, if this is the first node (the control plane) of this Kubernetes cluster, you don't need to set those variables, instead just run the installation command.&lt;br&gt;
This takes care of everything, including ensuring that k3s starts upon rebooting the VM.&lt;/p&gt;

&lt;p&gt;Check out the official K3s &lt;a href="https://docs.k3s.io/quick-start" rel="noopener noreferrer"&gt;quick start guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Expanding Your Possibilities with Kubernetes
&lt;/h2&gt;

&lt;p&gt;With our new node successfully integrated into the Kubernetes cluster, the possibilities are endless. From hosting websites to running various applications and databases, you can easily leverage the power of Kubernetes for your projects. In the near future, stay tuned as we tackle exciting projects such as building a portfolio website from scratch, covering everything from design and front-end development to back-end development, deployment to Kubernetes, and hosting online.&lt;/p&gt;
&lt;h2&gt;
  
  
  Monitoring Power Consumption with Smart Plug
&lt;/h2&gt;

&lt;p&gt;To keep track of the power consumption of our server, I'll include a smart plug in my setup. This handy device allows us to accurately measure the power consumed by the mini PC. Monitoring power consumption not only helps us optimize efficiency but also sheds light on the cost-effectiveness of having our own Kubernetes cluster compared to utilizing cloud services.&lt;br&gt;
In this case I am running 3 Mini PCs totaling 24 threads, 48 GB of RAM and NVME storage, all under 50W.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27jmycfmi1fjhjpuf4ea.jpg" 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%2F27jmycfmi1fjhjpuf4ea.jpg" alt="Cluster Power Consumption" width="800" height="1777"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog post, I demonstrated how to add a new node to your Kubernetes cluster in under 5 minutes using a compact mini PC. By following the step-by-step guide, you can expand the capabilities of your cluster and gain valuable insights into cloud computing. From cost-effectiveness to versatility, building and managing your own Kubernetes cluster opens up a world of possibilities for hosting various applications and accelerating your learning journey. Stay tuned for more exciting projects and developments on our channel!&lt;/p&gt;

&lt;p&gt;Thank you for reading and following. I am looking forward to sharing more insightful content with you in the future.&lt;/p&gt;

&lt;p&gt;Consider Subscribing to my YouTube channel:&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.youtube.com/@letstalkdev" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyt3.googleusercontent.com%2FRIzr-0Smkmg3dcAmBedb7FDoofVtML0mW5AtG8ixVmh9EDh9E8zPq7toYW243x3PChxCztcSxg%3Ds900-c-k-c0x00ffffff-no-rj" height="900" class="m-0" width="900"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.youtube.com/@letstalkdev" rel="noopener noreferrer" class="c-link"&gt;
            Let's Talk Dev - YouTube
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            I share my insights and tips on software engineering topics such as web development, databases, cloud computing, and more.
Hi, I'm Mihai and I'm a full-stack software engineer with a passion for creating innovative and user-friendly solutions using web and cloud technologies. I have a home lab where I like to experiment with Kubernetes and other cutting-edge technologies. I'm also a big fan of open-source software.
When I'm not coding, I enjoy photography, reading books, learning about finance and entrepreneurship, and watching movies.

          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.youtube.com%2Fs%2Fdesktop%2F5d82a8bc%2Fimg%2Ffavicon.ico" width="16" height="16"&gt;
          youtube.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>kubernetes</category>
      <category>k8s</category>
      <category>homelab</category>
    </item>
    <item>
      <title>A Year of Self-Hosting: 6 Open-Source Projects That Surprised Me in 2023</title>
      <dc:creator>Mihai Farcas</dc:creator>
      <pubDate>Tue, 19 Dec 2023 10:19:17 +0000</pubDate>
      <link>https://dev.to/mihailtd/a-year-of-self-hosting-6-open-source-projects-that-surprised-me-in-2023-1o33</link>
      <guid>https://dev.to/mihailtd/a-year-of-self-hosting-6-open-source-projects-that-surprised-me-in-2023-1o33</guid>
      <description>&lt;p&gt;Are you ready to supercharge your development workflow and take your projects to the next level? Look no further! In this post, I'm going to introduce you to the most innovative and useful open source tools that I discovered in 2023. These tools have revolutionized the way I create amazing apps, automate tasks, run machine learning models, and more. The best part? They're all self-hosted, giving you full control over your data and privacy. Don't miss out on these game-changers!&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch in video form
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/BRkpbffJBd4"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hanko: Passwordless Authentication Made Easy
Have you ever wished for a more secure and convenient way of authentication? With Hanko, you can say goodbye to passwords and welcome a passwordless future. Hanko is a self-hosted authentication platform that seamlessly integrates both social and passwordless login into any web application with just a few lines of code. No more password headaches or security concerns. Get started with Hanko and experience the future of authentication.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://www.hanko.io/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;hanko.io&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Directus: Low Code Backend Generation
Creating and managing your data model can be a breeze with Directus. This low code, GraphQL or REST backend generator allows you to effortlessly build and customize your data model using an intuitive no-code interface. Once you have your data model set up, Directus provides you with a fully-featured API that you can connect to any front-end framework of your choice. Whether it's for a headless CMS or a data-rich app, Directus has got you covered.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://directus.io/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdirectus.io%2F__og-image__%2Fstatic%2Fog.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://directus.io/" rel="noopener noreferrer" class="c-link"&gt;
            The Headless CMS + Backend for Every Custom Build
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Built for developers who need more than a CMS. Manage complex content, handle digital assets, and control permissions through an intuitive Studio.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdirectus.io%2Ffavicon.ico" width="48" height="48"&gt;
          directus.io
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;n8n: Your Self-Hosted Automation Platform
Imagine having your own automation platform that connects various apps and services, just the way you want. n8nmakes it possible! This self-hosted automation platform allows you to create visually stunning workflows and automate tasks using an intuitive user interface. With a vast array of integrations, it supports almost any service you can imagine. Build complex automations effortlessly and take full control of your workflows with n8n.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://n8n.io/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fn8niostorageaccount.blob.core.windows.net%2Fn8nio-strapi-blobs-stage%2Fassets%2Fog_image_website_3_afd66761a9.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://n8n.io/" rel="noopener noreferrer" class="c-link"&gt;
            AI Workflow Automation Platform - n8n
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            n8n is a workflow automation platform that uniquely combines AI capabilities with business process automation, giving technical teams the flexibility of code with the speed of no-code.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          n8n.io
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;PostgresML: Machine Learning Inside PostgreSQL
Combine the power of machine learning with the reliability of PostgreSQL with PostgresML. This complete MLOps platform, integrated as a PostgreSQL extension, opens up new possibilities for running machine learning models directly within your database. With support for text classification, generation, and summarization, you can fine-tune large language models with your own data without it ever leaving your PostgreSQL database. Experience the seamless integration of machine learning and PostgreSQL with PostgresML.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/postgresml" rel="noopener noreferrer"&gt;
        postgresml
      &lt;/a&gt; / &lt;a href="https://github.com/postgresml/postgresml" rel="noopener noreferrer"&gt;
        postgresml
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Postgres with GPUs for ML/AI apps.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
   
     
     
     &lt;img alt="Logo" width="520"&gt;
   
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;Postgres + GPUs for ML/AI applications.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;
| &lt;a href="https://postgresml.org/docs/" rel="nofollow noopener noreferrer"&gt;&lt;b&gt;Documentation&lt;/b&gt;&lt;/a&gt; | &lt;a href="https://postgresml.org/blog" rel="nofollow noopener noreferrer"&gt;&lt;b&gt;Blog&lt;/b&gt;&lt;/a&gt; | &lt;a href="https://discord.gg/DmyJP3qJ7U" rel="nofollow noopener noreferrer"&gt;&lt;b&gt;Discord&lt;/b&gt;&lt;/a&gt; |
&lt;/p&gt;




&lt;p&gt;Why do ML/AI in Postgres?&lt;/p&gt;

&lt;p&gt;Data for ML &amp;amp; AI systems is inherently larger and more dynamic than the models. It's more efficient, manageable and reliable to move models to the database, rather than constantly moving data to the models.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/postgresml/postgresml#getting-started" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/postgresml/postgresml#postgresml-cloud" rel="noopener noreferrer"&gt;PostgresML Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postgresml/postgresml#self-hosted" rel="noopener noreferrer"&gt;Self-hosted&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postgresml/postgresml#ecosystem" rel="noopener noreferrer"&gt;Ecosystem&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/postgresml/postgresml#large-language-models" rel="noopener noreferrer"&gt;Large Language Models&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/postgresml/postgresml#hugging-face" rel="noopener noreferrer"&gt;Hugging Face&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postgresml/postgresml#openai" rel="noopener noreferrer"&gt;OpenAI and Other Providers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/postgresml/postgresml#rag" rel="noopener noreferrer"&gt;RAG&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/postgresml/postgresml#chunk" rel="noopener noreferrer"&gt;Chunk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postgresml/postgresml#embed" rel="noopener noreferrer"&gt;Embed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postgresml/postgresml#rank" rel="noopener noreferrer"&gt;Rank&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postgresml/postgresml#transform" rel="noopener noreferrer"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/postgresml/postgresml#machine-learning" rel="noopener noreferrer"&gt;Machine Learning&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Architecture&lt;/h2&gt;
&lt;/div&gt;

&lt;div&gt;
   
     
     
     &lt;img alt="Logo" width="784"&gt;
   
&lt;/div&gt;

&lt;div&gt;
&lt;b&gt;PostgresML is a powerful Postgres extension that seamlessly combines data storage and machine learning inference within your database&lt;/b&gt;. By integrating these functionalities, PostgresML eliminates the need for separate systems and data transfers, enabling you to perform ML operations directly on your data where it resides.
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features at a glance&lt;/h2&gt;

&lt;/div&gt;


&lt;ul&gt;

&lt;li&gt;

&lt;strong&gt;In-Database ML/AI&lt;/strong&gt;: Run machine learning and AI operations directly within PostgreSQL&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;GPU Acceleration&lt;/strong&gt;: Leverage GPU power for faster computations and model inference&lt;/li&gt;

&lt;li&gt;…&lt;/li&gt;

&lt;/ul&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/postgresml/postgresml" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;ol&gt;
&lt;li&gt;SuperDuperDB: Machine Learning Made Easy for Database Users
If you're a database user who wants to dive into the world of machine learning, SuperDuperDB is here to assist you. This innovative project helps you create, train, and deploy machine learning models directly within your existing database. Similar to PostgreML, SuperDuperDB aims to make machine learning accessible for anyone who uses a database. Stay tuned for an upcoming video where I'll compare SuperDuperDB with PostgresML and delve deeper into this exciting tool.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://superduperdb.com/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;superduperdb.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Please take a moment to subscribe to my YouTube channel where I share more insights and practical tips / tutorials like this
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.youtube.com/@letstalkdev" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyt3.googleusercontent.com%2FRIzr-0Smkmg3dcAmBedb7FDoofVtML0mW5AtG8ixVmh9EDh9E8zPq7toYW243x3PChxCztcSxg%3Ds900-c-k-c0x00ffffff-no-rj" height="900" class="m-0" width="900"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.youtube.com/@letstalkdev" rel="noopener noreferrer" class="c-link"&gt;
            Let's Talk Dev - YouTube
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            I share my insights and tips on software engineering topics such as web development, databases, cloud computing, and more.
Hi, I'm Mihai and I'm a full-stack software engineer with a passion for creating innovative and user-friendly solutions using web and cloud technologies. I have a home lab where I like to experiment with Kubernetes and other cutting-edge technologies. I'm also a big fan of open-source software.
When I'm not coding, I enjoy photography, reading books, learning about finance and entrepreneurship, and watching movies.

          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.youtube.com%2Fs%2Fdesktop%2F5d82a8bc%2Fimg%2Ffavicon.ico" width="16" height="16"&gt;
          youtube.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Hugging Face: Collaboration and Open Source ML Models
Discover the collaborative power of Hugging Face, where the machine learning community comes together to share models, datasets, and applications. With hundreds of models at your fingertips, you can find pre-trained ML models for various applications such as text generation, classification, translation, and summarization. Hugging Face is free, transparent, and fosters a thriving community of learners and contributors. Explore, learn, and leverage the power of Hugging Face for your projects.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://huggingface.co" rel="noopener noreferrer"&gt;Hugging Face&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In conclusion, the year 2023 has brought a wave of groundbreaking open source projects that have transformed the way I create, automate, and innovate. From passwordless authentication to low code backends, self-hosted automation to machine learning inside databases, the possibilities are limitless. Don't let these game-changing tools slip under your radar. Embrace the power of open source and revolutionize your development journey today!&lt;/p&gt;

</description>
      <category>selfhost</category>
      <category>opensource</category>
      <category>machinelerning</category>
    </item>
  </channel>
</rss>
