<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<author><name>Josep Bigorra</name></author>
<title>Jointhefreeworld News</title>
<description>News and Insights from the Jointhefreeworld project!</description>
<generator>Emacs webfeeder.el</generator>
<link>https://jointhefreeworld.org</link>
<atom:link href="https://jointhefreeworld.org/rss.xml" rel="self" type="application/rss+xml"/>
<lastBuildDate>ma, 23 feb 2026 23:33:14 +0100</lastBuildDate>
<item>
  <title>Shared Libraries with Jenkins</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <h2>Writing a Jenkins Shared Library pipeline  <a id="writing-a-jenkins-shared-library-pipeline" class="anchor" href="#writing-a-jenkins-shared-library-pipeline">#</a></h2> <div class="outline-text-2" id="text-writing-a-jenkins-shared-library-pipeline">
 <p>
A good read to get started understanding about why and how we are doing
this, is the
 <a href="https://www.jenkins.io/doc/book/pipeline/shared-libraries/">Jenkins
official documentation</a>, which gives a good explanation about this, but
quite incomplete when it comes an actual example implementation.
</p>

 <p>
I have taken most of the ideas and the article from
 <a href="https://dev.to/kuperadrian">Adrian Kuper</a>, thank him and me for this
tutorial.
</p>

 <p>
In this blog post I will try to explain how to setup and develop a
shared pipeline library for Jenkins, that is easy to work on and can be
unit tested with JUnit5 and Mockito.
</p>

 <p>
This blog post is kinda long and touches many topics without explaining
them in full detail.
</p>

 <p>
In order to be able to develop deployment pipelines, in the form of
shared library, we will need to set up a Java & Groovy development
environment.
</p>

 <p>
For that purpose we will need the IntelliJ IDEA IDE that properly
supports Java and Groovy and has Gradle support.
</p>

 <p>
You should begin by downloading OpenJDK 8 and installing to your
machine, from
 <a href="https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html">here</a> .
After having installed the package, verify your Java version with the
javac -version command, which should display something like:
</p>

 <pre>$ javac -version

javac 1.8.0_231</pre>

 <p>
Following that you should download the Groovy language SDK from
 <a href="https://groovy.apache.org/download.html">here</a> and unzip it into your
SDKs folder. Then you should set an environment variable for
 <code>GROOVY_HOME</code> in your shell, for me ZSH:
</p>

 <pre> <span class="org-builtin">export</span>  <span class="org-variable-name">GROOVY_HOME</span>= <span class="org-string">"/Users/joe/Development/SDKs/groovy-3.0.7"</span></pre>

 <p>
and augment your path with the groovy bin folder:
</p>

 <pre> <span class="org-builtin">export</span>  <span class="org-variable-name">PATH</span>= <span class="org-string">"/Users/joe/Development/SDKs/groovy-3.0.7/bin:$PATH"</span></pre>

 <p>
You then have a setup that will be able to run Java and Groovy code
without problems.
</p>

 <p>
Then let’s create a new IntelliJ IDEA project. I suggest using the
IntelliJ IDEA Ultimate for Jenkins shared pipeline development, because
it is the only IDE I know of, that properly supports Java and Groovy and
has Gradle support, and has excellent plugins, auto-complete and other
amazing features. So, if you don’t have it installed it yet, go ahead
and get a license.
</p>

 <p>
Then you can open up the IDE and create a new project, select Gradle and
make sure to set the checkbox on Groovy.
</p>


 <div id="org70870e0" class="figure">
 <p> <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1610803588/jjba-site/blog/shared-library-jenkins/mvf2arsz0dmpi721uc6l_xdxosk.png"></img></p>
 <p> <span class="figure-number">Figure 1: </span>New Project</p>
</div>

 <p>
Next up, enter a GroupId and an ArtifactId.
</p>


 <div id="orgeaa348e" class="figure">
 <p> <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1610803587/jjba-site/blog/shared-library-jenkins/6jgw5g2khn8nt9rrc0tp_az9ijw.png"></img></p>
 <p> <span class="figure-number">Figure 2: </span>New Project Settings</p>
</div>

 <p>
Ignore the next window (the defaults are fine), click “Next”, enter a
project name and click “Finish”.
</p>


 <div id="orgd3eeecc" class="figure">
 <p> <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1610803664/jjba-site/blog/shared-library-jenkins/Screenshot-2019-01-04-at-12.14.52_aevfeu.png"></img></p>
 <p> <span class="figure-number">Figure 3: </span>Set defaults</p>
</div>

 <p>
IntelliJ should boot up with your new project. The folder structure in
your project should be something like the following.
</p>


 <div id="org0bfd5e5" class="figure">
 <p> <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1610803663/jjba-site/blog/shared-library-jenkins/Screenshot-2019-01-04-at-12.24.01_qak7rp.png"></img></p>
 <p> <span class="figure-number">Figure 4: </span>Initial Structure</p>
</div>

 <p>
This is cool for usual Java/Groovy projects, but for our purpose we have
to change things up a bit since Jenkins demands a project structure like
this:
</p>

 <pre class="example" id="org49a8e64">
├── build           # Gradle compilation results
├── build.gradle    # Gradle config for this project
├── gradle          # Gradle runtime libraries and JAR files
├── gradlew         # UNIX wrapper to run cradle, generated by the IDE
├── reports         # Custom folder where our test coverage reports will go
├── resources       # Necessary resources to run your pipelines, think JSON files, necessary config files
├── settings.gradle # Advanced Gradle setttings
├── src             # Library code will reside here, this is the source code root, organised as a usual Java project
│   └── org
│       └── company
│
│
├── test            # Unit tests for the library code, the contents of this folder will mimic the src folder structure
│
│
└── vars            # Globally accessible (from Jenkins) scripts and methods, when loading the library
    └── pipeline.gdsl
</pre>

 <p>
Make sure to add to your  <code>.gitignore</code> the  <code>.gradle</code>,  <code>build</code>,  <code>reports</code>,
 <code>.idea</code> folders.
</p>

 <p>
You might be wondering where does  <code>pipeline.gdsl</code> come from, well that
comes from your Jenkins instance, and depending on the plugins and
features you have installed on it, the file will contain different
content. This can be obtained from the pipeline syntax menu as seen in
the picture below. This file will ensure that your IDE understands
scripted pipeline steps. A message should pop up after having added the
contents to this file, with the text:
 <code>DSL descriptor file has been change and isn’t currently executed</code> to
which you should respond  <code>Activate Back</code>.
</p>


 <div id="org94d33c5" class="figure">
 <p> <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1611316353/jjba-site/blog/shared-library-jenkins/GDSL-link_m5b98g.png"></img></p>
 <p> <span class="figure-number">Figure 5: </span>Jenkins IntelliJ Pipeline GDSL</p>
</div>

 <p>
Once you are setup with the project structure like above, edit your
 <code>build.gradle</code> so that it resembles:
</p>

 <pre>buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.eriwen:gradle-cobertura-plugin:1.1.1'
    }
}

group 'org.company'
version '1.0-SNAPSHOT'


apply plugin: 'groovy'
apply plugin: 'cobertura'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
    maven {
        url 'https://repo.jenkins-ci.org/releases'
    }
    maven {
        url 'https://repo.jenkins-ci.org/public'
    }
}


dependencies {
    implementation group: 'org.jenkins-ci.main', name: 'jenkins-core', version: '2.85'
    implementation group: 'org.jenkins-ci.plugins.workflow', name: 'workflow-cps', version: '2.41', ext: 'jar'
    implementation group: 'org.jenkins-ci.plugins.workflow', name: 'workflow-support', version: '2.16', ext: 'jar'
    implementation group: 'org.jenkins-ci.plugins', name: 'script-security', version: '1.34', ext: 'jar'

    implementation 'org.codehaus.groovy:groovy-all:3.0.7'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
    testImplementation 'org.mockito:mockito-core:2.+'
}

test {
    jvmArgs '-noverify'
    useJUnitPlatform()
}

sourceSets {
    main {
        groovy {
            // all code files will be in either of the folders
            srcDirs = ['src', 'vars']
        }
    }
    test {
        groovy {
            srcDirs = ['test']
        }
    }
}

cobertura {
    format = 'html'
    includes = ['**/*.groovy']
    excludes = ['*_build.groovy']
    reportsDir = file("./reports")
}</pre>

 <p>
At this point we should have a nice folder structure and enough
dependencies to use to get to our goal. Cool, it’s time to implement our
shared library!
</p>
</div>
 <h2>The General Approach  <a id="the-general-approach" class="anchor" href="#the-general-approach">#</a></h2> <div class="outline-text-2" id="text-the-general-approach">
 <p>
First a quick run-down on how we build our library and on why we do it
that way:
</p>

 <p>
We will keep the “custom” steps inside var as simple as possible and
without any real logic. Instead, we create classes (inside src) that do
all the work.
</p>

 <p>
We create an interface, which declares methods for all required Jenkins
steps (sh, bat, error, etc.). The classes call steps only through this
interface.
</p>

 <p>
We write unit tests for your classes like you normally would with JUnit
and Mockito. This way we are able to:
</p>

 <ul class="org-ul"> <li>Compile and execute our library/unit tests without Jenkins</li>
 <li>Test that our classes work as intended</li>
 <li>Test that Jenkins steps are called with the right parameters</li>
 <li>Test the behaviour of our code when a Jenkins step fails</li>
 <li>Build, test, run metrics and deploy your Jenkins Pipeline Library
through Jenkins itself</li>
</ul> <p>
Now let’s get really going.
</p>
</div>
 <h2>The Interface For Step Access  <a id="the-interface-for-step-access" class="anchor" href="#the-interface-for-step-access">#</a></h2> <div class="outline-text-2" id="text-the-interface-for-step-access">
 <p>
First, we will create the interface inside  <code>org.somecompany</code> that will
be used by all classes to access the regular Jenkins steps like  <code>sh</code> or
 <code>error</code>. We will start with a simple example, and then I will provide a
more advanced one.
</p>

 <pre>package org.somecompany

interface IStepExecutor {
    int sh(String command)
    void error(String message)
    // add more methods for respective steps if needed
}</pre>

 <p>
This interface is neat, because it can be mocked inside our unit tests.
That way our classes become independent to Jenkins itself. For now,
let’s add an implementation that will be used in our vars Groovy
scripts:
</p>

 <pre>package org.somecompany

class StepExecutor implements IStepExecutor {
    // this will be provided by the vars script and
    // let's us access Jenkins steps
    private steps

    StepExecutor(steps) {
        this.steps = steps
    }

    @Override
    int sh(String command) {
        this.steps.sh returnStatus: true, script: "${command}"
    }

    @Override
    void error(String message) {
        this.steps.error(message)
    }
}</pre>

 <p>
Here is a more complex example, with more available methods. You can
expand on this by looking at the  <code>pipeline.gdsl</code> file and taking
abstractions from there, both for methods, and properties.
</p>

 <pre>import org.jenkinsci.plugins.workflow.cps.EnvActionImpl
import org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper

interface IStepExecutor {
    /**
     * Current build environment variables
     */
    public EnvActionImpl env

    /**
     * Current build details
     */
    public RunWrapper currentBuild

    /**
     * Current build parameters
     */
    public Map params

    /**
     * Shell Script
     * @param command
     * @return
     */
    int sh(String command)

    /**
     * Shell Script
     * @param label
     * @param command
     * @return
     */
    int sh(String label, String command)

    /**
     * Error signal
     * @param message
     */
    void error(String message)

    /**
     * Stage of a Jenkins build
     * @param name
     * @param body
     */
    void stage(String name, Closure body)

    /**
     * Execute closures in parallel
     * @param closures
     */
    void parallel(Map closures)

    /**
     * Recursively delete the current directory from the workspace
     */
    void deleteDir()

    /**
     * Update the commit status in GitHub
     * @param name
     * @param status
     */
    void updateGitlabCommitStatus(String name, String status)

    /**
     * Send Slack Message
     * @param channel
     * @param color
     * @param iconEmoji
     * @param message
     */
    void slackSend(String channel, String color, String iconEmoji, String message)

    /**
     * Accept GitHub Merge Request
     * @param useMRDescription
     * @param removeSourceBranch
     */
    void acceptGitHubMR(Boolean useMRDescription, Boolean removeSourceBranch)

    /**
     * Archive JUnit-formatted test results
     * @param location
     */
    void junit(String location)

    /**
     * Stash some files to be used later in the build
     * @param name
     * @param includes
     */
    void stash(String name, String includes)

    /**
     * Restore files previously stashed
     * @param name
     */
    void unstash(String name)

    /**
     * PowerShell Script
     * @param command
     * @return
     */
    int powershell(String command)

    /**
     * PowerShell Script
     * @param label
     * @param command
     * @return
     */
    int powershell(String label, String command)

    /**
     * Change current directory
     * @param directory
     * @param body
     */
    void dir(String directory, Closure body)

    /**
     * Allocate node. Change execution of build to said agent
     * @param name
     * @param body
     */
    void node(String name, Closure body)

    /**
     * Catch error and set build result to failure
     * @param params
     * @param body
     */
    void catchError(Map params, Closure body)

    /**
     * Add Cobertura coverage report result
     * @param location
     */
    void cobertura(String location)
}</pre>

 <p>
And the implementation:
</p>

 <pre>import org.jenkinsci.plugins.workflow.cps.EnvActionImpl
import org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper

final class StepExecutor implements IStepExecutor {
    // this will be provided by the vars script and
    // let's us access Jenkins steps
    private steps

    public EnvActionImpl env
    public RunWrapper currentBuild
    public Map params

    StepExecutor(steps) {
        this.steps = steps
        this.env = this.steps.env
        this.currentBuild = this.steps.currentBuild
        this.params = Collections.unmodifiableMap(this.steps.params)
    }

    @Override
    int sh(String command) {
        this.steps.sh returnStatus: true, script: "${command}"
    }

    @Override
    int sh(String description, String command) {
        this.steps.sh returnStatus: true, label: "${description}", script: "${command}"
    }

    @Override
    int powershell(String command) {
        this.steps.powershell returnStatus: true, script: "${command}"
    }

    @Override
    int powershell(String description, String command) {
        this.steps.powershell returnStatus: true, label: "${description}", script: "${command}"
    }

    @Override
    void error(String message) {
        this.steps.currentBuild.setResult(JobStatus.Failure)
        this.steps.error(message)
    }

    @Override
    void stage(String name, Closure body) {
        this.steps.stage(name, body)
    }

    @Override
    void parallel(Map closures) {
        this.steps.parallel(closures)
    }

    @Override
    void deleteDir() {
        this.steps.deleteDir()
    }

    @Override
    void updateGitlabCommitStatus(String name, String status) {
        this.steps.updateGitlabCommitStatus name: "${name}", status: "${status}"
    }

    @Override
    void slackSend(String channel, String color, String iconEmoji, String message) {
        this.steps.slackSend baseUrl: "https://hooks.slack.com/services/", botUser: true,
                channel: "${channel}", color: "${color}", iconEmoji: "${iconEmoji}",
                message: "${message}", teamDomain: "teamDomain",
                tokenCredentialId: "token", username: "webhookbot"
    }

    @Override
    void acceptGitHubMR(Boolean useMRDescription, Boolean removeSourceBranch) {
        this.steps.acceptGitHubMR useMRDescription: useMRDescription, removeSourceBranch: removeSourceBranch
    }

    @Override
    void stash(String name, String includes) {
        this.steps.stash name: "${name}", includes: "${includes}"
    }

    @Override
    void unstash(String name) {
        this.steps.unstash name: "${name}"
    }

    @Override
    void dir(String directory, Closure body) {
        this.steps.dir(directory, body)
    }

    @Override
    void node(String name, Closure body) {
        this.steps.node(name, body)
    }

    @Override
    void catchError(Map params, Closure body) {
        this.steps.catchError buildResult: params.buildResult,
                catchInterruptions: params.catchInterruptions,
                message: params.message,
                stageResult: params.stageResult,
                body: body
    }

    @Override
    void junit(String location) {
        this.steps.junit testResults: "${location}", allowEmptyResults: false
    }

    @Override
    void cobertura(String location) {
        this.steps.cobertura autoUpdateHealth: false,
                autoUpdateStability: false,
                coberturaReportFile: "${location}",
                conditionalCoverageTargets: '70, 0, 0',
                failUnhealthy: false,
                failUnstable: false,
                lineCoverageTargets: '80, 0, 0',
                maxNumberOfBuilds: 0,
                methodCoverageTargets: '80, 0, 0',
                onlyStable: false,
                sourceEncoding: 'ASCII',
                zoomCoverageChart: false
    }
}</pre>
</div>
 <h2>Adding Basic Dependency Injection  <a id="adding-basic-dependency-injection" class="anchor" href="#adding-basic-dependency-injection">#</a></h2> <div class="outline-text-2" id="text-adding-basic-dependency-injection">
 <p>
Because we don’t want to use the above implementation in our unit tests,
we will setup some basic dependency injection in order to swap the above
implementation with a mock during unit tests. If you are not familiar
with dependency injection, you should probably read up about it, since
explaining it here would be out-of-scope, but you might be fine with
just copy-pasting the code in this chapter and follow along.
</p>

 <p>
So, first we create the org.somecompany.ioc package and add an IContext
interface:
</p>

 <pre>package org.somecompany.ioc

import org.somecompany.IStepExecutor

interface IContext {
    IStepExecutor getStepExecutor()
}</pre>

 <p>
Again, this interface will be mocked for our unit tests. But for regular
execution of our library we still need an default implementation:
</p>

 <pre>package org.somecompany.ioc

import org.somecompany.IStepExecutor
import org.somecompany.StepExecutor

class DefaultContext implements IContext, Serializable {
    // the same as in the StepExecutor class
    private steps

    DefaultContext(steps) {
        this.steps = steps
    }

    @Override
    IStepExecutor getStepExecutor() {
        return new StepExecutor(this.steps)
    }
}</pre>

 <p>
To finish up our basic dependency injection setup, let’s add a “context
registry” that is used to store the current context (DefaultContext
during normal execution and a Mockito mock of IContext during unit
tests):
</p>

 <pre>package org.somecompany.ioc

class ContextRegistry implements Serializable {
    private static IContext context

    static void registerContext(IContext context) {
        context = context
    }

    static void registerDefaultContext(Object steps) {
        context = new DefaultContext(steps)
    }

    static IContext getContext() {
        return context
    }
}</pre>

 <p>
That’s it! Now we are free to code testable Jenkins steps inside  <code>vars</code>.
</p>
</div>
 <h2>Coding A Custom Jenkins Step  <a id="coding-a-custom-jenkins-step" class="anchor" href="#coding-a-custom-jenkins-step">#</a></h2> <div class="outline-text-2" id="text-coding-a-custom-jenkins-step">
 <p>
Let’s imagine for our example here, that we want to add a step to our
library that calls the some class that performs some data seeding to a
database. To do this we first add a groovy script  <code>example_build.groovy</code>
to the  <code>vars</code> folder that is called like our custom step we want to
implement. Since our script is called  <code>example_build.groovy</code> our step
will later be callable with  <code>example_build</code> in our  <code>Jenkinsfile</code>. Add
the following content to the script for now:
</p>

 <pre>void call(
        String environment,
        String envFile,
        String dataSeederBranch,
        String deploymentScriptsBranch
) {
    // TODO
}</pre>

 <p>
According to our general idea we want to keep our example_build script
as simple as possible and do all the work inside a unit-testable class.
So let’s create a new class  <code>DataSeederJob</code> in a new package
org.somecompany.jobs:
</p>

 <pre>package org.somecompany.jobs

final class DataSeederJob implements Serializable {
    private String workspace
    private String environment
    private String envFile
    private String dataSeederBranch
    private String deploymentScriptsBranch
    private String seedingEnvironment
    private String seedingMode
    private ArrayList<TargetRepository> repositories

    DataSeederJob(
            String workspace,
            String environment,
            String envFile,
            String dataSeederBranch,
            String deploymentScriptsBranch,
            String seedingEnvironment,
            String seedingMode
    ) {
        this.workspace = workspace
        this.environment = environment
        this.envFile = envFile
        this.dataSeederBranch = dataSeederBranch
        this.deploymentScriptsBranch = deploymentScriptsBranch
        this.seedingEnvironment = seedingEnvironment
        this.seedingMode = seedingMode

        this.repositories = [
                new TargetRepository(
                        "repo1",
                        this.deploymentScriptsBranch,
                        "deploymentscripts"
                ),
                new TargetRepository(
                        "repo2",
                        this.dataSeederBranch,
                        "dataseeder"
                )
        ]
    }

    void build() {
        IStepExecutor steps = ContextRegistry.getContext().getStepExecutor()

        steps.deleteDir()

        steps.stage("Cloning new content", {
            SourceControlUtils.parallelCheckoutCode(steps, this.repositories)
        })

        steps.stage("Preparing application environment", {
            int status = steps.sh("""
                 /bin/cp deploymentscripts/${this.environment}/DataSeeder/${this.envFile} dataseeder/dist/config.toml
            """)
            if (status != 0) {
                steps.error("Job failed! Copying env file exited with a non-zero status!")
            }
        })

        steps.stage("Running DataSeeder", {
            int status = steps.sh("""
                cd dataseeder/dist
                ./goseeders-linux-x86 -env=${this.seedingEnvironment} -mode=${this.seedingMode}
            """)
            if (status != 0) {
                steps.error("Job failed! Application exited with a non-zero status!")
            }
        })
    }
}</pre>

 <p>
As you can see, we use both the sh, deleteDir, stage and error steps in
our class, but instead of using them directly, we use the
ContextRegistry to get an instance of IStepExecutor to call Jenkins
steps with that. This way, we can swap out the context when we want to
unit test the build() method later.
</p>

 <p>
Now we can finish our script in  <code>vars</code> folder, which in this case will
also send a Slack message on failure:
</p>

 <pre>void call(
        String environment,
        String envFile,
        String dataSeederBranch,
        String deploymentScriptsBranch
) {
    ContextRegistry.registerDefaultContext(this)
    IStepExecutor steps = ContextRegistry.getContext().getStepExecutor()

    try {
        DataSeederJob buildExecutor = new DataSeederJob(
                steps.env.getProperty(EnvironmentVariables.workspace),
                environment,
                envFile,
                dataSeederBranch,
                deploymentScriptsBranch,
                steps.params["SeedingEnvironment"] as String,
                steps.params["SeedingMode"] as String
        )
        buildExecutor.build()
    } catch (e) {
        steps.currentBuild.setResult(JobStatus.Failure)
        throw e
    } finally {
        String result = JobStatus.Success
        if (steps.currentBuild.getResult() != null) {
            result = steps.currentBuild.getResult()
        }

        switch (result) {
            case JobStatus.Failure:
                steps.slackSend(
                        SlackChannels.monitoringChannel,
                        SlackColors.failure,
                        SlackEmojis.failure,
                        String.format("""
                        %s - TEST PIPELINE FRAMEWORK
                        PARAMETERS: %s
                        """,
                                steps.currentBuild.getFullDisplayName(),
                                steps.params.toString(),
                        ),
                )
                break
            default:
                break
        }
    }
}</pre>

 <p>
First, we set the context with the context registry. Since we are not in
a unit test, we use the default context. The  <code>this</code> that gets passed
into  <code>registerDefaultContext()</code> will be saved by the  <code>DefaultContext</code>
inside its private  <code>steps</code> variable and is used to access Jenkins steps.
After registering the context, we are free to instantiate our MsBuild
class and call the  <code>build()</code> method doing all the work.
</p>

 <p>
Nice, our  <code>vars</code> script is finished. Now we only have to write some unit
tests for our  <code>Job</code> class.
</p>
</div>
 <h2>Adding Unit Tests  <a id="adding-unit-tests" class="anchor" href="#adding-unit-tests">#</a></h2> <div class="outline-text-2" id="text-adding-unit-tests">
 <p>
At this point writing unit tests should be business as usual. We create
a new test class  <code>JobTest</code> inside the test folder with package
 <code>org.somecompany.jobs</code>. Before every test, we use Mockito to mock the
 <code>IContext</code> and  <code>IStepExecutor</code> interfaces and register the mocked
context. Then we can simply create a new  <code>Job</code> instance in our test and
verify the behaviour of our  <code>build()</code> method.
</p>

 <p>
Here is the data seeder test class:
</p>

 <pre>import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

import static org.mockito.ArgumentMatchers.any
import static org.mockito.ArgumentMatchers.anyString
import static org.mockito.Mockito.times
import static org.mockito.Mockito.verify

final class DataSeederJobTest {
    private DataSeederJob sut

    protected IContext context
    protected IStepExecutor steps

    @BeforeEach
    void setup() {
        context = mock(IContext.class)
        steps = mock(IStepExecutor.class)

        when(context.getStepExecutor()).thenReturn(steps)

        ContextRegistry.registerContext(context)
    }

    @BeforeEach
    void setupJob() {
        String workspace = "workspace"
        String environment = "environment"
        String envFile = "envFile"
        String dataSeederBranch = "dataSeederBranch"
        String deploymentScriptsBranch = "deploymentScriptsBranch"
        String seedingEnvironment = "seedingEnvironment"
        String seedingMode = "seedingMode"

        this.sut = new DataSeederJob(
                workspace,
                environment,
                envFile,
                dataSeederBranch,
                deploymentScriptsBranch,
                seedingEnvironment,
                seedingMode
        )
    }

    @Test
    void jobBuildCallsDeleteDirStep() {
        this.sut.build()

        verify(steps).deleteDir()
    }

    @Test
    void jobBuildCallsStageSteps() {
        this.sut.build()

        verify(steps, times(3)).stage(anyString(), any(Closure))
    }
}</pre>

 <p>
Another test class with several example tests, but unrelated to the data
seeder:
</p>

 <pre>package org.somecompany.jobs

import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

import static org.mockito.ArgumentMatchers.any
import static org.mockito.ArgumentMatchers.anyString
import static org.mockito.Mockito.*
import org.junit.jupiter.api.BeforeEach
import static org.mockito.Mockito.mock
import static org.mockito.Mockito.when


final class GenericGoJobTest {
    private GenericGoJob sut

    private String workspace = "workspace"
    private String appName = "appName"
    private String releaseDir = "releaseDir"
    private String repoName = "repoName"
    private String serviceName = "serviceName"
    private Boolean shouldUnitTest = false
    private Boolean deployToDifferentAgents = false
    private ArrayList<String> destinationAgents = ["destinationAgent"]
    private String mainGoFileLocation = "mainGoFileLocation"

    protected IContext context
    protected IStepExecutor steps

    @BeforeEach
    void setup() {
        context = mock(IContext.class)
        steps = mock(IStepExecutor.class)

        when(context.getStepExecutor()).thenReturn(steps)

        ContextRegistry.registerContext(context)
    }


    @BeforeEach
    void setupJob() {
        this.sut = new GenericGoJob(
                this.workspace,
                this.appName,
                this.releaseDir,
                this.repoName,
                this.serviceName,
                this.mainGoFileLocation,
                this.shouldUnitTest,
                this.deployToDifferentAgents,
                this.destinationAgents,
        )
    }

    @Test
    void verifyJobCallsDeleteDir() {
        this.sut.build()

        verify(steps).deleteDir()
    }

    @Test
    void verifyJobCallsStagesCorrectAmountOfTimes() {
        this.sut.build()

        verify(steps, times(5)).stage(anyString(), any(Closure))
    }

    @Test
    void verifyJobCallsStagesCorrectAmountOfTimesWithDifferentAgentOption() {
        this.deployToDifferentAgents = true
        this.setupJob()
        this.sut.build()

        verify(steps, times(4)).stage(anyString(), any(Closure))
    }

    @Test
    void verifyJobDoesNotCallNode() {
        this.sut.build()

        verify(steps, times(0)).node(anyString(), any(Closure))
    }

    @Test
    void verifyJobCallsNodeWithDifferentAgentOption() {
        this.deployToDifferentAgents = true
        this.setupJob()
        this.sut.build()

        verify(steps, times(1)).node(anyString(), any(Closure))
    }

    @Test
    void verifyJobCallsStageOneMoreTimeWithUnitTests() {
        this.shouldUnitTest = true
        this.setupJob()
        this.sut.build()

        verify(steps, times(6)).stage(anyString(), any(Closure))
    }

    @Test
    void verifyJobCallsNodeMultipleTimesWithDifferentAgentOption() {
        this.deployToDifferentAgents = true
        this.destinationAgents = [
                "test1",
                "test2",
                "test3",
                "test4",
                "test5",
        ]

        this.setupJob()
        this.sut.build()

        verify(steps, times(5)).node(anyString(), any(Closure))
    }

    @Test
    void verifyDeployGoSystemServiceCallsDir() {
        this.sut.deployGoSystemService(steps)

        verify(steps, times(1)).dir(anyString(), any(Closure))
    }

    @Test
    void verifyBuildGoApplicationCallsSh() {
        this.sut.buildGoApplication(steps)

        verify(steps, times(1)).sh(anyString())
    }

    @Test
    void verifyBuildGoApplicationCallsError() {
        when(steps.sh(anyString())).thenReturn(-1)

        this.sut.buildGoApplication(steps)

        verify(steps).error(anyString())
    }

    @Test
    void verifyUnitTestApplicationCallsStage() {
        this.sut.unitTestApplication(steps)

        verify(steps, times(1)).stage(anyString(), any(Closure))
    }

    @Test
    void verifyDeployBuildCallsNodeCorrectly() {
        this.deployToDifferentAgents = true
        this.destinationAgents = [
                "test1",
                "test2",
                "test3",
                "test4",
                "test5",
        ]
        this.setupJob()
        this.sut.deployBuild(steps)

        verify(steps, times(5)).node(anyString(), any(Closure))
    }


    @Test
    void verifyDeployBuildCallsStageCorrect() {
        this.sut.deployBuild(steps)

        verify(steps, times(1)).stage(anyString(), any(Closure))
    }


    @Test
    void verifyPrepareStashContentCallsSh() {
        this.sut.prepareStashContent(steps)

        verify(steps, times(2)).sh(anyString())
    }

    @Test
    void verifyPrepareStashCallsError() {
        when(steps.sh(anyString())).thenReturn(-1)

        this.sut.prepareStashContent(steps)

        verify(steps, times(2)).error(anyString())
    }

    @Test
    void verifyStashBuildCallsSh() {
        this.sut.stashBuild(steps)

        verify(steps, times(1)).sh(anyString())
    }

    @Test
    void verifyStashBuildCallsError() {
        when(steps.sh(anyString())).thenReturn(-1)

        this.sut.stashBuild(steps)

        verify(steps).error(anyString())
    }
}</pre>

 <p>
You can use the green play buttons on left of the IntelliJ code editor
to run the tests, which hopefully turn green.
</p>
</div>
 <h2>Wrapping Things Up  <a id="wrapping-things-up" class="anchor" href="#wrapping-things-up">#</a></h2> <div class="outline-text-2" id="text-wrapping-things-up">
 <p>
That’s basically it. Now it’s time to setup your library with Jenkins,
create a new job and run a  <code>Jenkinsfile</code> to test your new custom
example_build step. A simple test  <code>Jenkinsfile</code> could look like this:
</p>

 <pre>node('master') {
    // Load your library
    library('pipeline-framework@master')

    // call the script with parameters
    // if your call function does not require any params
    // you could simply do example_build.call(), which I prefer,
    // or simply example_build

    example_build.call(
            'Acceptance',
            'config.toml',
            'master',
            'stable'
    )
}</pre>

 <p>
Then you can decide either to add this to a Pipeline job immediately on
the script box, or checkout this small script from SCM, that is up to
you.
</p>

 <p>
Obviously there is still a lot more I could have talked about (things
like unit tests, dependency injection, Gradle, Jenkins configuration,
build and testing the library with Jenkins itself etc.), but I wanted to
keep this already very long blog post somewhat concise. I do hope
however, that the general idea and approach became clear and helps you
in creating a unit-testable shared library, that is more robust and
easier to work on than it normally would be.
</p>

 <p>
One last piece of advice: The unit tests and Gradle setup are pretty
nice and help a ton in easing the development of robust shared
pipelines, but unfortunately there is still quite a bit that can go
wrong inside your pipelines even though the library tests are green.
Things like the following, that mostly happen because of Jenkins’ Groovy
and sandbox weirdness:
</p>

 <ul class="org-ul"> <li>A class that does not implement Serializable which is necessary,
because “pipelines must survive Jenkins restarts”</li>
 <li>Using classes like java.io.File inside your library, which is
prohibited</li>
 <li>Syntax and spelling errors in your  <code>Jenkinsfile</code></li>
</ul> <p>
Therefore, it might be a good idea to have Jenkins instance solely for
integration testing, where new and modified  <code>vars</code> scripts can be tested
before going “live”.
</p>

 <p>
Again, feel free to write any kind of questions or feedback in the
comments, or contact me directly.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/ci/shared-libraries-with-jenkins/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/ci/shared-libraries-with-jenkins/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>CI / CD</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-01-16 za> </span></span>  <a href="/blog/articles/ci/shared-libraries-with-jenkins/index.html">Shared Libraries with Jenkins and Unit Tests</a>
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/ci/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/ci/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>A Great Programmer</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
If writing code were a science, all developers would pretty much be the
same. But it is not. And just like in art, no two developers have the
same thinking or perception while working towards the same outcome.
</p>

 <p>
While some struggle to produce the desired outcome, to a few, it comes
almost naturally, as if an epiphany hits them at the moment they start
writing code or solve a problem.
</p>

 <p>
Say no to artificial energy drinks.
 <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1600515371/jjba-site/blog/great-programmer/coffee_vsepjh.jpg"></img></p>

 <p>
And in a blog post, Steve McConnell, one of the experts in software
engineering talks about an original study which was carried in the late
1960s by Sackman, Erikson, and Grant. They found that the ratio of
initial coding time between the best and worst programmers was about 20
to 1.
</p>

 <p>
And the most interesting thing was that they found no relationship
between a programmer’s experience and code quality or productivity. In
simple words, writing good code is not the only factor that
differentiates a good programmer from a great one.
</p>

 <p>
Let us start with the good programmers first.
</p>
 <h2>Who is a good programmer?  <a id="who-is-a-good-programmer" class="anchor" href="#who-is-a-good-programmer">#</a></h2> <div class="outline-text-2" id="text-who-is-a-good-programmer">
 <p>
I would say it is someone with:
</p>

 <ul class="org-ul"> <li>Excellent technical skills and write clean, neat code.</li>
 <li>Solid knowledge of development techniques and problem-solving
expertise.</li>
 <li>Understanding programming best practices and when to employ them.</li>
 <li>An abiding passion for programming and strive to contribute to the
team.</li>
 <li>Respectable and likeable by other members of the team.</li>
</ul> <p>
So if you are a programmer and you have all the above traits,
Congratulations! You are a good programmer. Be proud of it.
</p>
</div>
 <h2>Now coming to the great ones.  <a id="now-coming-to-the-great-ones" class="anchor" href="#now-coming-to-the-great-ones">#</a></h2> <div class="outline-text-2" id="text-now-coming-to-the-great-ones.">
 <ul class="org-ul"> <li>They are rare.</li>
 <li>Their productivity is 3 times that of a good programmer and 10 times
that of a bad programmer.</li>
 <li>They belong to the top 1% who don’t just write code but have a set of
intangible traits that keep them poles apart from other programmers.</li>
</ul></div>
 <h2>TLDR;  <a id="tldr" class="anchor" href="#tldr">#</a></h2> <div class="outline-text-2" id="text-tldr">
 <blockquote>
 <p>
Great programmer  <code>=</code> Good programmer + a set of intangible traits
</p>
</blockquote>

 <p>
While it’s not easy, if you’re dedicated enough, here are those
intangible traits which you can cultivate within yourself to transition
from being a good programmer to becoming a great programmer:
</p>
</div>
 <h2>Abrupt learning capability.  <a id="abrupt-learning-capability" class="anchor" href="#abrupt-learning-capability">#</a></h2> <div class="outline-text-2" id="text-abrupt-learning-capability.">
 <p>
They are sharp-minded and that means they have the ability to learn new
technologies and aren’t browbeaten by new technologies. They have the
ability to integrate seemingly disparate bits of information and process
information on the fly.
</p>

 <p>
Every programmer will surely experience a situation where he or she
doesn’t know the answer. Great programmers will find different
resources, talk to the right people and find the solution no matter how
impossible it appears. The best skill anyone can possess is knowing how
to learn, and great programmers have mastered the skill of
self-learning.
</p>

 <p>
A great programmer doesn’t let his ego come in between his work and his
learning process. If he needs to know something, he will approach anyone
in the hierarchy; from the lowest to the highest.
</p>
</div>
 <h2>They balance pragmatism and perfectionism.  <a id="they-balance-pragmatism-and-perfectionism" class="anchor" href="#they-balance-pragmatism-and-perfectionism">#</a></h2> <div class="outline-text-2" id="text-they-balance-pragmatism-and-perfectionism.">
 <p>
John Allspaw, Chief Technology Officer at Etsy makes a good point in his
post
 <a href="https://www.kitchensoap.com/2012/10/25/on-being-a-senior-engineer/"> <i>On
being a senior engineer</i></a>.
</p>

 <p>
He says that top-notch developers are healthy skeptics, which tend to
ask themselves and their peers’ questions while they work, such as:
</p>

 <blockquote>
 <p>
What could I be missing?
</p>

 <p>
How will this not work?
</p>

 <p>
Will you please shoot as many holes as possible into my thinking on
this?
</p>

 <p>
Even if it’s technically sound, is it understandable enough for the rest
of the organization to operate, troubleshoot, and extend it?
</p>
</blockquote>

 <p>
The idea behind these questions is that they perfectly understand the
importance of peer review and by a solid peer-review only, good design
decisions can be made. So they “beg” for the bad news.
</p>

 <p>
A great programmer will tend to not trust their own code until they’ve
tested it extensively. Having said that, they also have the ability to
understand market dynamics and the need to ship the product at the
earliest. So they have the ability to make both quick and dirty hacks
and elegant and refined solutions, and the wisdom to choose which is
appropriate for a given situation at hand.
</p>

 <p>
Some lesser programmers will lack the extreme attention to detail
necessary for some problems. Others are stuck in perfectionist mode.
Great programmers balance the two with perfect precision.
</p>
</div>
 <h2>They have great intuition.  <a id="they-have-great-intuition" class="anchor" href="#they-have-great-intuition">#</a></h2> <div class="outline-text-2" id="text-they-have-great-intuition.">
 <p>
In the sixth book of  <i>The Nicomachean Ethics</i>, the famous philosopher
and statesman _Aristotle_discusses the fourth of five capabilities
people need to have for attaining true knowledge and thus becoming
successful in whatever they do: intuition.
</p>

 <p>
 <i>Aristotle</i>’s point is simple. Intuition is the way we start knowing
everything and knowledge gained by intuition must anchor all other
knowledge. In fact, this way of gaining knowledge is so foundational
that justification is impossible. That’s because knowledge by intuition
is not based on a series of facts or a line of reasoning to a
conclusion.
</p>

 <p>
Instead, we know intuitional truth simply by the process of
introspection and immediate awareness. From Steve Jobs to Richard
Branson to Warren Buffet, the intuitives are generally successful in
whatever they do, because they can see things more clearly and find the
best solutions to problems more quickly than others. No doubt, all these
individuals have a huge storage of expert knowledge and experience.
</p>

 <p>
But they also seem to have an abundance of intuition that comes
naturally to them and which enables them to grasp the essence of
complicated problems and find uncannily right solutions. Great
programmers typically display an intuitive understanding of algorithms,
technologies, and software architecture based on their extensive
experience and good development sense. They have the ability to
understand at a glance what tools in their arsenal best fit the problem
at hand.
</p>

 <p>
And their intuitive abilities extend well beyond development and coding.
This makes them highly versatile in articulating both technical and
non-technical problems with both a layman and a specialist audience.
</p>

 <p>
They are visionaries and they love challenges and will often seek to
break their own code (before others do) in their pursuit of excellence.
</p>
</div>
 <h2>They are master communicators.  <a id="they-are-master-communicators" class="anchor" href="#they-are-master-communicators">#</a></h2> <div class="outline-text-2" id="text-they-are-master-communicators.">
 <p>
To get your ideas across, you need to make it simple and communicate as
unambiguously as possible. Sounds simple? Isn’t it? Damien Filiatrault
has rightly said:
</p>

 <blockquote>
 <p>
Good communication skills directly correlate with good development
skills.
</p>
</blockquote>

 <p>
But unfortunately, this lack of clarity is the root cause of all
troubles at work. And this is because of a phenomenon called the Curse
of Knowledge. In 1990, a Stanford University graduate student in
psychology named Elizabeth Newton illustrated the curse of knowledge by
studying a simple game in which she assigned people to one of two roles:
“tapper” or “listener.”
</p>

 <p>
Each tapper was asked to pick a well-known song, such as “Happy
Birthday” and tap out the rhythm on a table. The listener’s job was to
guess the song. Over the course of Newton’s experiment, 120 songs were
tapped out. Listeners guessed only three of the songs correctly: a
success ratio of 2.5%.
</p>

 <p>
But before they guessed, Newton asked the tappers to predict the
probability that listeners would guess correctly. They predicted 50%.
The tappers got their message across one time in 40, but they thought
they would get it across one time in 2.
</p>

 <p>
his favourite IDE and using a dark editor color scheme.
 <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1600515371/jjba-site/blog/great-programmer/software-developer_nevets.jpg"></img></p>

 <p>
Why did this happen? When a tapper taps, it is impossible for her to
avoid hearing the tune playing along to her taps. Meanwhile, all the
listener can hear is a kind of bizarre Morse code. Yet the tappers were
flabbergasted by how hard the listeners had to work to pick up the tune.
The problem is that once we know something — say, the melody of a song
— we find it hard to imagine not knowing it.
</p>

 <p>
Our knowledge has “cursed” us. We have difficulty sharing it with others
because we cannot readily re-create their state of mind. That is why
great programmers always confirm after communicating the message to the
team.
</p>

 <p>
They also can understand problems clearly, break them down into
hypotheses and propose solutions cohesively. They understand concepts
quickly or ask the right questions to understand, and above all, they
don’t need every small bit to be written down in a document.
</p>

 <p>
So if you want to become a great programmer, you need to make sure there
is effective communication between you and your team. This not only
keeps you at a higher plane of commitment but also shows your superiors
that you are genuinely interested and invested in delivering a quality
product.
</p>
</div>
 <h2>Last thoughts  <a id="last-thoughts" class="anchor" href="#last-thoughts">#</a></h2> <div class="outline-text-2" id="text-last-thoughts">
 <p>
So as you can see here, to be the best-of-class in your field, you don’t
need any fancy degrees or even money to invest. All you need is an
attitude to learn, be insanely curious and an intuitive ability to
connect things based on the knowledge gained by you over the years.
</p>

 <p>
Also important is the need to cultivate a healthy positive attitude,
ditching that ego and have a tolerance to take and act on feedback. Once
you do all this, I promise you will achieve greatness. As Bob Marley
stated:
</p>

 <blockquote>
 <p>
The greatness of a man is not in how much wealth he acquires, but in his
integrity and his ability to affect those around him positively.
</p>
</blockquote>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/a-great-programmer/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/a-great-programmer/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>The Best Programmers I Know</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Original  <a href="https://endler.dev/2025/best-programmers/">article by Matthias Endler</a>
</p>

 <p>
I have met a lot of developers in my life.
Lately, I asked myself: “What does it take to be one of the best? What do they all have in common?”
</p>

 <p>
In the hope that this will be an inspiration to someone out there, I wrote down the traits I observed in the most exceptional people in our craft. I wish I had that list when I was starting out. Had I followed this path, it would have saved me a lot of time.
</p>
 <h2>Read the Reference  <a id="read-the-reference" class="anchor" href="#read-the-reference">#</a></h2> <div class="outline-text-2" id="text-org1f25a80">
 <p>
If there was one thing that I should have done as a young programmer, 
it would have been to  <b>read the reference</b> of the thing I was using.
I.e. read the [Apache Webserver Documentation]( <a href="https://httpd.apache.org/docs/2.4/">https://httpd.apache.org/docs/2.4/</a>),
the [Python Standard Library]( <a href="https://docs.python.org/3/library/index.html">https://docs.python.org/3/library/index.html</a>),
or the [TOML spec]( <a href="https://toml.io/en/v1.0.0">https://toml.io/en/v1.0.0</a>).
</p>

 <p>
Don’t go to Stack Overflow, don’t ask the LLM, don’t  <b>guess</b>, just go straight to the  <b> <b>source</b></b>.
Oftentimes, it’s surprisingly accessible and well-written.
</p>
</div>
 <h2>Know Your Tools Really Well  <a id="know-your-tools-really-well" class="anchor" href="#know-your-tools-really-well">#</a></h2> <div class="outline-text-2" id="text-orgf4a8068">
 <p>
Great devs understand the technologies they use on a  <b>fundamental level</b>.
</p>

 <p>
It’s one thing to be able to  <b>use</b> a tool and a whole other thing to truly  <b>grok</b> (understand) it.
A mere user will fumble around, get confused easily, hold it wrong and not optimize the config.
</p>

 <p>
An expert goes in (after reading the reference!)
and sits down to write a config for the tool of which they understand every single line and can explain it to a colleague.
That leaves no room for doubt!
</p>

 <p>
To know a tool well, you have to know:
</p>
 <ul class="org-ul"> <li>its history: who created it? Why? To solve which problem?</li>
 <li>its present: who maintains it? Where do they work? On what?</li>
 <li>its limitations: when is the tool not a good fit? When does it break?</li>
 <li>its ecosystem: what libraries exist? Who uses it? What plugins?</li>
</ul> <p>
For example, if you are a backend engineer and you make heavy use of Kafka,
I expect you to know a lot about Kafka – not just things you read on Reddit.
At least that’s what I expect if you want to be one of the best engineers.
</p>
</div>
 <h2>Read The Error Message  <a id="read-the-error-message" class="anchor" href="#read-the-error-message">#</a></h2> <div class="outline-text-2" id="text-orgc5557d0">
 <p>
As in  <b>Really Read the Error Message and Try to Understand What’s Written</b>.
Turns out, if you just sit and meditate about the error message, it starts to speak to you.
The best engineers can infer a ton of information from very little context.
Just by reading the error message, you can fix most of the problems on your own.
</p>

 <p>
It also feels like a superpower if you help someone who doesn’t have that skill.
Like “reading from a cup” or so.
</p>
</div>
 <h2>Break Down Problems  <a id="break-down-problems" class="anchor" href="#break-down-problems">#</a></h2> <div class="outline-text-2" id="text-org516bbd8">
 <p>
Everyone gets stuck at times.
The best know how to get unstuck.
They simplify problems until they become digestible.
That’s a hard skill to learn and requires a ton of experience.
Alternatively, you just have awesome problem-solving skills, e.g., you’re clever.
If not, you can train it, but there is no way around breaking down hard problems.
There are problems in this world that are too hard to solve at once for anyone involved.
</p>

 <p>
If you work as a professional developer, that is the bulk of the work you get paid to do:
breaking down problems.
If you do it right, it will feel like cheating:
you just solve simple problems until you’re done.
</p>
</div>
 <h2>Don’t Be Afraid To Get Your Hands Dirty  <a id="donrsquot-be-afraid-to-get-your-hands-dirty" class="anchor" href="#donrsquot-be-afraid-to-get-your-hands-dirty">#</a></h2> <div class="outline-text-2" id="text-org533cc7a">
 <p>
The best devs I know read a lot of code and they are not afraid to touch it.
They never say “that’s not for me” or “I can’t help you here.”
Instead, they just start and learn.
Code is  <b>just code</b>.
They can just pick up any skill that is required with time and effort. 
Before you know it, they become the go-to person in the team for whatever they touched.
Mostly because they were the only ones who were not afraid to touch it in the first place.
</p>
</div>
 <h2>Always Help Others  <a id="always-help-others" class="anchor" href="#always-help-others">#</a></h2> <div class="outline-text-2" id="text-orgeb13181">
 <p>
A related point.
Great engineers are in high demand and are always busy, but they always try to help.
That’s because they are naturally curious and their supportive mind is what made them great engineers in the first place.
It’s a sheer joy to have them on your team, because they are problem solvers.
</p>
</div>
 <h2>Write  <a id="write" class="anchor" href="#write">#</a></h2> <div class="outline-text-2" id="text-org0d85a9b">
 <p>
Most awesome engineers are well-spoken and happy to share knowledge.
</p>

 <p>
The best have some outlet for their thoughts: blogs, talks, open source, or a combination of those.
</p>

 <p>
I think there is a strong correlation between writing skills and programming.
All the best engineers I know have good command over at least one human language – often more.
Mastering the way you write is mastering the way you think and vice versa.
A person’s writing style says so much about the way they think.
If it’s confusing and lacks structure, their coding style will be too.
If it’s concise, educational, well-structured, and witty at times, their code will be too.
</p>

 <p>
Excellent programmers find joy in playing with words.
</p>
</div>
 <h2>Never Stop Learning  <a id="never-stop-learning" class="anchor" href="#never-stop-learning">#</a></h2> <div class="outline-text-2" id="text-org1440662">
 <p>
Some of the best devs I know are 60+ years old.
They can run circles around me.
Part of the reason is that they keep learning.
If there is a new tool they haven’t tried or a language they like, they will learn it.
This way, they always stay on top of things without much effort.
</p>

 <p>
That is not to be taken for granted: a lot of people stop learning really quickly after they
graduate from University or start in their first job.
They get stuck thinking that what they got taught in school is the “right” way to do things.
Everything new is bad and not worth their time.
So there are 25-year-olds who are “mentally retired” and 68-year-olds who are still fresh in their mind.
I try to one day belong to the latter group.
</p>

 <p>
Somewhat related, the best engineers don’t follow trends, but they will always carefully
evaluate the benefits of new technology. If they dismiss it, they can tell you exactly  <b>why</b>,
when the technology would be a good choice, and what the alternatives are.
</p>
</div>
 <h2>Status Doesn’t Matter  <a id="status-doesnrsquot-matter" class="anchor" href="#status-doesnrsquot-matter">#</a></h2> <div class="outline-text-2" id="text-org775e1cf">
 <p>
The best devs talk to principal engineers and junior devs alike. There is no hierarchy.
They try to learn from everyone, young and old.
The newcomers often aren’t entrenched in office politics yet and still have a fresh mind.
They don’t know why things are  <b>hard</b> and so they propose creative solutions.
Maybe the obstacles from the past are no more, which makes these people a great source of inspiration.
</p>
</div>
 <h2>Build a Reputation  <a id="build-a-reputation" class="anchor" href="#build-a-reputation">#</a></h2> <div class="outline-text-2" id="text-orgbae2e69">
 <p>
You can be a solid engineer if you  <b>do</b> good work, 
but you can only be one of the best if you’re  <b>known</b> for your good work;
at least within a (larger) organization.
</p>

 <p>
There are many ways to build a reputation for yourself:
</p>

 <ul class="org-ul"> <li>You built and shipped a critical service for a (larger) org.</li>
 <li>You wrote a famous tool</li>
 <li>You contribute to a popular open source tool</li>
 <li>You wrote a book that is often mentioned</li>
</ul> <p>
Why do I think it is important to be known for your work?
All of the above are ways to extend your radius of impact in the community.
Famous developers impact way more people than non-famous developers.
There’s only so much code you can write.
If you want to “scale” your impact, you have to become a thought leader.
</p>

 <p>
Building a reputation is a long-term goal.
It doesn’t happen overnight, nor does it have to.
And it won’t happen by accident.
You show up every day and do the work.
Over time, the work will speak for itself.
More people will trust you and your work and they will want to work with you.
You will work on more prestigious projects and the circle will grow.
</p>

 <p>
I once heard about this idea that your latest work should
overshadow everything you did before.
That’s a good sign that you are on the right track.
</p>
</div>
 <h2>Have Patience  <a id="have-patience" class="anchor" href="#have-patience">#</a></h2> <div class="outline-text-2" id="text-orgcce448e">
 <p>
You need patience with computers and humans.
Especially with yourself.
Not everything will work right away and people take time to learn.
It’s not that people around you are stupid; they just have incomplete information.
Without patience, it will feel like the world is against you and 
everyone around you is just incompetent. That’s a miserable place to be.
You’re too clever for your own good.
</p>

 <p>
To be one of the best, you need an incredible amount of patience, focus, and dedication.
You can’t afford to get distracted easily if you want to solve hard problems. 
You have to return to the keyboard to get over it.
You have to put in the work to push a project over the finishing line.
And if you can do so while not being an arrogant prick, that’s even better.
That’s what separates the best from the rest.
</p>
</div>
 <h2>Never Blame the Computer  <a id="never-blame-the-computer" class="anchor" href="#never-blame-the-computer">#</a></h2> <div class="outline-text-2" id="text-org124ab3c">
 <p>
Most developers blame the software, other people, their dog, or the weather for
flaky, seemingly “random” bugs.
</p>

 <p>
The best devs don’t.
</p>

 <p>
No matter how erratic or mischievous the behavior of a computer seems, 
there is  <b>always</b> a logical explanation: you just haven’t found it yet!
</p>

 <p>
The best keep digging until they find the reason.
They might not find the reason immediately, they might never find it, 
but they never blame external circumstances. 
</p>

 <p>
With this attitude, they are able to make incredible progress and learn things that others fail to.
When you mistake bugs for incomprehensible magic, magic is what it will always be.
</p>
</div>
 <h2>Don’t Be Afraid to Say “I Don’t Know”  <a id="donrsquot-be-afraid-to-say-ldquoi-donrsquot-knowrdquo" class="anchor" href="#donrsquot-be-afraid-to-say-ldquoi-donrsquot-knowrdquo">#</a></h2> <div class="outline-text-2" id="text-org66bba1e">
 <p>
In job interviews, I pushed candidates hard to at least say “I don’t know” once. 
The reason was not that I wanted to look superior (although some people certainly had that impression). 
No, I wanted to reach the boundary of their knowledge.
I wanted to stand with them on the edge of what they thought they knew.
Often, I myself didn’t know the answer. And to be honest, I didn’t care about the answer.
What I cared about was when people bullshitted their way through the interview.
</p>

 <p>
The best candidates said
“Huh, I don’t know, but that’s an interesting question! If I had to guess, I would say…”
and then they would proceed to deduce the answer.
That’s a sign that you have the potential to be a great engineer.
</p>

 <p>
If you are afraid to say “I don’t know”, you come from a position of hubris or defensiveness.
I don’t like bullshitters on my team.
Better to acknowledge that you can’t know everything.
Once you accept that, you allow yourself to learn.
“The important thing is that you don’t stop asking questions,” said Albert Einstein.
</p>
</div>
 <h2>Don’t Guess  <a id="donrsquot-guess" class="anchor" href="#donrsquot-guess">#</a></h2> <div class="outline-text-2" id="text-org7ac1ffe">
 <p>
“In the Face of Ambiguity, Refuse the Temptation to Guess”
That is one of my favorite rules in [PEP 20 – The Zen of Python]( <a href="https://peps.python.org/pep-0020/">https://peps.python.org/pep-0020/</a>).
</p>

 <p>
And it’s so, so tempting to guess!
</p>

 <p>
I’ve been there many times and I failed with my own ambition.
</p>

 <p>
When you guess, two things can happen:
</p>
 <ul class="org-ul"> <li>In the  <b>best case</b> you’re wrong and your incorrect assumptions lead to a bug.</li>
 <li>In the  <b>worst case</b> you are right… and you’ll never stop and second guess yourself. 
You build up your mental model based on the wrong assumptions.
This can haunt you for a long time.</li>
</ul> <p>
Again, resist the urge to guess.
Ask questions, read the reference, use a debugger, be thorough.
Do what it takes to get the answer.
</p>
</div>
 <h2>Keep It Simple  <a id="keep-it-simple" class="anchor" href="#keep-it-simple">#</a></h2> <div class="outline-text-2" id="text-orgf89a551">
 <p>
Clever engineers write clever code.
Exceptional engineers write simple code.
</p>

 <p>
That’s because most of the time, simple is enough. 
And simple is more maintainable than complex.
Sometimes it  <b>does</b> matter to get things right, but
knowing the difference is what separates the best from the rest. 
</p>

 <p>
You can achieve a whole lot by keeping it simple.
Focus on the right things.
</p>
</div>
 <h2>Final Thoughts  <a id="final-thoughts" class="anchor" href="#final-thoughts">#</a></h2> <div class="outline-text-2" id="text-org806e911">
 <p>
The above is not a checklist or a competition;
and great engineering is not a race.
</p>

 <p>
Just don’t trick yourself into thinking that you can skip the hard work.
There is no shortcut. Good luck with your journey.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/best-programmers/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/best-programmers/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Black Box Testing in modern Software</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Testing software at a high level means freedom of implementation and refactoring, while maintaining guarantees of correctness. This is something all good engineers love 💘
</p>

 <blockquote>
 <p>
Black-box testing is a method of software testing that examines the functionality of an application without peering into its internal structures or workings.
</p>
</blockquote>

 <p>
In my opinion, for complex systems and system interactions, one should default to writing a lot of black-box tests, and some unit tests where it makes sense, and leave other kinds of integration tests out of scope, until it might make sense.
</p>


 <div id="org4c9e6ee" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/resources/images/black-box-testing.png"></img></p>
</div>
 <h2>Black box tests are the best at BDD  <a id="black-box-tests-are-the-best-at-bdd" class="anchor" href="#black-box-tests-are-the-best-at-bdd">#</a></h2> <div class="outline-text-2" id="text-org2247915">
 <p>
Black box tests stimulate functional, requirement and behaviour driven testing.
</p>

 <p>
Testing a system becomes simpler and we can cover many more “real” edge cases.
</p>
</div>
 <h2>Unit testing still has its place  <a id="unit-testing-still-has-its-place" class="anchor" href="#unit-testing-still-has-its-place">#</a></h2> <div class="outline-text-2" id="text-orgd3fe1f1">
 <p>
Unit testing is an invaluable tool that should also be used in parallel to black box tests and other high level tests.
</p>

 <p>
These tests are very easy to use, useful and give also good information about a system.
</p>

 <p>
Ideally, your “core domain” should be fully tested, and your “business logic” should be encoded in more pure code, ideally as data.
</p>
</div>
 <h2>Dealing with dependencies  <a id="dealing-with-dependencies" class="anchor" href="#dealing-with-dependencies">#</a></h2> <div class="outline-text-2" id="text-orgecaaa8c">
 <p>
When we start using external dependencies in a system like databases, caches, external APIs, etc.
You have 3 choices:
</p>
 <ul class="org-ul"> <li>create and use mocks</li>
 <li>create and use stubs (dummy implementations)</li>
 <li>use real dependencies</li>
</ul></div>
 <h3>Mocks are inherently evil  <a id="mocks-are-inherently-evil" class="anchor" href="#mocks-are-inherently-evil">#</a></h3> <div class="outline-text-3" id="text-org766a860">
 <p>
Mocks are generally painful to write, read, debug and maintain.
</p>

 <p>
They should be avoided when possible, we should use real implementations for most tests to a system.
testcontainers is a great library for this purpose, and I use it extensively.
</p>
</div>
 <h3>Java baggage  <a id="java-baggage" class="anchor" href="#java-baggage">#</a></h3> <div class="outline-text-3" id="text-org2e0e5a5">
 <p>
Lots of developers coming from a traditional enterprisy JDK environment know what we mean.
</p>

 <p>
This tendency of doing one class per file, and creating tests for every single class and every single method along with extensive Mockito ideology.
</p>
</div>
 <h2>The cure  <a id="the-cure" class="anchor" href="#the-cure">#</a></h2> <div class="outline-text-2" id="text-orgd8ff85b">
 <p>
No marrying the test structure to code structure. No testing every individual class when not needed.
</p>

 <p>
Ensure we test functionalities, almost never test how the code is written / implemented (this gives flexibility and freedom to refactor).
</p>

 <p>
Write many black box tests. Attempt to test all “user paths” and possible interactions with the system, good and bad, happy and unhappy, low load high load, etc.
</p>

 <p>
Writing many unit tests where it makes sense. Preferably using data generators, property based, or auto-generated test cases, with a set of inputs.
</p>
</div>
 <h2>What’s in it for me ?  <a id="whatrsquos-in-it-for-me-" class="anchor" href="#whatrsquos-in-it-for-me-">#</a></h2> <div class="outline-text-2" id="text-org512de9b">
 <p>
Easier and simpler tests of the entire system, tests have lower complexity.
</p>

 <p>
Easy to cover 100% of a “user flow” or a “data flow”.
</p>

 <p>
Low chance of false positives (partly thanks to avoiding mocks too).
</p>

 <p>
This allows for a good test-driven development approach, and more confidence in product.
</p>

 <p>
Testers require less technical knowledge, programming or IT skills and do not need to learn all nitty gritty implementation details of the system.
</p>

 <p>
More loose coupling from the code means more freedom of implementation + refactor.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/black-box-testing/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/black-box-testing/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Breaking free of Javascript</title>
  <description><![CDATA[<div id="content" class="content max-w-full">
 <div id="orgd04f052" class="figure">
 <p> <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1630256482/jjba-site/blog/breaking-free-from-js/1_hTGEAKTrOdt_vRzNUCcgRA_qgtbyc.png"></img></p>
</div>

 <p>
Javascript has a stranglehold on all Front End Development. If you write
code for the browser, then it’s most likely written directly in
Javascript or its very close cousin TypeScript. The problem is that
Javascript is a terrible language.
</p>

 <p>
TLDR: You should break free from Javascript by learning PureScript which
compiles to Javascript.
</p>

 <p>
Typescript and other attempts to curtail Javascript are about as
effective as a band-aid on a puncture wound. One might argue that it’s
better than nothing but eventually, you’re still going to bleed out.
</p>

 <p>
The language has undergone many changes since its initial development,
which consisted of a whopping 10 days, but all of these changes are just
polishing a turd.
</p>

 <p>
Javascript is a veritable Smorgasbord of languages paradigms. It has
some Object Oriented, Functional and Procedural features all mixed
together in an unpalatable Schizophrenic Goulash (mixed metaphor
intended).
</p>

 <p>
There are more bad parts of Javascript than good parts and anyone
working in Javascript on a daily basis will attest to the fact that
being a good Javascript Developer is more about knowing what NOT to do.
</p>

 <p>
Seasoned Javascript Developers have a litany of language constructs that
they routinely avoid like the plague lest they fall victim to the
plethora of runtime exceptions that are routinely encountered in
production, e.g. the dreaded “undefined is not a function”.
</p>

 <p>
Javascript’s reign is supreme thanks to its monopolistic hold on the
Browser. All previous attempts to extricate the Browser from the tyranny
of Javascript have long since failed leaving most leery of attempting
yet another failed coup d’état.
</p>
 <h2>Freedom or Death  <a id="freedom-or-death" class="anchor" href="#freedom-or-death">#</a></h2> <div class="outline-text-2" id="text-freedom-or-death">

 <div id="org3e4127a" class="figure">
 <p> <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1630256482/jjba-site/blog/breaking-free-from-js/1_0xnuE8J8c0Ivwe_ud5i5xA_qk6ehg.jpg"></img></p>
</div>

 <p>
What options do we have?
</p>

 <p>
We could decide not to develop applications for the Browser. I like to
think that we should develop mostly on the server-side by default,
unless the situation requires very advanced client-side features and
state. I would personally recommend Go and Haskell as strong candidates
for server side applications. This of course could be done in a number
of different languages.
</p>

 <p>
We could create an Open Source Browser that would allow for other
languages or perhaps it could have a built-in language that’s “better”
than Javascript.
</p>

 <p>
But our Browser would be completely incompatible with every single web
site on the planet. This may appear to be Freedom at first but it most
definitely is Death. No one but the most fervent would adopt this.
</p>

 <p>
We could develop a Browser Extension that allows for a better developer
experience. This too has been tried before and since we’re reaching a
near monopoly in Browser development by only the largest of companies,
our initial taste of Freedom could, on a whim of a corporate giant, be
transformed into sudden Death.
</p>

 <p>
Most affected by an oppressive environment are too busy trying to
survive in the current climate than to overturn it.
</p>

 <p>
Revolutions are rare, dangerous and costly but subversion isn’t.
</p>
</div>
 <h2>If you can’t beat ’em, join ’em (sort of)  <a id="if-you-canrsquot-beat-rsquoem-join-rsquoem-sort-of" class="anchor" href="#if-you-canrsquot-beat-rsquoem-join-rsquoem-sort-of">#</a></h2> <div class="outline-text-2" id="text-if-you-cant-beat-em-join-em-sort-of">
 <p>
Javascript’s stranglehold on the Browser isn’t a new phenomenon. We’ve
seen this very thing before. In fact, it’s rampant in the hardware
world.
</p>

 <p>
A Microprocessor has a single instruction set that can never be
superseded by any other. Not without completely replacing the hardware.
</p>

 <p>
Yet, we don’t call for revolution but instead work to insulate ourselves
from the deficiencies of such a system. We did this over half a century
ago when we created high-level languages.
</p>

 <p>
Any flaws or complexities in the underlying architecture are squelched
by an abstraction layer that frees us from having to regularly consider
the pitfalls.
</p>

 <p>
By writing a compiler, we freed ourselves from the tyranny of a single
platform and by using this same approach, we can free ourselves from our
current dilemma.
</p>
</div>
 <h2>A Horse of a Different Color  <a id="a-horse-of-a-different-color" class="anchor" href="#a-horse-of-a-different-color">#</a></h2> <div class="outline-text-2" id="text-a-horse-of-a-different-color">

 <div id="org383294a" class="figure">
 <p> <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1630256482/jjba-site/blog/breaking-free-from-js/1_g4vok0cblQYGTiK5_k_Nmg_hyftb6.jpg"></img></p>
</div>

 <p>
What we want is a way to write Javascript without having to write
Javascript. To do that, we’re going to need a Transpiler.
</p>

 <p>
A Transpiler will compile code in one language and produce code in
another. Technically, CoffeeScript, TypeScript and Babel are Transpilers
but they start with nearly Javascript and produce Javascript.
</p>

 <p>
These solutions do not give us the benefits that we’re hoping for. This
is the equivalent of writing in Assembly Language instead of Machine
Code.
</p>

 <p>
What we want is a whole new language. One that avoids all of the
terrible design decisions of Javascript. There are many languages that
transpile to Javascript that are far superior to Javascript.
</p>

 <p>
I’m going to concentrate on Functional Programming Languages only
because it’s becoming very clear that Functional Programming is the
future of our industry.
</p>

 <p>
This is evident by the mass adoption of Functional Features in today’s
most popular languages. This is historically what’s been seen right
before a major paradigm shift is about to occur in the software
industry.
</p>

 <p>
For the curious, Richard Feldman does a wonderful job of making this
argument in this entertaining and illuminating talk The Next Paradigm
Shift in Programming.
</p>
</div>
 <h3>Go  <a id="go" class="anchor" href="#go">#</a></h3> <div class="outline-text-3" id="text-go">
 <p>
GopherJS is an honourable mention and could be exactly what you search
if you are into Go:  <a href="https://github.com/gopherjs/gopherjs">see GopherJS
on GitHub</a>
</p>
</div>
 <h3>Elm  <a id="elm" class="anchor" href="#elm">#</a></h3> <div class="outline-text-3" id="text-elm">

 <div id="org3934d7d" class="figure">
 <p> <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1630256482/jjba-site/blog/breaking-free-from-js/1_yok_lg3cm73w-eeJttUY2A_xzgznt.png"></img></p>
</div>

 <p>
Elm is a great beginner language for Functional Programming. The
ecosystem is mature and I have personally been responsible for a team
that put over 160K lines of Elm code into production without a single
line of Elm code producing a Runtime Error.
</p>

 <p>
Elm is a dialect of ML and a very small subset of Haskell.
</p>

 <p>
If you want to dip your toe into the Statically Typed, Purely Functional
Programming world, then Elm can be a great starting point
( <a href="https://elm-lang.org/">https://elm-lang.org/</a>).
</p>

 <p>
Unfortunately, Elm’s lack of power quickly shows as your application
becomes complex and the resources for learning are somewhat limited. The
go-to book for learning Elm is Elm in Action.
</p>
</div>
 <h3>ReasonML  <a id="reasonml" class="anchor" href="#reasonml">#</a></h3> <div class="outline-text-3" id="text-reasonml">
 <p>
Facebook uses Functional Programming Languages, one of which is Haskell,
the granddaddy of them all. The other notable language is the one they
developed called ReasonML. It’s a dialect of OCaml, which is a dialect
of ML.
</p>

 <p>
It touts safety and interoperability with both Javascript and OCaml
ecosystems ( <a href="https://reasonml.github.io/">https://reasonml.github.io/</a>).
</p>

 <p>
Unfortunately, Reason isn’t a Pure Functional Language and so it suffers
from many of the problems that Imperative Languages do. It’s a
compromise the way that TypeScript is a compromise.
</p>

 <p>
There are a few books on Reason, Web Development with ReasonML:
Type-Safe, Functional Programming for JavaScript Developers and ReasonML
Quick Start Guide: Build fast and type-safe React applications that
leverage the JavaScript and OCaml ecosystems
</p>
</div>
 <h3>Fable  <a id="fable" class="anchor" href="#fable">#</a></h3> <div class="outline-text-3" id="text-fable">
 <p>
For those married to the .NET ecosystem, there’s Fable, a language that
lets you write in Microsoft’s Functional Programming Language, F#, and
compiler to Javascript.
</p>

 <p>
Fable supports most of the F# core library and most of the commonly used
.NET APIs ( <a href="https://fable.io/">https://fable.io/</a>).
</p>

 <p>
Unfortunately, like ReasonML, Fable is not a Pure Functional Programming
language either.
</p>

 <p>
I couldn’t seem to find any books on it but here’s a free online “book”,
The Elmish Book. The use of the word “Elm” in the title seems to be
coincidental and has nothing to do with the Elm language.
</p>
</div>
 <h3>PureScript  <a id="purescript" class="anchor" href="#purescript">#</a></h3> <div class="outline-text-3" id="text-purescript">

 <div id="org1728178" class="figure">
 <p> <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1630256482/jjba-site/blog/breaking-free-from-js/1_w0WBjtEDr_ESj8FdDApaOw_jimozj.png"></img></p>
</div>

 <p>
PureScript was developed by Haskell developers who stole as much as they
could from Haskell while making some great improvements along the way.
</p>

 <p>
This language is my personal favorite. All new projects at my company
will be developed in this language. It has all of the expressive power
of Haskell yet it runs beautifully in the Browser producing clean
readable Javascript ( <a href="https://www.purescript.org/">https://www.purescript.org/</a>).
</p>

 <p>
It’s a Pure Functional Language (hence its name) just like Haskell. It
is the most powerful of all the languages listed here but unfortunately
has a big downside.
</p>

 <p>
The learning curve is pretty steep. That’s what motivated me to write my
book to make that process as painless as possible. Once you put in the
work to learn PureScript, it will pay you back ten fold in dividends.
</p>

 <p>
There are 2 books I know of. The free one, which is great if you already
know Haskell, PureScript by Example.
</p>

 <p>
If you’ve never seen a Functional Language or if you have no idea what
Functional Programming is and you’re interested in the most powerful of
all of the aforementioned languages, then I’d suggest you consider my
book, Functional Programming Made Easier: A Step-by-Step Guide.
</p>

 <p>
It’s a complete Functional Programming course for Imperative Programmers
of any language. It starts from the very beginning of Functional
Programming and by the end, you’ve developed a web-server and front-end
single page application in PureScript.
</p>
</div>
 <h2>Too Good to be True?  <a id="too-good-to-be-true" class="anchor" href="#too-good-to-be-true">#</a></h2> <div class="outline-text-2" id="text-too-good-to-be-true">

 <div id="orga3a84c3" class="figure">
 <p> <img loading="lazy" style="" src="https://res.cloudinary.com/dehs6irlh/image/upload/v1630256482/jjba-site/blog/breaking-free-from-js/1_Hgvz80kAKCqSaMojl5oP1g_iipeq9.png"></img></p>
</div>

 <p>
All of these languages are very different from Javascript. They can be
downright scary. It’s not like going from Java to C# or from Java to
Javascript.
</p>

 <p>
These are Functional Programming Languages. You might be thinking that
what you’d really like is Java, C# or Python but in the Browser.
</p>

 <p>
But the biggest gains in program safety and developer productivity is
only possible from a Functional Programming Language.
</p>

 <p>
That’s a pretty bold claim and for the unconvinced, I invite them to ask
programmers who routinely program in a Functional Language in their
professional work and ask them if they miss their old Imperative
Programming Languages.
</p>

 <p>
I’d be willing to bet that 99 out of 100 would say that they’d never go
back to the old way of programming. Then ask them how much effort it
took to learn these new fangled beasts.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/breaking-free-of-javascript/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/breaking-free-of-javascript/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Don’t Reward the Best Firefighter</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <h2>The “Hero” Trap  <a id="the-hero-trap" class="anchor" href="#the-hero-trap">#</a></h2> <div class="outline-text-2" id="text-org96ac697">
 <p>
Every engineering team has that one  <b>“hero.”</b> You know the one: the 3 AM incident response god.
They dive into a production dumpster fire, pull a rabbit out of a hat, and somehow bring the system back online.
</p>

 <p>
We love them for it. We give them the shout-outs in Slack, the fat bonuses, and the “Senior Staff” titles because they’re the “go-to” person when everything breaks.
</p>

 <p>
But by making them the main character, we’re lowkey ensuring our culture stays a mess.
</p>
</div>
 <h3>Visible Heroes vs. Invisible Wins  <a id="visible-heroes-vs-invisible-wins" class="anchor" href="#visible-heroes-vs-invisible-wins">#</a></h3> <div class="outline-text-3" id="text-orgce28130">
 <p>
For every loud firefighter, there’s an invisible  <b>fire preventer.</b> This is the engineer who spends a month refactoring a messy legacy service that no one else wants to touch.
</p>

 <p>
Their work doesn’t show up as a shiny new feature on the roadmap. Their success is silent—it’s the catastrophic outage that  <b>didn’t</b> happen six months from now.
</p>

 <p>
And their reward? Often, it’s getting passed over for a promo because their “impact” wasn’t as visible as the person who “saved the day.”
</p>


 <div id="org3f48b9e" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/static-assets/blog/img/software-firefighter.png"></img></p>
</div>
</div>
 <h3>We Built a Broken Game  <a id="we-built-a-broken-game" class="anchor" href="#we-built-a-broken-game">#</a></h3> <div class="outline-text-3" id="text-orge40b2f1">
 <p>
This is a total incentive fail, and honestly, it’s on all of us. Performance reviews are fundamentally biased toward  <b>reactive work.</b>
</p>

 <p>
Managers are great at measuring things that are visible on a dashboard:
</p>

 <ul class="org-ul"> <li>Features shipped</li>
 <li>Tickets closed</li>
 <li>Incidents resolved</li>
</ul> <p>
There is no column on the spreadsheet for  <b>“disasters averted.”</b>
</p>

 <p>
As a result, we’ve built a career ladder that basically encourages engineers to let things smolder, knowing they’ll get more credit for putting out a blaze than for making sure there’s no fire in the first place.
</p>
</div>
 <h3>Redefining “Impact”  <a id="redefining-impact" class="anchor" href="#redefining-impact">#</a></h3> <div class="outline-text-3" id="text-org07f64d2">
 <p>
It’s time to stop treating “impact” as a synonym for “loud activity.” Real impact is the verifiable elimination of future risk.
</p>

 <ul class="org-ul"> <li> <b>The Automation Win:</b> The engineer who fixes a flaky, manual   deployment isn’t just “closing a ticket.” They’re giving every dev on  the team their time back, forever. That’s massive, compounding impact.</li>
 <li> <b>The Refactor Win:</b> The engineer who cleans up a bug-prone module isn’t just “tidying up.” They are measurably lowering the failure rate for the entire business. That is direct risk reduction.</li>
</ul> <p>
We need to start hyping up the architects of fireproof buildings, not just the people who are good with a hose.
</p>

 <p>
This takes a conscious effort to hunt for the “invisible” work. We need to use data to quantify risk  <i>before</i> it fails and treat the reduction of that risk as a top-tier contribution.
</p>

 <p>
Next time you’re sitting in a performance calibration, ask yourself the hard question:  <b>Are we promoting the people who are best at navigating a broken system, or the ones who are actually fixing it?</b>
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/dont-reward-the-best-firefighter/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/dont-reward-the-best-firefighter/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>German naming convention</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <div id="table-of-contents" role="doc-toc">
 <h2>Table of Contents</h2>
 <div id="text-table-of-contents" role="doc-toc">
 <ul> <li> <a href="#expect-the-violent-psychopath">Expect the Violent Psychopath</a></li>
 <li> <a href="#naming-tropes">Naming Tropes</a></li>
 <li> <a href="#its-all-greek-to-me">It’s All Greek To Me</a></li>
 <li> <a href="#german-dutch-naming-convention">German / Dutch Naming Convention</a></li>
 <li> <a href="#isomorphic-naming">Isomorphic Naming</a></li>
</ul></div>
</div>
 <p>
There’s one thing that could make our life as software engineers much
easier: better naming convention.
</p>
 <h2>Expect the Violent Psychopath  <a id="expect-the-violent-psychopath" class="anchor" href="#expect-the-violent-psychopath">#</a></h2> <div class="outline-text-2" id="text-expect-the-violent-psychopath">
 <p>
You’re trying to tell a story with your code. Your code should tell that
story clearly, not cryptically, for an audience besides yourself. A good
yardstick for deciding what kind of audience you are writing for is to
imagine someone who has a familiarity with your domain but not your
program’s take on the domain. I think programmers forget that, as they
are authors, they have readers.
</p>

 <p>
A famous and regularly quoted piece of advice, from the mailing list
comp.lang.c in 1991, John F. Woods wrote:
</p>

 <blockquote>
 <p>
Always code as if the guy who ends up maintaining your code will be a
violent psychopath who knows where you live. Code for readability.
</p>
</blockquote>

 <p>
It’s hard to put it better than that.
</p>
</div>
 <h2>Naming Tropes  <a id="naming-tropes" class="anchor" href="#naming-tropes">#</a></h2> <div class="outline-text-2" id="text-naming-tropes">
 <p>
There are some common naming conventions which are departures from plain
English, usually in the interest of brevity:
</p>

 <ul class="org-ul"> <li>Abbreviations: when words are abbreviated such as  <code>fct</code> for
“function”,  <code>dfn</code> for “definition”,  <code>ctx</code> for “context.”</li>
 <li>It’s All Greek To Me: using simply  <code>a</code>,  <code>x</code>, etc. as in mathematics.</li>
 <li>“Hungarian” notation: any prefix or suffix notation in which a single
letter is used to refer to a type or property of the variable, as in
sigils like  <code>$foo</code> (“scalar foo”),  <code>lpszFoo</code> (“long pointer string
zero-terminated”), or  <code>fooL</code> (list of foo).</li>
 <li>Acronyms: using initial letters to refer to concepts:  <code>throwVE</code>
(“throw validation error”).</li>
</ul> <p>
Most of these are unnecessary and/or harmful.
</p>
</div>
 <h2>It’s All Greek To Me  <a id="itrsquos-all-greek-to-me" class="anchor" href="#itrsquos-all-greek-to-me">#</a></h2> <div class="outline-text-2" id="text-its-all-greek-to-me">
 <p>
A word on this convention. Single letter naming comes from mathematical
tradition; it means “there isn’t a good noun for this because it’s
general”. A person of X height. In some cases, this is actually
reasonable. Consider:
</p>

 <p>
 <code>identity x = x</code>
</p>

 <p>
The identity function isn’t enhanced by calling its parameter thing; it
literally doesn’t matter what it is, especially in some typed languages.
In fact, one could argue that it’s harmful to try to using a meaningful
English name.
</p>

 <p>
However, anywhere that your variables have some meaning, by using “Greek
convention”, you’re throwing away information that could help someone to
digest your code better. You’re not trying to fit your code on a napkin.
</p>
</div>
 <h2>German / Dutch Naming Convention  <a id="german--dutch-naming-convention" class="anchor" href="#german--dutch-naming-convention">#</a></h2> <div class="outline-text-2" id="text-german-dutch-naming-convention">
 <p>
This is what I consider good naming convention. I discovered this
convention while working with a German colleague, who, I’d always joked,
uses long variable names, and almost never abbreviates anything.
However, the more I read his code, the more I realised I was able to
read the story he was trying to tell, and appreciated it a lot: Using as
many words as necessary to clearly name something. Everything.
</p>

 <p>
I called this “German” naming convention although same applies for
Dutch, as a reference to the fact that the German language is known for
its compound words, which can become comically long and specific at
times. Some examples include, Betäubungsmittelverschreibungsverordnung
(“regulation requiring a prescription for an anaesthetic”),
Rechtsschutzversicherungsgesellschaften (“legal protection insurance
companies”), and the 1999 German “Word of the Year”:
Rindfleischetikettierungsüberwachungsaufgabenübertragungsgesetz (“beef
labelling regulation and delegation of supervision law”).
</p>

 <p>
Don’t write  <code>fopen</code> when you can write  <code>openFile</code>. Write
 <code>throwValidationError</code> and not  <code>throwVE</code>. Call that name  <code>function</code> and
not  <code>fct</code>. That’s German naming convention. Do this and your readers
will appreciate it.
</p>
</div>
 <h2>Isomorphic Naming  <a id="isomorphic-naming" class="anchor" href="#isomorphic-naming">#</a></h2> <div class="outline-text-2" id="text-isomorphic-naming">
 <p>
This convention complements German naming convention completely.
</p>

 <p>
Isomorphic naming is to say that the name of the variable is the same
form of the name of the type. A simple heuristic, in other words: just
use the name of the type.
</p>

 <p>
Here’s a real sample where better naming convention would make this
easier to read without being a cryptographer:
</p>

 <pre>updateColExp
  :: QualifiedTable -> RenameField -> ColExp -> IO ColExp
updateColExp qt rf (ColExp fld val) =
  ColExp updatedFld <$> updatedVal
  ...</pre>

 <p>
Look at this naming convention. This may be appropriate if you’re in
some kind of code golfing competition, but I can’t even pronounce these
names. Applying the type-based naming heuristic, we get:
</p>

 <pre>updateColumnExpression
  :: QualifiedTable -> RenameField -> ColumnExpression -> IO ColumnExpression
updateColumnExpression qualifiedTable renameField (ColumnExpression field value) =
  ColumnExpression updatedField <$> updatedValue
  ...</pre>

 <p>
Look, it’s readable, plain English! Isn’t this a huge improvement? Any
maintainer reading this code can read each variable and know what it is.
I can even pronounce the names out loud.
</p>

 <p>
Note that this convention only works well when your types are well-named
too, by German naming convention.
</p>

 <p>
Original post can be found at
 <a href="https://chrisdone.com/posts/german-naming-convention/">Chris Done’s
site</a>.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/german-naming-convention/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/german-naming-convention/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title></title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <h2>Getting rid of Git history  <a id="getting-rid-of-git-history" class="anchor" href="#getting-rid-of-git-history">#</a></h2> <div class="outline-text-2" id="text-org7199ac5">
 <p>
as
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/getting-rid-of-git-history/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/getting-rid-of-git-history/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Hexagon of Doom - The Cost of Over-Abstraction and Indirection</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <i>Disclaimer: This article reflects personal experiences and gripes within specific team environments. Your mileage may vary, but the warning against premature or redundant abstraction stands.</i>
</p>
 <h2>When “Clean Code” Becomes “Complicated Code”  <a id="when-ldquoclean-coderdquo-becomes-ldquocomplicated-coderdquo" class="anchor" href="#when-ldquoclean-coderdquo-becomes-ldquocomplicated-coderdquo">#</a></h2> <div class="outline-text-2" id="text-org44bcc13">
 <p>
Hexagonal Architecture, often called  <b>Ports and Adapters (P&A)</b>, is lauded for its promise of decoupling the core business logic (the “domain”) from external concerns (databases, UIs, APIs). In theory, it’s a beautiful solution for creating adaptable, testable systems.
</p>

 <p>
However, like many architectural patterns, P&A is  <b>not</b> a universal good. In practice—especially for  <b>small projects</b>,  <b>small teams</b>, and particularly when using modern frameworks that provide powerful  <b>Dependency Injection (DI)</b> and layering capabilities (like  <b>ZIO</b> or Spring)—it often transforms from an asset into a  <b>liability</b>, drowning projects in unnecessary indirection and cognitive load.
</p>

 <p>
Let me explain why I think that in many contemporary environments, P&A introduces  <b>net harm</b> by prioritizing abstract purity over practical simplicity.
</p>
</div>
 <h2>The Double-Layering Paradox (Hex + Layers)  <a id="the-double-layering-paradox-hex--layers" class="anchor" href="#the-double-layering-paradox-hex--layers">#</a></h2> <div class="outline-text-2" id="text-orga8dd2aa">
 <p>
The primary goal of P&A is to invert dependencies: the domain defines an interface (a  <b>Port</b>), and an external module implements it (an  <b>Adapter</b>). This keeps the domain clean.
</p>

 <p>
When you already utilize a powerful, effect-aware layering system like  <b>ZIO Layers</b>, this benefit is almost entirely redundant, leading to an architectural redundancy:
</p>

 <p>
 <b>Indirection for Indirection’s Sake:</b>
P&A adds interfaces for every dependency. When combined with a framework’s natural  <b>Service</b> and  <b>Layer</b> abstractions, you end up with  <b>two or more levels of indirection</b> to reach a simple implementation.
</p>

 <p>
Every time a developer needs to trace a call, they must traverse the application layer, the ZIO Service/Layer boundary,  <b>and</b> the Port/Adapter boundary.
</p>

 <p>
This complexity makes  <b>debugging significantly more painful</b> and slows down the basic task of understanding code flow.
</p>
</div>
 <h2>Complexity Debt: Small Teams, Big Overkill  <a id="complexity-debt-small-teams-big-overkill" class="anchor" href="#complexity-debt-small-teams-big-overkill">#</a></h2> <div class="outline-text-2" id="text-org7c84b2b">
 <p>
The value of an abstraction must justify its cost. For a tiny microservice that mainly performs CRUD operations or orchestrates two external calls, the architectural overhead of P&A is rarely justified.
</p>

 <p>
 <b>The 9/10 Rule:</b>
Most small services  <b>are not complex enough</b> to warrant this pattern. We often see P&A implemented universally because  <i>“it’s good practice,”</i> not because the domain demands it.
</p>

 <p>
This is  <i>architecture astronautics</i> —designing for a future complexity that never materializes.
</p>

 <p>
 <b>Onboarding Nightmare:</b>
Team members, especially new joiners, already struggle to grasp complex functional programming paradigms, frameworks, effects and layers, etc. Adding the P&A pattern on top of this introduces a massive  <b>cognitive hurdle</b>.
</p>

 <p>
The result is a team that spends more time studying the  <b>structure</b> of the code than solving the  <b>business problem</b>. If a developer needs four hours just to restudy the system structure before making a change, the architecture is failing.
</p>

 <p>
 <b>Change is More Difficult:</b>
Making a simple change now often requires modifications across three or four files (Domain Port, Application Service, Infrastructure Adapter, and the Layer wiring). This distributed logic dramatically increases the difficulty and risk associated with even minor feature updates.
</p>

 <p>
This snippet illustrates the cognitive tax of over-abstraction. You might see something like this in over-engineered code:
</p>
 <pre>val result =
  for {
    order <- OrderService.create(dto)
    _     <- NotificationService.notify(order)
  } yield order

val run = result.provide(
  OrderService.live,
  NotificationService.live,
  OrderProcessorLive.layer,
  PaymentServiceStripeAdapter.layer,
  InventoryPortDatabaseAdapter.layer,
  NotificationPortEmailAdapter.layer,
  HandlebarsMailTemplating.layer,
  MailTemplatingAdapter.layer,
)</pre>

 <p>
A simple CRUD endpoint now requires juggling four adapters and multiple ports — none of which add business value.
</p>

 <p>
Compare it to this, simpler and easier on everyone:
</p>
 <pre>val result =
  for {
    order <- OrderService.create(dto)
    _     <- NotificationService.notify(order)
  } yield order

val run = result.provide(
  OrderService.live,
  NotificationService.live
)</pre>
</div>
 <h2>The Testability Illusion  <a id="the-testability-illusion" class="anchor" href="#the-testability-illusion">#</a></h2> <div class="outline-text-2" id="text-orgde52171">
 <p>
A core selling point of P&A is enhanced testability. By defining a Port, you can easily mock the Adapter implementation.
</p>

 <p>
However, this benefit is moot. Frameworks already provide an elegant, built-in mechanism for swapping implementations (a.k.a.,  <b>Layer Stubbing</b> or  <b>Mocking</b>).
</p>

 <pre>// ZIO: Define a test layer with a mock implementation
val mockPaymentService: ULayer[PaymentServicePort] = ZLayer.succeed {
  new PaymentServicePort {
    def process(p: Payment) = ZIO.unit // Mocked behavior
  }
}
// Now run the test using the 'provide' method with the mock layer
// The Port interface itself wasn't strictly necessary for the mocking!</pre>

 <p>
The P&A abstraction is simply surplus to requirements when robust DI tooling is available.
</p>
</div>
 <h2>The Tyranny of Types and Namespaces  <a id="the-tyranny-of-types-and-namespaces" class="anchor" href="#the-tyranny-of-types-and-namespaces">#</a></h2> <div class="outline-text-2" id="text-org11f0051">
 <p>
P&A, when combined with enthusiastic Domain-Driven Design (DDD) and strict folder structures, can lead to an explosion of files, types, and excessively deep namespaces.
</p>

 <p>
This kind of verbose, deeply nested imports are telltale signs of  <b>over-architecting</b>. It suggests a system size and complexity that usually only exists in a large, decades-old monolith, not a small, modern service. The sheer volume of types to track creates  <b>cognitive overhead</b> that actively slows development.
</p>

 <blockquote>
 <p>
🧩 Observation:
Below you see how we’ve defined 5+ types and layers just to wire a single function.
Every refactor means updating the Port, Adapter, and the wiring.
Native dependency system already is your “Port”.
</p>
</blockquote>

 <pre>// --- Domain Port ---
trait PaymentServicePort {
  def process(payment: Payment): Task[Receipt]
}

// --- Domain Model ---
final case class Payment(id: String, amount: BigDecimal)
final case class Receipt(id: String, status: String)

// --- Application Service (uses the Port) ---
final class PaymentProcessor(paymentService: PaymentServicePort) {
  def handle(p: Payment): Task[Receipt] =
    paymentService.process(p)
}

// --- Infrastructure Adapter ---
final class StripePaymentAdapter extends PaymentServicePort {
  override def process(p: Payment): Task[Receipt] =
    ZIO.succeed(Receipt(p.id, "OK - charged via Stripe"))
}

// --- ZIO Layer wiring (adds a second indirection) ---
object PaymentLayers {
  val stripeLayer: ULayer[PaymentServicePort] = 
    ZLayer.succeed(new StripePaymentAdapter)

  val processorLayer: URLayer[PaymentServicePort, PaymentProcessor] =
    ZLayer.fromFunction(new PaymentProcessor(_))
}

// --- Usage ---
val app = for {
  processor <- ZIO.service[PaymentProcessor]
  r         <- processor.handle(Payment("p1", 42))
  _         <- ZIO.logInfo(r.toString)
} yield ()

val runApp =
  app.provide(
    PaymentLayers.processorLayer,
    PaymentLayers.stripeLayer
  )</pre>
</div>
 <h2>A Simpler Prescription for Sanity  <a id="a-simpler-prescription-for-sanity" class="anchor" href="#a-simpler-prescription-for-sanity">#</a></h2> <div class="outline-text-2" id="text-orgabe86f3">
 <p>
Instead of resorting to heavy patterns like P&A, small teams can achieve clean, maintainable, and highly testable code with a simpler “cocktail” of established, less intrusive patterns:
</p>

 <ul class="org-ul"> <li> <b>Good Domain-Driven Design (DDD):</b> Focus on correct  <b>naming</b>, clear  <b>domain models</b>, and ubiquitous language. This is where the most valuable abstraction lies.</li>
 <li> <b>Simple Structure:</b> A combination of  <b>MVC</b> (Model-View-Controller, or a simple  <b>Application Service</b> layer) for structure, combined with  <b>Command and Query</b> abstractions for separating read/write concerns, provides excellent clarity without excessive indirection.</li>
 <li> <b>Harness Native DI:</b> Leverage your framework’s native DI system fully. These tools were designed to manage dependencies cleanly; don’t fight them by adding manual indirection.</li>
</ul></div>
 <h2>Know When to Stop  <a id="know-when-to-stop" class="anchor" href="#know-when-to-stop">#</a></h2> <div class="outline-text-2" id="text-org1fcae5c">
 <p>
Hexagonal Architecture is a powerful tool, but it’s a tool for scaling complexity. For the vast majority of small to medium-sized projects—especially those built with modern, DI-rich frameworks—it represents a premature optimization that results in  <b>architecture debt</b> and  <b>developer burnout</b>.
</p>

 <p>
Before adopting a pattern, ask the critical question:  <b>Does this solve a problem I have today, or am I abstracting for a problem I might never have?</b>
</p>

 <p>
Often, the healthiest, most maintainable architecture is the simplest one that works. We must resist the urge to complicate code in the name of purity.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/hexagon-of-doom/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/hexagon-of-doom/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Most Technical Problems are People Problems</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
I have worked at several companies doing Software Engineering and I feel like I’ve seen the best and the worst. From aging systems containing millions of lines of untested code, built on frameworks past their expiry date, to repulsive code and deployment constructs that stemmed from disagreements, bad communication, and terrible processes, I’ve seen it all, ticking technical time bombs, and all, but one specific case really illustrated the cultural rot for me.
</p>

 <p>
I once worked at a big furniture company famous worldwide, which had an enormous amount of technical debt - millions of lines of code, no unit tests, frameworks that were well over 2 decades out of date, things running on mainframe IBM computer to which no replacement parts can be found, etc.
</p>

 <p>
On one specific project, we had a market need to get features to market really fast, but there were no limitations in tech stack or so, so it was a golden opportunity to create something beautiful and maintainable.
</p>

 <p>
Rather than communicating with other teams to learn, or seeing what industry standards we live by in this day and age, this team simply copied & pasted a few hundred thousand lines of the legacy code, and started hacking things onto it, effectively horseshoeing it into something that would work.
</p>

 <p>
For the non-technical reader, this is an enormous problem because now we have two different outdated (legacy) systems, which will start diverging, and apart from the fact that the systems are old, the software practices questionable, and the hardware is not even manufactured anymore, now all features & bug fixes must be solved in two separate codebases that will grow apart over time.  When I heard about this, a young & naive version of me thought he could fix the situation….
</p>

 <p>
The article which inspired me to write this one is found at  <a href="https://blog.joeschrag.com/2023/11/most-technical-problems-are-really.html">Helmet Hair</a>.
</p>
 <h2>Tech Debt is caused mostly by People Problems  <a id="tech-debt-is-caused-mostly-by-people-problems" class="anchor" href="#tech-debt-is-caused-mostly-by-people-problems">#</a></h2> <div class="outline-text-2" id="text-org4693f4d">
 <p>
Then there is tech debt.  <b>Tech debt projects are always a hard sell to management, because even if everything goes flawlessly, the code just does roughly what it did before</b>.  This project of mine to refactor the legacy system into something modern was no exception, and the optics weren’t great.  I did as many engineers do and  <i>ignored the politics</i>, put my head down, and got it done.
</p>

 <p>
For the curious minds, yes, I managed to deploy something working at the end, and replaced the old system (eventually), but the project was really not well received by my engineer colleagues (management was indifferent).
</p>

 <p>
I realized I was essentially trying to solve a people problem with a technical solution.   <b>Most of the developers at this company were happy doing the same thing today that they did yesterday… and five years ago</b>.
</p>

 <p>
As  <a href="https://andrewharmellaw.github.io/">Andrew Harmel-Law</a> points out, code tends to follow the personalities of the people that wrote it.  The code was calcified because the developers were also.  Personality types who dislike change tend not to design their code with future change in mind.
</p>

 <p>
Most technical problems are really people problems.  Think about it.  Why does technical debt exist?  Because requirements weren’t properly clarified before work began.  Because a salesperson promised an unrealistic deadline to a customer.  Because a developer chose an outdated technology because it was comfortable.  Because management was too reactive and cancelled a project mid-flight.  Because someone’s ego wouldn’t let them see a better way of doing things. Because technology is made by people, and people are bound to make mistakes.
</p>

 <p>
The core issue with the project was that admitting the need for refactoring was also to admit that the way the company was building software was broken and that individual skillsets were sorely out of date. Trying to fix one part of many other problematic ones, while other developers continued doing as they always did.
</p>

 <p>
In my career, I’ve already met several engineers openly tell me,  <i>“I don’t want to learn anything new”</i> . I realized that you’ll never clean up tech debt faster than others create it.  It is like triage in an emergency room, you must stop the bleeding first, then you can fix whatever is broken.
</p>

 <p>
 <b>An Ideal World</b>: The project also showed me how impossible the engineer’s ideal of a world is, in which engineering problems can be solved in a vacuum - staying out of “politics” and letting the work speak for itself - a world where deadlines don’t exist…and let’s be honest, neither do customers.
</p>

 <p>
This ideal world rarely exists.  The vast majority of projects have non-technical stakeholders, and telling them “just trust me; we’re working on it” doesn’t cut it.  I realized that  <b>the perception that your team is getting a lot done is just as important as getting a lot done</b>.
</p>

 <p>
Non-technical people do not intuitively understand the level of effort required or the need for tech debt cleanup; it must be communicated effectively by engineering - in both initial estimates & project updates.  Unless leadership has an engineering background, the value of the technical debt work likely needs to be quantified and shown as business value.
</p>

 <p>
Perhaps these are the lessons that prep one for more senior positions.  In my opinion, anyone above senior engineer level needs to know how to collaborate cross-functionally, regardless of whether they choose a technical or management track.  Schools teach Computer Science, not navigating personalities, egos, and personal blindspots.  
</p>

 <p>
I have worked with some incredible engineers - the type that have deep technical knowledge on just about any technology you bring up.  When I was younger, I wanted to be that engineer - and to some degrees I feel like I did become that. For all of their (considerable) strengths, more often than not, those engineers shy away from the interpersonal.  The tragedy is that they are incredibly productive ICs, but may fail with bigger initiatives because they are only one person (a single processor core can only go so fast).
</p>

 <p>
Perhaps equally valuable is the  <i>heads up coder</i>: the person who is deeply technical, but also able to pick their head up & see project risks coming (technical & otherwise) and steer the team around them.
</p>

 <hr></hr> <p>
The journey from technical problem solver to effective engineering leader often involves a sobering realization: the code is the culture made manifest.
</p>

 <p>
The catastrophic technical debt I’ve often seen, is rarely about the lack of technical skill, it is most often a symptom of deeper organizational failures. This includes fear of change, short-term managerial thinking, and a profound communication gap between the builders and the stakeholders.
</p>

 <p>
To truly tackle technical debt, we must evolve beyond the “Heads-Down” coder and embrace the Heads-Up Coder. This senior perspective understands that refactoring and modernization aren’t technical projects, but essential parts of day-to-day work as engineer.
</p>

 <p>
You cannot clean up technical debt without first addressing the people, process, and politics that created it.
</p>

 <p>
Focusing solely on the code is like sweeping the kitchen floor while the roof is leaking.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/most-technical-problems-are-people-problems/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/most-technical-problems-are-people-problems/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Markdown Cheat-sheet for Beginners</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <div id="table-of-contents" role="doc-toc">
 <h2>Table of Contents</h2>
 <div id="text-table-of-contents" role="doc-toc">
 <ul> <li> <a href="#org155fa85">Common Formatting</a>
 <ul> <li> <a href="#org050f9a2">Headers</a></li>
 <li> <a href="#orgdd8f1b7">Emphasis (Bold and Italic)</a></li>
 <li> <a href="#org60fe631">Lists</a>
 <ul> <li> <a href="#org3ca9b37">Unordered Lists (bullet points)</a></li>
 <li> <a href="#org68dbfa1">Ordered Lists (numbered)</a></li>
</ul></li>
</ul></li>
 <li> <a href="#org657c636">Links and Images</a>
 <ul> <li> <a href="#orgc8d8409">Links</a></li>
 <li> <a href="#org690e062">Images</a></li>
</ul></li>
 <li> <a href="#orgf889d6d">Other Useful Elements</a>
 <ul> <li> <a href="#org9135add">Blockquotes</a></li>
 <li> <a href="#org727bd11">Horizontal Rule</a></li>
 <li> <a href="#orgd8ca469">Code Blocks</a></li>
</ul></li>
 <li> <a href="#org8d9b788">On editors</a></li>
</ul></div>
</div>
 <p>
Markdown is a simple, lightweight markup language used for formatting plain text. It’s designed to be easy to read and write, and it can be converted into HTML, PDF, LaTEX and many other formats.
</p>

 <p>
It’s a very popular format for writing documentation, blog posts, and notes. It is extremely future-proof since you write documents in plain-text, with some sprinkles of markup.
</p>

 <p>
The key idea is to use simple punctuation to add formatting.
</p>

 <p>
You don’t need to memorize all of these. Just remember the basics and refer back to this guide as needed. The best way to learn Markdown is to start writing!
</p>
 <h2>Common Formatting  <a id="common-formatting" class="anchor" href="#common-formatting">#</a></h2> <h3>Headers  <a id="headers" class="anchor" href="#headers">#</a></h3> <div class="outline-text-3" id="text-org050f9a2">
 <p>
Headers are used for titles and subtitles. They are created with the hash symbol ( <code>#</code>). The number of hashes determines the size of the header.
</p>

 <pre class="example" id="orge8b1f93">
# This is a large title (H1)
## This is a major heading (H2)
### This is a sub-heading (H3)
#### This is a smaller heading (H4)
</pre>
</div>
 <h3>Emphasis (Bold and Italic)  <a id="emphasis-bold-and-italic" class="anchor" href="#emphasis-bold-and-italic">#</a></h3> <div class="outline-text-3" id="text-orgdd8f1b7">
 <p>
You can make text bold or italic to add emphasis.
</p>

 <pre class="example" id="org865f761">
This is **bold text** using two asterisks.
This is also __bold text__ using two underscores.

This is *italic text* using a single asterisk.
This is also _italic text_ using a single underscore.
</pre>
</div>
 <h3>Lists  <a id="lists" class="anchor" href="#lists">#</a></h3> <div class="outline-text-3" id="text-org60fe631">
 <p>
Lists are great for organizing information.
</p>
</div>
 <h4>Unordered Lists (bullet points)  <a id="unordered-lists-bullet-points" class="anchor" href="#unordered-lists-bullet-points">#</a></h4> <div class="outline-text-4" id="text-org3ca9b37">
 <p>
Use a hyphen ( <code>-</code>) followed by a space.
</p>

 <pre class="example" id="orge9d6c63">
- First item in the list
- Second item in the list
  - A nested item
- Third item
</pre>
</div>
 <h4>Ordered Lists (numbered)  <a id="ordered-lists-numbered" class="anchor" href="#ordered-lists-numbered">#</a></h4> <div class="outline-text-4" id="text-org68dbfa1">
 <p>
Use a number followed by a period and a space.
</p>

 <pre class="example" id="org736fe0b">
1. First step
2. Second step
3. Third step
   1. A nested step
4. Final step
</pre>
</div>
 <h2>Links and Images  <a id="links-and-images" class="anchor" href="#links-and-images">#</a></h2> <h3>Links  <a id="links" class="anchor" href="#links">#</a></h3> <div class="outline-text-3" id="text-orgc8d8409">
 <p>
To link to another webpage, use the format:  <code>[text to display](URL)</code>.
</p>

 <pre class="example" id="orge3b1407">
Visit the official [Markdown website](https://daringfireball.net/projects/markdown/).
</pre>
</div>
 <h3>Images  <a id="images" class="anchor" href="#images">#</a></h3> <div class="outline-text-3" id="text-org690e062">
 <p>
Images are similar to links, but they start with an exclamation mark ( <code>!</code>).
</p>

 <pre class="example" id="orgeeffdd9">
![Alt text for the image](https://www.example.com/image.jpg)
</pre>
</div>
 <h2>Other Useful Elements  <a id="other-useful-elements" class="anchor" href="#other-useful-elements">#</a></h2> <h3>Blockquotes  <a id="blockquotes" class="anchor" href="#blockquotes">#</a></h3> <div class="outline-text-3" id="text-org9135add">
 <p>
To quote text from another source, use the `>` symbol.
</p>

 <pre class="example" id="orgfee4d0c">
> "The simplest way to write in Markdown is to just start typing."
>
> This can span multiple lines.
</pre>
</div>
 <h3>Horizontal Rule  <a id="horizontal-rule" class="anchor" href="#horizontal-rule">#</a></h3> <div class="outline-text-3" id="text-org727bd11">
 <p>
A horizontal rule is a line that separates content. Use three or more hyphens ( <code>------</code>).
</p>
</div>
 <h3>Code Blocks  <a id="code-blocks" class="anchor" href="#code-blocks">#</a></h3> <div class="outline-text-3" id="text-orgd8ca469">
 <p>
To show code or text that should not be formatted, use three backticks ( <code>```</code>) before and after the text.
</p>

 <pre class="example" id="org15cc01b">
```
This text is inside a code block.
It will not be formatted with bold or italic.
```
</pre>

 <hr></hr></div>
 <h2>On editors  <a id="on-editors" class="anchor" href="#on-editors">#</a></h2> <div class="outline-text-2" id="text-org8d9b788">
 <p>
Technical users will be at ease with Markdown, and can edit it and preview it from their favorite editor (think Emacs, Vim, VSCode, IntelliJ, etc.)
</p>

 <p>
For non-technical users, the best Markdown editors are those that prioritize a clean, simple, and intuitive user interface. 
</p>

 <p>
The “What You See Is What You Get” (WYSIWYG) Approach: I recommend MarkText (desktop app), A free and open-source alternative to Typora, offering a real-time preview experience. It’s known for its sleek design and focus on a clean, elegant interface.
</p>

 <p>
The “Two-Pane” or “Live Preview” Approach: Ghostwriter (desktop app), Dillinger (web based), StackEdit (web based).
</p>

 <p>
The “Note-Taking” Approach: Obisidan (desktop app), Joplin (desktop app)
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/simple-markdown-cheatsheet/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/simple-markdown-cheatsheet/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Why SQL SELECT * is often a bad idea</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
There are some anti-patterns one should avoid when writing SQL queries. Sometimes these may seem like a shortcut, but in reality this can lead to bugs, problems, and brittle applications.
</p>

 <p>
It’s almost always better to use the explicit column list in the SELECT query than a * (star) wildcard. It not only improves the performance but also makes your code more explicit. It also helps you create maintainable code, which will not break when you add/remove columns from your table, especially if you have views that refer to the original table.
</p>
 <h2>SELECT *  <a id="select-" class="anchor" href="#select-">#</a></h2> <div class="outline-text-2" id="text-org7c41f81">
 <p>
Doing a  <code>SELECT *</code> may seem like a time-saver, but it’s actually setting you up for problems in the long run, specially when database schema changes.
</p>
</div>
 <h3>Breaks Views While Adding New Columns to a Table  <a id="breaks-views-while-adding-new-columns-to-a-table" class="anchor" href="#breaks-views-while-adding-new-columns-to-a-table">#</a></h3> <div class="outline-text-3" id="text-org6847c4b">
 <p>
When you use SELECT * in views, then you create subtle bugs if a new column has been added ro an old one is removed from the table. Why? Because your view might break, or start returning an incorrect result.
</p>
</div>
 <h3>Dependency on Order of Columns on ResultSet  <a id="dependency-on-order-of-columns-on-resultset" class="anchor" href="#dependency-on-order-of-columns-on-resultset">#</a></h3> <div class="outline-text-3" id="text-orga28fbb0">
 <p>
When you use the SELECT * query in your application and have any dependency on order of column, which you should not, the ordering of the result set will change if you add a new column or change the order of columns.
</p>
</div>
 <h3>Conflicts in a JOIN Query  <a id="conflicts-in-a-join-query" class="anchor" href="#conflicts-in-a-join-query">#</a></h3> <div class="outline-text-3" id="text-orgea87535">
 <p>
When you use SELECT * in JOIN query, you can introduce complications when multiple tables have columns with the same name e.g. status, active, name, etc.
</p>
</div>
 <h3>More Application Memory  <a id="more-application-memory" class="anchor" href="#more-application-memory">#</a></h3> <div class="outline-text-3" id="text-org4f37539">
 <p>
Due to this increase in data, your application may require more memory just to hold unnecessary data that it will not be using
</p>
</div>
 <h3>Increased Network Traffic  <a id="increased-network-traffic" class="anchor" href="#increased-network-traffic">#</a></h3> <div class="outline-text-3" id="text-org18fcf64">
 <p>
SELECT * obviously returns more data than required to the client, which, in turn, will use more network bandwidth.
</p>
</div>
 <h3>Unnecessary I/O (Input Output)  <a id="unnecessary-io-input-output" class="anchor" href="#unnecessary-io-input-output">#</a></h3> <div class="outline-text-3" id="text-orgb69e9ed">
 <p>
By using SELECT *, you can be returning unnecessary data that will just be ignored, but fetching that data is not free of cost.
</p>
</div>
 <h2>COUNT(*)  <a id="count" class="anchor" href="#count">#</a></h2> <div class="outline-text-2" id="text-org1d89682">
 <p>
One should default to using  <code>COUNT</code> clauses with column names, such as  <code>COUNT(id)</code>, since this will count values which are non-NULL.
</p>

 <p>
If NULL is explicitly wanted then one can choose for  <code>COUNT(1)</code> or  <code>COUNT(*)</code>.
There is a negligible performance difference, at least in PostgreSQL between 1 and * , so use at your discretion.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/sql-select-all/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/sql-select-all/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>SSR wins over Javascript</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
In this day and age, server side rendering proves it is stable and more
effective than the JavaScript bloat we are growing used to. Any simple
page, with perhaps at most 3 KB of actual text content will download
over 2 MB of JavaScript in order to simply function.
</p>

 <p>
Besides that fact, SPA and API situations, where you have a decoupled
frontend from the backend, still do not justify the fact of using
JavaScript, or even worse, any of its frameworks. That paradigm can
easily be, in most cases, fulfilled by server side rendering in the
backend language of your choice, which will spit out a digested HTML for
your clients.
</p>

 <p>
In specific, if you keep the same programming language, in my case Go,
across your applications, you can share a lot of logic, data models, and
you get a consistent developer experience, and an easier to maintain
system.
</p>

 <p>
Not to mention the fact that the JavaScript ecosystem goes with the
wind, is the most unstable place I have ever seen, and most of the times
I need to look into some source code written in that language, of some
external package dependency, I start questioning the author’s sanity,
and mine, and also my career choices.
</p>

 <p>
Going further, with the bloated state management tools, and broken
concurrency model of JavaScript, as well as the insane “features” of the
language, and then seeing TypeScript, a “sub-set” of the language, which
also brings its own horrors and pre-compilation, I have no doubt that
the show must come to a stop, and for my professional needs, as a
software engineer at an e-commerce platform, I have decided to throw
away all the SPA code (3 attempts) that has previously been in
production, and go in a totally oposite direction.
</p>

 <p>
This direction may seem unorthodox, but it has many reasons that make it
a success, and a joy to work with, and extend.
</p>

 <p>
To give some background, the previous SPA I helped create and worked
with, that consumed my API’s data, was created using Vue.js 2, SCSS with
scoped styles (horror!), VueX, and TypeScript.
</p>

 <p>
This combination has quickly lead to spaghetti code of terrible quality,
and lots of it. To make matters worse, there was a transition of API v1
to v2, where some data models changed, and the developer decided to
refuse that change, and write his own mappers, to convert those v2 data
models to v1, and vice-versa, in order to comply with my API, which he
was interfacing with.
</p>

 <p>
As you can imagine, this has lead to an unmaintainable project, that no
one dares to touch.
</p>

 <p>
So I decided to follow my beloved KISS principle, and to go ahead and
get started on writing a SOLID coded Go application, that will act as
the API consumer, and spit out processed HTML for the client’s browser.
</p>

 <p>
I also followed the principle of “graceful degradation”, which in basic
terms, means that the website should function perfectly without
JavaScript, and it should only be used to enhance the user experience,
like in heavy animations, sliders, etc. By no means should JavaScript be
the center of the application, due to all the negative aspects it
brings, and due to the superior language that Go is.
</p>

 <p>
I have been met with much success with this application, and can really
say confidently that my future endeavours will always go the same route,
unless really necessary to code a more client-side application, in which
case I will most likely turn to GopherJS or such, or perhaps some Go to
WebAssembly, so I don’t need to write any more JavaScript ever.
</p>

 <p>
I want to list some of the advantages that I have found, and am sure
anyone will find when doing things more in an “old but gold” old-school
approach of building websites, server side rendered:
</p>

 <ul class="org-ul"> <li>In my case, one language for the whole platform 😀 Go !</li>
 <li>Native browser features, like remembering how far in the list of the
previous page you were when you go back.</li>
 <li>SEO is greatly improved, and you don’t even need to think about it as
much. Search engines will easily crawl your site, and will read
correctly formed HTML.</li>
 <li>Security improvements, due to not exposing application code, or API
calls in the client’s browser.</li>
 <li>Simpler front-end applications, no mapping, no state management, no
problems. API data directly to HTML.</li>
 <li>Go is a well designed, compiled, statically typed and concurrent
language. Why not use it for client-facing applications?</li>
 <li>The ecosystem around Go is much more stable and reliable than
JavaScript’s.</li>
 <li>The standard library of Go is great, and can power most of your needs
without additional thrid-party dependencies.</li>
 <li>High-concurrency and asynchronous process capabilities in the
client-facing applications.</li>
 <li>Accessibility is greatly improved due to the HTML being delivered as
already rendered, and we can care more about writing semantically
correct HTML, instead of caring so much about the newest JS framework.</li>
 <li>Supporting security conscious people and organizations: let’s face it
there’s bad people doing heinous things with JavaScript, so the
easiest solution is to get rid of JavaScript.</li>
 <li>Mobile devices, web-views, and embedded devices are better supported,
without inconsistencies.</li>
 <li>Search engine spiders only follow real links - JavaScript confuses
them.</li>
 <li>Cross site scripting attacks risk is greatly reduced.</li>
 <li>Hacking/Defacement through DOM manipulation is no longer possible.</li>
 <li>Severe speed improvements, both on first, and on subsequent loads.</li>
</ul> <p>
I really have no intentions to be part of the spaghetti mess that
JavaScript easily becomes, I want a consistent and predictible language,
that compiles to binary code and can easily beat any out there.
</p>

 <p>
As for the SPA fans out there, I know it has its use cases, but let’s
face it, JS is doing so much more than it should since React and buddies
came along, this has gotten way out of hand and it is time to stop.
</p>

 <p>
Thanks for your attention, and I look forward to seeing comments.
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/ssr-wins-over-javascript/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/ssr-wins-over-javascript/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>My Tech Radar</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Tech changes fast. But it’s becoming an ever-more critical component of success.
</p>

 <p>
A Tech Radar is our trusty compass and map, charting the ever-shifting landscape of technology. It’s not just some dusty document; it’s a living, breathing artifact that reflects our collective wisdom, our triumphs, and yes, our hard-won lessons.
</p>

 <p>
At its core, a Tech Radar is a visual tool that helps us categorize and assess various technologies – be they programming languages, development tools, ingenious techniques, or even the very platforms we build upon. It typically organizes these “blips” into different quadrants, like “Languages & Frameworks” or “Tools,” and then, crucially, places them into “rings” that signify their current status. Think of these rings as a spectrum, guiding our decisions:
</p>

 <dl class="org-dl"> <dt>Adopt</dt> <dd>These are the technologies we’ve embraced, the ones that have proven their mettle in the trenches. They’re reliable, we’re confident in them, and they’re our go-to for new projects. When something lands here, it means it’s been thoroughly vetted and consistently delivers.</dd>
 <dt>Trial</dt> <dd>Here, you’ll find the promising newcomers or existing technologies we’re actively experimenting with. We’ve seen some success, they’re showing real potential, and we’re ready to put them through their paces on a project or two to truly understand their strengths and limitations.</dd>
 <dt>Assess</dt> <dd>This ring is for the intriguing ideas, the nascent technologies that have piqued our interest. They might be revolutionary, or they might just be a flash in the pan. We’re keeping an eye on them, doing our research, and perhaps even building a small prototype to see if they hold water.</dd>
 <dt>Deprecate</dt> <dd> <p>
This is where we park the technologies we’re actively discouraging for new work. Maybe they’ve been superseded by something better, maybe they’re too high-maintenance, or perhaps they simply don’t align with our long-term vision. It’s about being pragmatic and cutting our losses, preventing new projects from inheriting technical debt.
</p>

 <hr></hr></dd>
</dl> <h2>✅ Adopt  <a id="-adopt" class="anchor" href="#-adopt">#</a></h2> <h3>🐂 Languages & Frameworks  <a id="-languages-amp-frameworks" class="anchor" href="#-languages-amp-frameworks">#</a></h3> <div class="outline-text-3" id="text-org7469f66">
 <ul class="org-ul"> <li>Guile Scheme</li>
 <li>GNU Artanis</li>
 <li>Emacs Lisp</li>
 <li>Common Lisp</li>
 <li>Haskell</li>
 <li>Typescript</li>
 <li>Javascript (vanilla)</li>
 <li>Rust</li>
 <li>GTK4 Libadwaita</li>
</ul></div>
 <h3>🧰️ Tools  <a id="️-tools" class="anchor" href="#️-tools">#</a></h3> <div class="outline-text-3" id="text-orgf7f9bd9">
 <ul class="org-ul"> <li>GNU Guix</li>
 <li>SQLite</li>
 <li>PostgreSQL</li>
 <li>Emacs</li>
 <li>Org mode (Emacs)</li>
 <li>Servant (Haskell), API as  a type</li>
</ul></div>
 <h3>⚙️ Techniques  <a id="️-techniques" class="anchor" href="#️-techniques">#</a></h3> <div class="outline-text-3" id="text-orgb81d28c">
 <ul class="org-ul"> <li>Plain SQL queries</li>
 <li>Guix Manifests</li>
 <li>Guix dev shells</li>
 <li>Nix Flakes</li>
 <li>Nix dev shells</li>
 <li>Woodpecker CI/CD</li>
</ul></div>
 <h3>🌐 Platforms  <a id="-platforms" class="anchor" href="#-platforms">#</a></h3> <div class="outline-text-3" id="text-orgf3375cd">
 <ul class="org-ul"> <li>Custom low-power green VPS</li>
</ul> <hr></hr></div>
 <h2>❌ Deprecate  <a id="-deprecate" class="anchor" href="#-deprecate">#</a></h2> <h3>🐂 Languages & Frameworks  <a id="-languages-amp-frameworks" class="anchor" href="#-languages-amp-frameworks">#</a></h3> <div class="outline-text-3" id="text-org77c5add">
 <ul class="org-ul"> <li>Scala</li>
 <li>ZIO (Scala)</li>
 <li>Svelte</li>
</ul></div>
 <h3>🧰️ Tools  <a id="️-tools" class="anchor" href="#️-tools">#</a></h3> <div class="outline-text-3" id="text-orgd1591de">
 <ul class="org-ul"> <li>MySQL</li>
</ul></div>
 <h3>🌐 Platforms  <a id="-platforms" class="anchor" href="#-platforms">#</a></h3> <div class="outline-text-3" id="text-org982d8f0">
 <ul class="org-ul"> <li>Amazon AWS</li>
</ul></div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/tech-radar/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/tech-radar/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Development</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2026-02-03 di> </span></span>  <a href="/blog/articles/development/dont-reward-the-best-firefighter/index.html">Don’t Reward the Best Firefighter</a> - For every loud firefighter, there’s an invisible  <b>fire preventer.</b> This is the engineer who spends a month refactoring a messy legacy service that no one else wants to touch.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-12-05 vr> </span></span>  <a href="/blog/articles/development/most-technical-problems-are-people-problems/index.html">Most Technical Problems are People Problems</a> - You cannot clean up technical debt without first addressing the people, process, and politics that created it.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-10-27 ma> </span></span>  <a href="/blog/articles/development/hexagon-of-doom/index.html">Hexagon of Doom - The Cost of Over-Abstraction and Indirection</a> - Let me explain why I think Ports&Adapter / Hexagonal architecture introduces  <b>net harm</b> to software projects.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-09-15 ma> </span></span>  <a href="/blog/articles/development/simple-markdown-cheatsheet/index.html">Simple Markdown Cheatsheet</a> - Markdown is a simple, lightweight markup language used for formatting plain text. It’s designed to be easy to read and write, and it can be converted into HTML, PDF, LaTEX and many other formats.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-04-11 vr> </span></span>  <a href="/blog/articles/development/best-programmers/index.html">The Best Programmers I Know</a> - I have met a lot of developers in my life. Lately, I asked myself: “What does it take to be one of the best? What do they all have in common?”
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2024-06-18 di> </span></span>  <a href="/blog/articles/development/tech-radar/index.html">My Tech Radar</a> - A Tech Radar is our trusty compass and map, charting the ever-shifting landscape of technology. 
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2024-02-27 di> </span></span>  <a href="/blog/articles/development/sql-select-all/index.html">Why SQL SELECT * is often a bad idea</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2024-02-26 ma> </span></span>  <a href="/blog/articles/development/black-box-testing/index.html">Black Box Testing in modern Software</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-01-31 zo> </span></span>  <a href="/blog/articles/development/ssr-wins-over-javascript/index.html">SSR wins over Javascript</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-09-21 di> </span></span>  <a href="/blog/articles/development/german-naming-convention/index.html">German / Dutch naming convention</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-08-29 zo> </span></span>  <a href="/blog/articles/development/breaking-free-of-javascript/index.html">Breaking free of Javascript</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2020-09-18 vr> </span></span>  <a href="/blog/articles/development/a-great-programmer/index.html">What makes a great programmer ?</a>
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/development/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/development/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Emacs and Scala setup with Eglot</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
In this post I want to show you how to setup your favourite text editor, Emacs, as a super powerful and capable Scala IDE (integrated development environment) with the latest and most performant approach.
</p>

 <p>
You might think I am crazy and I make my life more difficult than it needs to be. Let me tell you this  already, my development experience in Emacs with Scala is 5 star ⭐. I use this setup at work extensively and cannot think of a better way to be productive.
</p>

 <p>
I see VSCode and IntelliJ colleagues (peasants), prisoners of proprietary tech, stuck to mouse usage, having to click around and hide the countless panes and useless tooltips their IDEs throw at them, and they are unable to customize things to what they need, nor do they have an understanding of the inner workings of their IDE, which IMHO puts them at a disadvantage.
</p>

 <p>
Just learn Emacs already!
</p>
 <h2>Metals  <a id="metals" class="anchor" href="#metals">#</a></h2> <div class="outline-text-2" id="text-org1bd03dc">
 <p>
Needless to say, the best way to get Scala working with “language-server” compatible integrations is to use Metals LSP. You can read more about it  <a href="https://scalameta.org/metals/">on their website</a>  and how it integrates with several editors.
I usually install it with  <a href="https://get-coursier.io/">coursier</a> doing something along the lines of:
</p>
 <pre>coursier bootstrap --java-opt -XX:+UseG1GC --java-opt -XX:+UseStringDeduplication --java-opt -Xss4m --java-opt -Xms100m --java-opt -Dmetals.client=emacs org.scalameta:metals_2.13:0.11.12 -o $ <span class="org-variable-name">HOME</span>/.local/bin/metals-emacs -f</pre>

 <p>
Note: ensure that  <code>$HOME/.local/bin</code> is in your path and Emacs will automagically pick it up.
</p>
</div>
 <h2>Emacs package manager - Elpaca  <a id="emacs-package-manager---elpaca" class="anchor" href="#emacs-package-manager---elpaca">#</a></h2> <div class="outline-text-2" id="text-org1980b0a">
 <p>
I am enjoying using Elpaca everyday. It’s the most advanced, reliable and performant package manager ever made for Emacs. It integrates also seamlessly with  <code>use-package</code> and pushes you into doing things in a maintainable way.
Read  <a href="https://github.com/progfolio/elpaca">more about it here</a>.
You can still learn from my config even if you don’t use it, but I do whole-heartedly recommend it.
</p>
</div>
 <h2>Eglot  <a id="eglot" class="anchor" href="#eglot">#</a></h2> <div class="outline-text-2" id="text-orge7560e5">
 <p>
I whole-heartedly recommend  <code>eglot</code>. Eglot, a.k.a. Emacs Polyglot is the Emacs LSP client that stays out of your way.
You can read more about it  <a href="https://github.com/joaotavora/eglot">here</a>.
</p>

 <p>
Eglot is to be integrated into Emacs core, and is more performant and minimalistic than lsp-mode. I like to immediately start eglot when opening a Scala file.
</p>
 <pre>( <span class="org-keyword">use-package</span> eglot
   <span class="org-builtin">:hook</span> (
         (scala-mode . eglot-ensure)
          <span class="org-comment-delimiter">;; </span> <span class="org-comment">other modes go here</span>
          <span class="org-comment-delimiter">;; </span> <span class="org-comment">e.g.</span>
          <span class="org-comment-delimiter">;; </span> <span class="org-comment">(haskell-mode . eglot-ensure)</span>
         ))</pre>

 <p>
Once you install it (or load it, since in new Emacs versions it should be built-in), you will need to configure certain things to ensure it can work together with Scala Metals, the Scala language server.
</p>

 <p>
Here we add a wonderful functionality of optimizing imports and formatting code on save.
</p>
 <pre>( <span class="org-keyword">defun</span>  <span class="org-function-name">my-eglot-organize-imports</span> () ( <span class="org-keyword">interactive</span>)
        (eglot-code-actions nil nil  <span class="org-string">"source.organizeImports"</span> t))
 (add-hook 'before-save-hook 'my-eglot-organize-imports nil t)
 (add-hook 'before-save-hook 'eglot-format-buffer)</pre>
</div>
 <h2>Treesitter  <a id="treesitter" class="anchor" href="#treesitter">#</a></h2> <div class="outline-text-2" id="text-orgec652bf">
 <p>
For all my syntax highlighting and syntax tree needs I use  <code>tree-sitter</code>, which soon will also be built into Emacs.
</p>
 <pre>( <span class="org-keyword">use-package</span> tree-sitter
    <span class="org-builtin">:config</span>
   (global-tree-sitter-mode))

( <span class="org-keyword">use-package</span> tree-sitter-langs
   <span class="org-builtin">:after</span> tree-sitter)</pre>
</div>
 <h2>Scala Development  <a id="scala-development" class="anchor" href="#scala-development">#</a></h2> <div class="outline-text-2" id="text-org6d27a57">
 <p>
Enable scala-mode for indentation and certain language rules, with Treesitter highlighting.
</p>

 <pre>( <span class="org-keyword">use-package</span> scala-mode
   <span class="org-builtin">:interpreter</span> ( <span class="org-string">"scala"</span> . scala-mode)
   <span class="org-builtin">:hook</span> (scala-mode . tree-sitter-hl-mode)
  )</pre>
</div>
 <h2>flycheck  <a id="flycheck" class="anchor" href="#flycheck">#</a></h2> <div class="outline-text-2" id="text-org2c9c17e">
 <p>
Flycheck is an enhancement over  <code>flymake</code> and helps better visualize and interact with errors and warnings in your Emacs buffers.
</p>
 <pre>( <span class="org-keyword">use-package</span> flycheck  <span class="org-builtin">:config</span> (global-flycheck-mode))</pre>

 <p>
For integrating Flycheck and Eglot, check out the cool  <a href="https://github.com/intramurz/flycheck-eglot">flycheck-eglot package</a>.
</p>
</div>
 <h2>company  <a id="company" class="anchor" href="#company">#</a></h2> <div class="outline-text-2" id="text-org82180d7">
 <p>
For all my auto-complete needs I use  <code>company</code> which works wonderfully and is highly customizable.
</p>
 <pre>( <span class="org-keyword">use-package</span> company
   <span class="org-builtin">:custom</span>
  (company-minimum-prefix-length 1)
  (company-idle-delay 0.5)
  (company-tooltip-align-annotations t)
  (company-tooltip-margin 2)
   <span class="org-builtin">:config</span>
  (global-company-mode))</pre>

 <p>
The  <code>company-quickhelp</code> package will help to visualize available documentation right in the auto-completion tooltip, a feature present in many modern IDEs.
</p>
 <pre>( <span class="org-keyword">use-package</span> company-quickhelp
   <span class="org-builtin">:after</span> (company)
   <span class="org-builtin">:config</span>
  (company-quickhelp-mode))</pre>

 <p>
With all of this setup you will be able to have a productive experience, that surpasses the performance and joy of use of other IDEs.
You may want to, on a per project basis, run  <code>sbt bloopInstall</code> to get the full experience of Metals LSP. This requires the plugin:  <code>addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.6")</code>.
</p>

 <p>
You may have more success with running the  <code>bloopInstall</code> as  <code>sbt -Dbloop.export-jar-classifiers=sources bloopInstall</code>.
</p>

 <p>
Also, remember that running  <code>M-x eglot*</code> will show all eglot commands available, and teach you some of the shortcuts too.
</p>

 <p>
Feel free to check  <a href="https://git.sr.ht/~teutonicjoe/dotfiles">my dotfiles on SourceHut</a> which might help you get your Emacs setup just right 👌.
</p>

 <p>
Have a nice development day today!
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/emacs/emacs-and-scala-setup-with-eglot/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/emacs/emacs-and-scala-setup-with-eglot/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Emacs for absolute beginners</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
In this article, I’m going to give you exactly what you need to get started using Emacs and understand the basic concepts and key bindings of the editor. I know this article might seem long, but I promise you will come out with a plethora of knowledge about Emacs.
</p>

 <p>
I have taken lots of parts and inspiration from  <a href="https://systemcrafters.cc/emacs-essentials/absolute-beginners-guide-to-emacs/">the excellent guide made by System Crafters</a>.
Watch the great introductory video too  <a href="https://www.youtube.com/watch?v=48JlgiBpw_I">on YouTube</a> !
</p>
 <h2>Installation  <a id="installation" class="anchor" href="#installation">#</a></h2> <div class="outline-text-2" id="text-org602873f">
 <p>
Emacs can be installed on GNU/Linux, macOS and Windows and more. It is one of the most ported pieces of software in existence. There are very few limits to where it can run.
</p>

 <p>
The latest stable version is 28 at the time of writing, so it’s best to try and find that version (or later) for your operating system. However, much of what I will show you should work on many previous versions of Emacs.
</p>
</div>
 <h3>GNU/Linux  <a id="gnulinux" class="anchor" href="#gnulinux">#</a></h3> <div class="outline-text-3" id="text-orga1bde9f">
 <p>
GNU/Linux is the easiest OS for installing and using Emacs. It is available in (pretty much) every GNU/Linux distribution’s package manager, typically under the name  <code>emacs</code>, so it’s easy to find!
</p>

 <p>
Just keep in mind that your distribution may have an older version of Emacs in their package repository (possibly version 26) so you might need to find another source to install the latest version.
</p>
</div>
 <h3>GUI or Terminal?  <a id="gui-or-terminal" class="anchor" href="#gui-or-terminal">#</a></h3> <div class="outline-text-3" id="text-orgcacab68">
 <p>
On GNU/Linux, there are often emacs-no-x packages that don’t include the graphical UI if you don’t need it. There are no major differences in behavior between GUI and terminal Emacs so you can use whichever you feel most comfortable with.
</p>

 <p>
One major benefit of graphical Emacs is the ability to use multiple fonts for text display and a full range of colors. It is recommendable to use GUI Emacs if possible. Also, try to get rid of the bad habit you may have from vi, opening editor at files from terminal. Emacs can and should stay open the whole day.
</p>
</div>
 <h3>macOS  <a id="macos" class="anchor" href="#macos">#</a></h3> <div class="outline-text-3" id="text-org233f623">
 <p>
Installation on macOS with Homebrew is easy! There’s a default recipe called emacs which can be installed with the following command:
</p>
 <pre>brew install --cask emacs</pre>

 <p>
An alternative recipe called Emacs Plus provides additional options for customizing your Emacs install, check out its README to learn how to use it.
</p>

 <p>
You can also download a .app for Emacs from the site  <a href="https://emacsformacosx.com/">https://emacsformacosx.com/</a>
</p>
</div>
 <h3>Windows  <a id="windows" class="anchor" href="#windows">#</a></h3> <div class="outline-text-3" id="text-org94599e5">
 <p>
On Windows, you can download Emacs directly from  <a href="https://www.gnu.org/software/emacs/">GNU website</a>!
</p>

 <p>
If you use MSYS2, you can install it using Pacman:
</p>
 <pre>pacman -S mingw-w64-x86_64-emacs</pre>

 <p>
You can also install it using Chocolatey:
</p>
 <pre>choco install emacs</pre>
</div>
 <h2>Basic concepts  <a id="basic-concepts" class="anchor" href="#basic-concepts">#</a></h2> <div class="outline-text-2" id="text-org65f188a">
 <p>
Let’s talk about the basic things you need to understand about Emacs to use it effectively!
</p>
</div>
 <h3>User interface  <a id="user-interface" class="anchor" href="#user-interface">#</a></h3> <div class="outline-text-3" id="text-orgdf84135">
 <p>
Emacs has a menu and tool bar like many conventional graphical programs. They can be useful at first to learn the functionality that is available, but I think that you won’t need them for very long!
</p>

 <p>
Note that the menu bar actually is present in the terminal version of Emacs!
</p>

 <p>
If you’re coming from another IDE or editor, you might expect to see a file tree on the left side of the window. This isn’t provided by Emacs by default, but it’s easy to add through community packages! There are other ways to show files in Emacs that are even better, in my opinion.
</p>

 <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Menu-Bar.html">Emacs Manual: The Menu Bar</a>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Tool-Bars.html">Emacs Manual: Tool Bars</a>
</p>
</div>
 <h3>Windows and Frames  <a id="windows-and-frames" class="anchor" href="#windows-and-frames">#</a></h3> <div class="outline-text-3" id="text-orgf39bee5">
 <p>
The concept of a “window” is different in Emacs than what you probably know from using graphical computing environments.  In modern desktop environments, a window is a graphical interface of a program which is managed by the window manager of the desktop environment, usually with buttons to close or minimize it.
</p>

 <p>
In Emacs, a window is more like a “pane” in the desktop window of Emacs.  A window in Emacs always displays a buffer.  Windows can also be split in arbitrary ways, both horizontally and vertically, so that you can create whatever window layout you like.  Each of these windows can show different buffers or even the same buffer!
</p>

 <p>
What you think of as a window in typical desktop environments, Emacs calls a “frame”!  Emacs can display multiple frames (desktop windows) at the same time.  These frames all share the same internal state and buffers.  Some people never use more than one frame, others use many frames.  It all depends on how you prefer to use Emacs!
</p>

 <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Basic-Window.html#Basic-Window">Emacs Manual: Concepts of Emacs Windows</a>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Frames.html#Frames">Emacs Manual: Frames and Graphical Displays</a>
</p>
</div>
 <h3>Buffers  <a id="buffers" class="anchor" href="#buffers">#</a></h3> <div class="outline-text-3" id="text-org939d144">
 <p>
A buffer holds text and other information that is usually displayed in a window.  The most obvious example is a buffer that contains the contents of a file for the purpose of editing it.
</p>

 <p>
However, there are many types of special buffers that are used only for displaying temporary information or user interface elements!  The Magit package provides an excellent interface for Git inside of a custom Emacs buffer.
</p>

 <p>
Buffers can be one of the more confusing aspects of Emacs to beginners because you don’t have any indication of what buffers are open until you try to switch to another buffer.
</p>

 <p>
Some important buffers you will definitely see when you use Emacs:
</p>

 <ul class="org-ul"> <li> <code>*scratch*</code> - Basically like a blank sheet of paper for taking notes, writing temporary Emacs Lisp expressions, or whatever you want!</li>
 <li> <code>*Messages*</code> - This contains log messages and all the text that gets written to the echo area at the bottom of the screen</li>
 <li> <code>*Warnings*</code> - A list of potential errors that may be displayed from time to time</li>
</ul> <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Buffers.html#Buffers">Emacs Manual: Using Multiple Buffers</a>
</p>
</div>
 <h3>The Mode Line  <a id="the-mode-line" class="anchor" href="#the-mode-line">#</a></h3> <div class="outline-text-3" id="text-orge348bf4">
 <p>
When coming from other editors, you might expect to see a “status bar” at the bottom of the main editor window that gives you information about the state of the current buffer and the editor.  Emacs also has this, but does it slightly differently!
</p>

 <p>
The mode line is a line of text displayed at the bottom of every window (pane) in Emacs.  It displays information about the current buffer you’re viewing and also global status information:
</p>

 <ul class="org-ul"> <li>The line and column of the cursor</li>
 <li>The major mode of the buffer</li>
 <li>The minor modes active in the buffer (or globally in Emacs)</li>
</ul> <p>
The major difference between the mode line and the status bar is that there is a mode line under  <b>every</b> visible window, so when you split the window, you’ll see multiple mode lines!  There are benefits to this even though it takes up extra screen space.
</p>

 <p>
The mode line is fully customizable and can be made to look very nice either through your own configuration or from community packages!
</p>

 <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Mode-Line.html">Emacs Manual: The Mode Line</a>
</p>
</div>
 <h3>The Echo Area and Minibuffer  <a id="the-echo-area-and-minibuffer" class="anchor" href="#the-echo-area-and-minibuffer">#</a></h3> <div class="outline-text-3" id="text-orgb68e753">
 <p>
The echo area is a line at the very bottom of the frame which displays informational text when you perform certain operations in Emacs.
</p>

 <p>
It also turns into a prompt at times when you run a command that needs to accept user input; this prompt is called the “minibuffer”!  You can think of it like a temporary buffer that is used for interacting with the user.  It can also expand its height to be slightly larger than a single line when needed.
</p>

 <p>
One example of the minibuffer in use can be seen when we attempt to run a command by name.
</p>

 <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Echo-Area.html">Emacs Manual: The Echo Area</a>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Minibuffer.html#Minibuffer">Emacs Manual: The Minibuffer</a>
</p>
</div>
 <h3>Commands  <a id="commands" class="anchor" href="#commands">#</a></h3> <div class="outline-text-3" id="text-org2a03b29">
 <p>
In Emacs, there are a variety of built in commands that enable a lot of interesting and useful behavior, especially things that aren’t specifically for text editing!  You can think of Emacs as more of a personal productivity suite than a plain text editor.
</p>

 <p>
To run a command, you can press  <code>Alt+x</code> (or  <code>M-x</code> in Emacs lingo).  This will bring up a prompt where you can type in the name of the command to be run.
</p>

 <p>
This prompt features a completion system (like many prompts in Emacs) so you can press  <code>TAB</code> to show all possible commands that you can run.
</p>

 <p>
Try out the following commands:
</p>

 <ul class="org-ul"> <li> <code>dired</code> ( <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html#Dired">Manual</a>)</li>
 <li> <code>calendar</code> ( <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Calendar_002fDiary.html#Calendar_002fDiary">Manual</a>)</li>
 <li> <code>eshell</code> ( <a href="https://www.gnu.org/software/emacs/manual/html_mono/eshell.html">Manual</a>)</li>
 <li> <code>tetris</code> :) ( <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Amusements.html#Amusements">Manual</a>)</li>
</ul> <p>
New commands can be installed into Emacs using community packages, and you can also write your own!  We’ll cover this in another article.
</p>

 <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Commands.html">Emacs Manual: Keys and Commands</a>
</p>
</div>
 <h3>Major and Minor Modes  <a id="major-and-minor-modes" class="anchor" href="#major-and-minor-modes">#</a></h3> <div class="outline-text-3" id="text-org881665b">
 <p>
In other editors, there is usually functionality that gets enabled for files with a particular extension, e.g. Python programming functionality for  <code>.py</code> files.
</p>

 <p>
Emacs also has this!  This functionality is provided through something called a “major mode.”  A major mode provides the primary functionality for a particular buffer and it is usually activated based on the extension of a file you open in that buffer.
</p>

 <p>
As we’ve seen before, some buffers are not files and have special functionality!  This functionality also comes from custom major modes.  In this case, the major mode is being activated using a command, typically with the name of the mode.
</p>

 <p>
The major mode is what we see down in the mode line which indicates what type of buffer we are looking it.
</p>

 <p>
There can only be one major mode active in a buffer at once!
</p>

 <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Modes.html">Emacs Manual: Major and Minor Modes</a>
</p>
</div>
 <h4>Minor Modes  <a id="minor-modes" class="anchor" href="#minor-modes">#</a></h4> <div class="outline-text-4" id="text-org743dd89">
 <p>
Minor modes are different in that many minor modes can be active in a single buffer, and even globally across Emacs.
</p>

 <p>
Minor modes typically provide helpful functionality that isn’t specific to the major mode of the current buffer, but things you might need to customize your workflow or even change the display of things in Emacs.
</p>

 <p>
Try out  <code>hl-line-mode</code> and  <code>global-hl-line-mode</code> as an example of local and global minor modes!
</p>
</div>
 <h3>Basic Key Bindings  <a id="basic-key-bindings" class="anchor" href="#basic-key-bindings">#</a></h3> <div class="outline-text-3" id="text-org1c2426f">
 <p>
Emacs is most efficient and productive when you focus on keyboard-based control.  The key binding system in Emacs is one of the most flexible and customizable I’ve ever seen; once you start customizing Emacs’ bindings for your own personal workflow, you’ll see how limited other programs are by comparison.
</p>
</div>
 <h3>Understanding Emacs Key Bindings  <a id="understanding-emacs-key-bindings" class="anchor" href="#understanding-emacs-key-bindings">#</a></h3> <div class="outline-text-3" id="text-org0927b76">
 <p>
You will often see people write out the key bindings in a specific format when explaining things.  Let’s quickly cover what everything means since you will see it often!
</p>

 <ul class="org-ul"> <li> <code>C-c</code> - hold the Ctrl key and press the letter ’c’</li>
 <li> <code>C-x C-s</code> - hold the Ctrl key and press the letters ’x’ then ’s’ while still holding Ctrl</li>
 <li> <code>C-x b</code> - hold the Ctrl key and press ’x’, then release Ctrl and press ’b’</li>
 <li> <code>M-x</code> - hold the Alt key and press ’x’ (you will see this often like  <code>M-x find-file</code>)</li>
 <li> <code>M-g C-s</code> - hold the Alt key and press the letter ’g’, release Alt, hold Ctrl and press ’s’</li>
</ul> <p>
These single-letters can be interpreted as follows:
</p>

 <ul class="org-ul"> <li> <code>C</code> - Ctrl</li>
 <li> <code>M</code> - Alt (Meta in Emacs lingo)</li>
 <li> <code>S</code> - Shift</li>
 <li> <code>s</code> - Super (Windows key)</li>
</ul> <p>
Generally when you see a capital  <code>C</code>,  <code>M</code>, or  <code>S</code> hyphened together with another key, those should all be pressed together, i.e.  <code>C-M-s</code> or  <code>M-S-d</code>.
</p>

 <p>
One last important thing to mention are the two main key prefixes that have special meaning:
</p>

 <ul class="org-ul"> <li> <code>C-x</code> - This is a prefix for all of Emacs’ primary key bindings like  <code>C-x C-f</code></li>
 <li> <code>C-c</code> - This is considered to be a combination of bindings created by active major and minor modes or by the user!</li>
</ul> <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Key-Sequences.html">Emacs Manual: Key Sequences</a>
</p>
</div>
 <h3>Opening and Saving Files  <a id="opening-and-saving-files" class="anchor" href="#opening-and-saving-files">#</a></h3> <div class="outline-text-3" id="text-org525a485">
 <p>
To open a file in Emacs, press  <code>C-x C-f</code> ( <code>find-file</code>).  This will bring up a prompt in the minibuffer so that you can type in the file name.
</p>

 <p>
You can also navigate through directories by deleting the directory path and using  <code>TAB</code> to complete parts of directory and file names!
</p>

 <p>
When you’ve opened a file into a buffer, you can make edits to it and then save the file with  <code>C-x C-s</code> ( <code>save-buffer</code>).
</p>

 <p>
You can also save the buffer to a different file (“Save as” in other editors) with  <code>C-x C-w</code> ( <code>write-file</code>).
</p>

 <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Visiting-Files.html#Visiting-Files">Emacs Manual: Visiting Files</a>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Saving-Buffers.html#Saving-Buffers">Emacs Manual: Saving Buffers</a>
</p>
</div>
 <h3>Switching Buffers  <a id="switching-buffers" class="anchor" href="#switching-buffers">#</a></h3> <div class="outline-text-3" id="text-org2c0ca0e">
 <p>
As we talked about before, Emacs can have many buffers open at the same time but you will only see the buffers that are currently open in a window.
</p>

 <p>
If you want to switch between buffers, you can use the  <code>C-x b</code> ( <code>switch-to-buffer</code>) binding to be prompted for a buffer to switch to.  This prompt features completions, so press  <code>TAB</code> at any time to see the possible buffers based on the current text you’ve entered.
</p>

 <p>
There’s also  <code>C-x C-b</code> ( <code>list-buffers</code>) which will show you a full listing of all the buffers that are open in Emacs.
</p>

 <p>
Once you start customizing Emacs, there are a variety of packages that make this even easier and enable you to customize it for your workflow!
</p>

 <p>
You can also easily move between buffers using the  <code>C-x <left arrow></code> and  <code>C x <right arrow></code> keys!
</p>

 <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/List-Buffers.html#List-Buffers">Emacs Manual: Listing Existing Buffers</a>
</p>
</div>
 <h3>Cutting and Copying Text  <a id="cutting-and-copying-text" class="anchor" href="#cutting-and-copying-text">#</a></h3> <div class="outline-text-3" id="text-orgd10c415">
 <p>
This is an area which always confuses new Emacs users!  Many programs across Linux and Windows use  <code>C-c</code> to copy text and  <code>C-x</code> to copy and delete the selected text (cut).
</p>

 <p>
This is not the case in Emacs!  As we mentioned before, these two key bindings are actually special key prefixes in Emacs so they aren’t used for cut and copy.
</p>

 <p>
In Emacs, to “kill” text means to “cut” it, basically copy it and delete it.  The most common thing you will do is to kill a region, either to just delete the text or to cut it to be pasted somewhere else.
</p>

 <p>
But to kill a region, you first need to select one!  You can begin marking a region using  <code>C-SPC</code> ( <code>set-mark-command</code>) then use the arrow keys to move the cursor to expand or shrink the selection.
</p>

 <p>
Now that you have a region selected, you can use  <code>C-w</code> ( <code>kill-region</code>) to cut the text or  <code>M-w</code> ( <code>kill-ring-save</code>) to copy it.
</p>

 <p>
One interesting aspect of killing text is that it gets stored in the “kill ring” to be used later.  We will discuss this in a future episode!
</p>

 <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Killing.html">Emacs Manual: Killing and Moving Text</a>
</p>
</div>
 <h3>Pasting Text  <a id="pasting-text" class="anchor" href="#pasting-text">#</a></h3> <div class="outline-text-3" id="text-org43afcab">
 <p>
In typical Emacs style, the concept of “pasting” text has a different name: “yank.”
</p>

 <p>
You can press  <code>C-y</code> to yank (paste) the most recent text from the kill ring back into this buffer.
</p>

 <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Yanking.html#Yanking">Emacs Manual: Yanking</a>
</p>
</div>
 <h3>CUA Mode  <a id="cua-mode" class="anchor" href="#cua-mode">#</a></h3> <div class="outline-text-3" id="text-org7a9cd42">
 <p>
If you  <b>must</b> have the old  <code>C-c</code> (copy)  <code>C-x</code> (cut) and  <code>C-v</code> (paste) behavior that you’re familiar with, you can turn on the CUA mode using the menu item “Options -> Cut/Paste with C-x/C-c/C-v (CUA Mode)”.
</p>

 <p>
This will make the cut and copy key bindings work when you’ve selected a region of text with the mouse or keyboard.  It will also turn  <code>C-v</code> into a Paste keybinding which will do what you expect!
</p>

 <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/CUA-Bindings.html#CUA-Bindings">Emacs Manual: CUA Bindings</a>
</p>
</div>
 <h3>Undo and Redo  <a id="undo-and-redo" class="anchor" href="#undo-and-redo">#</a></h3> <div class="outline-text-3" id="text-org44b724b">
 <p>
You can undo changes to a buffer by pressing  <code>C-_</code> (Ctrl+underscore) to run the  <code>undo</code> command.  An alternative binding which is easier to press is  <code>C-/</code>
</p>

 <p>
To redo something that you deleted with undo, press  <code>C-g C-_</code>, but note that pressing  <code>C-_</code> again right after this will keep redoing things that you’ve undo’ed!  It will then cycle back to undoing once you’ve reached the end of your redo history.
</p>

 <p>
As you can see, Emacs’ undo system operates differently than what you’re used to!  There are packages that can replace this with more understood behavior; we will talk about them in another article.
</p>

 <p>
 <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Undo.html">Emacs Manual: Undo</a>
 <a href="https://stackoverflow.com/a/3529243">StackOverflow answer about how to undo and redo</a>
</p>
</div>
 <h3>Cancelling Operations  <a id="cancelling-operations" class="anchor" href="#cancelling-operations">#</a></h3> <div class="outline-text-3" id="text-org577b9d9">
 <p>
Sometimes you might run a command that you want to cancel before it completes.  For this you can press  <code>C-g</code> (Ctrl+g).  This interrupts any active command and brings you back to a normal state in Emacs.
</p>

 <p>
One example is showing any prompt, like the one for the ( <code>find-file</code>) command.  If you decide you want to cancel that prompt, just press  <code>C-g</code>.
</p>

 <p>
Sometimes you might need to press it repeatedly before you can fully get back to normal!
</p>

 <p>
If Emacs ever seems to be hung, try this key binding first before killing the process.
</p>
</div>
 <h3>Learning More Key Bindings  <a id="learning-more-key-bindings" class="anchor" href="#learning-more-key-bindings">#</a></h3> <div class="outline-text-3" id="text-orgf64b458">
 <p>
There are two ways to figure out more key bindings for Emacs, especially when editing different types of files:
</p>

 <ul class="org-ul"> <li>As we talked about before, look at the menu bar for common commands and their keys</li>
 <li>Run the command  <code>describe-bindings</code></li>
 <li>Run the command  <code>describe-key</code> ( <code>C-h k</code>) to learn what command is bound to a specific key combination!</li>
</ul></div>
 <h3>The Help System  <a id="the-help-system" class="anchor" href="#the-help-system">#</a></h3> <div class="outline-text-3" id="text-org44c3e25">
 <p>
We’ll cover this in detail in another article, but the whole Emacs manual is built in to Emacs and you can find help on any function or variable in Emacs using the  <code>describe-*</code> functions!
</p>
</div>
 <h2>Configuring Emacs  <a id="configuring-emacs" class="anchor" href="#configuring-emacs">#</a></h2> <div class="outline-text-2" id="text-org9009c46">
 <p>
There are two ways to configure Emacs to customize its behavior.  We won’t go in depth on either of these in this article, I just want to point them out to you since it will be an obvious question you might have!
</p>
</div>
 <h3>The Customization UI  <a id="the-customization-ui" class="anchor" href="#the-customization-ui">#</a></h3> <div class="outline-text-3" id="text-org84dbd1f">
 <p>
Emacs provides a full user interface for customizing all options in the editor.  To access it, run the command  <code>customize</code>.
</p>

 <p>
You can either navigate through the settings hierarchy to see what is available or put your cursor in the search box, type a term, then press  <code>ENTER</code>.
</p>

 <p>
Each setting will have an input field of some kind that you can change by putting your cursor in the box and editing the value.  Once you’re finished editing, you can click the “Apply” button to save the changes.
</p>

 <p>
Try searching for “tab width” in the search box!
</p>
</div>
 <h3>The  <code>init.el</code> file  <a id="the-codeinitelcode-file" class="anchor" href="#the-codeinitelcode-file">#</a></h3> <div class="outline-text-3" id="text-org3993b2b">
 <p>
Once you’ve become sufficiently comfortable with Emacs, you’ll want to investigate how to configure Emacs using the  <code>init.el</code> file.  Emacs can be completely configured and extended using Lisp code!
</p>

 <p>
In your configuration file, you can write your own functions and commands to add new behavior to Emacs.  This is where a lot of the true power of Emacs comes into play!
</p>

 <p>
Check out the series  <a href="https://www.youtube.com/watch?v=74zOY-vgkyw&list=PLEoMzSkcN8oPH1au7H6B7bBJ4ZO7BXjSZ">Emacs From Scratch</a> if you want to learn how to build up a modern Emacs configuration from scratch using the  <code>init.el</code> file and a bunch of community packages.
</p>
</div>
 <h2>What’s next?  <a id="whatrsquos-next" class="anchor" href="#whatrsquos-next">#</a></h2> <div class="outline-text-2" id="text-org950ff05">
 <p>
This article should give you much of what you need to know to start using Emacs!  However, we weren’t able to cover many things in depth.
</p>

 <p>
I’ve already been making a ton of other articles about Emacs on this channel, so you should definitely check out SystemCrafter’s playlists if you want to learn a lot more:
</p>

 <ul class="org-ul"> <li> <a href="https://www.youtube.com/watch?v=74zOY-vgkyw&list=PLEoMzSkcN8oPH1au7H6B7bBJ4ZO7BXjSZ">Emacs From Scratch</a></li>
 <li> <a href="https://www.youtube.com/watch?v=wKTKmE1wLyw&list=PLEoMzSkcN8oMHJ6Xil1YdnYtlWd5hHZql">Emacs Tips</a></li>
 <li> <a href="https://www.youtube.com/watch?v=f7xB2fFk1tQ&list=PLEoMzSkcN8oNPbEMYEtswOVTvq7CVddCS">Emacs Desktop Environment</a></li>
 <li> <a href="https://www.youtube.com/watch?v=E-NAM9U5JYE&list=PLEoMzSkcN8oNvsrtk_iZSb94krGRofFjN">Emacs IDE</a></li>
 <li> <a href="https://www.youtube.com/watch?v=yZRyEhi4y44&list=PLEoMzSkcN8oM-kA19xOQc8s0gr0PpFGJQ">Emacs Mail</a></li>
 <li> <a href="https://www.youtube.com/watch?v=RQK_DaaX34Q&list=PLEoMzSkcN8oPQtn7FQEF3D7sroZbXuPZ7">Learning Emacs Lisp</a></li>
</ul></div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/emacs/emacs-for-absolute-begginners/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/emacs/emacs-for-absolute-begginners/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Emacs registers - a god-send for your day job</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Ever had to work very long files, in projects that you are not familiar with, and felt very lost, without an anchor point?
</p>

 <p>
Enter Emacs and its registry system, which allows you to “bookmark” locations of a file (buffer) and return to them, and much much more!
</p>
 <h2>Registers  <a id="registers" class="anchor" href="#registers">#</a></h2> <div class="outline-text-2" id="text-orge50764b">
 <p>
Emacs registers are places you can save text or positions for later use. Text and rectangles saved in registers can be copied into the buffer once or many times; you can move point to a position saved in a register.
</p>

 <p>
Each register has a name which is a single character. A register can store a piece of text, a rectangle, a position, a window configuration or a file name, but only one thing at any given time. Whatever you store in a register remains there until you store something else in that register. To see what a register r contains, use  <code>M-x view-register</code>.
</p>

 <p>
 <code>M-x view-register RET r</code>
Display a description of what register r contains.
</p>
</div>
 <h2>Saving Positions in Registers  <a id="saving-positions-in-registers" class="anchor" href="#saving-positions-in-registers">#</a></h2> <div class="outline-text-2" id="text-org837509c">
 <p>
Saving a position records a spot in a buffer so that you can move back there later. Moving to a saved position reselects that buffer and moves point to that spot.
</p>

 <p>
 <code>C-x r SPC r</code>
Save position of point in register r (point-to-register).
 <code>C-x r j r</code>
Jump to the position saved in register r (jump-to-register).
To save the current position of point in a register, choose a name r and type  <code>C-x r SPC r</code>. The register r retains the position thus saved until you store something else in that register.
</p>

 <p>
The command  <code>C-x r j r</code> moves point to the position recorded in register r. The register is not affected; it continues to record the same position. You can jump to the same position using the same register any number of times.
</p>
</div>
 <h2>Saving Text in Registers  <a id="saving-text-in-registers" class="anchor" href="#saving-text-in-registers">#</a></h2> <div class="outline-text-2" id="text-org631d80b">
 <p>
When you want to insert a copy of the same piece of text several times, it may be inconvenient to yank it from the kill ring, since each subsequent kill moves that entry further down the ring. An alternative is to store the text in a register with  <code>C-x r s (copy-to-register)</code> and then retrieve it with  <code>C-x r i (insert-register)</code>.
</p>

 <p>
 <code>C-x r s r</code>
Copy region into register r  <code>(copy-to-register)</code>.
 <code>C-x r i r</code>
Insert text from register r  <code>(insert-register)</code>.
 <code>C-x r s r</code> stores a copy of the text of the region into the register named r. Given a numeric argument,  <code>C-x r s r</code> deletes the text from the buffer as well.
</p>

 <p>
 <code>C-x r i r</code> inserts in the buffer the text from register r. Normally it leaves point before the text and places the mark after, but with a numeric argument  <code>C-u</code> it puts point after the text and the mark before.
</p>
</div>
 <h2>Saving Rectangles in Registers  <a id="saving-rectangles-in-registers" class="anchor" href="#saving-rectangles-in-registers">#</a></h2> <div class="outline-text-2" id="text-org2e5d09b">
 <p>
A register can contain a rectangle instead of linear text. The rectangle is represented as a list of strings. See section Rectangles, for basic information on how to specify a rectangle in the buffer.
</p>

 <p>
 <code>C-x r r r</code>
Copy the region-rectangle into register r (copy-region-to-rectangle). With numeric argument, delete it as well.
 <code>C-x r i r</code>
Insert the rectangle stored in register r (if it contains a rectangle) (insert-register).
</p>

 <p>
The  <code>C-x r i r</code> command inserts a text string if the register contains one, and inserts a rectangle if the register contains one.
</p>
</div>
 <h2>Saving Window Configurations in Registers  <a id="saving-window-configurations-in-registers" class="anchor" href="#saving-window-configurations-in-registers">#</a></h2> <div class="outline-text-2" id="text-orgb3d3db4">
 <p>
You can save the window configuration of the selected frame in a register, or even the configuration of all frames, and restore the configuration later.
</p>

 <p>
 <code>C-x r w r</code>
Save the state of the selected frame’s windows in register r (window-configuration-to-register).
 <code>C-x r f r</code>
Save the state of all windows in all frames in register r (frame-configuration-to-register).
</p>

 <p>
Use  <code>C-x r j r</code> to restore a window or frame configuration. This is the same command used to restore a cursor position. When you restore a frame configuration, any existing frames not included in the configuration become invisible. If you wish to delete these frames instead, use C-u C-x r j r.
</p>
</div>
 <h2>Keeping File Names in Registers  <a id="keeping-file-names-in-registers" class="anchor" href="#keeping-file-names-in-registers">#</a></h2> <div class="outline-text-2" id="text-org0f5cf05">
 <p>
If you visit certain file names frequently, you can visit them more conveniently if you put their names in registers. Here’s the Lisp code used to put a file name in a register:
</p>

 <p>
 <code>(set-register ?r '(file . name))</code>
For example,
</p>

 <p>
 <code>(set-register ?z '(file . "/gd/gnu/emacs/19.0/src/ChangeLog"))</code>
puts the file name shown in register `z’.
</p>

 <p>
To visit the file whose name is in register r, type  <code>C-x r j r</code>. (This is the same command used to jump to a position or restore a frame configuration.)
</p>

 <p>
Go to the previous, next section.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/emacs/emacs-registers/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/emacs/emacs-registers/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>YAML Schemas in Emacs with Eglot</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Are you someone that enjoys Emacs and the amazing built-in package Eglot, which enables Emacs to provide intelligent completions and error reporting, linting, and more with language servers ?
</p>

 <p>
Are you ocasionally editing YAML files and would like to use JSON Schemas for YAML, get some feedback from Emacs, the right completions for a configuration file ?
</p>
 <h2>Almost a type system for YAML 💚  <a id="almost-a-type-system-for-yaml-" class="anchor" href="#almost-a-type-system-for-yaml-">#</a></h2> <div class="outline-text-2" id="text-org7509317">
 <p>
Let me introduce  <a href="https://github.com/redhat-developer/yaml-language-server">yaml-language-server</a> (easily installed from Nix too).
</p>

 <p>
By the way if you want to see advanced Eglot configuration check the manual or my own dotfiles at:  <a href="https://codeberg.org/jjba23/sss">https://codeberg.org/jjba23/sss</a>.
</p>

 <p>
Say no more, configure Eglot directly like below.
This will ensure you can load several schemas with semantic / domain meaning, but always have the  <code>yamllint</code> schema as fallback.
</p>
</div>
 <h2>Configuring Eglot  <a id="configuring-eglot" class="anchor" href="#configuring-eglot">#</a></h2> <div class="outline-text-2" id="text-org3937cc2">
 <pre>( <span class="org-keyword">setq-default</span> eglot-workspace-configuration
              '( <span class="org-builtin">:yaml</span> (  <span class="org-builtin">:format</span> ( <span class="org-builtin">:enable</span> t)
                         <span class="org-builtin">:validate</span> t
                         <span class="org-builtin">:hover</span> t
                         <span class="org-builtin">:completion</span> t
                         <span class="org-builtin">:schemas</span> (https://raw.githubusercontent.com/my-user/my-project/project.schema.yml [ <span class="org-string">"project.yml"</span>]
                                  https://json.schemastore.org/yamllint.json [ <span class="org-string">"/*.yml"</span>])
                         <span class="org-builtin">:schemaStore</span> ( <span class="org-builtin">:enable</span> t))
                  <span class="org-comment-delimiter">;; </span> <span class="org-comment">here other language server configurations</span>
                ))</pre>


 <p>
And have Eglot start  <code>yaml-language-server --stdio</code> automatically.
</p>

 <p>
See the language server’s documentation for more details on how to load YAML schemas from various sources, even declaratively in the YAML file itself.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/emacs/yaml-schemas-in-emacs-eglot/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/emacs/yaml-schemas-in-emacs-eglot/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Emacs</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2024-12-04 wo> </span></span>  <a href="/blog/articles/emacs/yaml-schemas-in-emacs-eglot/index.html">YAML Schemas in Emacs with Eglot</a> Are you editing YAML files and would like to use JSON Schemas for YAML in Emacs ?
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2024-08-13 di> </span></span>  <a href="/blog/articles/emacs/emacs-registers/index.html">Emacs registers - a god-send for your day job</a> - Ever had to work very long files, in projects that you are not familiar with, and felt very lost, without an anchor point? Enter Emacs and its registry system, which allows you to “bookmark” locations of a file (buffer) and return to them, and much much more!
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2023-04-28 vr> </span></span>  <a href="/blog/articles/emacs/emacs-for-absolute-begginners/index.html">Emacs for absolute beginners</a> - In this article, I’m going to give you exactly what you need to get started using Emacs and understand the basic concepts and key bindings of the editor.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2023-04-26 wo> </span></span>  <a href="/blog/articles/emacs/emacs-and-scala-setup-with-eglot/index.html">Emacs and Scala setup with Eglot</a>
Learn how to setup your favourite text editor, Emacs, as a super powerful and capable Scala IDE (integrated development environment) with the latest and most performant approach.
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/emacs/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/emacs/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Jails with a loopback IP</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
In order to keep all of the jails behind a single public IP address,
you’ll need to set up a loopback interface and direct the incoming and
outgoing traffic of your Jails with a proper firewall like  <code>pf</code>. Learn
how to get started on an amazing setup.
</p>

 <p>
There are multiple ways to manage your jails, but iocage is one of the
more popular ones. In terms of jail managers it’s a fairly new player in
the game of jail management and is being very actively developed. It has
a full rewrite in Python, and while the code in the background might be
different, the actual user interface has stayed very similar.
</p>

 <p>
Iocage makes use of ZFS clones in order to create base jails, which
allow for sharing of one set of system packages between multiple jails,
reducing the amount of resources necessary. Alternatively, jails can be
completely independent of each other; however, using a base jail makes
it easier to update multiple jails as well.
</p>

 <p>
You can install it from a binary package:
</p>

 <pre>pkg install -y py37-iocage</pre>
 <h2>Setting up the zpool  <a id="setting-up-the-zpool" class="anchor" href="#setting-up-the-zpool">#</a></h2> <div class="outline-text-2" id="text-setting-up-the-zpool">
 <p>
It is a great idea to separate the jails storage device from the host
system’s storage. Ideally in a separate physical device, but a separate
partition will also do.
</p>

 <p>
This means that you would be in a situation where your  <code>zroot</code> is
already setup, and you have a free device/partition where you can create
a second  <code>zpool</code> to be used specifically for the Jails.
</p>

 <p>
Doing a  <code>gpart show</code> in my machine reveals the following setup:
</p>

 <pre>=>      40  41942960  da0  GPT  (20G)
            40      1024    1  freebsd-boot  (512K)
          1064       984       - free -  (492K)
          2048   4194304    2  freebsd-swap  (2.0G)
       4196352  20971520    3  freebsd-zfs  (10G)
      25167872  16773120    4  freebsd-zfs  (8.0G)
      41940992      2008       - free -  (1.0M)</pre>

 <p>
This means I want to create a new pool on  <code>da0p4</code> with the name  <code>iocage</code>
since my system has been installed on  <code>da0p3</code>.
</p>

 <p>
This can be achieved very simply with the command:
</p>

 <pre>zpool create iocage da0p4</pre>

 <p>
With the pool created, you can now activate  <code>iocage</code> to use the wanted
pool:
</p>

 <pre>iocage activate iocage</pre>

 <p>
Then fetch the latest FreeBSD release (or the one you prefer) to be used
to setup jails:
</p>

 <pre>iocage fetch</pre>

 <p>
Add the following new line to your  <code>/etc/fstab</code> file to improve the jail
performance:
</p>

 <pre>fdescfs /dev/fd fdescfs rw 0 0</pre>
</div>
 <h2>Setting up the network  <a id="setting-up-the-network" class="anchor" href="#setting-up-the-network">#</a></h2> <div class="outline-text-2" id="text-setting-up-the-network">
 <p>
You could go ahead and create your jail right off, but the networking
will not work out of the box. Take a minute and do some basic network
configuration before creating your first jail.
</p>
</div>
 <h3>Virtual Interface  <a id="virtual-interface" class="anchor" href="#virtual-interface">#</a></h3> <div class="outline-text-3" id="text-virtual-interface">
 <p>
For our internal network, we create a cloned loopback device called
 <code>lo1</code>. Therefore we need to customize the  <code>/etc/rc.conf</code> file, adding
the following two lines:
</p>

 <p>
In order to keep all of the jails behind a single public IP address,
you’ll need to set up a new network interface. This new interface will
be a clone of the loopback interface which will have an IP address
assigned to it. You can use any RFC 1918 address space. In this
tutorial,  <code>192.168.0.1</code> will be used. Add the following to
 <code>/etc/rc.conf</code> to get the new interface set up:
</p>

 <pre> <span class="org-comment-delimiter"># </span> <span class="org-comment">/etc/rc.conf</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">Setup the interface that all jails will use</span>
 <span class="org-variable-name">cloned_interfaces</span>= <span class="org-string">"lo1"</span>
 <span class="org-variable-name">ipv4_addrs_lo1</span>= <span class="org-string">"192.168.0.1/24"</span>

 <span class="org-variable-name">gateway_enable</span>= <span class="org-string">"YES"</span>

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Enable port forwarding and packet filtering</span>
 <span class="org-variable-name">pf_enable</span>= <span class="org-string">"YES"</span>

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Enable iocage at startup</span>
 <span class="org-variable-name">iocage_enable</span>= <span class="org-string">"YES"</span></pre>

 <p>
This defines a  <code>/24</code> network, offering IP addresses for a maximum of 254
jails:
</p>

 <pre>joe@devjails > ipcalc 192.168.0.1/24

Address:   192.168.0.1          11000000.10101000.00000000. 00000001
Netmask:   255.255.255.0 = 24   11111111.11111111.11111111. 00000000
Wildcard:  0.0.0.255            00000000.00000000.00000000. 11111111
=>
Network:   192.168.0.0/24       11000000.10101000.00000000. 00000000
HostMin:   192.168.0.1          11000000.10101000.00000000. 00000001
HostMax:   192.168.0.254        11000000.10101000.00000000. 11111110
Broadcast: 192.168.0.255        11000000.10101000.00000000. 11111111
Hosts/Net: 254                   Class C, Private Internet</pre>

 <p>
Then we need to restart the network. Please be aware of currently active
SSH sessions as they will be dropped during restart. It’s a good moment
to ensure you have KVM or physical access to that server ;-)
</p>

 <p>
With those entries in  <code>/etc/rc.conf</code> the interfaces will all be created
and configured at boot time, so give the machine a nice reboot
</p>

 <p>
After booting, an  <code>ifconfig</code> should now show a new interface:
</p>

 <pre>lo1:  <span class="org-variable-name">flags</span>=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
     <span class="org-variable-name">options</span>=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
    inet 192.168.0.1 netmask 0xffffff00
    groups: lo
    nd6  <span class="org-variable-name">options</span>=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL></pre>
</div>
 <h3>NAT for packet forwarding  <a id="nat-for-packet-forwarding" class="anchor" href="#nat-for-packet-forwarding">#</a></h3> <div class="outline-text-3" id="text-nat-for-packet-forwarding">
 <p>
Now that you have an interface to use with your jails, you’ll need to
get some packet forwarding set up. Edit  <code>/etc/pf.conf</code> (which will be
empty by default) according to the following
</p>

 <pre> <span class="org-variable-name">ext_if</span>= <span class="org-string">"em0"</span>
 <span class="org-variable-name">jail_if</span>= <span class="org-string">"lo1"</span>

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Public IP address</span>
 <span class="org-variable-name">ip_pub</span>= <span class="org-string">"192.168.178.40"</span>

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Packet normalization</span>
scrub <span class="org-keyword"> in</span> all

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Skip packet filtering on loopback interfaces</span>
 <span class="org-builtin">set</span> skip on lo0
 <span class="org-builtin">set</span> skip on lo1

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Allow outbound connections from within the jails</span>
nat pass on $ <span class="org-variable-name">ext_if</span> from 192.168.0.0/24 to any -> $ <span class="org-variable-name">ip_pub</span></pre>

 <p>
The first 3 lines define a couple of useful variables – called macros
in PF parlance. The nat line instructs PF to mask outbound traffic from
the jails (all of them) behind the IP address of the external interface.
In short, all of your outbound jail traffic will come from the IP
address of your droplet.
</p>

 <p>
With that in place, you can enable and start PF:
</p>

 <pre>service pf enable
service pf start</pre>

 <p>
Before you load the firewall ruleset, test the config file to ensure
that all is well:
</p>

 <pre>pfctl -nvf /etc/pf.conf</pre>

 <p>
That command will cause PF to parse the rules in /etc/pf.conf, and print
them back out to the console. If there are syntax errors, they will be
called out.
</p>

 <p>
Your output should be very similar to:
</p>

 <pre>ext_if =  <span class="org-string">"em0"</span>
jail_if =  <span class="org-string">"lo1"</span>
IP_PUB =  <span class="org-string">"192.168.178.40"</span>
 <span class="org-builtin">set</span> skip on { lo0 }
 <span class="org-builtin">set</span> skip on { lo1 }
scrub <span class="org-keyword"> in</span> all fragment reassemble
nat pass on em0 inet from 192.168.0.0/24 to any -> 192.168.178.40</pre>

 <p>
Then reload the firewall rules with:
</p>

 <pre>pfctl -F all -f /etc/pf.conf</pre>
</div>
 <h2>Creating the first jail  <a id="creating-the-first-jail" class="anchor" href="#creating-the-first-jail">#</a></h2> <div class="outline-text-2" id="text-creating-the-first-jail">
 <p>
It’s time to create & start a jail:
</p>

 <pre>iocage create -n  <span class="org-string">"mydb"</span> -r 12.2-RELEASE  <span class="org-variable-name">ip4_addr</span>= <span class="org-string">"lo1|192.168.0.2"</span>
iocage start mydb</pre>

 <p>
Those commands will have a lot of output, and may end with a warning.
You can safely ignore the warnings. The jail needs to be told how to do
DNS lookups. The simple way to solve this is to copy the hosts
/etc/resolv.conf into the jail. Assuming your zpool was setup to point
to /iocage:
</p>

 <pre>mkdir /iocage/iocage/jails/mydb/etc
cp /etc/resolv.conf /iocage/iocage/jails/mydb/etc/resolv.conf</pre>

 <p>
Then start the machine and enter the console:
</p>

 <pre>iocage start mydb
iocage console mydb</pre>

 <p>
There will be a lot of stuff on the console – very similar to what you
should have seen when you first connected to your Droplet.
</p>

 <p>
Notice that your prompt has changed. Congratulations, you are inside
your jail! It’s probably a good idea to test your connectivity to the
outside world, but by default, and for security reasons, FreeBSD jails
are not allowed to ping. To test connectivity, you can use telnet:
</p>

 <pre>telnet www.digitalocean.com 80</pre>

 <p>
That command will open up a very basic connection to a webserver at
Digital Ocean. You can get out of it pressing Control-] to close the
connection, followed by quit to close telnet.
</p>

 <pre>Trying 104.16.24.4...
Connected to www.digitalocean.com.
Escape character is  <span class="org-string">'^]'</span>.
^]
telnet> quit
Connection closed.</pre>

 <p>
Now you are ready to install your desired software and set up the wanted
services in the jail. It is a good idea to get familiar with  <code>iocage</code>
since it has many handy commands to manage the jails.
</p>

 <p>
In my case, I installed MariaDB on this jail, and for that purpose,
opened up a port redirection in the firewall, so that traffic from the
public-facing interface will be redirected to the internal jail’s port.
You can do this by adding this line to the end of  <code>/etc/pf.conf</code>, with
 <code>192.168.0.4</code> being the internal IP I have assigned to this jail:
</p>

 <pre>rdr on $ <span class="org-variable-name">ext_if</span> proto tcp from any to $ <span class="org-variable-name">ip_pub</span> port 3306 -> 192.168.0.4 port 3306</pre>

 <p>
Then reload the firewall rules with:
</p>

 <pre>pfctl -F all -f /etc/pf.conf</pre>
</div>
 <h2>Locking down the firewall  <a id="locking-down-the-firewall" class="anchor" href="#locking-down-the-firewall">#</a></h2> <div class="outline-text-2" id="text-locking-down-the-firewall">
 <p>
The way things stand right now, your jail is working, but the host
system is pretty wide-open. If you edit your  <code>/etc/pf.conf</code> once more,
we can restrict all inbound traffic that is not destined for a jail
except for SSH.
</p>

 <p>
Edit your file to look like:
</p>

 <pre> <span class="org-variable-name">ext_if</span>= <span class="org-string">"em0"</span>
 <span class="org-variable-name">jail_if</span>= <span class="org-string">"lo1"</span>
 <span class="org-variable-name">jail_net</span>= $ <span class="org-variable-name">jail_if</span>:network

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Public IP address</span>
 <span class="org-variable-name">ip_pub</span>= <span class="org-string">"192.168.178.40"</span>

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Packet normalization</span>
scrub <span class="org-keyword"> in</span> all

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Skip packet filtering on loopback interfaces</span>
 <span class="org-builtin">set</span> skip on lo0
 <span class="org-builtin">set</span> skip on lo1

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Allow outbound connections from within the jails</span>
nat pass on $ <span class="org-variable-name">ext_if</span> from 192.168.0.0/24 to any -> $ <span class="org-variable-name">ip_pub</span>

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Port redirect for MariaDB</span>
rdr pass on $ <span class="org-variable-name">ext_if</span> proto tcp to port 3306 -> 192.168.0.4

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Set the default: block everything</span>
block all

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Allow the jail traffic to be translated</span>
pass from { lo0, $ <span class="org-variable-name">jail_net</span> } to any keep state

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Allow SSH in to the host</span>
pass <span class="org-keyword"> in</span> inet proto tcp to $ <span class="org-variable-name">ext_if</span> port ssh

 <span class="org-comment-delimiter"># </span> <span class="org-comment">Allow OB traffic</span>
pass out all keep state</pre>

 <p>
Now you have a secure machine, that only takes traffic from the wanted
ports. This starts feeling production ready!
</p>
</div>
 <h2>Jail tweaks  <a id="jail-tweaks" class="anchor" href="#jail-tweaks">#</a></h2> <div class="outline-text-2" id="text-jail-tweaks">
 <p>
Jump back into your jail with  <code>iocage console -f mydb</code> and add the
following 2 lines to  <code>/etc/rc.conf</code>:
</p>

 <pre> <span class="org-comment-delimiter"># </span> <span class="org-comment">Disable the RPC daemon</span>
 <span class="org-variable-name">rpcbind_enable</span>= <span class="org-string">"NO"</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">Clear /tmp at startup</span>
 <span class="org-variable-name">clear_tmp_enable</span>= <span class="org-string">"YES"</span></pre>

 <p>
Go on now, create your universe of inter-connected systems, welcome to
the world of  <b>FreeBSD</b> jails!
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/freebsd/jails-with-a-loopback-ip/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/freebsd/jails-with-a-loopback-ip/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>pkg or ports ?</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <div id="table-of-contents" role="doc-toc">
 <h2>Table of Contents</h2>
 <div id="text-table-of-contents" role="doc-toc">
 <ul> <li> <a href="#what-i-prefer">What I prefer</a></li>
 <li> <a href="#package-pkg-benefits">Package (pkg) Benefits</a></li>
 <li> <a href="#port-benefits">Port Benefits</a></li>
</ul></div>
</div>
 <p>
FreeBSD is bundled with a rich collection of system tools as part of the
base system. In addition, FreeBSD provides two complementary
technologies for installing third-party software:
</p>

 <ul class="org-ul"> <li>the FreeBSD Ports Collection, for installing from source</li>

 <li>packages, for installing from pre-built binaries.</li>
</ul> <p>
Either method may be used to install software from local media or from
the network.
</p>

 <p>
For more detailed information you can refer to
 <a href="https://docs.freebsd.org/en/books/handbook/ports/">Chapter 4.
Installing Applications: Packages and Ports</a>
</p>

 <p>
While the two technologies are similar, packages and ports each have
their own strengths. You should select the technology that meets your
requirements for installing a particular application.
</p>
 <h2>What I prefer  <a id="what-i-prefer" class="anchor" href="#what-i-prefer">#</a></h2> <div class="outline-text-2" id="text-what-i-prefer">
 <p>
My policy is to use pre-compiled binaries as much as possible to:
</p>

 <ul class="org-ul"> <li>avoid the need of tinkering with foreign source code and compiler
options</li>

 <li>have easily reproducible build</li>

 <li>update more easily</li>

 <li>use more reliable and stable versions.</li>
</ul></div>
 <h2>Package (pkg) Benefits  <a id="package-pkg-benefits" class="anchor" href="#package-pkg-benefits">#</a></h2> <div class="outline-text-2" id="text-package-pkg-benefits">
 <ul class="org-ul"> <li>A compressed package tarball is typically smaller than the compressed
tarball containing the source code for the application.</li>

 <li>Packages do not require compilation time. For large applications, such
as Mozilla, KDE, or GNOME, this can be important on a slow system.</li>

 <li>Packages do not require any understanding of the process involved in
compiling software on FreeBSD.</li>
</ul></div>
 <h2>Port Benefits  <a id="port-benefits" class="anchor" href="#port-benefits">#</a></h2> <div class="outline-text-2" id="text-port-benefits">
 <ul class="org-ul"> <li>Packages are normally compiled with conservative options because they
have to run on the maximum number of systems. By compiling from the
port, one can change the compilation options.</li>

 <li>Some applications have compile-time options relating to which features
are installed. For example, Apache can be configured with a wide
variety of different built-in options.</li>

 <li>In some cases, multiple packages will exist for the same application
to specify certain settings. For example, Ghostscript is available as
a ghostscript package and a ghostscript-nox11 package, depending on
whether or not Xorg is installed. Creating multiple packages rapidly
becomes impossible if an application has more than one or two
different compile-time options.</li>

 <li>The licensing conditions of some software forbid binary distribution.
Such software must be distributed as source code which must be
compiled by the end-user.</li>

 <li>Some people do not trust binary distributions or prefer to read
through source code in order to look for potential problems.</li>

 <li>Source code is needed in order to apply custom patches.</li>
</ul></div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/freebsd/pkg-or-ports/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/freebsd/pkg-or-ports/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Practical rc.d scripting and Go</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
FreeBSD uses the init system, and system services must be made as rc.d
scripts.
</p>

 <p>
You can find more detailed information and examples in the handbook:
 <a href="https://docs.freebsd.org/en/articles/rc-scripting/">Practical rc.d
scripting</a>.
</p>
 <h2>CLI options choice for daemons  <a id="cli-options-choice-for-daemons" class="anchor" href="#cli-options-choice-for-daemons">#</a></h2> <div class="outline-text-2" id="text-cli-options-choice-for-daemons">
 <p>
Find below the options we normally use for any  <code>/etc/rc.d</code> script as
daemon. See more options by in the terminal issuing: man daemon
</p>

 <p>
 <code>-f</code>: Redirect standard input, standard output and standard error to
 <code>/dev/null</code>. When this option is used together with any of the options
related to file or  <code>syslog</code> output, the standard file descriptors are
first redirected to  <code>/dev/null</code>, then  <code>stdout</code> and/or  <code>stderr</code> is
redirected to a file or to  <code>syslog</code> as specified by the other options.
</p>

 <p>
 <code>-S</code>: Enable  <code>syslog</code> output. This is implicitly applied if other
 <code>syslog</code> parameters are provided. The default values are  <code>daemon</code>,
 <code>notice</code>, and  <code>daemon</code> for facility, priority, and tag, respectively.
</p>

 <p>
 <code>-P</code> : Write the ID of the daemon process into the file with given name
using the  <code>pidfile</code> functionality. The program is executed in a spawned
child process while the daemon waits until it terminates to keep the
 <code>supervisor_pidfile</code> locked and removes it after the process exits. The
 <code>supervisor_pidfile</code> owner is the user who runs the daemon regardless of
whether the  <code>-u</code> option is used or not.
</p>

 <p>
 <code>-r</code>: Supervise and restart the program after a one-second delay if it
has been terminated. Connecting a script to the rc.d framework
</p>

 <p>
In a nutshell,  <code>rcorder</code> takes a set of files, examines their contents,
and prints a dependency-ordered list of files from the set to stdout.
The point is to keep dependency information inside the files so that
each file can speak for itself only. A file can specify the following
information:
</p>

 <ul class="org-ul"> <li>the names of the “conditions” (which means services to us) it provides
with  <code># KEYWORD</code>:</li>

 <li>the names of the “conditions” it requires with  <code># REQUIRE</code>:</li>

 <li>the names of the “conditions” this file should run before with
 <code># BEFORE</code>:</li>

 <li>additional keywords that can be used to select a subset from the whole
set of files ( <code>rcorder</code> can be instructed via options to include or
omit the files having particular keywords listed.) with # KEYWORD:</li>
</ul> <p>
As a rule of thumb, every custom made rc.d script should provide 1
daemon, and require  <code>DAEMON</code> and  <code>networking</code> to be initialized. Thus
the first lines of your rc.d script will generally look something like:
</p>

 <pre> <span class="org-comment-delimiter">#</span> <span class="org-comment">!/bin/</span> <span class="org-keyword">sh</span>
 <span class="org-comment-delimiter">#</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">PROVIDE: <name of this rc.d script></span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">REQUIRE: DAEMON networking</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">KEYWORD:</span></pre>
</div>
 <h2>Daemon load order  <a id="daemon-load-order" class="anchor" href="#daemon-load-order">#</a></h2> <div class="outline-text-2" id="text-daemon-load-order">
 <p>
The order in which the daemons load is highly important. For this
example, our  <code>my_service</code> rc.d script should run as a daemon and should
be able to access the network.
</p>

 <p>
This means that it should only load after  <code>DAEMON</code> and  <code>networking</code> are
loaded and running.
</p>

 <p>
You can verify the load order with:
</p>

 <pre>service -e</pre>

 <p>
The correct load order in this case then would be:
</p>

 <pre>service -e

/etc/rc.d/cleanvar
/etc/rc.d/ip6addrctl
/etc/rc.d/netif
/etc/rc.d/virecover
/etc/rc.d/motd
/etc/rc.d/os-release
/etc/rc.d/newsyslog
/etc/rc.d/syslogd
/etc/rc.d/my_service
/etc/rc.d/cron</pre>
</div>
 <h2>Go applications as daemons  <a id="go-applications-as-daemons" class="anchor" href="#go-applications-as-daemons">#</a></h2> <div class="outline-text-2" id="text-go-applications-as-daemons">
 <p>
In the case of Go binaries, I will use the daemon in a straightforward
manner. See the example below for one of my Go applications, running as
a compiled binary. I assume
 <code>/root/internalApplications/my-service-folder</code> is the folder where the
service is located and should be running from:
</p>

 <pre> <span class="org-comment-delimiter">#</span> <span class="org-comment">!/bin/</span> <span class="org-keyword">sh</span>
 <span class="org-comment-delimiter">#</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">PROVIDE: my_service</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">REQUIRE: DAEMON networking</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">KEYWORD:</span>

 <span class="org-builtin">.</span> /etc/rc.subr

 <span class="org-variable-name">name</span>= <span class="org-string">"my_service"</span>
 <span class="org-variable-name">rcvar</span>= <span class="org-string">"my_service_enable"</span>
 <span class="org-variable-name">my_service_chdir</span>= <span class="org-string">"/root/internalApplications/my-service-folder"</span>
 <span class="org-variable-name">my_service_user</span>= <span class="org-string">"root"</span>
 <span class="org-variable-name">my_service_command</span>= <span class="org-string">"/root/internalApplications/my-service-folder/app"</span>
 <span class="org-variable-name">pidfile</span>= <span class="org-string">"/var/run/${name}.pid"</span>
 <span class="org-variable-name">command</span>= <span class="org-string">"/usr/sbin/daemon"</span>
 <span class="org-variable-name">command_args</span>= <span class="org-string">"-P ${pidfile} -r -f -S ${my_service_command}"</span>

load_rc_config $ <span class="org-variable-name">name</span>
: ${ <span class="org-variable-name">my_service_enable</span>:=no}

run_rc_command  <span class="org-string">"$1"</span></pre>
</div>
 <h2>Shell scripts as daemons  <a id="shell-scripts-as-daemons" class="anchor" href="#shell-scripts-as-daemons">#</a></h2> <div class="outline-text-2" id="text-shell-scripts-as-daemons">
 <p>
Shell scripts that run utilities can also be daemonized. See the example
below I use for Jaeger:
</p>

 <pre> <span class="org-comment-delimiter">#</span> <span class="org-comment">!/bin/</span> <span class="org-keyword">sh</span>

 <span class="org-comment-delimiter"># </span> <span class="org-comment">PROVIDE: jaeger_tracer</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">REQUIRE: DAEMON networking</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">KEYWORD:</span>
 <span class="org-builtin">.</span> /etc/rc.subr

 <span class="org-variable-name">name</span>= <span class="org-string">"jaeger_tracer"</span>
 <span class="org-variable-name">rcvar</span>= <span class="org-string">"jaeger_tracer_enable"</span>
 <span class="org-variable-name">jaeger_tracer_user</span>= <span class="org-string">"root"</span>
 <span class="org-variable-name">pidfile</span>= <span class="org-string">"/var/run/${name}.pid"</span>
 <span class="org-variable-name">jaeger_tracer_command</span>= <span class="org-string">"/root/internalApplications/run-jaeger.sh"</span>
 <span class="org-variable-name">command</span>= <span class="org-string">"/usr/sbin/daemon"</span>
 <span class="org-variable-name">command_args</span>= <span class="org-string">"-P ${pidfile} -r -f -S ${jaeger_tracer_command}"</span>

load_rc_config $ <span class="org-variable-name">name</span>
: ${ <span class="org-variable-name">jaeger_tracer_enable</span>:=no}

run_rc_command  <span class="org-string">"$1"</span></pre>
</div>
 <h2>Conclusion  <a id="conclusion" class="anchor" href="#conclusion">#</a></h2> <div class="outline-text-2" id="text-conclusion">
 <p>
Once the rc.d script is created then you should make it executable with
</p>

 <pre>chmod +x /etc/rc.d/my_service</pre>

 <p>
and you can then use it as a system service whose output is in
 <code>/var/log/messages</code>.
</p>

 <pre>service my_service status
service my_service enable
service my_service start
service my_service restart
service my_service stop</pre>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/freebsd/practical-rcd-scripting-and-go/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/freebsd/practical-rcd-scripting-and-go/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>rc.d scripting</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
FreeBSD uses the init system, and system services must be made as rc.d
scripts.
</p>

 <p>
You can find more detailed information and examples in the handbook:
 <a href="https://docs.freebsd.org/en/articles/rc-scripting/">Practical rc.d
scripting in FreeBSD</a>.
</p>
 <h2>CLI options choice for daemons  <a id="cli-options-choice-for-daemons" class="anchor" href="#cli-options-choice-for-daemons">#</a></h2> <div class="outline-text-2" id="text-cli-options-choice-for-daemons">
 <p>
Find below the options we normally use for any  <code>/etc/rc.d</code> script as
daemon. See more options by in the terminal issuing:
</p>

 <pre class="example" id="orga475bd7">
man daemon
</pre>

 <p>
 <code>-f</code>: Redirect standard input, standard output and standard error to
 <code>/dev/null</code>. When this option is used together with any of the options
related to file or syslog output, the standard file descriptors are
first redirected to  <code>/dev/null</code>, then stdout and/or stderr is redirected
to a file or to syslog as specified by the other options.
</p>

 <p>
 <code>-S</code>: Enable syslog output. This is implicitly applied if other syslog
parameters are provided. The default values are  <code>daemon</code>,  <code>notice</code>, and
 <code>daemon</code> for facility, priority, and tag, respectively.
</p>

 <p>
 <code>-P <supervisor pid file></code>: Write the ID of the daemon process into the
file with given name using the  <code>pidfile</code> functionality. The program is
executed in a spawned child process while the daemon waits until it
terminates to keep the  <code>supervisor_pidfile</code> locked and removes it after
the process exits. The  <code>supervisor_pidfile</code> owner is the user who runs
the daemon regardless of whether the  <code>-u</code> option is used or not.
</p>

 <p>
 <code>-r</code>: Supervise and restart the program after a one-second delay if it
has been terminated.
</p>
</div>
 <h2>Connecting a script to the rc.d framework  <a id="connecting-a-script-to-the-rcd-framework" class="anchor" href="#connecting-a-script-to-the-rcd-framework">#</a></h2> <div class="outline-text-2" id="text-connecting-a-script-to-the-rc.d-framework">
 <p>
In a nutshell,
 <a href="https://www.freebsd.org/cgi/man.cgi?query=rcorder&sektion=8&format=html">rcorder</a>
takes a set of files, examines their contents, and prints a
dependency-ordered list of files from the set to stdout. The point is to
keep dependency information inside the files so that each file can speak
for itself only. A file can specify the following information:
</p>

 <ul class="org-ul"> <li>the names of the “conditions” (which means services to us) it provides
with  <code># KEYWORD</code>:</li>
 <li>the names of the “conditions” it requires with  <code># REQUIRE</code>:</li>
 <li>the names of the “conditions” this file should run before with
 <code># BEFORE</code>:</li>
 <li>additional keywords that can be used to select a subset from the whole
set of files (rcorder(8) can be instructed via options to include or
omit the files having particular keywords listed.) with  <code># KEYWORD</code>:</li>
</ul> <p>
As a rule of thumb, every custom made rc.d script should provide 1
daemon, and require  <code>DAEMON</code> and  <code>networking</code> to be initialized. Thus
the first lines of your rc.d script will generally look something like:
</p>

 <pre> <span class="org-comment-delimiter">#</span> <span class="org-comment">!/bin/</span> <span class="org-keyword">sh</span>
 <span class="org-comment-delimiter">#</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">PROVIDE: <name of this rc.d script></span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">REQUIRE: DAEMON networking</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">KEYWORD:</span></pre>
</div>
 <h2>Daemon load order  <a id="daemon-load-order" class="anchor" href="#daemon-load-order">#</a></h2> <div class="outline-text-2" id="text-daemon-load-order">
 <p>
The order in which the daemons load is highly important. For this
example, imagine you have an API application running with an rc.d script
called  <code>my_api_service</code>. It should run as a daemon and should be able to
access the network.
</p>

 <p>
This means that it should only load after  <code>DAEMON</code> and  <code>networking</code> are
loaded and running.
</p>

 <p>
You can verify the load order with:
</p>

 <pre class="example" id="orgd19f1f1">
service -e
</pre>

 <p>
The correct load order in this case then would be :
</p>

 <pre class="example" id="orgd387ac4">
service -e

/etc/rc.d/cleanvar
/etc/rc.d/ip6addrctl
/etc/rc.d/netif
/etc/rc.d/virecover
/etc/rc.d/motd
/etc/rc.d/os-release
/etc/rc.d/newsyslog
/etc/rc.d/syslogd
/etc/rc.d/my_api_service
/etc/rc.d/cron
</pre>
</div>
 <h2>Binaries as daemons  <a id="binaries-as-daemons" class="anchor" href="#binaries-as-daemons">#</a></h2> <div class="outline-text-2" id="text-binaries-as-daemons">
 <p>
In the case of binaries, we will use the daemon in a straightforward
manner. We will run our service as  <code>root</code> user since this will be
running inside a jail, where  <code>root</code> is the only existing user. Feel free
to adjust to your use case. By convention I always create a folder
called  <code>internalApplications</code> inside any jail, and place my binaries
inside there. See the example below for  <code>my_api_service</code>:
</p>

 <pre> <span class="org-comment-delimiter">#</span> <span class="org-comment">!/bin/</span> <span class="org-keyword">sh</span>
 <span class="org-comment-delimiter">#</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">PROVIDE: my_api_service</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">REQUIRE: DAEMON networking</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">KEYWORD:</span>

 <span class="org-builtin">.</span> /etc/rc.subr

 <span class="org-variable-name">name</span>= <span class="org-string">"my_api_service"</span>
 <span class="org-variable-name">rcvar</span>= <span class="org-string">"my_api_service_enable"</span>
 <span class="org-variable-name">my_api_service_chdir</span>= <span class="org-string">"/root/internalApplications/myAPIWorkingDirectory/"</span>
 <span class="org-variable-name">my_api_service_user</span>= <span class="org-string">"root"</span>
 <span class="org-variable-name">my_api_service_command</span>= <span class="org-string">"/root/internalApplications/myAPIWorkingDirectory/app"</span>
 <span class="org-variable-name">pidfile</span>= <span class="org-string">"/var/run/${name}.pid"</span>
 <span class="org-variable-name">command</span>= <span class="org-string">"/usr/sbin/daemon"</span>
 <span class="org-variable-name">command_args</span>= <span class="org-string">"-P ${pidfile} -r -f -S ${my_api_service_command}"</span>

load_rc_config $ <span class="org-variable-name">name</span>
: ${ <span class="org-variable-name">my_api_service_enable</span>:=no}

run_rc_command  <span class="org-string">"$1"</span></pre>
</div>
 <h2>Shell scripts as daemons  <a id="shell-scripts-as-daemons" class="anchor" href="#shell-scripts-as-daemons">#</a></h2> <div class="outline-text-2" id="text-shell-scripts-as-daemons">
 <p>
Shell scripts that run utilities can also be daemonized. See the example
below:
</p>

 <pre> <span class="org-comment-delimiter">#</span> <span class="org-comment">!/bin/</span> <span class="org-keyword">sh</span>

 <span class="org-comment-delimiter"># </span> <span class="org-comment">PROVIDE: my_script_service</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">REQUIRE: DAEMON networking</span>
 <span class="org-comment-delimiter"># </span> <span class="org-comment">KEYWORD:</span>
 <span class="org-builtin">.</span> /etc/rc.subr

 <span class="org-variable-name">name</span>= <span class="org-string">"my_script_service"</span>
 <span class="org-variable-name">rcvar</span>= <span class="org-string">"my_script_service_enable"</span>
 <span class="org-variable-name">my_script_service_user</span>= <span class="org-string">"root"</span>
 <span class="org-variable-name">pidfile</span>= <span class="org-string">"/var/run/${name}.pid"</span>
 <span class="org-variable-name">my_script_service_command</span>= <span class="org-string">"/root/internalApplications/my-script.sh"</span>
 <span class="org-variable-name">command</span>= <span class="org-string">"/usr/sbin/daemon"</span>
 <span class="org-variable-name">command_args</span>= <span class="org-string">"-P ${pidfile} -r -f -S ${my_script_service_command}"</span>

load_rc_config $ <span class="org-variable-name">name</span>
: ${ <span class="org-variable-name">my_script_service_enable</span>:=no}

run_rc_command  <span class="org-string">"$1"</span></pre>

 <p>
Hopefully you have become a little wiser about rc.d scripting and can
“daemonize” anything that comes your way :)
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/freebsd/rcd-scripting/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/freebsd/rcd-scripting/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Root on ZFS with partitions</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
It is important to have a clean separation of concerns, both in your
code, as in your machine’s setup. If you are looking for information on
how to get a ZFS FreeBSD setup on one hard-drive with multiple
partitions, this is what you want.
</p>

 <p>
This guide assumes you want to install FreeBSD and manually create the
ZFS pool, to change default settings, or to not use the entire disk.
</p>

 <p>
If you just want to setup ZFS on the entire disk, use the ’ZFS’ option
in the bsdinstall partitioning menu.
</p>

 <ol class="org-ol"> <li>Boot FreeBSD install DVD or USB Memstick</li>
 <li>Select Install, and answer questions such as keyboard layout and
hostname</li>
 <li>When prompted to partition the disk, choose the  <code>shell</code> option. In
this mode you are expected to create a root file system mounted under
 <code>/mnt</code> that the installer will install the operating system into.</li>
</ol> <p>
Now to the installation steps, start by determining which disks you wish
to use:
</p>

 <pre>camcontrol devlist
 <span class="org-comment-delimiter"># </span> <span class="org-comment">or alternatively</span>
geom disk list</pre>

 <p>
That should return something like
 <code>TOSHIBA HDWN180 GX2M at scbus7 target 0 lun 0 (ada0,pass1)</code>
</p>

 <p>
SATA disks usually start with ada, followed by a number. SAS and USB
disks start with da, followed by a number. The rest of this page assumes
the disk is  <code>ada0</code>, replace it with your disk devices name in all
commands below.
</p>

 <p>
Proceed to create a fresh partition table, erasing ALL data on the
disk!:
</p>

 <pre> <span class="org-comment-delimiter"># </span> <span class="org-comment">The first command is not needed if you are working on an empty new disk</span>
gpart destroy ada0
gpart create -s gpt ada0</pre>

 <p>
Then create the boot code partition:
</p>

 <p>
for Legacy Boot:
</p>

 <pre> <span class="org-comment-delimiter"># </span> <span class="org-comment">Confirmed working on FreeBSD 13</span>
gpart add -a 4k -s 512K -t freebsd-boot ada0
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada0</pre>

 <p>
for UEFI Boot we will need more space and some more manual steps:
</p>

 <pre> <span class="org-comment-delimiter"># </span> <span class="org-comment">Confirmed working on FreeBSD 13</span>
gpart add -t efi -s 40M ada0
newfs_msdos -F 32 -c 1 /dev/ada0p1
mount -t msdosfs /dev/ada0p1 /mnt
mkdir -p /mnt/EFI/BOOT
cp /boot/loader.efi /mnt/EFI/BOOT/BOOTX64.efi
umount /mnt</pre>

 <p>
We will now be creating the needed partitions to setup the system as we
wish. I will be working with a 20GB hard drive, which I want to split in
3 partitions. 2GB for Swap, 10 GB for the FreeBSD installation and the
remaining (8GB) for the Jails storage, in a secondary pool which will
later be created.
</p>

 <p>
Note that while a ZFS Swap Volume can be used instead of the
freebsd-swap partition, it is not recommended, and crash dumps can’t be
saved to the ZFS Swap Volume.
</p>

 <p>
Some of the  <code>gpart</code> options explained: *  <code>-a {number}</code>: controls
alignment. *  <code>-s {size}</code>: sets the size of the partition, if not set, it
will default to the remaining space on the disk. *  <code>-l {name}</code>: sets the
label for the partition
</p>

 <pre>gpart add -a 1m -s 4G -t freebsd-swap -l swap0 ada0
gpart add -a 1m -s 10G -t freebsd-zfs -l disk0 ada0
gpart add -a 1m -t freebsd-zfs -l disk1 ada0</pre>

 <p>
Find the device for the freebsd-zfs partition created above with
 <code>gpart show -p ada0</code>
</p>

 <pre>=>      40  41942960  ada0  GPT  (20G)
        40      1024    1  freebsd-boot  (512K)
        1064       984       - free -  (492K)
        2048   4194304    2  freebsd-swap  (2.0G)
        4196352  20971520    3  freebsd-zfs  (10G)
        25167872  16773120    4  freebsd-zfs  (8.0G)
        41940992      2008       - free -  (1.0M)</pre>

 <p>
Our FreeBSD installation will be on  <code>ada0p3</code>.
</p>

 <p>
For proceeding with the install we will mount a  <code>tmpfs</code> filesystem to
 <code>/mnt</code> with:
</p>

 <pre>mount -t tmpfs tmpfs /mnt</pre>

 <p>
We will assume zroot as the name of the ystem’s  <code>zpool</code>, it could be
anything (i.e. tank, data, mypool), and to create it we do:
</p>

 <pre>zpool create -o  <span class="org-variable-name">altroot</span>=/mnt zroot ada0p3</pre>

 <p>
We will use the lz4 compression algorithm, since it is fast enough to be
used by default, even for uncompressible data. It can be enabled with:
</p>

 <pre>zfs set  <span class="org-variable-name">compress</span>=on zroot</pre>

 <p>
We will then create a Boot Environment hierarchy with:
</p>

 <pre>zfs create -o  <span class="org-variable-name">mountpoint</span>=none zroot/ROOT
zfs create -o  <span class="org-variable-name">mountpoint</span>=/ -o  <span class="org-variable-name">canmount</span>=noauto zroot/ROOT/default
mount -t zfs zroot/ROOT/default /mnt</pre>

 <p>
and then proceed to create the rest of filesystems required for FreeBSD
to be installed to this ZFS Pool:
</p>

 <pre>zfs create -o  <span class="org-variable-name">mountpoint</span>=/tmp -o  <span class="org-variable-name">exec</span>=on -o  <span class="org-variable-name">setuid</span>=off zroot/tmp
zfs create -o  <span class="org-variable-name">canmount</span>=off -o  <span class="org-variable-name">mountpoint</span>=/usr zroot/usr
zfs create zroot/usr/home
zfs create -o  <span class="org-variable-name">exec</span>=off -o  <span class="org-variable-name">setuid</span>=off zroot/usr/src
zfs create zroot/usr/obj
zfs create -o  <span class="org-variable-name">mountpoint</span>=/usr/ports -o  <span class="org-variable-name">setuid</span>=off zroot/usr/ports
zfs create -o  <span class="org-variable-name">exec</span>=off -o  <span class="org-variable-name">setuid</span>=off zroot/usr/ports/distfiles
zfs create -o  <span class="org-variable-name">exec</span>=off -o  <span class="org-variable-name">setuid</span>=off zroot/usr/ports/packages
zfs create -o  <span class="org-variable-name">canmount</span>=off -o  <span class="org-variable-name">mountpoint</span>=/var zroot/var
zfs create -o  <span class="org-variable-name">exec</span>=off -o  <span class="org-variable-name">setuid</span>=off zroot/var/audit
zfs create -o  <span class="org-variable-name">exec</span>=off -o  <span class="org-variable-name">setuid</span>=off zroot/var/crash
zfs create -o  <span class="org-variable-name">exec</span>=off -o  <span class="org-variable-name">setuid</span>=off zroot/var/log
zfs create -o  <span class="org-variable-name">atime</span>=on -o  <span class="org-variable-name">exec</span>=off -o  <span class="org-variable-name">setuid</span>=off zroot/var/mail
zfs create -o  <span class="org-variable-name">exec</span>=on -o  <span class="org-variable-name">setuid</span>=off zroot/var/tmp</pre>

 <p>
then we will set a symlink to home, and set the correct permissions
with:
</p>

 <pre>ln -s /usr/home /mnt/home
chmod 1777 /mnt/var/tmp
chmod 1777 /mnt/tmp</pre>

 <p>
We can then finalize the zpool creation, by setting the boot environment
configuration:
</p>

 <pre>zpool set  <span class="org-variable-name">bootfs</span>=zroot/ROOT/default zroot</pre>

 <p>
To finish the installation, we will create a new entry in the  <code>fstab</code> of
the installer, which later will be stored in our system. Now is your
opportunity to attach other devices if needed as well, but for this
tutorial, simply adding the swap is enough:
</p>

 <pre>cat << EOF > /tmp/bsdinstall_etc/fstab
 <span class="org-sh-heredoc"># Device Mountpoint FStype Options Dump Pass#</span>
 <span class="org-sh-heredoc">/dev/gpt/swap0 none swap sw 0 0</span>
 <span class="org-sh-heredoc">EOF</span></pre>

 <p>
We can then  <code>exit</code> the shell Partitioning mode, at which point
bsdinstall will continue and complete the installation.
</p>

 <p>
In the post installation step, when asked if you would like to drop into
the installed system, choose yes, and execute the following:
</p>

 <pre>sysrc  <span class="org-variable-name">zfs_enable</span>= <span class="org-string">"YES"</span>
 <span class="org-builtin">echo</span>  <span class="org-variable-name">zfs_load</span>= <span class="org-string">"YES"</span> >> /boot/loader.conf</pre>

 <p>
You are now ready to reboot into your newly installed FreeBSD system.
Simply type  <code>exit</code> at the current prompt, and eject the installation
media, when the machine restarts.
</p>
 <h2>Welcome to the magical world of FreeBSD!  <a id="welcome-to-the-magical-world-of-freebsd" class="anchor" href="#welcome-to-the-magical-world-of-freebsd">#</a></h2> <div class="outline-text-2" id="text-welcome-to-the-magical-world-of-freebsd">
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/freebsd/root-on-zfs-with-partitions/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/freebsd/root-on-zfs-with-partitions/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Running PostgreSQL on FreeBSD</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
PostgreSQL or Postgres is a powerful object-relational high-performance
database management system (ORDBMS) published under a flexible BSD-style
license. PostgreSQL is well suited for large databases and has many
advanced features.
</p>

 <p>
In this tutorial, I will show you how to install and configure a
PostgreSQL database server on FreeBSD. We will install the latest
version of PostgreSQL 11 on the FreeBSD 12.0 system.
</p>
 <h2>Prerequisites  <a id="prerequisites" class="anchor" href="#prerequisites">#</a></h2> <div class="outline-text-2" id="text-prerequisites">
 <p>
For this guide, we will use FreeBSD 12 with 2 GB of RAM memory and 2
CPUs. If you have a large deployment, you will need more than that. You
will also need the root privileges for package installation.
</p>
</div>
 <h2>Update and Upgrade Packages  <a id="update-and-upgrade-packages" class="anchor" href="#update-and-upgrade-packages">#</a></h2> <div class="outline-text-2" id="text-update-and-upgrade-packages">
 <p>
Firstly, we will update the packages repositories and upgrade all
packages to the latest version using the  <code>pkg</code> package management tool
for FreeBSD.
</p>

 <pre>pkg update
pkg upgrade</pre>
</div>
 <h2>Install PostgreSQL 11  <a id="install-postgresql-11" class="anchor" href="#install-postgresql-11">#</a></h2> <div class="outline-text-2" id="text-install-postgresql-11">
 <p>
In this step, we’re going to install the latest stable version
PostgreSQL 11. By default, the FreeBSD repository provides multiple
versions of PostgreSQL package. You can use the following command to
check all available version of PostgreSQL packages.
</p>

 <pre>pkg search postgresql</pre>

 <p>
You will get multiple versions of PostgreSQL database server.
</p>

 <p>
Now install the PostgreSQL 11 package using the command below.
</p>

 <pre>pkg install postgresql11-server postgresql11-client</pre>

 <p>
Next, we need to add the PostgreSQL service to the system boot and
initialize the database before starting the service. Add the PostgreSQL
to the system boot using the command below.
</p>

 <pre>sysrc  <span class="org-variable-name">postgresql_enable</span>=yes</pre>

 <p>
Now initialize the PostgreSQL database, and then start the service,
using the following commands
</p>

 <pre>/usr/local/etc/rc.d/postgresql initdb
service postgresql start
service postgresql status</pre>

 <p>
Verify the output of the last command gives a similar output:
</p>

 <pre>root@bsdstation:/home/joe  <span class="org-comment-delimiter"># </span> <span class="org-comment">service postgresql status</span>
pg_ctl: server is running (PID: 1122)
/usr/local/bin/postgres  <span class="org-string">"-D"</span>  <span class="org-string">"/var/db/postgres/data11"</span></pre>

 <p>
The PostgreSQL service is up and running on FreeBSD 12.0. Additionally
you can check the system port used by the PostgreSQL service using the
sockstat command below. You should get the port  <code>5432</code> is used by the
PostgreSQL service.
</p>

 <pre>sockstat -l4 -P tcp</pre>
</div>
 <h2>Configure PostgreSQL Authentication  <a id="configure-postgresql-authentication" class="anchor" href="#configure-postgresql-authentication">#</a></h2> <div class="outline-text-2" id="text-configure-postgresql-authentication">
 <p>
In this step, we’re going to set up the authentication method for
PostgreSQL. PostgreSQL supports different authentication methods such as
trust authentication (default), password-based authentication, Kerberos,
GSSAPI, LDAP, RADIUS, and PAM. For this guide, we’re going to set up the
password-based authentication using MD5. Go to the
 <code>/var/db/postgresql/data11</code> directory, edit the  <code>pg_hba.conf</code> file using
a text editor.
</p>

 <pre> <span class="org-builtin">cd</span> /var/db/postgres/data11
vi pg_hba.conf</pre>

 <p>
Now change the authentication method for all local connection to  <code>md5</code>
as below, and add a line to allow external access to the database if
needed.
</p>

 <pre> <span class="org-comment-delimiter"># </span> <span class="org-comment">TYPE  DATABASE        USER            ADDRESS                 METHOD</span>

 <span class="org-comment-delimiter"># </span> <span class="org-comment">"local" is for Unix domain socket connections only</span>
 <span class="org-builtin">local</span>   all             all                                     trust
 <span class="org-comment-delimiter"># </span> <span class="org-comment">IPv4 local connections:</span>
host    all             all             127.0.0.1/32            md5
 <span class="org-comment-delimiter"># </span> <span class="org-comment">IPv6 local connections:</span>
host    all             all             ::1/128                 md5
 <span class="org-comment-delimiter"># </span> <span class="org-comment">External connections</span>
host    all             all             192.168.66.1/32         md5</pre>

 <p>
Save and close the file, and then restart the PostgreSQL service,
enabling the password-based authentication using  <code>md5</code> for the
PostgreSQL server.
</p>

 <pre>service postgresql restart</pre>
</div>
 <h2>Setup New User and Database  <a id="setup-new-user-and-database" class="anchor" href="#setup-new-user-and-database">#</a></h2> <div class="outline-text-2" id="text-setup-new-user-and-database">
 <p>
In this step, we’re going to set up a new user and database on
PostgreSQL. We’re going to create a new password for default user
 <code>postgres</code>, and create a new user and database. Log in to the ’postgres’
user using the command below.
</p>

 <pre>su - postgres</pre>

 <p>
Now login to the interactive PostgreSQL shell  <code>psql</code>.
</p>

 <pre>psql</pre>

 <p>
Then create a new password for the  <code>postgres</code> user.
</p>

 <pre>\password postgres
TYPE THE PASSWORD</pre>

 <p>
Next, we will create a new user called  <code>joe</code> with the database  <code>joe_db</code>.
And the give privileges for the user to the database by running the
following queries.
</p>

 <pre> <span class="org-keyword">CREATE</span> DATABASE joe_db;
 <span class="org-keyword">CREATE</span>  <span class="org-builtin">USER</span> joe  <span class="org-keyword">WITH</span> ENCRYPTED PASSWORD  <span class="org-string">'password123#'</span>;
 <span class="org-keyword">GRANT</span>  <span class="org-keyword">ALL</span>  <span class="org-keyword">PRIVILEGES</span>  <span class="org-keyword">ON</span> DATABASE joe_db  <span class="org-keyword">TO</span> joe;</pre>

 <p>
You can now exit from the PostgreSQL interactive shell with  <code>\q</code>. As a
result, the password for the default  <code>postgres</code> user has been created.
And the new user and database have been set up.
</p>
</div>
 <h2>Testing connection  <a id="testing-connection" class="anchor" href="#testing-connection">#</a></h2> <div class="outline-text-2" id="text-testing-connection">
 <p>
Log in to the  <code>postgres</code> user and then run the  <code>psql</code> command to get
into the PostgreSQL interactive shell.
</p>

 <pre>su - postgres
psql</pre>

 <p>
Show list users and database on the PostgreSQL server using the
following queries. You will get the new user  <code>joe</code> and the database
 <code>joe_db</code> on the result.
</p>

 <pre>\du
\l</pre>

 <p>
Type  <code>\q</code> to exit from the psql shell. Next, we will log in using the
created user  <code>joe</code> to the database  <code>joe_db</code> using the command below.
</p>

 <pre>psql -U joe -d joe_db -W</pre>

 <p>
Type the  <code>joe</code> password to continue. Now we will proceed to create a new
table  <code>user_table</code> and insert some data into it.
</p>

 <pre> <span class="org-keyword">CREATE</span>  <span class="org-keyword">TABLE</span>  <span class="org-function-name">user_table</span> (id  <span class="org-type">INT</span>,  <span class="org-keyword">name</span> TEXT, site TEXT);
 <span class="org-keyword">INSERT</span>  <span class="org-keyword">INTO</span> user_table (id,  <span class="org-keyword">name</span>, site)  <span class="org-keyword">VALUES</span> ( 1 ,  <span class="org-string">'Joe the Man'</span>,  <span class="org-string">'jjbigorra.netlify.app'</span>);</pre>

 <p>
Show content of tables using the following query.
</p>

 <pre> <span class="org-keyword">SELECT</span> *  <span class="org-keyword">FROM</span> user_table;</pre>

 <p>
Finally, the installation and configuration of PostgreSQL 11 on the
FreeBSD 12.0 system has been completed successfully.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/freebsd/running-postgresql-on-freebsd/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/freebsd/running-postgresql-on-freebsd/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Updating FreeBSD in iocage</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
In this document we will explain how to migrate to a newer FreeBSD
version both on hosts and on jails.
</p>

 <p>
You can always refer to
 <a href="https://docs.freebsd.org/en/books/handbook/cutting-edge/">Chapter 24:
Updating and Upgrading FreeBSD</a> for more detailed information.
</p>
 <h2>Updating the host  <a id="updating-the-host" class="anchor" href="#updating-the-host">#</a></h2> <div class="outline-text-2" id="text-updating-the-host">
 <p>
FreeBSD is known for being reliable and to be painlessly upgradeable,
even with custom setups, like I do, with manual partitioning, ZFS on
root, FreeBSD can handle this easily.
</p>

 <p>
We should start by evaluating the current version we have installed,
with:
</p>

 <pre>uname -mrs</pre>

 <p>
which in my case renders  <code>FreeBSD 12.2-RELEASE amd64</code>.
</p>

 <p>
We should make sure you apply all existing pending updates for FreeBSD
12.x:
</p>

 <pre>sudo freebsd-update fetch
sudo freebsd-update install
sudo pkg update
sudo pkg upgrade</pre>

 <p>
Make sure to have a snapshot of the machine or VMWare snapshot for a VM.
</p>

 <p>
Once all updates are installed, we can then proceed to do the upgrade
(in this case to  <code>13.0-RELEASE</code>):
</p>

 <pre>sudo freebsd-update -r 13.0-RELEASE upgrade</pre>

 <p>
After that process is done, which may take a while, you will get
prompted
</p>

 <pre class="example" id="orgfca4aa7">
To install the downloaded upgrades, run "/usr/sbin/freebsd-update install"
</pre>

 <p>
You should thus run:
</p>

 <pre>sudo /usr/sbin/freebsd-update install</pre>

 <p>
Then reboot the machine, then run again:
</p>

 <pre>sudo /usr/sbin/freebsd-update install</pre>

 <p>
Then you should perform a second reboot and you will have a system with
the new OS but old packages.
</p>

 <p>
Your  <code>/etc/resolv.conf</code> might be overriden during the update. Make sure
to check this.
</p>

 <p>
The next logical step to follow, after the last reboot, is to upgrade
all packages of the system, once again with:
</p>

 <pre>sudo pkg update
sudo pkg upgrade</pre>

 <p>
Once all software is up-to-date, run again:
</p>

 <pre>sudo /usr/sbin/freebsd-update install</pre>

 <p>
and another reboot is recommended.
</p>
</div>
 <h2>Updating jails  <a id="updating-jails" class="anchor" href="#updating-jails">#</a></h2> <div class="outline-text-2" id="text-updating-jails">
 <p>
Even though this is a low-risk process, for production systems that
cannot allow any downtime it is recommended to simply create a new jail
with the new release, and switch traffic to the new jail. This requires
more work, but will be safer, and is a benefit of having a jailed
environment.
</p>

 <p>
Upon a successful update of your host’s system, any of your existing
jails will still be using the release where you created them. Ideally
you should always keep your jails to the same major release as your
host.
</p>

 <p>
You can get an overview of your jails with:
</p>

 <pre>sudo iocage list</pre>

 <p>
You should pre-fetch the wanted release files, which will then be
available for all upgrades and for any new jails you might want to
create with said version.
</p>

 <pre class="example" id="org7c2bf1e">
sudo iocage fetch -r 13.0-RELEASE
</pre>

 <p>
If the machine you are working on contains many jails, you should likely
open several SSH sessions and upgrade the jails in parallel, of course
at the cost of CPU & RAM usage.
</p>

 <p>
In order to upgrade a jail’s FreeBSD version you should run:
</p>

 <pre>sudo iocage upgrade <name of your jail> -r 13.0-RELEASE</pre>

 <p>
then we must update all packages within the jail:
</p>

 <pre>sudo iocage pkg <name of your jail> update
sudo iocage pkg <name of your jail> upgrade -y</pre>

 <p>
it is recommendable to restart the jail after the procedure:
</p>

 <pre>sudo iocage restart <name of your jail></pre>
</div>
 <h2>Cleaning up  <a id="cleaning-up" class="anchor" href="#cleaning-up">#</a></h2> <div class="outline-text-2" id="text-cleaning-up">
 <p>
It is highly recommendable to cleanup your system after verifying
everything is stable and in order. Several files, backups and rollbacks
can then be deleted, often saving 8GB+ of space. There are several handy
tricks to be able to clean a FreeBSD machine and shave some disk GB.
</p>

 <p>
You can do some cleanup by removing the fetched pkg files, both on your
host
</p>

 <pre>sudo pkg clean</pre>

 <p>
and on your jails:
</p>

 <pre>sudo iocage pkg <your jail> clean -y</pre>

 <p>
You can check the current allocated size for zpools by running:
</p>

 <pre class="example" id="orgec5fd76">
zpool list

NAME     SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
iocage  19.5G  13.5G  5.97G        -         -    66%    69%  1.00x    ONLINE  -
zroot   17.5G  3.72G  13.8G        -         -    23%    21%  1.00x    ONLINE  -
</pre>

 <p>
You can check which zfs file systems are currently taking more space
with:
</p>

 <pre class="example" id="org7dcb49d">
zfs list

NAME                                       USED  AVAIL     REFER  MOUNTPOINT
iocage                                    13.5G  5.38G       24K  /iocage
iocage/iocage                             13.5G  5.38G     29.5K  /iocage/iocage
iocage/iocage/download                     803M  5.38G       24K  /iocage/iocage/download
iocage/iocage/download/12.2-RELEASE        402M  5.38G      402M  /iocage/iocage/download/12.2-RELEASE
iocage/iocage/download/13.0-RELEASE        401M  5.38G      401M  /iocage/iocage/download/13.0-RELEASE
iocage/iocage/images                        24K  5.38G       24K  /iocage/iocage/images
iocage/iocage/jails                       10.5G  5.38G       24K  /iocage/iocage/jails
iocage/iocage/jails/elk-d                 4.19G  5.38G     25.5K  /iocage/iocage/jails/elk-d
iocage/iocage/jails/elk-d/root            4.19G  5.38G     4.51G  /iocage/iocage/jails/elk-d/root
iocage/iocage/jails/jaeger-d              4.00G  5.38G     25.5K  /iocage/iocage/jails/jaeger-d
iocage/iocage/jails/jaeger-d/root         4.00G  5.38G     4.32G  /iocage/iocage/jails/jaeger-d/root
iocage/iocage/jails/web-server-d          2.26G  5.38G     25.5K  /iocage/iocage/jails/web-server-d
iocage/iocage/jails/web-server-d/root     2.26G  5.38G     2.57G  /iocage/iocage/jails/web-server-d/root
iocage/iocage/log                           28K  5.38G       28K  /iocage/iocage/log
iocage/iocage/releases                    2.26G  5.38G       24K  /iocage/iocage/releases
iocage/iocage/releases/12.2-RELEASE       1.20G  5.38G       24K  /iocage/iocage/releases/12.2-RELEASE
iocage/iocage/releases/12.2-RELEASE/root  1.20G  5.38G     1.20G  /iocage/iocage/releases/12.2-RELEASE/root
iocage/iocage/releases/13.0-RELEASE       1.06G  5.38G       24K  /iocage/iocage/releases/13.0-RELEASE
iocage/iocage/releases/13.0-RELEASE/root  1.06G  5.38G     1.06G  /iocage/iocage/releases/13.0-RELEASE/root
iocage/iocage/templates                     24K  5.38G       24K  /iocage/iocage/templates
zroot                                     3.72G  13.2G       24K  /zroot
zroot/ROOT                                3.23G  13.2G       24K  none
zroot/ROOT/default                        3.23G  13.2G     3.23G  /
zroot/tmp                                 26.5K  13.2G     26.5K  /tmp
zroot/usr                                  497M  13.2G       24K  /usr
zroot/usr/home                            3.50M  13.2G     3.50M  /usr/home
zroot/usr/obj                               24K  13.2G       24K  /usr/obj
zroot/usr/ports                             72K  13.2G       24K  /usr/ports
zroot/usr/ports/distfiles                   24K  13.2G       24K  /usr/ports/distfiles
zroot/usr/ports/packages                    24K  13.2G       24K  /usr/ports/packages
zroot/usr/src                              493M  13.2G      493M  /usr/src
zroot/var                                  259K  13.2G       24K  /var
zroot/var/audit                             24K  13.2G       24K  /var/audit
zroot/var/crash                             24K  13.2G       24K  /var/crash
zroot/var/log                              135K  13.2G      135K  /var/log
zroot/var/mail                              28K  13.2G       28K  /var/mail
zroot/var/tmp                               24K  13.2G       24K  /var/tmp
</pre>

 <p>
By looking at the above output you can see we have both the 12.2-RELEASE
and 13.0-RELEASE versions of FreeBSD saved in our machine. In our case,
we have successfully upgraded to 13.0-RELEASE and thus can remove all
files stored related to 12.2-RELEASE. We can do this by simply removing
the zfs dataset containing the 12.2-RELEASE download:
</p>

 <pre>sudo zfs destroy -r iocage/iocage/download/12.2-RELEASE</pre>

 <p>
Be extremely wary when running this command and ask someone more
experienced if you are doubting!
</p>

 <p>
We also can then clean the freebsd-update remaining files by removing
the rollback and creating a new empty folder:
</p>

 <pre>sudo rm -rf /var/db/freebsd-update/files
sudo mkdir /var/db/freebsd-update/files
sudo chmod 755 /var/db/freebsd-update/files</pre>

 <p>
This should also be done in the jails if you upgraded them:
</p>

 <pre>sudo iocage exec <your jail> rm -rf /var/db/freebsd-update/files
sudo iocage exec <your jail> mkdir /var/db/freebsd-update/files
sudo iocage exec <your jail> chmod 755 /var/db/freebsd-update/files</pre>

 <p>
When you update to a new major version you might end up keeping old
datasets lying around. These can be seen like above in the output of zfs
list.
</p>

 <p>
Very likely at  <code>iocage/iocage/releases/12.2-RELEASE</code> and
 <code>iocage/iocage/releases/12.2-RELEASE/root</code>.
</p>

 <p>
We must first find the “cloned” datasets with:
</p>

 <pre>sudo zfs list -t snapshot -o name,clones</pre>

 <p>
which outputs something like:
</p>

 <pre class="example" id="org3a552c4">
NAME                                                  CLONES
iocage/iocage/releases/12.2-RELEASE/root@database     iocage/iocage/jails/database/root
iocage/iocage/releases/12.2-RELEASE/root@cache-store  iocage/iocage/jails/cache-store/root
</pre>

 <p>
and then we can promote the clones to be the primary datasets for that
jail:
</p>

 <pre>sudo zfs promote iocage/iocage/jails/database/root
sudo zfs promote iocage/iocage/jails/cache-store/root</pre>

 <p>
The clones can be removed with:
</p>

 <pre>sudo zfs destroy iocage/iocage/releases/12.2-RELEASE/root
sudo zfs destroy iocage/iocage/releases/12.2-RELEASE</pre>

 <p>
After all the cleanup it is recommended to restart the machine and
verify it all works as expected.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/freebsd/updating-freebsd-in-iocage/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/freebsd/updating-freebsd-in-iocage/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>FreeBSD</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-12-02 do> </span></span>  <a href="/blog/articles/freebsd/rcd-scripting/index.html">rc.d scripting</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-09-17 vr> </span></span>  <a href="/blog/articles/freebsd/pkg-or-ports/index.html">pkg or ports ?</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-08-31 di> </span></span>  <a href="/blog/articles/freebsd/updating-freebsd-in-iocage/index.html">Updating FreeBSD in iocage</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-08-31 di> </span></span>  <a href="/blog/articles/freebsd/practical-rcd-scripting-and-go/index.html">Practical rc.d scripting and Go</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2020-11-19 do> </span></span>  <a href="/blog/articles/freebsd/jails-with-a-loopback-ip/index.html">Jails with a loopback IP</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2020-11-19 do> </span></span>  <a href="/blog/articles/freebsd/root-on-zfs-with-partitions/index.html">Root on ZFS with partitions</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2020-09-19 za> </span></span>  <a href="/blog/articles/freebsd/running-postgresql-on-freebsd/index.html">Running PostgreSQL on FreeBSD</a>
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/freebsd/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/freebsd/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Arch Linux UEFI + Encryption</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
This is a step by step guide to installing Arch Linux on UEFI with full
disk encryption. It deliberately contains no unnecessary words or bling.
It is heavily based on the Arch Linux wiki’s installation guide so if
you’re ever stuck, just refer to it and the rest of
 <a href="https://wiki.archlinux.org/">the awesome Arch wiki</a>.
</p>
 <h3>Download ISO  <a id="download-iso" class="anchor" href="#download-iso">#</a></h3> <div class="outline-text-3" id="text-download-iso">
 <p>
Download the latest ISO from  <a href="https://archlinux.org/download/">the Arch
Linux website</a>.
</p>
</div>
 <h3>Create Bootable USB Stick  <a id="create-bootable-usb-stick" class="anchor" href="#create-bootable-usb-stick">#</a></h3> <div class="outline-text-3" id="text-create-bootable-usb-stick">
 <p>
You can skip this step if you just want to run Arch Linux in a VM. In
that case, just run the ISO from your favorite VM management tool like
QEMU, VirtualBox or VMWare.
</p>

 <p>
Insert an USB stick into your computer and run  <code>lsblk</code> to find the
correct disk.
</p>

 <p>
Then run  <code>sudo umount /dev/sdx</code> or whatever your USB stick is named.
</p>

 <p>
Run
 <code>sudo dd bs=4M if=path/to/input.iso of=/dev/sdx oflag=sync status=progress</code>
to write the ISO to the USB stick. Don’t forget to replace the two paths
with the correct ones.
</p>

 <p>
Insert the USB stick into the target computer and boot it from there.
</p>

 <p>
As soon as you can see the Arch Linux prompt, you are ready for the next
step. If you don’t know how to boot from a USB stick on a computer, you
probably shouldn’t go for Arch Linux and its “do-it yourself” attitude.
</p>
</div>
 <h3>Check for UEFI support  <a id="check-for-uefi-support" class="anchor" href="#check-for-uefi-support">#</a></h3> <div class="outline-text-3" id="text-check-for-uefi-support">
 <p>
Run  <code>ls /sys/firmware/efi/efivars</code> to check if that directory exists.
</p>

 <p>
If it doesn’t, your system does not support UEFI and this guide is not
for you and you should refer to the official Arch Linux Installation
Guide for Legacy BIOS / MBR instead.
</p>
</div>
 <h3>Establish Connectivity  <a id="establish-connectivity" class="anchor" href="#establish-connectivity">#</a></h3> <div class="outline-text-3" id="text-establish-connectivity">
 <p>
Connect the computer via ethernet (recommended) or run  <code>iwctl</code> to log
into WiFi. Check for internet connectivity with  <code>ping archlinux.org</code>.
Once connected make sure the clock is synced with
 <code>timedatectl set-ntp true</code>.
</p>
</div>
 <h3>Partition  <a id="partition" class="anchor" href="#partition">#</a></h3> <div class="outline-text-3" id="text-partition">
 <p>
Check for different drives and partitions with  <code>lsblk</code> and then start to
partition with  <code>gdisk /dev/nvme0n1</code> (or whatever the disk is).
</p>

 <p>
Delete any existing partitions using  <code>d</code>.
</p>

 <p>
Create boot partition with  <code>n</code> with default number, default first
sector, last sector at  <code>+512M</code> and select  <code>ef00</code> “EFI System” as the
type.
</p>

 <p>
Create root partition with  <code>n</code> with default number, default first
sector, default last sector and select  <code>8300</code> “Linux filesystem” as the
type.
</p>

 <p>
Press  <code>w</code> to write partitions.
</p>

 <p>
Run  <code>lsblk</code> again to verify partitioning.
</p>
</div>
 <h3>Encrypt Root Partition  <a id="encrypt-root-partition" class="anchor" href="#encrypt-root-partition">#</a></h3> <div class="outline-text-3" id="text-encrypt-root-partition">
 <p>
Run  <code>cryptsetup -y -v luksFormat /dev/nvme0n1p2</code> and then type  <code>YES</code> and
the new encryption password to encrypt the root partition.
</p>

 <p>
Run  <code>cryptsetup open /dev/nvme0n1p2 cryptroot</code> to open the encrypted
partition.
</p>
</div>
 <h3>Create File Systems  <a id="create-file-systems" class="anchor" href="#create-file-systems">#</a></h3> <div class="outline-text-3" id="text-create-file-systems">
 <p>
Create the boot file system with  <code>mkfs.fat -F32 /dev/nvme0n1p1</code> (or
whatever the partition is called).
</p>

 <p>
Create the root file system with  <code>mkfs.ext4 /dev/mapper/cryptroot</code>.
</p>
</div>
 <h3>Mount File Systems  <a id="mount-file-systems" class="anchor" href="#mount-file-systems">#</a></h3> <div class="outline-text-3" id="text-mount-file-systems">
 <p>
Run  <code>mount /dev/mapper/cryptroot /mnt</code> to mount the root file system.
</p>

 <p>
Run  <code>mkdir /mnt/boot</code> to create the boot directory.
</p>

 <p>
Run  <code>mount /dev/nvme0n1p1 /mnt/boot</code> to mount your boot file system.
</p>

 <p>
Run  <code>lsblk</code> again to verify mounting.
</p>
</div>
 <h3>Create Swap File (not needed on VMs)  <a id="create-swap-file-not-needed-on-vms" class="anchor" href="#create-swap-file-not-needed-on-vms">#</a></h3> <div class="outline-text-3" id="text-create-swap-file-not-needed-on-vms">
 <p>
Run  <code>dd if=/dev/zero of=/mnt/swapfile bs=1M count=20576 status=progress</code>
to create the swap file where the count is the number of megabytes you
want the swap file to be (usually around 1.5 times the size of your
RAM).
</p>

 <p>
Run  <code>chmod 600 /mnt/swapfile</code> to set the right permissions on it.
</p>

 <p>
Run  <code>mkswap /mnt/swapfile</code> to make it an actual swap file.
</p>

 <p>
Run  <code>swapon /mnt/swapfile</code> to turn it on.
</p>
</div>
 <h3>Install Arch Linux  <a id="install-arch-linux" class="anchor" href="#install-arch-linux">#</a></h3> <div class="outline-text-3" id="text-install-arch-linux">
 <p>
Run  <code>pacstrap /mnt base base-devel linux linux-firmware neovim</code> to
install Arch Linux (linux-firmware is not needed on VMs).
</p>
</div>
 <h3>Generate File System Table  <a id="generate-file-system-table" class="anchor" href="#generate-file-system-table">#</a></h3> <div class="outline-text-3" id="text-generate-file-system-table">
 <p>
Run  <code>genfstab -U /mnt >> /mnt/etc/fstab</code> to generate fstab with UUIDs.
</p>
</div>
 <h3>Switch to Your New Linux Installation  <a id="switch-to-your-new-linux-installation" class="anchor" href="#switch-to-your-new-linux-installation">#</a></h3> <div class="outline-text-3" id="text-switch-to-your-new-linux-installation">
 <p>
Run  <code>arch-chroot /mnt</code> to switch to your new Arch Linux installation.
</p>
</div>
 <h3>Set Locales  <a id="set-locales" class="anchor" href="#set-locales">#</a></h3> <div class="outline-text-3" id="text-set-locales">
 <p>
Run  <code>ln -sf /usr/share/zoneinfo/Europe/Amsterdam /etc/localtime</code> (or
whatever your timezone is) to set your time zone.
</p>

 <p>
Run  <code>hwclock --systohc</code>.
</p>

 <p>
Run  <code>nvim /etc/locale.gen</code> and uncomment yours (e.g. en_US.UTF-8 UTF-8).
</p>

 <p>
Run  <code>locale-gen</code> to generate the locales.
</p>

 <p>
Run  <code>echo 'LANG=en_US.UTF-8' > /etc/locale.conf</code>.
</p>
</div>
 <h3>Set Hostname  <a id="set-hostname" class="anchor" href="#set-hostname">#</a></h3> <div class="outline-text-3" id="text-set-hostname">
 <p>
Run  <code>echo 'myHostname' > /etc/hostname</code> (or whatever your hostname
should be).
</p>

 <p>
Run  <code>nvim /etc/hosts</code> and insert the following lines:
</p>

 <pre class="example" id="orga6b7cc8">
127.0.0.1     localhost
::1           localhost
127.0.1.1     arch.localdomain        myHostname
</pre>

 <p>
for the last line: change  <code>myHostname</code> to whatever hostname you picked
in the previous step.
</p>
</div>
 <h3>Set Root Password  <a id="set-root-password" class="anchor" href="#set-root-password">#</a></h3> <div class="outline-text-3" id="text-set-root-password">
 <p>
Run  <code>passwd</code> and set your root password.
</p>
</div>
 <h3>Configure Initramfs  <a id="configure-initramfs" class="anchor" href="#configure-initramfs">#</a></h3> <div class="outline-text-3" id="text-configure-initramfs">
 <p>
Run  <code>nvim /etc/mkinitcpio.conf</code> and, to the  <code>HOOKS</code> array, add
 <code>keyboard</code> between  <code>autodetect</code> and  <code>modconf</code> and add  <code>encrypt</code> between
 <code>block</code> and  <code>filesystems</code>.
</p>

 <p>
Run  <code>mkinitcpio -P</code>.
</p>
</div>
 <h3>Install Boot Loader  <a id="install-boot-loader" class="anchor" href="#install-boot-loader">#</a></h3> <div class="outline-text-3" id="text-install-boot-loader">
 <p>
Run  <code>pacman -S grub efibootmgr intel-ucode</code> (or  <code>amd-ucode</code> if you have
an AMD processor) to install the GRUB package and CPU microcode.
</p>

 <p>
Run  <code>blkid -s UUID -o value /dev/nvme0n1p2</code> to get the UUID of the
device.
</p>

 <p>
Run  <code>nvim /etc/default/grub</code> and set  <code>GRUB_TIMEOUT=0</code> to disable GRUB
waiting until it chooses your OS (only makes sense if you don’t dual
boot with another OS), then set
 <code>GRUB_CMDLINE_LINUX</code>“cryptdevice=UUID=xxxx:cryptroot”= while replacing
 <code>xxxx</code> with the UUID of the  <code>nvme0n1p2</code> device to tell GRUB about our
encrypted file system.
</p>

 <p>
Run
 <code>grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB</code>
to install GRUB for your system.
</p>

 <p>
Run  <code>grub-mkconfig -o /boot/grub/grub.cfg</code> to configure GRUB.
</p>
</div>
 <h3>Install Network Manager  <a id="install-network-manager" class="anchor" href="#install-network-manager">#</a></h3> <div class="outline-text-3" id="text-install-network-manager">
 <p>
Run  <code>pacman -S networkmanager</code> to install NetworkManager.
</p>

 <p>
Run  <code>systemctl enable NetworkManager</code> to run NetworkManager at boot.
</p>
</div>
 <h3>Reboot  <a id="reboot" class="anchor" href="#reboot">#</a></h3> <div class="outline-text-3" id="text-reboot">
 <p>
Run  <code>exit</code> to return to the outer shell.
</p>

 <p>
Run  <code>reboot</code> to get out of the setup by restarting the machine.
</p>

 <p>
After the machine starts, remove the installation medium and you will
boot into Arch Linux from your HDD.
</p>
</div>
 <h3>Connect to WiFi (only needed if there’s no ethernet connection)  <a id="connect-to-wifi-only-needed-if-therersquos-no-ethernet-connection" class="anchor" href="#connect-to-wifi-only-needed-if-therersquos-no-ethernet-connection">#</a></h3> <div class="outline-text-3" id="text-connect-to-wifi-only-needed-if-theres-no-ethernet-connection">
 <p>
The use of  <code>nmcli</code> is prefered to  <code>iwctl</code> for reasons of simplicity and
user-friendliness.
</p>

 <p>
Run  <code>nmcli d wifi list</code> to list the available networks.
</p>

 <p>
Run  <code>nmcli d wifi connect MY_WIFI password MY_PASSWORD</code> to connect to
one of them.
</p>
</div>
 <h3>Add User  <a id="add-user" class="anchor" href="#add-user">#</a></h3> <div class="outline-text-3" id="text-add-user">
 <p>
Run  <code>EDITOR=nvim visudo</code> and uncomment  <code>%wheel ALL=(ALL) NOPASSWD: ALL</code>
to allow members of the  <code>wheel</code> group to run privileged commands.
</p>

 <p>
Run  <code>useradd --create-home --groups wheel,video joe</code> (or whatever your
user name should be) to create the user.
</p>

 <p>
Run  <code>passwd joe</code> to set your password.
</p>

 <p>
Run  <code>exit</code> and log back in with your new user.
</p>
</div>
 <h3>Install a Firewall  <a id="install-a-firewall" class="anchor" href="#install-a-firewall">#</a></h3> <div class="outline-text-3" id="text-install-a-firewall">
 <p>
Run  <code>sudo pacman -S nftables</code> to install the firewall
</p>

 <p>
Run  <code>sudo nvim /etc/nftables.conf</code> to edit the config to our liking and
remove the part about allowing incoming SSH connections if you don’t
need that.
</p>

 <p>
Run  <code>sudo systemctl enable nftables.service --now</code> to enable the
firewall.
</p>
</div>
 <h3>Enable Time Synchronization  <a id="enable-time-synchronization" class="anchor" href="#enable-time-synchronization">#</a></h3> <div class="outline-text-3" id="text-enable-time-synchronization">
 <p>
Run  <code>sudo systemctl enable systemd-timesyncd.service --now</code> to enable
automated time synchronization.
</p>
</div>
 <h3>Improve Power Management (only makes sense on laptops)  <a id="improve-power-management-only-makes-sense-on-laptops" class="anchor" href="#improve-power-management-only-makes-sense-on-laptops">#</a></h3> <div class="outline-text-3" id="text-improve-power-management-only-makes-sense-on-laptops">
 <p>
Run  <code>sudo pacman -S tlp tlp-rdw</code> to install TLP.
</p>

 <p>
Run  <code>sudo systemctl enable tlp.service --now</code> to run power optimizations
automatically.
</p>

 <p>
Run  <code>sudo systemctl enable NetworkManager-dispatcher.service --now</code> to
prevent conflicts.
</p>

 <p>
Run  <code>sudo tlp-stat</code> and follow any recommendations there.
</p>
</div>
 <h3>Enable Scheduled fstrim  <a id="enable-scheduled-fstrim" class="anchor" href="#enable-scheduled-fstrim">#</a></h3> <div class="outline-text-3" id="text-enable-scheduled-fstrim">
 <p>
This only makes sense for SSD.
</p>

 <p>
Run  <code>sudo systemctl enable fstrim.timer --now</code> to enable regular
housekeeping of your SSD.
</p>
</div>
 <h3>Enable Scheduled Mirrorlist Updates  <a id="enable-scheduled-mirrorlist-updates" class="anchor" href="#enable-scheduled-mirrorlist-updates">#</a></h3> <div class="outline-text-3" id="text-enable-scheduled-mirrorlist-updates">
 <p>
Run  <code>sudo pacman -S reflector</code> to install reflector.
</p>

 <p>
Run  <code>sudo nvim /etc/xdg/reflector/reflector.conf</code> and change the file to
your liking.
</p>

 <p>
Run=sudo systemctl enable reflector.timer –now= to enable running
reflector regularly.
</p>
</div>
 <h3>Reduce Swappiness  <a id="reduce-swappiness" class="anchor" href="#reduce-swappiness">#</a></h3> <div class="outline-text-3" id="text-reduce-swappiness">
 <p>
This only makes sense if you have more than 4GB of RAM.
</p>

 <p>
Run
 <code>echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.conf</code> to
reduce the swappiness permanently.
</p>
</div>
 <h3>The coolest Pacman  <a id="the-coolest-pacman" class="anchor" href="#the-coolest-pacman">#</a></h3> <div class="outline-text-3" id="text-the-coolest-pacman">
 <p>
If you want to make Pacman look cooler you can edit the configuration
file with  <code>sudo nvim /etc/pacman.conf</code> and uncomment the  <code>Color</code> option
and add just below the  <code>ILoveCandy</code> option.
</p>
</div>
 <h3>Installing Plasma DE  <a id="installing-plasma-de" class="anchor" href="#installing-plasma-de">#</a></h3> <div class="outline-text-3" id="text-installing-plasma-de">
 <p>
I personally choose for Plasma DE (KDE), but of course if you prefer
another setup now is the time to leave this guide. Hope you found it
useful.
</p>

 <p>
To install Plasma run
 <code>sudo pacman -S xorg plasma plasma-wayland-session kde-applications</code>.
This might take a while.
</p>

 <p>
Then enable auto-start at boot with
</p>

 <pre>sudo systemctl enable sddm.service
sudo systemctl enable NetworkManager.service</pre>

 <p>
And restart your machine with  <code>sudo reboot</code>.
</p>
</div>
 <h2>Welcome to the master race of Arch Linux  <a id="welcome-to-the-master-race-of-arch-linux" class="anchor" href="#welcome-to-the-master-race-of-arch-linux">#</a></h2> <div class="outline-text-2" id="text-welcome-to-the-master-race-of-arch-linux">
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/gnu-linux/arch-linux-uefi-encryption/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/gnu-linux/arch-linux-uefi-encryption/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Building Conky with Wayland Support on GNU Guix</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Conky is a lightweight system monitor that can display system statistics on the desktop. While it was originally built for X11, recent versions have added experimental Wayland support. Since I use GNU Guix and run a Wayland-based environment (Sway), I wanted to get Conky building with Wayland support. This post explains how I achieved that.
</p>

 <p>
Guix is a functional package manager that allows you to define software packages declaratively. Since Conky is not in the official Guix repository with Wayland support enabled, I created a custom package definition for it.
</p>

 <p>
Enabled Wayland Build Option: The  <code>-DBUILD_WAYLAND=ON</code> flag ensures Wayland support is compiled in.
</p>

 <p>
Added Required Dependencies: Added  <code>gperf</code> ,  <code>cairo</code>,  <code>pango</code>   <code>wayland</code> and  <code>wayland-protocols</code> to inputs.
</p>

 <p>
Since Conky was originally designed for X11, some adjustments are needed for Wayland:
</p>

 <p>
No own_window: In X11, Conky runs in its own window. On Wayland, it needs to be embedded into a compositor-specific layer.
</p>

 <p>
Use xwayland If Needed: Some features might require running Conky through XWayland.
</p>

 <p>
Wayland-Specific Patches: Some users have patched Conky to integrate better with Wayland. If needed, applying community patches might help.
</p>

 <p>
With a bit of tweaking, I got Conky running with Wayland on GNU Guix. While it’s still experimental, it works well enough for basic system monitoring. If you’re on a similar setup and want a lightweight system monitor, give this a try!
</p>

 <p>
Below a screenshot of how it runs in Sway, on Guix (SSS - Supreme Sexp System):
</p>


 <div id="orgd55a87a" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/static-assets/blog/img/conky-wayland/2025-02-17.png"></img></p>
</div>


 <p>
Below is the Guile Scheme code I used:
</p>

 <pre>( <span class="org-keyword">define-module</span> ( <span class="org-type">sss</span> packages conky)
   <span class="org-builtin">#:use-module</span> (guix packages)
   <span class="org-builtin">#:use-module</span> (guix utils)
   <span class="org-builtin">#:use-module</span> (guix download)
   <span class="org-builtin">#:use-module</span> (guix git-download)
   <span class="org-builtin">#:use-module</span> (guix build-system cmake)
   <span class="org-builtin">#:use-module</span> ((guix licenses)
                 <span class="org-builtin">#:prefix</span> license:)
   <span class="org-builtin">#:use-module</span> (gnu packages curl)
   <span class="org-builtin">#:use-module</span> (gnu packages fontutils)
   <span class="org-builtin">#:use-module</span> (gnu packages image)
   <span class="org-builtin">#:use-module</span> (gnu packages linux)
   <span class="org-builtin">#:use-module</span> (gnu packages freedesktop)
   <span class="org-builtin">#:use-module</span> (gnu packages gtk)
   <span class="org-builtin">#:use-module</span> (gnu packages lua)
   <span class="org-builtin">#:use-module</span> (gnu packages ncurses)
   <span class="org-builtin">#:use-module</span> (gnu packages pkg-config)
   <span class="org-builtin">#:use-module</span> (gnu packages gperf)
   <span class="org-builtin">#:use-module</span> (gnu packages pulseaudio)
   <span class="org-builtin">#:use-module</span> (gnu packages xorg))

( <span class="org-keyword">define-public</span>  <span class="org-function-name">sss-conky</span>
  (package
    (name  <span class="org-string">"conky"</span>)
    (home-page  <span class="org-string">"https://github.com/brndnmtthws/conky"</span>)
    (version  <span class="org-string">"1.22.0"</span>)
    (source
     (origin
       (method git-fetch)
       (uri (git-reference
             (url home-page)
             (commit (string-append  <span class="org-string">"v"</span> version))))
       (file-name (git-file-name name version))
       (sha256
        (base32  <span class="org-string">"08ggr2nks3g1lk5k9hlv9mzyzbxms6yamhw4ndhayhn6n9dzqsnx"</span>))))
    (build-system cmake-build-system)
    (arguments
     `( <span class="org-builtin">#:configure-flags</span> (list  <span class="org-string">"-DRELEASE=true"</span>  <span class="org-string">"-DBUILD_PULSEAUDIO=ON"</span>
                                <span class="org-string">"-DBUILD_WLAN=ON"</span>  <span class="org-string">"-DBUILD_TESTS=ON"</span>
                                <span class="org-string">"-DBUILD_WAYLAND=ON"</span>)
        <span class="org-builtin">#:phases</span> (modify-phases %standard-phases
                  (add-after 'unpack 'add-freetype-to-search-path
                    (lambda* ( <span class="org-builtin">#:key</span> inputs  <span class="org-builtin">#:allow-other-keys</span>)
                      (substitute*  <span class="org-string">"cmake/ConkyPlatformChecks.cmake"</span>
                        (( <span class="org-string">"set\\(INCLUDE_SEARCH_PATH"</span>)
                         (string-append  <span class="org-string">"set(INCLUDE_SEARCH_PATH "</span>
                                        (assoc-ref inputs  <span class="org-string">"freetype"</span>)
                                         <span class="org-string">"/include/freetype2 "</span>))) #t))
                  (replace 'install
                    (lambda* ( <span class="org-builtin">#:key</span> outputs  <span class="org-builtin">#:allow-other-keys</span>)
                      ( <span class="org-keyword">let*</span> ((out (assoc-ref outputs  <span class="org-string">"out"</span>))
                             (bin (string-append out  <span class="org-string">"/bin"</span>)))
                        (install-file  <span class="org-string">"src/conky"</span> bin)) #t)))))
    (inputs (list freetype
                  imlib2
                  libx11
                  libxdamage
                  libxext
                  cairo
                  libxft
                  libxi
                  libxinerama
                  pango
                  pulseaudio
                  lua
                  gperf
                  ncurses
                  wayland
                  wayland-protocols
                  curl
                  wireless-tools))
    (native-inputs (list pkg-config))
    (synopsis  <span class="org-string">"Lightweight system monitor for X"</span>)
    (description
      <span class="org-string">"Conky is a lightweight system monitor for X that displays operating</span>
 <span class="org-string">system statistics (CPU, disk, and memory usage, etc.) and more on the</span>
 <span class="org-string">desktop."</span>)
    (license license:gpl3+)))</pre>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/gnu-linux/conky-wayland-guix/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/gnu-linux/conky-wayland-guix/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>GNU Guix VM aarch64</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
One day, I decided on a whim to try Guix in a VM on a M3 Mac.
</p>

 <p>
It seemed like a good idea at the time, but I’d never used Guix before and it ended up being quite a grind to figure out how to get it running.
</p>

 <p>
The initial issue for me was that Guix doesn’t provide iso installer images for aarch64.
</p>

 <p>
Yes, you can build one yourself, but after I’d put in the time to figure out how to do that, though, the iso installer would just hang. The serial console would say
</p>


 <pre class="example" id="org7b4874e">
waiting for partition '31393730-3031-3031-3139-333333313833' to appear...
</pre>

 <p>
The Guix ISO installer didn’t work for me on aarch64. Making a qcow2 VM image or doing a manual install did work.
</p>

 <p>
I show a list of steps for getting Guix installed on an aarch64 VM on macOS, and include a small starter confguration file.
</p>

 <p>
It can be helpful to pull a specific commit of the distro that includes a working, precompiled kernel.
</p>

 <p>
Update the Guix package descriptions and basic packages:
</p>

 <pre class="example" id="org6ac7172">
user@debian:~$ guix pull
</pre>

 <p>
This will take a while.
</p>

 <p>
Create a Guix configuration file on the Debian system. It defines how your Guix install is set up and what it will initially contain.
</p>

 <p>
Put the following into a file called  <code>config.scm</code> on Debian:
</p>

 <pre class="example" id="orge9c94ac">
(use-modules (gnu))
(use-service-modules networking)
(use-package-modules certs)

(operating-system
  (host-name "guix")
  (timezone "Europe/Berlin")
  (locale "en_US.utf8")

  (bootloader (bootloader-configuration
                (bootloader grub-efi-bootloader)
                (targets '("/boot/efi"))))
  (kernel-arguments (list "console=ttyS0,115200"))
  (file-systems (append
          (list (file-system
                          (device "/dev/vda2")
                          (mount-point "/")
                          (type "ext4"))
                        (file-system
                          (device "/dev/vda1")
                          (mount-point "/boot/efi")
                          (type "vfat")))
                      %base-file-systems))

  (users (cons (user-account
                (name "yourname")
                (group "users")

                (supplementary-groups '("wheel"
                                        "audio" "video")))
               %base-user-accounts))

  (packages (append (list nss-certs) %base-packages))

  (services (append (list (service dhcp-client-service-type))
                    %base-services)))
</pre>

 <p>
This was adapted from the Guix  <code>bare-bones.tmpl</code> and  <code>lightweight-desktop.tmpl</code> files.
</p>

 <p>
Build a Guix VM image. This will be the qemu hard drive for your Guix VM.
</p>

 <pre class="example" id="orga54fbf2">
guix system image --image-type=qcow2 --image-size=140G config.scm
</pre>

 <p>
This will take a while.
</p>

 <p>
At the end of the process, it will leave you with the name of a qcow2 image file:
</p>

 <pre class="example" id="orgfee8703">
/gnu/store/z08hk66ig6dn32ivvysphr0d2b0alym0-image.qcow2
</pre>

 <p>
Mine was 422Mb in size.
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/gnu-linux/gnu-guix-virtual-machine-image-aarch64/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/gnu-linux/gnu-guix-virtual-machine-image-aarch64/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title></title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <h2>Increase the file descriptor count  <a id="increase-the-file-descriptor-count" class="anchor" href="#increase-the-file-descriptor-count">#</a></h2> <div class="outline-text-2" id="text-orgac77032">
 <p>
Originally written by Marin Todorov.
</p>

 <p>
In Linux, you can change the maximum amount of open files. You may modify this number by using the ulimit command. It grants you the ability to control the resources available for the shell or process started by it.
</p>

 <p>
Read Also: Set Linux Running Processes Limits on Per-Userl Level
</p>

 <p>
In this short tutorial we will show you how to check your current limit of open files and files descriptions, but to do so, you will need to have root access to your system.
</p>

 <p>
First, Lets see how we can find out the maximum number of opened file descriptors on your Linux system.
Find Linux Open File Limit
</p>

 <p>
The value is stored in:
</p>

 <p>
818354
</p>

 <p>
The number you will see, shows the number of files that a user can have opened per login session. The result might be different depending on your system.
</p>

 <p>
For example on a CentOS server of mine, the limit was set to 818354, while on Ubuntu server that I run at home the default limit was set to 176772.
</p>

 <p>
If you want to see the hard and soft limits, you can use the following commands:
Check Hard Limit in Linux
</p>

 <p>
4096
</p>

 <p>
Check Soft Limits in Linux
</p>

 <p>
1024
</p>

 <p>
To see the hard and soft values for different users, you can simply switch user with “su” to the user which limits you want to check.
</p>

 <p>
For example:
</p>

 <p>
$ ulimit -Sn
</p>

 <p>
1024
</p>

 <p>
$ ulimit -Hn
</p>

 <p>
4096
</p>

 <p>
How to Check System wide File Descriptors Limits in Linux
</p>

 <p>
If you are running a server, some of your applications may require higher limits for opened file descriptors. A good example for such are MySQL/MariaDB services or Apache web server.
</p>

 <p>
You can increase the limit of opened files in Linux by editing the kernel directive fs.file-max. For that purpose, you can use the sysctl utility.
</p>

 <p>
Sysctl is used to configure kernel parameters at runtime.
</p>

 <p>
For example, to increase open file limit to 500000, you can use the following command as root:
</p>

 <p>
You can check the current value for opened files with the following command:
</p>

 <p>
$ cat /proc/sys/fs/file-max
</p>

 <p>
With the above command the changes you have made will only remain active until the next reboot. If you wish to apply them permanently, you will have to edit the following file:
</p>

 <p>
Add the following line:
</p>

 <p>
fs.file-max=500000
</p>

 <p>
Of course, you can change the number per your needs. To verify the changes again use:
</p>

 <p>
Users will need to logout and login again for the changes to take effect. If you want to apply the limit immediately, you can use the following command:
</p>

 <p>
Set User Level Open File limits in Linux
</p>

 <p>
The above examples, showed how to set global limits, but you may want to apply limits per user basis. For that purpose, as user root, you will need to edit the following file:
</p>

 <p>
If you are a Linux administrator, I suggest you that you become very familiar with that file and what you can do to it. Read all of the comments in it as it provides great flexibility in terms of managing system resources by limiting users/groups on different levels.
</p>

 <p>
The lines that you should add take the following parameters:
</p>

 <p>
<domain>        <type>  <item>  <value>
</p>

 <p>
Here is an example of setting a soft and hard limits for user marin:
</p>

 <p>
## Example hard limit for max opened files
marin        hard nofile 4096
## Example soft limit for max opened files
marin        soft nofile 1024
</p>

 <p>
Final thoughts
</p>

 <p>
This brief article showed you a basic example of how you can check and configure global and user level limits for maximum number of opened files.
</p>

 <p>
While we just scratched the surface, I highly encourage you to have a more detailed look and read regarding /etc/sysctl.conf and /etc/security/limits.conf and learn how to use them. They will be of great help for you one day.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/gnu-linux/increase-the-file-descriptor-limit-on-gnu-linux/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/gnu-linux/increase-the-file-descriptor-limit-on-gnu-linux/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Legendary Lisp Laptop - a modern Lisp machine with Framework laptop</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
For the past month or so, I’ve been running Guix system on my Framework laptop, turning it into what I like to call a modern Lisp machine.
</p>

 <p>
I have affectionately also started calling it a Legendary Lisp Laptop - LLL
</p>

 <p>
I chose the Framework Laptop 13,5" since it is big enough for me and it is really lightweight and portable. I mostly have external monitors anyway, at home and at work.
</p>
 <h2>Technical specifications  <a id="technical-specifications" class="anchor" href="#technical-specifications">#</a></h2> <div class="outline-text-2" id="text-org15e7a10">
 <ul class="org-ul"> <li>AMD Ryzen™ 5 7640U (up to 4.9GHz, 6-core/12-thread)</li>
 <li>Memory: DDR5-5600 - 32GB (2 x 16GB)</li>
 <li>Storage: WD_BLACK™ SN770 NVMe™- M.2 2280 - 1TB</li>
 <li>Battery - 55Wh</li>
 <li>Webcam Module (1st Gen)</li>
 <li>13.5" 2256x1504 60Hz matte display</li>
 <li>WiFi: RZ616 WiFi</li>
 <li>USB-C x2, USB-A, HDMI, Ethernet</li>
</ul> <p>
Below you can see the laptop before placing the keyboard, display bezel, SSD and RAM in. You can tell this is simple and easy to repair :)
</p>


 <div id="orgb163d51" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/static-assets/blog/img/lisp-machine-laptop/4.jpg"></img></p>
</div>
</div>
 <h2>Why Framework?  <a id="why-framework" class="anchor" href="#why-framework">#</a></h2> <div class="outline-text-2" id="text-org44e547a">
 <p>
Framework laptops stand out in a market dominated by disposable, locked-down devices. Their modular design means users can replace or upgrade parts easily, extending the laptop’s lifespan far beyond that of typical consumer models. This approach not only saves money but also significantly reduces electronic waste.
</p>

 <p>
Check out their website here:  <a href="https://frame.work/">https://frame.work/</a>
</p>

 <p>
By designing a laptop that prioritizes repairability and fixability, Framework empowers users to maintain and upgrade their devices instead of discarding them. This has a profound ecological impact — fewer laptops ending up in landfills means less e-waste and a more sustainable approach to personal computing.
</p>

 <p>
Choosing a Framework laptop isn’t just about flexibility and performance; it’s also a commitment to sustainability and responsible consumption. If you’re looking for a machine that aligns with both high customizability and environmental consciousness, Framework is the way to go.
</p>

 <p>
I am extremely pleased with the laptop. Keyboard is great actually, it has also backlight, screen is high resolution and has very nice colors, WiFi range is very good, and CPU is surprisingly good, even with me choosing the lowest-powered one. Overall I am extremely satisfied with this machine, and the price too.
</p>
</div>
 <h2>The assembly process  <a id="the-assembly-process" class="anchor" href="#the-assembly-process">#</a></h2> <div class="outline-text-2" id="text-orgf6c7a81">
 <p>
Below follow a lot of pictures about the unboxing and assembly process. I chose for the DIY edition, which means you need to assemble the entire thing yourself.
</p>

 <p>
You can see the assembly guide of Framework here:  <a href="https://guides.frame.work/Guide/Framework+Laptop+13+(AMD+Ryzen%E2%84%A2+7040+Series)+DIY+Edition+Quick+Start+Guide/211">https://guides.frame.work/Guide/Framework+Laptop+13+(AMD+Ryzen%E2%84%A2+7040+Series)+DIY+Edition+Quick+Start+Guide/211</a>
</p>

 <p>
You can also choose for a model that comes pre-assembled, but for me, this is part of the fun.
</p>


 <div id="org421e296" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/static-assets/blog/img/lisp-machine-laptop/2.jpg"></img></p>
</div>

 <p>
Below you can see the “hot-swappable” adapter cards, you can choose your connectors to your taste. I chose 2 USB-C, 1 HDMI, 1 USB-A and 1 ethernet port for every now and then.
</p>


 <div id="org51a6a42" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/static-assets/blog/img/lisp-machine-laptop/1.jpg"></img></p>
</div>

 <p>
Below you can see the SSD, RAM and keyboard.
</p>


 <div id="org867da35" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/static-assets/blog/img/lisp-machine-laptop/3.jpg"></img></p>
</div>

 <p>
Below you can see the Guix install screen I booted using a USB.
</p>

 <p>
Note: I had to manually tweak the BIOS settings a bit, disabling secure boot and setting the date and time correctly, to get the installer to connect properly to Internet. Framework provides a really nice BIOS actually, really happy about it.
</p>


 <div id="org7fc4e81" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/static-assets/blog/img/lisp-machine-laptop/5.jpg"></img></p>
</div>

 <p>
Below you can see me running Emacs on a TTY, working without a graphical session. I do this sometimes when I am in the mood :)
</p>


 <div id="orge8fb9c8" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/static-assets/blog/img/lisp-machine-laptop/6.jpg"></img></p>
</div>

 <p>
Below you can see the Framework running SSS Sway session, with Emacs, Thunar and the Foot terminal.
</p>


 <div id="org9ec975d" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/static-assets/blog/img/lisp-machine-laptop/7.jpg"></img></p>
</div>

 <p>
And here SSS in all its glory:
</p>


 <div id="orgfbc573c" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/static-assets/other/img/sss-2025-02-04.png"></img></p>
</div>
</div>
 <h2>About the software I run on it  <a id="about-the-software-i-run-on-it" class="anchor" href="#about-the-software-i-run-on-it">#</a></h2> <div class="outline-text-2" id="text-org63d0150">
 <p>
With Guix’s declarative system configuration and my setup which uses, among others, Emacs, Sway, Qutebrowser, in SSS (the Supreme Sexp System), this machine is my daily driver for both work and personal engineering projects.
</p>

 <p>
Guix is the perfect operating system for a Lisp enthusiast. It embraces the same principles: functional purity, immutability, and reproducibility. The entire system configuration is written in Lisp (Guile Scheme), making it a natural fit for someone who appreciates the elegance of Lisp. By using Guix, I can declaratively manage my entire system state and configurations, rolling back configurations seamlessly when needed.
</p>

 <p>
SSS, my custom environment, brings the power of s-expressions to every aspect of my workflow. Instead of relying on traditional shell scripting, I use Lisp to configure and automate my system.
</p>

 <p>
If you are interested, read more about it here:  <a href="https://codeberg.org/jjba23/sss">https://codeberg.org/jjba23/sss</a>
</p>

 <p>
At work, I primarily develop in Scala, and despite my heavily Lisp-centric setup, this laptop functions perfectly for that. Guix allows me to keep isolated, reproducible environments using Guix (and Nix) shell, so I can spin up development environments without polluting my system.
</p>

 <p>
Whether I’m writing functional code, hacking on my Guix configuration, or working in Emacs Lisp, my laptop stays flexible and efficient.
</p>

 <p>
Using a Lisp-driven system in 2025 might sound niche, but it has brought immense joy and efficiency to my workflow. The Framework laptop itself is an excellent hardware choice due to its repairability and modular design, and Guix ensures my software stack remains under my control. With SSS, Emacs, and Sway, I feel like I’m using a machine that truly adapts to me, rather than the other way around.
</p>

 <p>
If you’re interested in building your own modern Lisp machine, I highly recommend Fractal Design North cases for desktops, and Framework laptops for portable devices - also give Guix a spin.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/gnu-linux/legendary-lisp-laptop/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/gnu-linux/legendary-lisp-laptop/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Open VPN 3 on NixOS with Web-based SAML</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <h2>OpenVPN 3 on NixOS with Web-based SAML  <a id="openvpn-3-on-nixos-with-web-based-saml" class="anchor" href="#openvpn-3-on-nixos-with-web-based-saml">#</a></h2> <div class="outline-text-2" id="text-org00b4a75">
 <p>
Recently at work we migrated from a simple OpenVPN profile with AWS credentials to a profile that authenticates based on SAML via your browser.
</p>

 <p>
Worth noting, SAML web-based authentication for OpenVPN only works with OpenVPN 3. This means that we need OpenVPN 3 now running, and also that you can’t run the VPN as a systemd service unfortunately.
</p>

 <p>
I got it working previously with Void Linux, but I have since moved to NixOS, my love 💘.
</p>

 <p>
I was struggling for a while in finding the best way to run the VPN with NixOS in the nicest way possible. This solution likely also applies to people running the Nix package manager in other distros, though I have not tested that.
</p>

 <p>
The solution is quite simple and reliable thanks to Nix, and way simpler than my other attempts in other distros, having to even build OpenVPN from source.
</p>

 <p>
All you need to do, is in your  <code>/etc/nixos/configuration.nix</code> to add the  <code>openvpn3</code> package to the list of system programs to install.
</p>

 <pre>environment.systemPackages = with pkgs; [
  # ........ 
  openvpn3
];</pre>

 <p>
Then, and very importantly, you need to add a line that enables the OpenVPN3 client.
</p>

 <pre>programs.openvpn3.enable = true;</pre>

 <p>
I highly recommend using the NixOS package and option search website, e.g.  <a href="https://search.nixos.org">https://search.nixos.org</a> . This is also extremely useful when searching on how to best configure your Nix systems.
</p>

 <p>
I then usually create a shell alias to start the VPN I want and auto auth with the browser. For me, using Fish shell and configuring it via Nix, this looks something like the following:
</p>

 <pre>programs.fish.shellAliases = {
  zd-vpn = "openvpn3 session-start --config ~/Documenten/my-vpn-file.ovpn && openvpn3 session-auth";
};</pre>

 <p>
Then just run your command, and your browser should open automatically and authenticate.
</p>

 <p>
Send me a mail if you have any questions or comments.
Stay positive, sharp, critical, caring for one another, and loving Nix & reproducible systems.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/gnu-linux/openvpn3-on-nixos-with-web-based-saml/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/gnu-linux/openvpn3-on-nixos-with-web-based-saml/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Open VPN 3 on Void Linux</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <h2>OpenVPN 3 on Void Linux  <a id="openvpn-3-on-void-linux" class="anchor" href="#openvpn-3-on-void-linux">#</a></h2> <div class="outline-text-2" id="text-org61d0f74">
 <p>
Recently at work we migrated from a simple OpenVPN profile with AWS credentials to a profile that authenticates based on SAML via your browser. This means that we need OpenVPN 3 now running. At the time of writing there was no package in the Void Linux repos for v3 so I decided to build from source, since otherwise this would mean I cannot do my work, from Void Linux.
</p>

 <p>
In this post I explain how you should go about installing OpenVPN 3 from source on Void Linux.
</p>

 <p>
First remove your existing OpenVPN installation. Bear in mind that this means also removing the NetworkManager extension.
</p>

 <pre>sudo xbps-remove openvpn NetworkManager-openvpn</pre>

 <p>
You should then ensure that your system is up to date and install at least the following packages (maybe more are required that I missed).
</p>

 <pre>sudo xbps-install -Syu
sudo xbps-install -Sy automake autoconf autoconf-archive pkg-config liblz4-devel lz4 jsoncpp jsoncpp-devel libcap-ng-devel tinyxml2 tinyxml2-devel</pre>

 <p>
Before installing it’s useful to configure the groups and users required for this:
</p>

 <pre>sudo groupadd -r openvpn
sudo useradd -r -s /sbin/nologin -g openvpn openvpn</pre>

 <p>
Then navigate to a directory of your choice (for me  <code>~/Ontwikkeling/Build</code>) and clone the source code of the OpenVPN 3 client there.
</p>

 <pre> <span class="org-builtin">cd</span> ~/Ontwikkeling/Build
git clone https://github.com/OpenVPN/openvpn3-linux.git
 <span class="org-builtin">cd</span> openvpn3-linux</pre>

 <p>
After having navigated to that folder you can proceed to the building and installation.
</p>

 <pre>./bootstrap.sh
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var
make
sudo make install
sudo openvpn3-admin init-config --write-configs</pre>

 <p>
Then make sure to reboot your system, and you can now enjoy using OpenVPN 3. See below how I use it:
</p>

 <pre>sudo openvpn3 session-start --config my-file.ovpn && sudo openvpn3 session-auth</pre>

 <p>
That’s all folks!
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/gnu-linux/openvpn3-on-voidlinux/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/gnu-linux/openvpn3-on-voidlinux/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Podman root-less setup on GNU Guix</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Note: There is a better way to go about this, Guix now contains  <code>rootless-podman-service-type</code> which will take care of it all pretty much for you. This article is thus outdated, and explains how we did things before that!
</p>

 <p>
Thanks Hugo Buddelmeijer for alerting me to that, he wrote a blog post here:  <a href="https://entropynaut.com/post/guixpodman/">https://entropynaut.com/post/guixpodman/</a>
</p>

 <p>
Have you ever heard about Docker ? Containerization has revolutionized the way we deploy and manage applications. By isolating processes and their dependencies, containers offer a lightweight and efficient solution for software deployment and help reproducibility.
</p>

 <p>
GNU Guix, a powerful and pure functional system and package manager, provides a robust foundation for building and managing software systems.
</p>

 <p>
By leveraging Podman, a daemonless container engine, we can achieve rootless containerization, enhancing security and flexibility.
</p>

 <p>
In this post I will explain what it takes to setup Podman in a root-less manner, for your user in Guix.
</p>

 <p>
Every engineer in anno 2024 ends up spinning a “Docker” container or two in their job or as a hobby, so for me it’s important to be able to do this seamlessly in my beloved Guix system, or as I have recently taken to calling it, Supreme Sexp System - see more  <a href="https://codeberg.org/jjba23/sss">here</a>.
</p>
 <h2>Why not Docker?  <a id="why-not-docker" class="anchor" href="#why-not-docker">#</a></h2> <div class="outline-text-2" id="text-org4d1843b">
 <p>
Podman is basically an upgrade in several fronts:
</p>

 <ul class="org-ul"> <li>Security</li>
 <li>Simplicity</li>
 <li>Modularity</li>
 <li>Consistency</li>
 <li>Features (pods, compose, kube, etc)</li>
</ul> <p>
Basically all the functionality of the docker, but a bit cleaner implementation and organization wise.
</p>
</div>
 <h2>Adding to Guix  <a id="adding-to-guix" class="anchor" href="#adding-to-guix">#</a></h2> <div class="outline-text-2" id="text-orgf8dc17c">
 <p>
Make sure to remove Docker installation first completely and then the  <code>docker</code> group from your users, if you previously used docker:
</p>

 <pre>(user-account
  (name  <span class="org-string">"joe"</span>)
  (group  <span class="org-string">"users"</span>)
  (supplementary-groups '( <span class="org-string">"wheel"</span>  <span class="org-string">"netdev"</span>  <span class="org-string">"audio"</span>  <span class="org-string">"video"</span>  <span class="org-string">"input"</span>)))</pre>

 <p>
Then we will need to allocate some sub-uids and sub-gids, and for that we create a  <code>etc-service</code> with Guix:
</p>

 <pre>( <span class="org-keyword">define</span>  <span class="org-function-name">sss-joe-subuid</span>
(simple-service
 'podman-subuid-subgid
  <span class="org-comment-delimiter">;; </span> <span class="org-comment">If subuid/subgid will be needed somewhere else, the service must be</span>
  <span class="org-comment-delimiter">;; </span> <span class="org-comment">created to handle it.</span>
 etc-service-type
 `(( <span class="org-string">"subuid"</span>
    ,(plain-file
       <span class="org-string">"subuid"</span>
      (string-append  <span class="org-string">"joe"</span>  <span class="org-string">":100000:65536\n"</span>)))
   ( <span class="org-string">"subgid"</span>
    ,(plain-file
       <span class="org-string">"subgid"</span>
      (string-append  <span class="org-string">"joe"</span>  <span class="org-string">":100000:65536\n"</span>))))))</pre>

 <p>
 <code>iptables</code> service or equivalent is necessary for networking in Podman:
</p>
 <pre>( <span class="org-keyword">define</span>  <span class="org-function-name">sss-iptables</span> (service iptables-service-type
                              (iptables-configuration)))</pre>


 <p>
You can feel free to also alias in your shell docker to podman, to help you rebuild muscle memory, e.g. .
</p>
 <pre>alias docker-compose= <span class="org-string">"podman-compose"</span>
alias docker= <span class="org-string">"podman"</span>
alias podman-unix-socket= <span class="org-string">"podman system service --time=0 unix:///tmp/podman.sock"</span></pre>

 <p>
For running with Testcontainers, one should use the Unix socket.
</p>

 <p>
 <code>podman system service --time=0 unix:///tmp/podman.sock</code>
</p>


 <p>
 <code>DOCKER_HOST</code> should be set to the socket you use, e.g.  <code>unix:///tmp/podman.sock</code>
</p>

 <p>
You can do this with Guix home or manually before running certain programs.
</p>

 <p>
You should also configure container registries and policies, for example with Guix Home:
</p>

 <pre>`(( <span class="org-string">".config/containers/registries.conf"</span>
          ,(plain-file
             <span class="org-string">"registries.conf"</span>
             <span class="org-string">"unqualified-search-registries = ['docker.io', \</span>
 <span class="org-string">'registry.fedoraproject.org', \</span>
 <span class="org-string">'registry.access.redhat.com', \</span>
 <span class="org-string">'registry.centos.org']"</span>))

         ( <span class="org-string">".config/containers/policy.json"</span>
          ,(plain-file
             <span class="org-string">"policy.json"</span>
             <span class="org-string">"{\"default\": [{\"type\": \"insecureAcceptAnything\"}]}"</span>))    
         )</pre>


 <p>
You will then need some packages from Guix packages:
</p>

 <pre>slirp4netns podman podman-compose passt</pre>
</div>
 <h2>Testing  <a id="testing" class="anchor" href="#testing">#</a></h2> <div class="outline-text-2" id="text-org0750286">
 <p>
Make sure you reboot and have cleaned any previous trace of Docker.
</p>


 <p>
Check if things work then:
</p>

 <pre>podman ps -a
podman run --rm alpine ls / -lia
podman images
podman ps -a
podman run -dt -p 8080:80/tcp httpd
podman stop -l
podman rm -l</pre>

 <p>
Or run your favourite integration test pipeline.
</p>
</div>
 <h2>Enjoy  <a id="enjoy" class="anchor" href="#enjoy">#</a></h2> <div class="outline-text-2" id="text-org9c40257">
 <p>
🎉 Now you should be set to run testcontainers, even with Ryuk. Otherwise make sure to tweak  <code>~/.testcontainers.properties</code>.
</p>

 <p>
Podman is in technical terms also superior and cleaner than Docker, as well as a more permissive license.
</p>

 <p>
Using a root-less setup (no sudo for docker) one achieve more stability and flexibility in the system.
</p>

 <p>
Podman is also daemon-less, which brings great benefits, but can be used via Unix sockets too on demand.
</p>
</div>
 <h2>More on this  <a id="more-on-this" class="anchor" href="#more-on-this">#</a></h2> <div class="outline-text-2" id="text-orgf911978">
 <p>
See the official documentation of Podman root-less here:
 <a href="https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md">https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md</a>
 <a href="https://github.com/containers/podman/blob/main/rootless.md">https://github.com/containers/podman/blob/main/rootless.md</a>
 <a href="https://opensource.com/article/19/2/how-does-rootless-podman-work">https://opensource.com/article/19/2/how-does-rootless-podman-work</a>
</p>
</div>
 <h3>Shoutout to Andrew!  <a id="shoutout-to-andrew" class="anchor" href="#shoutout-to-andrew">#</a></h3> <div class="outline-text-3" id="text-orgd88cc7e">
 <p>
Make sure to check Andrew Tropin’s video for another great explanation on this interesting topic:
</p>

 <p>
 <a href="https://www.youtube.com/watch?v=CC7t7foYkko&list=LL&index=1&t=305s">https://www.youtube.com/watch?v=CC7t7foYkko&list=LL&index=1&t=305s</a>
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/gnu-linux/podman-root-less-guix/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/gnu-linux/podman-root-less-guix/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Moving from Sway to Hyprland -  Archived SwayFX config</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
After using Sway as my daily Wayland compositor for quite some time, I recently made the switch to Hyprland. The decision wasn’t made lightly, as Sway, especially with the SwayFX fork, served me well. However, Hyprland’s growing community and advanced feature set made it an attractive choice.
</p>
 <h2>Why Hyprland?  <a id="why-hyprland" class="anchor" href="#why-hyprland">#</a></h2> <div class="outline-text-2" id="text-org6d9b64f">
 <p>
The main reasons for switching are:
</p>

 <p>
Community Size: Hyprland has a much larger and more active community. This means more contributions, faster development, and better support.
</p>

 <p>
Advanced Features: Hyprland offers built-in window animations, hybrid tiling and floating layouts, and fine-grained customization that surpass what Sway provides out of the box.
</p>

 <p>
Modern Approach: The configuration syntax is modern and expressive, making it easier to maintain.
</p>

 <p>
Check my latest Lisp based configuration of Hyprland here:  <a href="https://codeberg.org/jjba23/sss/src/branch/trunk/lib/hyprland.scm">https://codeberg.org/jjba23/sss/src/branch/trunk/lib/hyprland.scm</a>
</p>
</div>
 <h2>SwayFX Configuration (For Posterity)  <a id="swayfx-configuration-for-posterity" class="anchor" href="#swayfx-configuration-for-posterity">#</a></h2> <div class="outline-text-2" id="text-org500b011">
 <p>
I wanted to archive my custom SwayFX configuration, which was written entirely in Lisp using Guix’s home-services. This setup, part of the Supreme Sexp System (SSS), includes dynamic wallpapers, custom keybindings, and aesthetic tweaks like rounded corners and blur effects.
</p>

 <p>
Here is the full configuration:
</p>

 <pre> <span class="org-comment-delimiter">;;; </span> <span class="org-comment">SSS - Supreme Sexp System</span>

 <span class="org-comment-delimiter">;; </span> <span class="org-comment">Copyright (C) 2025 - Josep Bigorra, jjba23  <a href="mailto:jjbigorra%40gmail.com"><jjbigorra@gmail.com></a></span>

 <span class="org-comment-delimiter">;; </span> <span class="org-comment">sss is free software: you can redistribute it and/or modify</span>
 <span class="org-comment-delimiter">;; </span> <span class="org-comment">it under the terms of the GNU General Public License as published by</span>
 <span class="org-comment-delimiter">;; </span> <span class="org-comment">the Free Software Foundation, either version 3 of the License, or</span>
 <span class="org-comment-delimiter">;; </span> <span class="org-comment">(at your option) any later version.</span>

 <span class="org-comment-delimiter">;; </span> <span class="org-comment">sss is distributed in the hope that it will be useful,</span>
 <span class="org-comment-delimiter">;; </span> <span class="org-comment">but WITHOUT ANY WARRANTY; without even the implied warranty of</span>
 <span class="org-comment-delimiter">;; </span> <span class="org-comment">MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span>
 <span class="org-comment-delimiter">;; </span> <span class="org-comment">GNU General Public License for more details.</span>

 <span class="org-comment-delimiter">;; </span> <span class="org-comment">You should have received a copy of the GNU General Public License</span>
 <span class="org-comment-delimiter">;; </span> <span class="org-comment">along with sss.  If not, see  <a href="https://www.gnu.org/licenses/"><https://www.gnu.org/licenses/></a>.</span>

(load  <span class="org-string">"./palette.scm"</span>)

( <span class="org-keyword">define-module</span> ( <span class="org-type">sss</span> sway)
   <span class="org-builtin">#:use-module</span> (gnu home)
   <span class="org-builtin">#:use-module</span> (gnu home services)
   <span class="org-builtin">#:use-module</span> (gnu home services shells)
   <span class="org-builtin">#:use-module</span> (gnu packages emacs)
   <span class="org-builtin">#:use-module</span> (gnu packages wm)
   <span class="org-builtin">#:use-module</span> (gnu packages terminals)
   <span class="org-builtin">#:use-module</span> (gnu packages admin)
   <span class="org-builtin">#:use-module</span> (gnu home services shepherd)
   <span class="org-builtin">#:use-module</span> (gnu system keyboard)
   <span class="org-builtin">#:use-module</span> (guix gexp)
   <span class="org-builtin">#:use-module</span> (gnu home services sway)
   <span class="org-builtin">#:use-module</span> (gnu home services sound)
   <span class="org-builtin">#:use-module</span> (gnu home services desktop)
   <span class="org-builtin">#:use-module</span> (sss palette))

( <span class="org-keyword">define</span>  <span class="org-function-name">sss-sway-gestures</span>
  `((swipe:3:right .  <span class="org-string">"workspace next_on_output"</span>)
    (swipe:3:left .  <span class="org-string">"workspace prev_on_output"</span>)
    (swipe:3:down .  <span class="org-string">"move to scratchpad"</span>)
    (swipe:3:up .  <span class="org-string">"scratchpad show"</span>)))

 <span class="org-comment-delimiter">;; </span> <span class="org-comment">Defines a list of application identifiers for floating windows in Sway.</span>
 <span class="org-comment-delimiter">;; </span> <span class="org-comment">These applications are specified to open as floating windows, </span>
 <span class="org-comment-delimiter">;; </span> <span class="org-comment">ensuring they don't tile with other windows and maintain a distinct </span>
 <span class="org-comment-delimiter">;; </span> <span class="org-comment">appearance for usability.</span>
( <span class="org-keyword">define</span>  <span class="org-function-name">sss-sway-floating-windows</span>
  `( <span class="org-string">"org.kde.kcalc"</span>  <span class="org-string">"org.gnome.Calculator"</span>  <span class="org-string">"pavucontrol"</span>
     <span class="org-string">"org.jointhefreeworld.metainfog"</span>))

 <span class="org-comment-delimiter">;; </span> <span class="org-comment">Define diverse wallpapers based on the active color scheme. </span>
( <span class="org-keyword">begin</span>
  ( <span class="org-keyword">define*</span> ( <span class="org-function-name">sss-sway-wallpaper</span>  <span class="org-builtin">#:key</span> sss-clone-dir sss-active-palette)
    ( <span class="org-keyword">cond</span>
      ((equal? 'sss-palette-ef-cyprus sss-active-palette)
       (format #f  <span class="org-string">"~a/resources/wallpapers/some-forest.jpg"</span> sss-clone-dir))
      ((equal? 'sss-palette-ef-dream sss-active-palette)
       (format #f  <span class="org-string">"~a/resources/wallpapers/1362745.png"</span> sss-clone-dir))
      ((equal? 'sss-palette-heavy-metal sss-active-palette)
       (format #f  <span class="org-string">"~a/resources/wallpapers/heavy-wall3.jpg"</span> sss-clone-dir))
      ((equal? 'sss-palette-solarized-light sss-active-palette)
       (format #f  <span class="org-string">"~a/resources/wallpapers/ofcoisp7abfe1.jpeg"</span> sss-clone-dir))
      ((equal? 'sss-palette-ef-autumn sss-active-palette)
       (format #f  <span class="org-string">"~a/resources/wallpapers/0mar2ygf59je1.jpeg"</span> sss-clone-dir))
      ( <span class="org-keyword">else</span> (format #f  <span class="org-string">"~a/resources/wallpapers/some-forest.jpg"</span> sss-clone-dir))))
  ( <span class="org-keyword">export</span> sss-sway-wallpaper))

( <span class="org-keyword">define*</span> ( <span class="org-function-name">sss-sway-startup-programs</span>  <span class="org-builtin">#:key</span> (wallpaper-setter  <span class="org-string">""</span>)
                                    (extra-startups '()))
  (append extra-startups
          `( <span class="org-string">"lxsession"</span>  <span class="org-string">"mako"</span>
             <span class="org-string">"dbus-update-activation-environment --all"</span>
             <span class="org-string">"emacs --daemon"</span>
             <span class="org-string">"waybar"</span>
             <span class="org-string">"foot -s"</span>
             <span class="org-string">"transmission-daemon"</span>
            ,(format #f  <span class="org-string">"swww-daemon & sleep 1 && ~a"</span> wallpaper-setter)
             <span class="org-string">"conky -d"</span>
             <span class="org-string">"podman system service --time=0 unix:///tmp/podman.sock"</span>)))

( <span class="org-keyword">define*</span> ( <span class="org-function-name">sss-sway-startup-reload-programs</span>  <span class="org-builtin">#:key</span> sss-active-palette)
  ( <span class="org-keyword">let</span> ((gtk-theme-name ( <span class="org-keyword">cond</span>
                          ((equal? 'sss-palette-ef-cyprus sss-active-palette)
                            <span class="org-string">"Yaru-sage"</span>)
                          ((equal? 'sss-palette-heavy-metal sss-active-palette)
                            <span class="org-string">"Yaru-red-dark"</span>)
                          ((equal? 'sss-palette-ef-dream sss-active-palette)
                            <span class="org-string">"Yaru-magenta-dark"</span>)
                          ((equal? 'sss-palette-ef-autumn sss-active-palette)
                            <span class="org-string">"Yaru-dark"</span>)
                          ((equal? 'sss-palette-solarized-light
                                   sss-active-palette)
                            <span class="org-string">"Yaru"</span>)
                          ( <span class="org-keyword">else</span>  <span class="org-string">"Yaru-sage-dark"</span>)))
        (icon-theme-name ( <span class="org-keyword">cond</span>
                           ((equal? 'sss-palette-ef-cyprus sss-active-palette)
                             <span class="org-string">"Yaru-sage"</span>)
                           ((equal? 'sss-palette-heavy-metal
                                    sss-active-palette)
                             <span class="org-string">"Yaru-red-dark"</span>)
                           ((equal? 'sss-palette-ef-dream sss-active-palette)
                             <span class="org-string">"Yaru-magenta-dark"</span>)
                           ((equal? 'sss-palette-ef-autumn sss-active-palette)
                             <span class="org-string">"Yaru-dark"</span>)
                           ((equal? 'sss-palette-solarized-light
                                    sss-active-palette)
                             <span class="org-string">"Yaru"</span>)
                           ( <span class="org-keyword">else</span>  <span class="org-string">"Yaru-sage-dark"</span>))))
    
    `(,(format #f  <span class="org-string">"gsettings set $gnome-schema gtk-theme '~a'"</span> gtk-theme-name) ,
      (format #f  <span class="org-string">"gsettings set $gnome-schema icon-theme '~a'"</span> icon-theme-name)
       <span class="org-string">"gsettings set $gnome-schema cursor-theme 'Yaru'"</span>
       <span class="org-string">"gsettings set $gnome-schema cursor-size 24"</span>
       <span class="org-string">"gsettings set $gnome-schema font-name 'Inter'"</span>)))

( <span class="org-keyword">begin</span>
  ( <span class="org-keyword">define*</span> ( <span class="org-function-name">sss-sway-outputs</span>  <span class="org-builtin">#:key</span> sss-clone-dir)
    (list (sway-output (identifier '*))))
  ( <span class="org-keyword">export</span> sss-sway-outputs))

( <span class="org-keyword">begin</span>
  ( <span class="org-keyword">define*</span> ( <span class="org-function-name">sss-sway-variables</span>  <span class="org-builtin">#:key</span> sss-clone-dir sss-active-palette)
    `((mod .  <span class="org-string">"Mod4"</span>) (left .  <span class="org-string">"Left"</span>)
      (down .  <span class="org-string">"Down"</span>)
      (up .  <span class="org-string">"Up"</span>)
      (right .  <span class="org-string">"Right"</span>)
      (gnome-schema .  <span class="org-string">"org.gnome.desktop.interface"</span>)
      (editor .  <span class="org-string">"emacsclient -c"</span>)
      (bloated-browser .  <span class="org-string">"google-chrome"</span>)
      (browser .  <span class="org-string">"QT_QPA_PLATFORM=xcb qutebrowser"</span>)
      (term .  <span class="org-string">"footclient"</span>)
      (wallpaper-setter unquote
                        (format #f
                          <span class="org-string">"swww img ~a --transition-step 10 --transition-fps 30 --transition-type center"</span>

                         (sss-sway-wallpaper  <span class="org-builtin">#:sss-clone-dir</span> sss-clone-dir
                                              <span class="org-builtin">#:sss-active-palette</span>
                                             sss-active-palette)))
      (password-manager .  <span class="org-string">"$HOME/.nix-profile/bin/1password"</span>)
      (locker unquote
              (string-join '( <span class="org-string">"swaylock"</span>  <span class="org-string">"--screenshots"</span>
                              <span class="org-string">"--clock"</span>
                              <span class="org-string">"--indicator"</span>
                              <span class="org-string">"--indicator-radius 100"</span>
                              <span class="org-string">"--indicator-thickness 7"</span>
                              <span class="org-string">"--effect-blur 7x5"</span>
                              <span class="org-string">"--effect-vignette 0.5:0.5"</span>
                              <span class="org-string">"--ring-color bb00cc"</span>
                              <span class="org-string">"--key-hl-color 880033"</span>
                              <span class="org-string">"--line-color 00000000"</span>
                              <span class="org-string">"--inside-color 00000088"</span>
                              <span class="org-string">"--separator-color 00000000"</span>
                              <span class="org-string">"--grace 2"</span>
                              <span class="org-string">"--fade-in 0.2"</span>)  <span class="org-string">" "</span>))
      (menu .  <span class="org-string">"rofi -show drun"</span>)
      (runner .  <span class="org-string">"rofi -show run"</span>)
      (windower .  <span class="org-string">"rofi -show window"</span>)))
  ( <span class="org-keyword">export</span> sss-sway-variables))

( <span class="org-keyword">define</span>  <span class="org-function-name">sss-sway-modes</span>
  (list (sway-mode (mode-name  <span class="org-string">"resize"</span>)
                   (keybindings '(($left .  <span class="org-string">"resize shrink width 10px"</span>)
                                  ($down .  <span class="org-string">"resize grow height 10px"</span>)
                                  ($up .  <span class="org-string">"resize shrink height 10px"</span>)
                                  ($right .  <span class="org-string">"resize grow width 10px"</span>)
                                  (Return .  <span class="org-string">"mode \"default\""</span>)
                                  (Escape .  <span class="org-string">"mode \"default\""</span>))))))

( <span class="org-keyword">define-public</span>  <span class="org-function-name">sss-sway-keybindings</span>
  `(($mod+Return .  <span class="org-string">"exec $term"</span>) ($mod+t .  <span class="org-string">"exec $term"</span>)
    ($mod+shift+period .  <span class="org-string">"exec grimshot copy screen"</span>)
    ($mod+period .  <span class="org-string">"exec grimshot save screen"</span>)
    ($mod+shift+comma .  <span class="org-string">"exec grimshot copy area"</span>)
    ($mod+comma .  <span class="org-string">"exec grimshot save area"</span>)
    ($mod+k .  <span class="org-string">"kill"</span>)
    ($mod+l .  <span class="org-string">"exec $locker"</span>)
    ($mod+Shift+b .  <span class="org-string">"exec $wallpaper-setter"</span>)
    ($mod+slash .  <span class="org-string">"exec $menu"</span>)
    ($mod+i .  <span class="org-string">"exec $browser"</span>)
    ($mod+Shift+i .  <span class="org-string">"exec $bloated-browser"</span>)
    ($mod+e .  <span class="org-string">"exec $editor"</span>)
    ($mod+minus .  <span class="org-string">"exec $password-manager"</span>)
    ($mod+Shift+c .  <span class="org-string">"reload"</span>)
    ($mod+$left .  <span class="org-string">"focus left"</span>)
    ($mod+$down .  <span class="org-string">"focus down"</span>)
    ($mod+$up .  <span class="org-string">"focus up"</span>)
    ($mod+$right .  <span class="org-string">"focus right"</span>)
    ($mod+Shift+$left .  <span class="org-string">"move left"</span>)
    ($mod+Shift+$down .  <span class="org-string">"move down"</span>)
    ($mod+Shift+$up .  <span class="org-string">"move up"</span>)
    ($mod+Shift+$right .  <span class="org-string">"move right"</span>)
    ($mod+p .  <span class="org-string">"workspace prev_on_output"</span>)
    ($mod+n .  <span class="org-string">"workspace next_on_output"</span>)
    ($mod+1 .  <span class="org-string">"workspace number 1"</span>)
    ($mod+2 .  <span class="org-string">"workspace number 2"</span>)
    ($mod+3 .  <span class="org-string">"workspace number 3"</span>)
    ($mod+4 .  <span class="org-string">"workspace number 4"</span>)
    ($mod+5 .  <span class="org-string">"workspace number 5"</span>)
    ($mod+6 .  <span class="org-string">"workspace number 6"</span>)
    ($mod+7 .  <span class="org-string">"workspace number 7"</span>)
    ($mod+8 .  <span class="org-string">"workspace number 8"</span>)
    ($mod+9 .  <span class="org-string">"workspace number 9"</span>)
    ($mod+0 .  <span class="org-string">"workspace number 10"</span>)
    ($mod+Shift+1 .  <span class="org-string">"move container to workspace number 1"</span>)
    ($mod+Shift+2 .  <span class="org-string">"move container to workspace number 2"</span>)
    ($mod+Shift+3 .  <span class="org-string">"move container to workspace number 3"</span>)
    ($mod+Shift+5 .  <span class="org-string">"move container to workspace number 5"</span>)
    ($mod+Shift+4 .  <span class="org-string">"move container to workspace number 4"</span>)
    ($mod+Shift+6 .  <span class="org-string">"move container to workspace number 6"</span>)
    ($mod+Shift+7 .  <span class="org-string">"move container to workspace number 7"</span>)
    ($mod+Shift+8 .  <span class="org-string">"move container to workspace number 8"</span>)
    ($mod+Shift+9 .  <span class="org-string">"move container to workspace number 9"</span>)
    ($mod+Shift+0 .  <span class="org-string">"move container to workspace number 10"</span>)
    ($mod+b .  <span class="org-string">"splith"</span>)
    ($mod+v .  <span class="org-string">"splitv"</span>)
    ($mod+s .  <span class="org-string">"layout stacking"</span>)
    ($mod+w .  <span class="org-string">"layout tabbed"</span>)
    ($mod+h .  <span class="org-string">"layout toggle split"</span>)
    ($mod+f .  <span class="org-string">"fullscreen"</span>)
    ($mod+Shift+space .  <span class="org-string">"floating toggle"</span>)
    ($mod+space .  <span class="org-string">"focus mode_toggle"</span>)
    ($mod+a .  <span class="org-string">"focus parent"</span>)
    ($mod+Shift+minus .  <span class="org-string">"move scratchpad"</span>)
    ($mod+Shift+m .  <span class="org-string">"sway output Virtual-1 mode 1920x1200"</span>)
    ($mod+Shift+s .  <span class="org-string">"scratchpad show"</span>)
    ($mod+r .  <span class="org-string">"exec $runner"</span>)
    (Alt+tab .  <span class="org-string">"exec $windower"</span>)
    ($mod+Shift+e unquote
                  #~(string-append  <span class="org-string">"exec "</span>
                     #$sway
                      <span class="org-string">"/bin/swaynag -t warning -m \\\n    "</span>
                      <span class="org-string">"'You pressed the exit shortcut.  Do you really want to exit sway?"</span>
                      <span class="org-string">" This will end your Wayland session.' \\</span>
 <span class="org-string">    "</span>
                      <span class="org-string">"-B 'Yes, exit sway' \\\n    '"</span>
                     #$sway
                      <span class="org-string">"/bin/swaymsg exit'"</span>))
    (XF86MonBrightnessDown .  <span class="org-string">"exec sudo light -U 3"</span>)
    (XF86MonBrightnessUp .  <span class="org-string">"exec sudo light -A 3"</span>)
    (XF86AudioRaiseVolume .  <span class="org-string">"exec pactl set-sink-volume @DEFAULT_SINK@ +5%"</span>)
    (XF86AudioLowerVolume .  <span class="org-string">"exec pactl set-sink-volume @DEFAULT_SINK@ -5%"</span>)
    (XF86AudioMute .  <span class="org-string">"exec pactl set-sink-mute @DEFAULT_SINK@ toggle"</span>)
    (XF86AudioMicMute .  <span class="org-string">"exec pactl set-source-mute @DEFAULT_SOURCE@ toggle"</span>)
    (XF86AudioPlay .  <span class="org-string">"exec playerctl play-pause"</span>)
    (XF86AudioNext .  <span class="org-string">"exec playerctl next"</span>)
    (XF86AudioPrev .  <span class="org-string">"exec playerctl previous"</span>)
    ($mod+Shift+r .  <span class="org-string">"mode \"resize\""</span>)))

( <span class="org-keyword">define</span>  <span class="org-function-name">sss-swayfx-config</span>
  `( <span class="org-string">"corner_radius 12"</span>  <span class="org-string">"shadows enable"</span>  <span class="org-string">"blur enable"</span>
     <span class="org-string">"default_dim_inactive 0.2"</span>  <span class="org-string">"dim_inactive_colors.unfocused #000000FF"</span>
     <span class="org-string">"dim_inactive_colors.urgent #900000FF"</span>))

( <span class="org-keyword">define*</span> ( <span class="org-function-name">sss-sway-extra-content</span>  <span class="org-builtin">#:key</span> sss-active-palette)
  `( <span class="org-string">"gaps inner 12"</span>  <span class="org-string">"gaps outer 8"</span>

     <span class="org-comment-delimiter">;; </span> <span class="org-comment">class                 border  backgr. text    indicator child_border</span>
    ,(format #f
              <span class="org-string">"client.focused ~a ~a ~a ~a ~a"</span>
             (sss-get-color sss-active-palette
                            'primary)
             (sss-get-color sss-active-palette
                            'primary)
             (sss-get-color sss-active-palette
                            'text)
             (sss-get-color sss-active-palette
                            'primary)
             (sss-get-color sss-active-palette
                            'primary))
    ,(format #f
              <span class="org-string">"client.focused_inactive ~a ~a ~a ~a ~a"</span>
             (sss-get-color sss-active-palette
                            'primary)
             (sss-get-color sss-active-palette
                            'primary)
             (sss-get-color sss-active-palette
                            'text)
             (sss-get-color sss-active-palette
                            'primary)
             (sss-get-color sss-active-palette
                            'primary))
    ,(format #f
              <span class="org-string">"client.unfocused ~a ~a #808f80 ~a ~a"</span>
             (sss-get-color sss-active-palette
                            'background-l)
             (sss-get-color sss-active-palette
                            'background-l)
             (sss-get-color sss-active-palette
                            'background-l)
             (sss-get-color sss-active-palette
                            'background-l))
     <span class="org-string">"client.urgent           #b02930 #b02930 #cfdfd5 #900000   #900000"</span>
     <span class="org-string">"client.placeholder      #000000 #0c0c0c #cfdfd5 #000000   #0c0c0c"</span>
    ,(format #f  <span class="org-string">"client.background ~a"</span>
             (sss-get-color sss-active-palette
                            'text))
    ,(format #f  <span class="org-string">"seat seat0 xcursor_theme ~a ~a"</span>  <span class="org-string">"Yaru"</span>  <span class="org-string">"24"</span>)))

( <span class="org-keyword">begin</span>
  ( <span class="org-keyword">define*</span> ( <span class="org-function-name">sss-sway-service-type</span>  <span class="org-builtin">#:key</span> sss-clone-dir
                                  sss-keyboard-layout
                                  sss-keyboard-caps-to-ctrl
                                  sss-active-palette
                                  sss-sway-extra-startups)
    (service home-sway-service-type
             (sway-configuration (packages (list swayfx))
                                 (gestures sss-sway-gestures)
                                 (startup-programs (sss-sway-startup-programs
                                                     <span class="org-builtin">#:wallpaper-setter</span> (format
                                                                        #f
                                                                         <span class="org-string">"swww img ~a --transition-step 10 --transition-fps 30 --transition-type center"</span>

                                                                        (sss-sway-wallpaper
                                                                          <span class="org-builtin">#:sss-active-palette</span>
                                                                         sss-active-palette
                                                                          <span class="org-builtin">#:sss-clone-dir</span>
                                                                         sss-clone-dir))
                                                     <span class="org-builtin">#:extra-startups</span>
                                                    sss-sway-extra-startups))
                                 (startup+reload-programs (sss-sway-startup-reload-programs
                                                            <span class="org-builtin">#:sss-active-palette</span>
                                                           sss-active-palette))
                                 (outputs (sss-sway-outputs  <span class="org-builtin">#:sss-clone-dir</span>
                                                            sss-clone-dir))
                                 (inputs (list (sway-input (identifier
                                                             <span class="org-string">"type:keyboard"</span>)
                                                           (layout (keyboard-layout
                                                                    sss-keyboard-layout
                                                                     <span class="org-builtin">#:options</span> ( <span class="org-keyword">cond</span>
                                                                                
                                                                                
                                                                                (sss-keyboard-caps-to-ctrl '
                                                                                 ( <span class="org-string">"ctrl:nocaps"</span>))

                                                                                
                                                                                ( <span class="org-keyword">else</span> '())))))
                                               (sway-input (identifier
                                                             <span class="org-string">"type:touchpad"</span>)
                                                           (tap #t))))
                                 (variables (sss-sway-variables
                                              <span class="org-builtin">#:sss-active-palette</span>
                                             sss-active-palette
                                              <span class="org-builtin">#:sss-clone-dir</span> sss-clone-dir))
                                 (modes sss-sway-modes)
                                 (keybindings sss-sway-keybindings)
                                 (extra-content (append sss-swayfx-config
                                                        ( <span class="org-keyword">map</span> ( <span class="org-keyword">lambda</span> (w)
                                                               (format #f
                                                                 <span class="org-string">"for_window [app_id=\"~a\"] floating enable"</span>
                                                                w))
                                                         sss-sway-floating-windows)
                                                        (sss-sway-extra-content
                                                          <span class="org-builtin">#:sss-active-palette</span>
                                                         sss-active-palette))))))
  ( <span class="org-keyword">export</span> sss-sway-service-type))</pre>
</div>
 <h2>Final Thoughts  <a id="final-thoughts" class="anchor" href="#final-thoughts">#</a></h2> <div class="outline-text-2" id="text-orgc21b190">
 <p>
Switching to Hyprland feels like a step forward into a more vibrant ecosystem (and nice and shiny graphics). Sway will always hold a special place in my heart as the first tiling Wayland compositor I customized with Lisp. However, Hyprland’s polish and active development make it the ideal choice for the Supreme Sexp System moving forward.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/gnu-linux/sway-guix-fully-lisp-configuration/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/gnu-linux/sway-guix-fully-lisp-configuration/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Create a Windows 11 bootable USB from GNU Linux</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Below is the procedure for creating a bootable USB flash drive with Windows 11. The same process should also work with any HDD/SSD connected to your system.
</p>
 <h2>Download Windows 11 image  <a id="download-windows-11-image" class="anchor" href="#download-windows-11-image">#</a></h2> <div class="outline-text-2" id="text-orga508f7f">
 <p>
 <a href="https://www.microsoft.com/software-download/windows11">https://www.microsoft.com/software-download/windows11</a>
</p>

 <pre>sha256sum Win11_English_x64v1.iso
4bc6c7e7c61af4b5d1b086c5d279947357cff45c2f82021bb58628c2503eb64e  Win11_English_x64v1.iso</pre>
</div>
 <h2>Plug your USB flash drive  <a id="plug-your-usb-flash-drive" class="anchor" href="#plug-your-usb-flash-drive">#</a></h2> <div class="outline-text-2" id="text-org9ed741c">
 <p>
Linux detected  <code>/dev/sda</code> as the USB stick, in your case it will most likely take a different name.
</p>
</div>
 <h2>Format your USB flash drive  <a id="format-your-usb-flash-drive" class="anchor" href="#format-your-usb-flash-drive">#</a></h2> <div class="outline-text-2" id="text-org3d28338">
 <p>
Work as root account and make sure to replace /dev/sda with your USB flash drive!
Use lsblk and dmesg | tail -50 commands to locate your USB flash drive.
</p>

 <pre>sudo wipefs -a /dev/sda
sudo parted /dev/sda
(parted) mklabel gpt                                                      
(parted) mkpart BOOT fat32 0% 1GiB
(parted) mkpart INSTALL ntfs 1GiB 10GiB
(parted) quit</pre>

 <p>
Check the drive layout now:
</p>

 <p>
In my case I’ve used 100% instead of 10GiB when created the “INSTALL” ntfs partition - mkpart INSTALL ntfs 1GiB 100%. But you can use anything that should be larger than 6 GiB to fit the data from Windows ISO image.
</p>

 <pre>sudo parted /dev/sda unit B print
Model: SanDisk Extreme (scsi)
Disk /dev/sda: 62742792192B
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start        End           Size          File system  Name     Flags
1      1048576B     1073741823B   1072693248B                BOOT     msftdata
2      1073741824B  62742593535B  61668851712B               INSTALL  msftdata</pre>
</div>
 <h2>Mount Windows ISO somewhere  <a id="mount-windows-iso-somewhere" class="anchor" href="#mount-windows-iso-somewhere">#</a></h2> <div class="outline-text-2" id="text-org6238bd5">
 <p>
I mounted it to /mnt/iso directory:
</p>

 <pre>sudo mkdir /mnt/iso
sudo mount /home/<your user>/Downloads/Win11_English_x64v1.iso /mnt/iso/</pre>
</div>
 <h2>Format 1st partition of your USB flash drive as FAT32  <a id="format-1st-partition-of-your-usb-flash-drive-as-fat32" class="anchor" href="#format-1st-partition-of-your-usb-flash-drive-as-fat32">#</a></h2> <div class="outline-text-2" id="text-org3edf860">
 <pre>sudo mkfs.vfat -n BOOT /dev/sda1
sudo mkdir /mnt/vfat
sudo mount /dev/sda1 /mnt/vfat/</pre>
</div>
 <h2>Copy everything from Windows ISO image except for the sources directory there  <a id="copy-everything-from-windows-iso-image-except-for-the-sources-directory-there" class="anchor" href="#copy-everything-from-windows-iso-image-except-for-the-sources-directory-there">#</a></h2> <div class="outline-text-2" id="text-orge29ca23">
 <pre>sudo rsync -r --progress --exclude sources --delete-before /mnt/iso/ /mnt/vfat/</pre>
</div>
 <h2>Copy only boot.wim file from the sources directory, while keeping the same path layout  <a id="copy-only-bootwim-file-from-the-sources-directory-while-keeping-the-same-path-layout" class="anchor" href="#copy-only-bootwim-file-from-the-sources-directory-while-keeping-the-same-path-layout">#</a></h2> <div class="outline-text-2" id="text-orgf672661">
 <pre>sudo mkdir /mnt/vfat/sources
sudo cp /mnt/iso/sources/boot.wim /mnt/vfat/sources/</pre>
</div>
 <h2>Format 2nd partition of your USB flash drive as NTFS  <a id="format-2nd-partition-of-your-usb-flash-drive-as-ntfs" class="anchor" href="#format-2nd-partition-of-your-usb-flash-drive-as-ntfs">#</a></h2> <div class="outline-text-2" id="text-org406a042">
 <pre>sudo mkfs.ntfs --quick -L INSTALL /dev/sda2 
sudo mkdir /mnt/ntfs
sudo mount /dev/sda2 /mnt/ntfs</pre>
</div>
 <h2>Copy everything from Windows ISO image there  <a id="copy-everything-from-windows-iso-image-there" class="anchor" href="#copy-everything-from-windows-iso-image-there">#</a></h2> <div class="outline-text-2" id="text-orgc79a271">
 <pre>sudo rsync -r --progress --delete-before /mnt/iso/ /mnt/ntfs/</pre>
</div>
 <h2>Unmount the USB flash drive and Windows ISO image  <a id="unmount-the-usb-flash-drive-and-windows-iso-image" class="anchor" href="#unmount-the-usb-flash-drive-and-windows-iso-image">#</a></h2> <div class="outline-text-2" id="text-org96e982a">
 <pre>sudo umount /mnt/ntfs
sudo umount /mnt/vfat
sudo umount /mnt/iso
sudo sync</pre>
</div>
 <h2>Power off your USB flash drive  <a id="power-off-your-usb-flash-drive" class="anchor" href="#power-off-your-usb-flash-drive">#</a></h2> <div class="outline-text-2" id="text-org924a519">
 <pre>sudo udisksctl power-off -b /dev/sda</pre>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/gnu-linux/windows-11-bootable-usb-from-gnu-linux/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/gnu-linux/windows-11-bootable-usb-from-gnu-linux/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>GNU/Linux</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-03-04 di> </span></span>  <a href="/blog/articles/gnu-linux/sway-guix-fully-lisp-configuration/index.html">Moving from Sway to Hyprland - Archived SwayFX config</a> - After using Sway as my daily Wayland compositor for quite some time, I recently made the switch to Hyprland. The decision wasn’t made lightly, as Sway, especially with the SwayFX fork, served me well.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-02-17 ma> </span></span>  <a href="/blog/articles/gnu-linux/conky-wayland-guix/index.html">Building Conky with Wayland Support on GNU Guix</a> -  Since I use GNU Guix and run a Wayland-based environment (Sway), I wanted to get Conky building with Wayland support.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-02-04 di> </span></span>  <a href="/blog/articles/gnu-linux/legendary-lisp-laptop/index.html">Legendary Lisp Laptop - Framework</a> - a modern Lisp machine with Framework laptop
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-01-11 za> </span></span> -  <a href="/blog/articles/gnu-linux/gnu-guix-virtual-machine-image-aarch64/index.html">GNU Guix Virtual Machine on AArch64/ARM64</a> - The Guix ISO installer didn’t work for me on aarch64. Making a qcow2 VM image or doing a manual install did work.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2024-12-09 ma> </span></span>  <a href="/blog/articles/gnu-linux/podman-root-less-guix/index.html">Podman root-less setup on GNU Guix system for easy containers under the Shepherd’s system</a> -  By leveraging Podman, a daemonless container engine, we can achieve rootless containerization, enhancing security and flexibility with Guix.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2024-12-03 di> </span></span>  <a href="https://guix.gnu/index.html/blog/2018/multi-dimensional-transactions-and-rollbacks-oh-my/">How Guix enables multi-dimensional rollbacks and more reproducibility!</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2023-11-02 do> </span></span>  <a href="/blog/articles/gnu-linux/openvpn3-on-nixos-with-web-based-saml/index.html">Open VPN 3 on NixOS with Web-based SAML</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2023-08-25 vr> </span></span>  <a href="/blog/articles/gnu-linux/windows-11-bootable-usb-from-gnu-linux/index.html">Bootable Windows 11 USB from GNU Linux</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2023-08-18 vr> </span></span>  <a href="/blog/articles/gnu-linux/openvpn3-on-voidlinux/index.html">OpenVPN3 on Void Linux</a> 
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-12-21 di> </span></span>  <a href="/blog/articles/gnu-linux/arch-linux-uefi-encryption/index.html">Arch Linux UEFI + Encryption guide</a>
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/gnu-linux/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/gnu-linux/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>File Descriptors and Go</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Ever heard of  <i>dangling pointers</i>? Have you ever left your database connections without closing them properly?
</p>

 <p>
One must pay special attention to this specially when dealing with lower
level languages like Go, C, and C++.
</p>

 <p>
Resource leaks really are a do or die in many applications, something
very often and very easily overlooked. I personally have had
applications catastrophically crash due to this. Read this to understand
useful patterns and practices avoiding these problems in Go…
</p>
 <h2>A true story!  <a id="a-true-story" class="anchor" href="#a-true-story">#</a></h2> <div class="outline-text-2" id="text-a-true-story">
 <p>
Last week I saw one of my beloved Go applications crash catastrophically
with such an error:
</p>

 <pre>server.go:3095: http: Accept error: accept tcp [::]:7002: accept4: too many open files; retrying <span class="org-keyword"> in</span> 5ms</pre>

 <p>
This error kept repeating for a good few minutes, until I luckily
spotted the issue, and temporarily fixed it by restarting the
application (Go binary as system service).
</p>

 <p>
The application in question deals with a lot of incoming and outgoing
HTTP requests, acting as a Facade between several services.
</p>

 <p>
Due to the nature of this application, many requests of all kinds are
sent, and sometimes I do not care about the response body of a performed
request, only about the returned status code, or not even that.
</p>

 <p>
This lead to a situation where I performed several requests ignoring the
response body with the  <code>_</code> variable.
</p>

 <p>
So please follow my advice, always, ALWAYS, close the response body of a
request.
</p>

 <p>
 <b>BAD</b>
</p>

 <pre>_, err := client.Do(request)
if err != nil {
  log.Println(err.Error())
  return nil
}</pre>

 <p>
 <b>GOOD</b>
</p>

 <pre>resp, err := client.Do(request)
if err != nil {
  log.Println(err.Error())
  return nil
}

defer resp.Body.Close()</pre>

 <p>
If you do not close the response body, or for that matter defer its
closing, the resources allocated for that will never be released, and
thus your application will keep it indefinitely reserved, in Unix
systems, in a file descriptor.
</p>

 <p>
Keep in mind, that the default limit per application is of 1024 file
descriptors. this can be manipulated, but in my opinion really should
not be done for web services, unless there is an actual necessity. Keep
it in the back of your head, if you need to increase this, you most
certainly have a leak in your program.
</p>

 <p>
The bad news is that not only HTTP requests will cause this issue.
Database connections, Redis connections, Buffered readers, Actual File
I/O operations…
</p>

 <p>
A solid example, is indeed the database connection:
</p>

 <p>
 <b>BAD</b>
</p>

 <pre>db, err := sql.Open(databaseType, connection)
if err != nil {
  log.Println(err.Error())
  panic(err.Error())
}

// If you do not defer close to the connection
// you will dangerously forget about doing so.</pre>

 <p>
 <b>GOOD</b>
</p>

 <pre>db, err := sql.Open(databaseType, connection)
if err != nil {
  log.Println(err.Error())
  panic(err.Error())
}

defer db.Close()
// Use db here, no risk of forgetting to close the db connection</pre>

 <p>
Anything that you have opened and forgot to close, will hog the system
and bring the file descriptor count upwards, and will come back to haunt
you. For that reason, you should check your system services file
descriptor count sometimes. This can easily be achieved with a couple
commands. Log in as root user in your Unix server and do a  <code>ps aux</code>.
</p>

 <p>
You might be wondering, Go is a Garbage Collected (GC) language, why
doesn’t it simply destroy these unused connections/handles/response
bodies?
</p>

 <p>
This simply is not the case since for the GC these handles are still
“referenced” and thus are not eligible for garbage collection. They are
basically dangling around, and you can avoid this bad situation with a
simple  <code>defer</code> statement.
</p>

 <p>
Imagining your application is called  <code>my-application</code> and is located at
 <code>/internalApplications/my-application/app</code>, you should filter the
=ps aux=output to find:
</p>

 <pre>root     531  0.0  0.1 1323436 8000 ?        Ssl  Nov12   0:35 /internalApplications/my-application/app</pre>

 <p>
What we are intereseted in here, is the 2nd column and 11th column,
which contain respectively the PID of the process and the name of the
process.
</p>

 <p>
To get a file descriptor count per PID, do  <code>ls /proc/{pid}/fd | wc -l</code>,
in this case you would need to do,  <code>ls /proc/531/fd | wc -l</code>
</p>

 <p>
You can take this script I made, that finds all services that are
located in the  <code>/internalApplications</code> folder and modify it, to suit
your needs:
</p>

 <pre> <span class="org-comment-delimiter">#</span> <span class="org-comment">!/bin/</span> <span class="org-keyword">bash</span>
 <span class="org-variable-name">pid</span>=( $( <span class="org-sh-quoted-exec">ps aux | grep /internalApplications/ | grep -v "grep" | awk '{print $2}'</span>) )
 <span class="org-variable-name">processName</span>=( $( <span class="org-sh-quoted-exec">ps aux | grep /internalApplications/ | grep -v "grep" | awk '{print $11}'</span>) )

 <span class="org-keyword">for</span> index <span class="org-keyword"> in</span> ${ <span class="org-variable-name">!</span>pid[*]};   <span class="org-keyword">do</span>
     <span class="org-builtin">printf</span>  <span class="org-string">"%s --> %s --> %s\n"</span>  <span class="org-string">"${pid[$index]}"</span>  <span class="org-string">"$(</span> <span class="org-sh-quoted-exec"> ls /proc/${pid[$index]}/fd | wc -l </span> <span class="org-string">)"</span>   <span class="org-string">"${processName[$index]}"</span>
 <span class="org-keyword">done</span></pre>

 <p>
Other good tips to avoid file descriptors being hogged are more related
to HTTP requests. If your application is exposed to other HTTP services,
ensure you follow the below tips.
</p>

 <p>
Always add a request close, unless you plan to have  <code>keep-alive</code>
connections. This can easily be done:
</p>

 <pre>req, err := http.NewRequestWithContext(
  context.Background(),
  "POST",
  "www.example.com",
  bytes.NewBuffer([]byte(`{"test": "example"}`)),
)
if err != nil {
  log.Println(err.Error())
  return nil, err
}

req.Header.Add("Content-Type", "application/json")
req.Header.Add("Charset", "utf-8")
// This will add a Connection: close header to the request
req.Close = true
// alternatively
req.Header.Add("Connection", "close")</pre>

 <p>
Set a default timeout for HTTP requests, to avoid hanging requests, or
malicious attempts:
</p>

 <pre>// Do this at the beggining of your application, in your `main.go`
http.DefaultClient.Timeout = 30 * time.Second</pre>

 <p>
If you use  <code>http.Server</code> directly then make sure to set some sensible
timeouts:
</p>

 <pre>srv := &http.Server{
  ReadTimeout:  10 * time.Second,
  WriteTimeout: 30 * time.Second,
  IdleTimeout:  100 * time.Second,
}

// optional disable keep alives
srv.SetKeepAlivesEnabled(false)</pre>

 <p>
If you use  <code>http.Client</code> directly then also make sure to set a sensible
timeout:
</p>

 <pre>client := &http.Client{Timeout: 30 * time.Second}</pre>

 <p>
In conclusion, you should always take special care with closing
resources properly so as to not have stale sockets, and file descriptors
in your application.
</p>

 <p>
Always cleanup after yourself, and if possible, do a
 <code>defer whatever.Close()</code> as close to the declarations as possible, so as
to not forget to do it further down the code. This also avoids resources
not being closed due to early returns.
</p>

 <p>
With great power, such as what Go gives developers, comes great
responsability.
</p>

 <p>
I will keep expanding this article as I find more useful tips for this,
stay tuned!
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/go/file-descriptors-and-go/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/go/file-descriptors-and-go/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>How I write HTTP services</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
This is a very interesting learning experience written originally by  <a href="https://pace.dev/blog/2018/05/09/how-I-write-http-services-after-eight-years.html">Mat Ryer</a>.
</p>

 <p>
The way I have written services has changed over time, so I wanted to
share how I write the services today—in case the patterns are useful
to you and your work.
</p>
 <h2>A Server struct  <a id="a-server-struct" class="anchor" href="#a-server-struct">#</a></h2> <div class="outline-text-2" id="text-a-server-struct">
 <p>
A Server struct is an object that represents the service, and holds all
of its dependencies.
</p>

 <p>
All of my components have a single server structure that usually ends up
looking something like this:
</p>

 <pre>type server struct {
    db     *someDatabase
    router *someRouter
    email  EmailSender
}</pre>

 <p>
As you can see, shared dependencies are fields of the struct, and not
stored as global variables. State is thus very centralized.
</p>
</div>
 <h2>routes.go  <a id="routesgo" class="anchor" href="#routesgo">#</a></h2> <div class="outline-text-2" id="text-routes.go">
 <p>
I have a single file inside every component called routes.go where all
the routing can live:
</p>

 <pre>package app

func (s *server) routes() {
    s.router.HandleFunc("/api/", s.handleAPI())
    s.router.HandleFunc("/about", s.handleAbout())
    s.router.HandleFunc("/", s.handleIndex())
}</pre>

 <p>
This is handy because most code maintenance starts with a URL and an
error report — so one glance at  <code>routes.go</code> will direct us where to
look.
</p>
</div>
 <h2>Handlers hang off the server  <a id="handlers-hang-off-the-server" class="anchor" href="#handlers-hang-off-the-server">#</a></h2> <div class="outline-text-2" id="text-handlers-hang-off-the-server">
 <p>
My HTTP handlers hang off the server:
</p>

 <pre>func (s *server) handleSomething() http.HandlerFunc { ... }</pre>

 <p>
Handlers can access the dependencies via the s server variable.
</p>
</div>
 <h2>Return the handler  <a id="return-the-handler" class="anchor" href="#return-the-handler">#</a></h2> <div class="outline-text-2" id="text-return-the-handler">
 <p>
My handler functions don’t actually handle the requests, they return a
function that does.
</p>

 <p>
This gives us a closure environment in which our handler can operate:
</p>

 <pre>func (s *server) handleSomething() http.HandlerFunc {
    thing := prepareThing()
    return func(w http.ResponseWriter, r *http.Request) {
        // use thing
    }
}</pre>

 <p>
The  <code>prepareThing</code> is called only once, so you can use it to do one-time
per-handler initialization, and then use the thing in the handler.
</p>

 <p>
Be sure to only read the shared data, if handlers are modifying
anything, remember you’ll need a  <code>mutex</code> or something to protect it.
</p>
</div>
 <h2>Take arguments for handler-specific dependencies  <a id="take-arguments-for-handler-specific-dependencies" class="anchor" href="#take-arguments-for-handler-specific-dependencies">#</a></h2> <div class="outline-text-2" id="text-take-arguments-for-handler-specific-dependencies">
 <p>
If a particular handler has a dependency, take it as an argument.
</p>

 <pre>func (s *server) handleGreeting(format string) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, format, "World")
    }
}</pre>

 <p>
The format variable is accessible to the handlers.
</p>
</div>
 <h2>HandlerFunc over Handler  <a id="handlerfunc-over-handler" class="anchor" href="#handlerfunc-over-handler">#</a></h2> <div class="outline-text-2" id="text-handlerfunc-over-handler">
 <p>
I use  <code>http.HandlerFunc</code> in almost every case now, rather than
 <code>http.Handler</code>.
</p>

 <pre>func (s *server) handleSomething() http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        ...
    }
}</pre>

 <p>
They are more or less interchangeable, so just pick whichever is simpler
to read. For me, that’s  <code>http.HandlerFunc</code>.
</p>
</div>
 <h2>Middleware are just Go functions  <a id="middleware-are-just-go-functions" class="anchor" href="#middleware-are-just-go-functions">#</a></h2> <div class="outline-text-2" id="text-middleware-are-just-go-functions">
 <p>
Middleware functions take an  <code>http.HandlerFunc</code> and return a new one
that can run code before and/or after calling the original handler —
or it can decide not to call the original handler at all.
</p>

 <pre>func (s *server) adminOnly(h http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        if !currentUser(r).IsAdmin {
            http.NotFound(w, r)
            return
        }
        h(w, r)
    }
}</pre>

 <p>
The logic inside the handler can optionally decide whether to call the
original handler or not — in the example above, if  <code>IsAdmin</code> is
 <code>false</code>, the handler will return an  <code>HTTP 404 Not Found</code> and return
(abort); notice that the  <code>h</code> handler is not called.
</p>

 <p>
If  <code>IsAdmin</code> is true, execution is passed to the h handler that was
passed in.
</p>

 <p>
Usually I have middleware listed in the  <code>routes.go</code> file:
</p>

 <pre>package app

func (s *server) routes() {
    s.router.HandleFunc("/api/", s.handleAPI())
    s.router.HandleFunc("/about", s.handleAbout())
    s.router.HandleFunc("/", s.handleIndex())
    s.router.HandleFunc("/admin", s.adminOnly(s.handleAdminIndex()))
}</pre>
</div>
 <h2>Request and response types can go in there too  <a id="request-and-response-types-can-go-in-there-too" class="anchor" href="#request-and-response-types-can-go-in-there-too">#</a></h2> <div class="outline-text-2" id="text-request-and-response-types-can-go-in-there-too">
 <p>
If an endpoint has its own request and response types, usually they’re
only useful for that particular handler.
</p>

 <p>
If that’s the case, you can define them inside the function.
</p>

 <pre>func (s *server) handleSomething() http.HandlerFunc {
    type request struct {
        Name string
    }
    type response struct {
        Greeting string `json:"greeting"`
    }
    return func(w http.ResponseWriter, r *http.Request) {
        ...
    }
}</pre>

 <p>
This de-clutters your package space and allows you to name these kinds
of types the same, instead of having to think up handler-specific
versions.
</p>

 <p>
In test code, you can just copy the type into your test function and do
the same thing. Or…
</p>
</div>
 <h2>Test types can help frame the test  <a id="test-types-can-help-frame-the-test" class="anchor" href="#test-types-can-help-frame-the-test">#</a></h2> <div class="outline-text-2" id="text-test-types-can-help-frame-the-test">
 <p>
If your request/response types are hidden inside the handler, you can
just declare new types in your test code.
</p>

 <p>
This is an opportunity to do a bit of storytelling to future generations
who will need to understand your code.
</p>

 <p>
For example, let’s say we have a  <code>Person</code> type in our code, and we reuse
it on many endpoints. If we had a  <code>/greet</code> endpoint, we might only care
about their name, so we can express this in test code:
</p>

 <pre>func TestGreet(t *testing.T) {
    is := is.New(t)
    p := struct {
        Name string `json:"name"`
    }{
        Name: "Mat Ryer",
    }
    var buf bytes.Buffer
    err := json.NewEncoder(&buf).Encode(p)
    is.NoErr(err) // json.NewEncoder
    req, err := http.NewRequest(http.MethodPost, "/greet", &buf)
    is.NoErr(err)
    //... more test code here</pre>

 <p>
It’s clear from this test, that the only field we care about is the
 <code>Name</code> of the person.
</p>
</div>
 <h2>sync.Once to setup dependencies  <a id="synconce-to-setup-dependencies" class="anchor" href="#synconce-to-setup-dependencies">#</a></h2> <div class="outline-text-2" id="text-sync.once-to-setup-dependencies">
 <p>
If I have to do anything very expensive when preparing the handler, I
defer it until when that handler is first called.
</p>

 <p>
This improves application startup time.
</p>

 <pre>func (s *server) handleTemplate(files string...) http.HandlerFunc {
    var (
        init    sync.Once
        tpl     *template.Template
        tplerr  error
    )
    return func(w http.ResponseWriter, r *http.Request) {
        init.Do(func(){
            tpl, tplerr = template.ParseFiles(files...)
        })
        if tplerr != nil {
            http.Error(w, tplerr.Error(), http.StatusInternalServerError)
            return
        }
        // use tpl
    }
}</pre>

 <p>
 <code>sync.Once</code> ensures the code is only executed one time, and other calls
(other people making the same request) will block until it’s finished.
</p>

 <p>
The error check is outside of the  <code>init</code> function, so if something does
go wrong we still surface the error and won’t lose it in the logs. If
the handler is not called, the expensive work is never done — this can
have big benefits depending on how your code is deployed.
</p>

 <p>
Remember that doing this, you are moving the initialization time from
startup, to runtime (when the endpoint is first accessed). I use Google
App Engine a lot, so this makes sense for me, but your case might be
different so it’s worth thinking about where and when to use  <code>sync.Once</code>
in this way.
</p>
</div>
 <h2>The server is testable  <a id="the-server-is-testable" class="anchor" href="#the-server-is-testable">#</a></h2> <div class="outline-text-2" id="text-the-server-is-testable">
 <p>
Our server type is very testable.
</p>

 <pre>func TestHandleAbout(t *testing.T) {
    is := is.New(t)
    srv := server{
        db:    mockDatabase,
        email: mockEmailSender,
    }
    srv.routes()
    req := httptest.NewRequest("GET", "/about", nil)
    w := httptest.NewRecorder()
    srv.ServeHTTP(w, req)
    is.Equal(w.StatusCode, http.StatusOK)
}</pre>

 <p>
Create a server instance inside each test — if expensive things lazy
load, this won’t take much time at all, even for big components. By
calling  <code>ServeHTTP</code> on the server, we are testing the entire stack
including routing and middleware, etc.
</p>

 <p>
You can of course call the handler methods directly if you want to avoid
this. Use  <code>httptest.NewRequest</code> and  <code>httptest.NewRecorder</code> to record
what the handlers are doing.
</p>

 <p>
This code sample uses is testing mini-framework (a mini alternative to
Testify) github.com/matryer/is
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/go/how-i-write-http-services/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/go/how-i-write-http-services/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Make or New ?</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
This is a post about Go’s built in  <code>make</code> and  <code>new</code> functions.
</p>

 <p>
As Rob Pike noted at Gophercon on 2014, Go has many ways of initialising
variables. Among them is the ability to take the address of a struct
literal which leads to several ways to do the same thing.
</p>

 <pre class="example" id="org07d94bf">
s := &SomeStruct{}
v := SomeStruct{}
s := &v              // identical
s := new(SomeStruct) // also identical
</pre>

 <p>
It is fair that people point out this redundancy in the language and
this sometimes leads them to search for other inconsistencies, most
notably the redundancy between  <code>make</code> and  <code>new</code>. On the surface it
appears that  <code>make</code> and  <code>new</code> do very similar things, so what is the
rationale for having both ?
</p>
 <h2>Why can’t we use make for everything ?  <a id="why-canrsquot-we-use-make-for-everything-" class="anchor" href="#why-canrsquot-we-use-make-for-everything-">#</a></h2> <div class="outline-text-2" id="text-why-cant-we-use-make-for-everything">
 <p>
Go does not have user defined generic types, but it does have several
built in types that can operate as generic lists, maps, sets, and
queues; slices, maps and channels.
</p>

 <p>
Because  <code>make</code> is designed to create these three built in generic types,
it must be provided by the runtime as there is no way to express the
function signature of  <code>make</code> directly in Go.
</p>

 <p>
Although  <code>make</code> creates generic slice, map, and channel values, they are
still just regular values;  <code>make</code> does not return pointer values.
</p>

 <p>
If  <code>new</code> was removed in favour  <code>make</code>, how would you construct a pointer
to an initialised value ?
</p>

 <pre class="example" id="orgec7c80d">
var x1 *int
var x2 = new(int)
</pre>

 <p>
x1 and x2 have the same type,  <code>*int</code>, x2 points to initialised memory
and may be safely de-referenced, the same is not true for x1.
</p>
</div>
 <h3>Why can’t we use new for everything ?  <a id="why-canrsquot-we-use-new-for-everything-" class="anchor" href="#why-canrsquot-we-use-new-for-everything-">#</a></h3> <div class="outline-text-3" id="text-why-cant-we-use-new-for-everything">
 <p>
Although the use of  <code>new</code> is rare, its behaviour is well specified.
</p>

 <p>
 <code>new(T)</code> always returns a  <code>*T</code> pointing to an initialised  <code>T</code>. As Go
doesn’t have constructors, the value will be initialised to T‘s zero
value.
</p>

 <p>
Using  <code>new</code> to construct a pointer to a slice, map, or channel zero
value works today and is consistent with the behaviour of  <code>new</code>.
</p>

 <pre class="example" id="orgdfc6f1c">
s := new([]string)
fmt.Println(len(*s))  // 0
fmt.Println(*s == nil) // true

m := new(map[string]int)
fmt.Println(m == nil) // false
fmt.Println(*m == nil) // true

c := new(chan int)
fmt.Println(c == nil) // false
fmt.Println(*c == nil) // true
</pre>
</div>
 <h3>Sure, but these are just rules, we can change them, right ?  <a id="sure-but-these-are-just-rules-we-can-change-them-right-" class="anchor" href="#sure-but-these-are-just-rules-we-can-change-them-right-">#</a></h3> <div class="outline-text-3" id="text-sure-but-these-are-just-rules-we-can-change-them-right">
 <p>
For the confusion they may cause,  <code>make</code> and  <code>new</code> are consistent;
 <code>make</code> only makes slices, maps, and channels,  <code>new</code> only returns
pointers to initialised memory.
</p>

 <p>
Yes,  <code>new</code> could be extended to operate like  <code>make</code> for slices, maps and
channels, but that would introduce its own inconsistencies.
</p>

 <ol class="org-ol"> <li> <code>new</code> would have special behaviour if the type passed to  <code>new</code> was a
slice, map or channel. This is a rule that every Go programmer would
have to remember.</li>

 <li>For slices and channels,  <code>new</code> would have to become variadic, taking
a possible length, buffer size, or capacity, as required. Again more
special cases to have to remember, whereas before  <code>new</code> took exactly
one argument, the type.</li>

 <li> <p>
 <code>new</code> always returns a  <code>*T</code> for the  <code>T</code> passed to it. That would mean
code like
</p>

 <p>
func Read(buf []byte) []byte // assume new takes an optional length
buf := Read(new([]byte, length))
</p></li>
</ol> <p>
would no longer be possible, requiring more special cases in the grammar
to permit  <code>*new([]byte, length)</code>.
</p>
</div>
 <h3>In summary  <a id="in-summary" class="anchor" href="#in-summary">#</a></h3> <div class="outline-text-3" id="text-in-summary">
 <p>
 <code>make</code> and  <code>new</code> do different things.
</p>

 <p>
If you are coming from another language, especially one that uses
constructors, it may appear that  <code>new</code> should be all you need, but Go is
not those languages, nor does it have constructors.
</p>

 <p>
My advice is to use  <code>new</code> sparingly, there are almost always easier or
cleaner ways to write your program without it.
</p>

 <p>
As a code reviewer, the use of  <code>new</code>, like the use of named return
arguments, is a signal that the code is trying to do something clever
and I need to pay special attention. It may be that code really is
clever, but more than likely, it can be rewritten to be clearer and more
idiomatic.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/go/make-or-new/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/go/make-or-new/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Opinionated Style Guide</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
This serves as a supplement to
 <a href="https://golang.org/doc/effective_go.html">Effective Go</a>, based on
years of experience and inspiration/ideas from conference talks.
</p>
 <h2>Add context to errors  <a id="add-context-to-errors" class="anchor" href="#add-context-to-errors">#</a></h2> <div class="outline-text-2" id="text-add-context-to-errors">
 <p>
 <b>Don’t:</b>
</p>

 <pre>file, err := os.Open("foo.txt")
if err != nil {
    return err
}</pre>

 <p>
Using the approach above can lead to unclear error messages because of
missing context.
</p>

 <p>
 <b>Do:</b>
</p>

 <pre>file, err := os.Open("foo.txt")
if err != nil {
    return fmt.Errorf("open foo.txt failed: %w", err)
}</pre>

 <p>
Wrapping errors with a custom message provides context as it gets
propagated up the stack. This does not always make sense. If you’re
unsure if the context of a returned error is at all times sufficient,
wrap it.
</p>
</div>
 <h2>Dependency management  <a id="dependency-management" class="anchor" href="#dependency-management">#</a></h2> <div class="outline-text-2" id="text-dependency-management">
</div>
 <h3>Use modules  <a id="use-modules" class="anchor" href="#use-modules">#</a></h3> <div class="outline-text-3" id="text-use-modules">
 <p>
Use  <a href="https://github.com/golang/go/wiki/Modules">modules</a>, since it is
the built-in go dependency management tooling and will be widely
supported (available with Go 1.11+).
</p>
</div>
 <h3>Use Semantic Versioning  <a id="use-semantic-versioning" class="anchor" href="#use-semantic-versioning">#</a></h3> <div class="outline-text-3" id="text-use-semantic-versioning">
 <p>
Tag your packages using  <a href="http://semver.org">Semantic Versioning</a>,
check the
 <a href="https://github.com/golang/go/wiki/Modules#how-to-prepare-for-a-release">modules
wiki</a> for more information about best practices regarding releases. The
git tag for your go package should have the format
 <code>v<major>.<minor>.<patch></code>, e.g.,  <code>v1.0.1</code>.
</p>
</div>
 <h2>Structured logging  <a id="structured-logging" class="anchor" href="#structured-logging">#</a></h2> <div class="outline-text-2" id="text-structured-logging">
 <p>
 <b>Don’t:</b>
</p>

 <pre>log.Printf("Listening on :%d", port)
http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
// 2017/07/29 13:05:50 Listening on :80</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>import "github.com/sirupsen/logrus"
// ...

logger.WithField("port", port).Info("Server is listening")
http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
// {"level":"info","msg":"Server is listening","port":"7000","time":"2017-12-24T13:25:31+01:00"}</pre>

 <p>
This is a harmless example, but using structured logging makes debugging
and log parsing easier.
</p>
</div>
 <h2>Avoid global variables  <a id="avoid-global-variables" class="anchor" href="#avoid-global-variables">#</a></h2> <div class="outline-text-2" id="text-avoid-global-variables">
 <p>
 <b>Don’t:</b>
</p>

 <pre>var db *sql.DB

func main() {
    db = // ...
    http.HandleFunc("/drop", DropHandler)
    // ...
}

func DropHandler(w http.ResponseWriter, r *http.Request) {
    db.Exec("DROP DATABASE prod")
}</pre>

 <p>
Global variables make testing and readability hard and every method has
access to them (even those, that don’t need it).
</p>

 <p>
 <b>Do:</b>
</p>

 <pre>func main() {
    db := // ...
    handlers := Handlers{DB: db}
    http.HandleFunc("/drop", handlers.DropHandler)
    // ...
}

type Handlers struct {
    DB *sql.DB
}

func (h *Handlers) DropHandler(w http.ResponseWriter, r *http.Request) {
    h.DB.Exec("DROP DATABASE prod")
}</pre>

 <p>
Use structs to encapsulate the variables and make them available only to
those functions that actually need them by making them methods
implemented for that struct.
</p>

 <p>
Alternatively, higher-order functions can be used to inject dependencies
via closures.
</p>

 <pre>func main() {
    db := // ...
    http.HandleFunc("/drop", DropHandler(db))
    // ...
}

func DropHandler(db *sql.DB) http.HandleFunc {
    return func (w http.ResponseWriter, r *http.Request) {
        db.Exec("DROP DATABASE prod")
    }
}</pre>

 <p>
If you really need global variables or constants, e.g., for defining
errors or string constants, put them at the top of your file.
</p>

 <p>
 <b>Don’t:</b>
</p>

 <pre>import "xyz"

func someFunc() {
    //...
}

const route = "/some-route"

func someOtherFunc() {
    // usage of route
}

var NotFoundErr = errors.New("not found")

func yetAnotherFunc() {
    // usage of NotFoundErr
}</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>import "xyz"

const route = "/some-route"

var NotFoundErr = errors.New("not found")

func someFunc() {
    //...
}

func someOtherFunc() {
    // usage of route
}

func yetAnotherFunc() {
    // usage of NotFoundErr
}</pre>
</div>
 <h2>Keep the happy path left  <a id="keep-the-happy-path-left" class="anchor" href="#keep-the-happy-path-left">#</a></h2> <div class="outline-text-2" id="text-keep-the-happy-path-left">
 <p>
 <b>Don’t:</b>
</p>

 <pre>if item, ok := someMap[someKey]; ok {
    return item
}
return ErrKeyNotFound</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>item, ok := someMap[someKey]
if !ok {
    return ErrKeyNotFound
}
return item</pre>

 <p>
This helps to keep your code clear and readable. Not doing it
accumulates in larger functions and leads to the happy path being buried
in a lot of if/for/… statements.
</p>
</div>
 <h2>Testing  <a id="testing" class="anchor" href="#testing">#</a></h2> <div class="outline-text-2" id="text-testing">
</div>
 <h3>Use an assert libary  <a id="use-an-assert-libary" class="anchor" href="#use-an-assert-libary">#</a></h3> <div class="outline-text-3" id="text-use-an-assert-libary">
 <p>
 <b>Don’t:</b>
</p>

 <pre>func TestAdd(t *testing.T) {
    actual := 2 + 2
    expected := 4
    if (actual != expected) {
        t.Errorf("Expected %d, but got %d", expected, actual)
    }
}</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>import "github.com/stretchr/testify/assert"

func TestAdd(t *testing.T) {
    actual := 2 + 2
    expected := 4
    assert.Equal(t, expected, actual)
}</pre>

 <p>
Using assert libraries makes your tests more readable, requires less
code and provides consistent error output.
</p>
</div>
 <h3>Use sub-tests to structure functional tests  <a id="use-sub-tests-to-structure-functional-tests" class="anchor" href="#use-sub-tests-to-structure-functional-tests">#</a></h3> <div class="outline-text-3" id="text-use-sub-tests-to-structure-functional-tests">
 <p>
 <b>Don’t:</b>
</p>

 <pre>func TestSomeFunctionSuccess(t *testing.T) {
    // ...
}

func TestSomeFunctionWrongInput(t *testing.T) {
    // ...
}</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>func TestSomeFunction(t *testing.T) {
    t.Run("success", func(t *testing.T){
        //...
    })

    t.Run("wrong input", func(t *testing.T){
        //...
    })
}</pre>
</div>
 <h3>Use table driven tests  <a id="use-table-driven-tests" class="anchor" href="#use-table-driven-tests">#</a></h3> <div class="outline-text-3" id="text-use-table-driven-tests">
 <p>
 <b>Don’t:</b>
</p>

 <pre>func TestAdd(t *testing.T) {
    assert.Equal(t, 1+1, 2)
    assert.Equal(t, 1+-1, 0)
    assert.Equal(t, 1, 0, 1)
    assert.Equal(t, 0, 0, 0)
}</pre>

 <p>
The above approach looks simpler, but it’s much harder to find a failing
case, especially when having hundreds of cases.
</p>

 <p>
 <b>Do:</b>
</p>

 <pre>func TestAdd(t *testing.T) {
    cases := []struct {
        A, B, Expected int
    }{
        {1, 1, 2},
        {1, -1, 0},
        {1, 0, 1},
        {0, 0, 0},
    }

    for _, tc := range cases {
        t.Run(fmt.Sprintf("%d + %d", tc.A, tc.B), func(t *testing.T) {
            t.Parallel()
            assert.Equal(t, t.Expected, tc.A+tc.B)
        })
    }
}</pre>

 <p>
Using table-driven tests in combination with subtests gives you direct
insight about which case is failing and which cases are tested. –
 <a href="https://youtu.be/8hQG7QlcLBk?t=7m34s">Mitchell Hashimoto at GopherCon
2017</a>
</p>

 <p>
Running subtests in parallel allow you to have a lot more test cases and
still get those awesomely fast go build times. –
 <a href="https://blog.golang.org/subtests">The Go Blog</a>
</p>
</div>
 <h3>Avoid mocks  <a id="avoid-mocks" class="anchor" href="#avoid-mocks">#</a></h3> <div class="outline-text-3" id="text-avoid-mocks">
 <p>
 <b>Don’t:</b>
</p>

 <pre>func TestRun(t *testing.T) {
    mockConn := new(MockConn)
    run(mockConn)
}</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>func TestRun(t *testing.T) {
    ln, err := net.Listen("tcp", "127.0.0.1:0")
    t.AssertNil(t, err)

    var server net.Conn
    go func() {
        defer ln.Close()
        server, err := ln.Accept()
        t.AssertNil(t, err)
    }()

    client, err := net.Dial("tcp", ln.Addr().String())
    t.AssertNil(err)

    run(client)
}</pre>

 <p>
Only use mocks if not otherwise possible, favor real implementations. –
 <a href="https://youtu.be/8hQG7QlcLBk?t=26m51s">Mitchell Hashimoto at GopherCon
2017</a>
</p>
</div>
 <h3>Avoid DeepEqual  <a id="avoid-deepequal" class="anchor" href="#avoid-deepequal">#</a></h3> <div class="outline-text-3" id="text-avoid-deepequal">
 <p>
 <b>Don’t:</b>
</p>

 <pre>type myType struct {
    id         int
    name       string
    irrelevant []byte
}

func TestSomething(t *testing.T) {
    actual := &myType{/* ... */}
    expected := &myType{/* ... */}
    assert.True(t, reflect.DeepEqual(expected, actual))
}</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>type myType struct {
    id         int
    name       string
    irrelevant []byte
}

func (m *myType) testString() string {
    return fmt.Sprintf("%d.%s", m.id, m.name)
}

func TestSomething(t *testing.T) {
    actual := &myType{/* ... */}
    expected := &myType{/* ... */}
    if actual.testString() != expected.testString() {
        t.Errorf("Expected '%s', got '%s'", expected.testString(), actual.testString())
    }
    // or assert.Equal(t, actual.testString(), expected.testString())
}</pre>

 <p>
Using  <code>testString()</code> for comparing structs helps on complex structs with
many fields that are not relevant for the equality check. This approach
only makes sense for very big or tree-like structs. –
 <a href="https://youtu.be/8hQG7QlcLBk?t=30m45s">Mitchell Hashimoto at GopherCon
2017</a>
</p>

 <p>
Google open sourced their  <a href="http://github.com/google/go-cmp">go-cmp</a>
package as a more powerful and safer alternative to  <code>reflect.DeepEqual</code>.
–  <a href="https://twitter.com/francesc/status/885630175668346880">Joe Tsai</a>.
</p>
</div>
 <h3>Add examples to your test files to demonstrate usage  <a id="add-examples-to-your-test-files-to-demonstrate-usage" class="anchor" href="#add-examples-to-your-test-files-to-demonstrate-usage">#</a></h3> <div class="outline-text-3" id="text-add-examples-to-your-test-files-to-demonstrate-usage">
 <pre>func ExamleSomeInterface_SomeMethod(){
    instance := New()
    result, err := instance.SomeMethod()
    fmt.Println(result, err)
    // Output: someResult, <nil>
}</pre>
</div>
 <h2>Use linters  <a id="use-linters" class="anchor" href="#use-linters">#</a></h2> <div class="outline-text-2" id="text-use-linters">
 <p>
Use all the linters included in
 <a href="https://github.com/golangci/golangci-lint">golangci-lint</a> to lint
your projects before committing.
</p>

 <pre> <span class="org-comment-delimiter"># </span> <span class="org-comment">Installation - replace vX.X.X with the version you want to use</span>
 <span class="org-variable-name">GO111MODULE</span>=on go get github.com/golangci/golangci-lint/cmd/golangci-lint@vX.X.X
 <span class="org-comment-delimiter"># </span> <span class="org-comment">traditional way without go module</span>
go get -u github.com/golangci/golangci-lint/cmd/golangci-lint


 <span class="org-comment-delimiter"># </span> <span class="org-comment">Usage in the project workspace</span>
golangci-lint run</pre>

 <p>
For detailed usage and the ci-pipeline installation guide visit
 <a href="https://github.com/golangci/golangci-lint">golangci-lint</a>.
</p>
</div>
 <h2>Use goimports  <a id="use-goimports" class="anchor" href="#use-goimports">#</a></h2> <div class="outline-text-2" id="text-use-goimports">
 <p>
Only commit gofmt’d files. Use  <code>goimports</code> for this to format/update the
import statements as well.
</p>
</div>
 <h2>Use meaningful variable names  <a id="use-meaningful-variable-names" class="anchor" href="#use-meaningful-variable-names">#</a></h2> <div class="outline-text-2" id="text-use-meaningful-variable-names">
 <p>
Avoid single-letter variable names. They may seem more readable to you
at the moment of writing but they make the code hard to understand for
your colleagues and your future self.
</p>

 <p>
 <b>Don’t:</b>
</p>

 <pre>func findMax(l []int) int {
    m := l[0]
    for _, n := range l {
        if n > m {
            m = n
        }
    }
    return m
}</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>func findMax(inputs []int) int {
    max := inputs[0]
    for _, value := range inputs {
        if value > max {
            max = value
        }
    }
    return max
}</pre>

 <p>
Single-letter variable names are fine in the following cases. * They are
absolut standard like … *  <code>t</code> in tests *  <code>r</code> and  <code>w</code> in http request
handlers *  <code>i</code> for the index in a loop * They name the receiver of a
method, e.g.,  <code>func (s *someStruct) myFunction(){}</code>
</p>

 <p>
Of course also too long variables names like
 <code>createInstanceOfMyStructFromString</code> should be avoided.
</p>
</div>
 <h2>Avoid side-effects  <a id="avoid-side-effects" class="anchor" href="#avoid-side-effects">#</a></h2> <div class="outline-text-2" id="text-avoid-side-effects">
 <p>
 <b>Don’t:</b>
</p>

 <pre>func init() {
    someStruct.Load()
}</pre>

 <p>
Side effects are only okay in special cases (e.g. parsing flags in a
cmd). If you find no other way, rethink and refactor.
</p>
</div>
 <h2>Favour pure functions  <a id="favour-pure-functions" class="anchor" href="#favour-pure-functions">#</a></h2> <div class="outline-text-2" id="text-favour-pure-functions">
 <blockquote>
 <p>
In computer programming, a function may be considered a pure function if
both of the following statements about the function hold: 1. The
function always evaluates the same result value given the same argument
value(s). The function result value cannot depend on any hidden
information or state that may change while program execution proceeds or
between different executions of the program, nor can it depend on any
external input from I/O devices. 2. Evaluation of the result does not
cause any semantically observable side effect or output, such as
mutation of mutable objects or output to I/O devices.
</p>
</blockquote>

 <p>
–  <a href="https://en.wikipedia.org/wiki/Pure_function">Wikipedia</a>
</p>

 <p>
 <b>Don’t:</b>
</p>

 <pre>func MarshalAndWrite(some *Thing) error {
    b, err := json.Marshal(some)
    if err != nil {
        return err
    }

    return ioutil.WriteFile("some.thing", b, 0644)
}</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>// Marshal is a pure func (even though useless)
func Marshal(some *Thing) ([]bytes, error) {
    return json.Marshal(some)
}

// ...</pre>

 <p>
This is obviously not possible at all times, but trying to make every
possible func pure makes code more understandable and improves
debugging.
</p>
</div>
 <h2>Don’t over-interface  <a id="donrsquot-over-interface" class="anchor" href="#donrsquot-over-interface">#</a></h2> <div class="outline-text-2" id="text-dont-over-interface">
 <p>
 <b>Don’t:</b>
</p>

 <pre>type Server interface {
    Serve() error
    Some() int
    Fields() float64
    That() string
    Are([]byte) error
    Not() []string
    Necessary() error
}

func debug(srv Server) {
    fmt.Println(srv.String())
}

func run(srv Server) {
    srv.Serve()
}</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>type Server interface {
    Serve() error
}

func debug(v fmt.Stringer) {
    fmt.Println(v.String())
}

func run(srv Server) {
    srv.Serve()
}</pre>

 <p>
Favour small interfaces and only expect the interfaces you need in your
funcs.
</p>
</div>
 <h2>Don’t under-package  <a id="donrsquot-under-package" class="anchor" href="#donrsquot-under-package">#</a></h2> <div class="outline-text-2" id="text-dont-under-package">
 <p>
Deleting or merging packages is far easier than splitting big ones up.
When unsure if a package can be split, do it.
</p>
</div>
 <h2>Handle signals  <a id="handle-signals" class="anchor" href="#handle-signals">#</a></h2> <div class="outline-text-2" id="text-handle-signals">
 <p>
 <b>Don’t:</b>
</p>

 <pre>func main() {
    for {
        time.Sleep(1 * time.Second)
        ioutil.WriteFile("foo", []byte("bar"), 0644)
    }
}</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>func main() {
    logger := // ...
    sc := make(chan os.Signal, 1)
    done := make(chan bool)

    go func() {
        for {
            select {
            case s := <-sc:
                logger.Info("Received signal, stopping application",
                    zap.String("signal", s.String()))
                done <- true
                return
            default:
                time.Sleep(1 * time.Second)
                ioutil.WriteFile("foo", []byte("bar"), 0644)
            }
        }
    }()

    signal.Notify(sc, os.Interrupt, os.Kill)
    <-done // Wait for go-routine
}</pre>

 <p>
Handling signals allows us to gracefully stop our server, close open
files and connections and therefore prevent file corruption among other
things.
</p>
</div>
 <h2>Divide imports  <a id="divide-imports" class="anchor" href="#divide-imports">#</a></h2> <div class="outline-text-2" id="text-divide-imports">
 <p>
 <b>Don’t:</b>
</p>

 <pre>import (
    "encoding/json"
    "github.com/some/external/pkg"
    "fmt"
    "github.com/this-project/pkg/some-lib"
    "os"
)</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>import (
    "encoding/json"
    "fmt"
    "os"

    "github.com/bahlo/this-project/pkg/some-lib"

    "github.com/bahlo/another-project/pkg/some-lib"
    "github.com/bahlo/yet-another-project/pkg/some-lib"

    "github.com/some/external/pkg"
    "github.com/some-other/external/pkg"
)</pre>

 <p>
Divide imports into four groups sorted from internal to external for
readability: 1. Standard library 2. Project internal packages 3. Company
internal packages 4. External packages
</p>
</div>
 <h2>Avoid unadorned return  <a id="avoid-unadorned-return" class="anchor" href="#avoid-unadorned-return">#</a></h2> <div class="outline-text-2" id="text-avoid-unadorned-return">
 <p>
 <b>Don’t:</b>
</p>

 <pre>func run() (n int, err error) {
    // ...
    return
}</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>func run() (n int, err error) {
    // ...
    return n, err
}</pre>

 <p>
Named returns are good for documentation, unadorned returns are bad for
readability and error-prone.
</p>
</div>
 <h2>Use canonical import path  <a id="use-canonical-import-path" class="anchor" href="#use-canonical-import-path">#</a></h2> <div class="outline-text-2" id="text-use-canonical-import-path">
 <p>
 <b>Don’t:</b>
</p>

 <pre>package sub</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>package sub // import "github.com/my-package/pkg/sth/else/sub"</pre>

 <p>
Adding the canonical import path adds context to the package and makes
importing easy.
</p>
</div>
 <h2>Avoid empty interface  <a id="avoid-empty-interface" class="anchor" href="#avoid-empty-interface">#</a></h2> <div class="outline-text-2" id="text-avoid-empty-interface">
 <p>
 <b>Don’t:</b>
</p>

 <pre>func run(foo interface{}) {
    // ...
}</pre>

 <p>
Empty interfaces make code more complex and unclear, avoid them where
you can.
</p>
</div>
 <h2>Main first  <a id="main-first" class="anchor" href="#main-first">#</a></h2> <div class="outline-text-2" id="text-main-first">
 <p>
 <b>Don’t:</b>
</p>

 <pre>package main // import "github.com/me/my-project"

func someHelper() int {
    // ...
}

func someOtherHelper() string {
    // ...
}

func Handler(w http.ResponseWriter, r *http.Reqeust) {
    // ...
}

func main() {
    // ...
}</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>package main // import "github.com/me/my-project"

func main() {
    // ...
}

func Handler(w http.ResponseWriter, r *http.Reqeust) {
    // ...
}

func someHelper() int {
    // ...
}

func someOtherHelper() string {
    // ...
}</pre>

 <p>
Putting  <code>main()</code> first makes reading the file a lot easier. Only the
 <code>init()</code> function should be above it.
</p>
</div>
 <h2>Use internal packages  <a id="use-internal-packages" class="anchor" href="#use-internal-packages">#</a></h2> <div class="outline-text-2" id="text-use-internal-packages">
 <p>
If you’re creating a cmd, consider moving libraries to  <code>internal/</code> to
prevent import of unstable, changing packages.
</p>
</div>
 <h2>Avoid helper/util  <a id="avoid-helperutil" class="anchor" href="#avoid-helperutil">#</a></h2> <div class="outline-text-2" id="text-avoid-helperutil">
 <p>
Use clear names and try to avoid creating a  <code>helper.go</code>,  <code>utils.go</code> or
even package.
</p>
</div>
 <h2>Embed binary data  <a id="embed-binary-data" class="anchor" href="#embed-binary-data">#</a></h2> <div class="outline-text-2" id="text-embed-binary-data">
 <p>
To enable single-binary deployments, use tools to add templates and
other static assets to your binary
(e.g.  <a href="https://github.com/gobuffalo/packr">github.com/gobuffalo/packr</a>).
</p>
</div>
 <h2>Use  <code>io.WriteString</code>  <a id="use-codeiowritestringcode" class="anchor" href="#use-codeiowritestringcode">#</a></h2> <div class="outline-text-2" id="text-use-io.writestring">
 <p>
A number of important types that satisfy  <code>io.Writer</code> also have a
 <code>WriteString</code> method, including  <code>*bytes.Buffer</code>,  <code>*os.File</code> and
 <code>*bufio.Writer</code>.  <code>WriteString</code> is behavioral contract with implicit
assent that passed string will be written in efficient way, without a
temporary allocation. Therefore using  <code>io.WriteString</code> may improve
performance at most, and at least string will be written in any way.
</p>

 <p>
 <b>Don’t:</b>
</p>

 <pre>var w io.Writer = new(bytes.Buffer)
str := "some string"
w.Write([]byte(str))</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>var w io.Writer = new(bytes.Buffer)
str := "some string"
io.WriteString(w, str)</pre>
</div>
 <h2>Use functional options  <a id="use-functional-options" class="anchor" href="#use-functional-options">#</a></h2> <div class="outline-text-2" id="text-use-functional-options">
 <pre>func main() {
    // ...
    startServer(
        WithPort(8080),
        WithTimeout(1 * time.Second),
    )
}

type Config struct {
    port    int
    timeout time.Duration
}

type ServerOpt func(*Config)

func WithPort(port int) ServerOpt {
    return func(cfg *Config) {
        cfg.port = port
    }
}

func WithTimeout(timeout time.Duration) ServerOpt {
    return func(cfg *Config) {
        cfg.timeout = timeout
    }
}

func startServer(opts ...ServerOpt) {
    cfg := new(Config)
    for _, fn := range opts {
        fn(cfg)
    }

    // ...
}</pre>
</div>
 <h2>Structs  <a id="structs" class="anchor" href="#structs">#</a></h2> <div class="outline-text-2" id="text-structs">
</div>
 <h3>Use named structs  <a id="use-named-structs" class="anchor" href="#use-named-structs">#</a></h3> <div class="outline-text-3" id="text-use-named-structs">
 <p>
If a struct has more than one field, include field names when
instantiating it.
</p>

 <p>
 <b>Don’t:</b>
</p>

 <pre>params := myStruct{
    1,
    true,
}</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>params := myStruct{
    Foo: 1,
    Bar: true,
}</pre>
</div>
 <h3>Avoid new keyword  <a id="avoid-new-keyword" class="anchor" href="#avoid-new-keyword">#</a></h3> <div class="outline-text-3" id="text-avoid-new-keyword">
 <p>
Using the normal syntax instead of the  <code>new</code> keyword makes it more clear
what is happening: a new instance of the struct is created  <code>MyStruct{}</code>
and we get the pointer for it with  <code>&</code>.
</p>

 <p>
 <b>Don’t:</b>
</p>

 <pre>s := new(MyStruct)</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>s := &MyStruct{}</pre>
</div>
 <h2>Consistent header naming  <a id="consistent-header-naming" class="anchor" href="#consistent-header-naming">#</a></h2> <div class="outline-text-2" id="text-consistent-header-naming">
 <p>
 <b>Don’t:</b>
</p>

 <pre>r.Header.Get("authorization")
w.Header.Set("Content-type")
w.Header.Set("content-type")
w.Header.Set("content-Type")</pre>

 <p>
 <b>Do:</b>
</p>

 <pre>r.Header.Get("Authorization")
w.Header.Set("Content-Type")</pre>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/go/opinionated-style-guide/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/go/opinionated-style-guide/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Project Structure</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
In this post I will try to give an explanation to the project structure
I follow commonly while making Go projects.
</p>

 <p>
This is a basic layout for Go application projects. It’s not an official
standard defined by the core Go dev team; however, it is a set of common
historical and emerging project layout patterns in the Go ecosystem.
Some of these patterns are more popular than others. It also has a
number of small enhancements along with several supporting directories
common to any large enough real world application.
</p>

 <p>
If you are trying to learn Go or if you are building a PoC or a toy
project for yourself this project layout is an overkill. Start with
something really simple (a single main.go file is more than enough). As
your project grows keep in mind that it’ll be important to make sure
your code is well structured otherwise you’ll end up with a messy code
with lots of hidden dependencies and global state. When you have more
people working on the project you’ll need even more structure. That’s
when it’s important to introduce a common way to manage
packages/libraries.
</p>

 <p>
When you have an open source project or when you know other projects
import the code from your project repository that’s when it’s important
to have private (aka internal) packages and code. Clone the repository,
keep what you need and delete everything else! Just because it’s there
it doesn’t mean you have to use it all. None of these patterns are used
in every single project. Even the vendor pattern is not universal.
</p>

 <p>
With Go 1.14 Go Modules are finally ready for production. Use Go Modules
unless you have a specific reason not to use them and if you do then you
don’t need to worry about $GOPATH and where you put your project. The
basic go.mod file in the repo assumes your project is hosted on GitHub,
but it’s not a requirement. The module path can be anything though the
first module path component should have a dot in its name (the current
version of Go doesn’t enforce it anymore, but if you are using slightly
older versions don’t be surprised if your builds fail without it). See
Issues 37554 and 32819 if you want to know more about it.
</p>

 <p>
This project layout is intentionally generic and it doesn’t try to
impose a specific Go package structure.
</p>

 <p>
This is a community effort. Open an issue if you see a new pattern or if
you think one of the existing patterns needs to be updated.
</p>

 <p>
If you need help with naming, formatting and style start by running
gofmt and golint. Also make sure to read these Go code style guidelines
and recommendations:
</p>

 <ul class="org-ul"> <li> <a href="https://talks.golang.org/2014/names.slide">https://talks.golang.org/2014/names.slide</a></li>

 <li> <a href="https://golang.org/doc/effective_go.html#names">https://golang.org/doc/effective_go.html#names</a></li>

 <li> <a href="https://blog.golang.org/package-names">https://blog.golang.org/package-names</a></li>

 <li> <a href="https://github.com/golang/go/wiki/CodeReviewComments">https://github.com/golang/go/wiki/CodeReviewComments</a></li>
</ul> <p>
More about naming and organizing packages as well as other code
structure recommendations:
</p>

 <ul class="org-ul"> <li> <a href="https://www.youtube.com/watch?v=PTE4VJIdHPg">GopherCon EU 2018:
Peter Bourgon - Best Practices for Industrial Programming</a></li>

 <li> <a href="https://www.youtube.com/watch?v=MzTcsI6tn-0">GopherCon Russia 2018:
Ashley McNamara + Brian Ketelsen - Go best practices</a></li>

 <li> <a href="https://www.youtube.com/watch?v=ltqV6pDKZD8">GopherCon 2017: Edward
Muller - Go Anti-Patterns</a></li>

 <li> <a href="https://www.youtube.com/watch?v=oL6JBUk6tj0">GopherCon 2018: Kat
Zien - How Do You Structure Your Go Apps</a></li>
</ul> <h2>Go Directories  <a id="go-directories" class="anchor" href="#go-directories">#</a></h2> <div class="outline-text-2" id="text-go-directories">
 <p>
 <code>/cmd</code>
</p>

 <p>
Main applications for this project.
</p>

 <p>
The directory name for each application should match the name of the
executable you want to have (e.g.,  <code>/cmd/myapp</code>).
</p>

 <p>
Don’t put a lot of code in the application directory. If you think the
code can be imported and used in other projects, then it should live in
the  <code>/pkg</code> directory. If the code is not reusable or if you don’t want
others to reuse it, put that code in the  <code>/internal</code> directory. You’ll
be surprised what others will do, so be explicit about your intentions!
</p>

 <p>
It’s common to have a small main function that imports and invokes the
code from the  <code>/internal</code> and  <code>/pkg</code> directories and nothing else.
</p>

 <p>
 <code>/internal</code>
</p>

 <p>
Private application and library code. This is the code you don’t want
others importing in their applications or libraries. Note that this
layout pattern is enforced by the Go compiler itself. See the Go 1.4
release notes for more details. Note that you are not limited to the top
level internal directory. You can have more than one internal directory
at any level of your project tree.
</p>

 <p>
You can optionally add a bit of extra structure to your internal
packages to separate your shared and non-shared internal code. It’s not
required (especially for smaller projects), but it’s nice to have visual
clues showing the intended package use. Your actual application code can
go in the  <code>/internal/app</code> directory (e.g.,  <code>/internal/app/myapp</code>) and
the code shared by those apps in the  <code>/internal/pkg</code> directory (e.g.,
 <code>/internal/pkg/myprivlib</code>). I do very often have  <code>/internal/domain</code>,
 <code>/internal/infrastructure</code> and  <code>/internal/usecases</code> by using clean
architecture.
</p>

 <p>
 <code>/pkg</code>
</p>

 <p>
Library code that’s ok to use by external applications (e.g.,
 <code>/pkg/mypubliclib</code>). Other projects will import these libraries
expecting them to work, so think twice before you put something here :-)
Note that the internal directory is a better way to ensure your private
packages are not importable because it’s enforced by Go. The  <code>/pkg</code>
directory is still a good way to explicitly communicate that the code in
that directory is safe for use by others. The I’ll take pkg over
internal blog post by Travis Jeffery provides a good overview of the pkg
and internal directories and when it might make sense to use them.
</p>

 <p>
It’s also a way to group Go code in one place when your root directory
contains lots of non-Go components and directories making it easier to
run various Go tools (as mentioned in these talks: Best Practices for
Industrial Programming from GopherCon EU 2018, GopherCon 2018: Kat
Zien - How Do You Structure Your Go Apps and GoLab 2018 - Massimiliano
Pippi - Project layout patterns in Go).
</p>

 <p>
See the  <code>/pkg</code> directory if you want to see which popular Go repos use
this project layout pattern. This is a common layout pattern, but it’s
not universally accepted and some in the Go community don’t recommend
it.
</p>

 <p>
It’s ok not to use it if your app project is really small and where an
extra level of nesting doesn’t add much value (unless you really want to
:-)). Think about it when it’s getting big enough and your root
directory gets pretty busy (especially if you have a lot of non-Go app
components).
</p>

 <p>
 <code>/api</code>
</p>

 <p>
OpenAPI/Swagger specs, JSON schema files, protocol definition files.
</p>

 <p>
 <code>/web</code>
</p>

 <p>
Web application specific components: static web assets, server side
templates and SPAs.
</p>

 <p>
 <code>/configs</code>
</p>

 <p>
Configuration file templates or default configs. Put your confd or
consul-template template files here.
</p>

 <p>
 <code>/init</code>
</p>

 <p>
System init (systemd, upstart, sysv) and process manager/supervisor
(runit, supervisord) configs.
</p>

 <p>
 <code>/scripts</code>
</p>

 <p>
Scripts to perform various build, install, analysis, etc operations.
These scripts keep the root level Makefile small and simple (e.g.,
 <a href="https://github.com/hashicorp/terraform/blob/master/Makefile">https://github.com/hashicorp/terraform/blob/master/Makefile</a>).
</p>

 <p>
 <code>/build</code>
</p>

 <p>
Packaging and Continuous Integration. Put your cloud (AMI), container
(Docker), OS (deb, rpm, pkg) package configurations and scripts in the
 <code>/build/package</code> directory.
</p>

 <p>
Put your CI (travis, circle, drone) configurations and scripts in the
 <code>/build/ci</code> directory. Note that some of the CI tools (e.g., Travis CI)
are very picky about the location of their config files. Try putting the
config files in the  <code>/build/ci</code> directory linking them to the location
where the CI tools expect them (when possible).
</p>

 <p>
 <code>/deployments</code>
</p>

 <p>
IaaS, PaaS, system and container orchestration deployment configurations
and templates (docker-compose, kubernetes/helm, mesos, terraform, bosh).
Note that in some repos (especially apps deployed with kubernetes) this
directory is called  <code>/deploy</code>.
</p>

 <p>
 <code>/test</code>
</p>

 <p>
Additional external test apps and test data. Feel free to structure the
 <code>/test</code> directory anyway you want. For bigger projects it makes sense to
have a data subdirectory. For example, you can have  <code>/test/data</code> or
 <code>/test/testdata</code> if you need Go to ignore what’s in that directory. Note
that Go will also ignore directories or files that begin with “.” or
“_“, so you have more flexibility in terms of how you name your test
data directory.
</p>

 <p>
 <code>/docs</code>
</p>

 <p>
Design and user documents (in addition to your godoc generated
documentation).
</p>

 <p>
 <code>/tools</code>
</p>

 <p>
Supporting tools for this project. Note that these tools can import code
from the  <code>/pkg</code> and  <code>/internal</code> directories.
</p>

 <p>
 <code>/examples</code>
</p>

 <p>
Examples for your applications and/or public libraries.
</p>

 <p>
 <code>/third_party</code>
</p>

 <p>
External helper tools, forked code and other 3rd party utilities (e.g.,
Swagger UI).
</p>

 <p>
 <code>/githooks</code>
</p>

 <p>
Git hooks.
</p>

 <p>
 <code>/assets</code>
</p>

 <p>
Other assets to go along with your repository (images, logos, etc).
</p>

 <p>
 <code>/website</code>
</p>

 <p>
This is the place to put your project’s website data if you are not
using GitHub pages.
</p>
</div>
 <h2>Directories You Shouldn’t Have  <a id="directories-you-shouldnrsquot-have" class="anchor" href="#directories-you-shouldnrsquot-have">#</a></h2> <div class="outline-text-2" id="text-directories-you-shouldnt-have">
 <p>
 <code>/src</code>
</p>

 <p>
Some Go projects do have a src folder, but it usually happens when the
devs came from the Java world where it’s a common pattern. If you can
help yourself try not to adopt this Java pattern. You really don’t want
your Go code or Go projects to look like Java :-)
</p>

 <p>
Don’t confuse the project level  <code>/src</code> directory with the  <code>/src</code>
directory Go uses for its workspaces as described in How to Write Go
Code. The  <code>$GOPATH</code> environment variable points to your (current)
workspace (by default it points to  <code>$HOME/go</code> on non-windows systems).
This workspace includes the top level  <code>/pkg</code>,  <code>/bin</code> and  <code>/src</code>
directories. Your actual project ends up being a sub-directory under
 <code>/src</code>, so if you have the  <code>/src</code> directory in your project the project
path will look like this:
 <code>/some/path/to/workspace/src/your_project/src/your_code.go</code>. Note that
with Go 1.11 it’s possible to have your project outside of your
 <code>GOPATH</code>, but it still doesn’t mean it’s a good idea to use this layout
pattern.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/go/project-structure/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/go/project-structure/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>SQL transactions</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
There are several advantages into using prepared statements and
transactions in SQL, in my case mostly with MariaDB. I will explain some
of the advantages, some of the caveats and handy tips to manage them,
specifically with Go.
</p>
 <h2>Why SQL Transactions ?  <a id="why-sql-transactions-" class="anchor" href="#why-sql-transactions-">#</a></h2> <div class="outline-text-2" id="text-why-sql-transactions">
 <p>
We want our unit of work to be reliable and consistent, even in case of
system failure.
</p>

 <p>
We want to provide isolation between programs that access the database
concurrently.
</p>

 <p>
When you start an explicit transaction and issue a DML (Data
Manipulation Language) statement, the resources being locked by the
statement remain locked, and the results of statement are not visible
from outside the transaction until you manually commit or rollback it.
</p>

 <p>
This is what you may or may not need.
</p>

 <p>
The InnoDB storage engine, which is my default go-to database storage
engine and the one you should be going to for relational data, supports
ACID-compliant transactions. SQL transactions are also a great way to
avoid data races in the database engines, and to run queries against a
cluster of databases, while preserving data consistency and integrity, a
performant way to do batch operations, a way to avoid SQL injections
into the database, and more. ACID properties
</p>

 <p>
In order to achieve these 2 goals, a database transaction must satisfy
the ACID properties, where:
</p>

 <ul class="org-ul"> <li>A is Atomicity, which means either all operations of the transaction
complete successfully, or the whole transaction fails, and everything
is rolled back, the database is unchanged.</li>

 <li>C is Consistency, which means the database state should remains valid
after the transaction is executed. More precisely, all data written to
the database must be valid according to predefined rules, including
constraints, cascades, and triggers.</li>

 <li>I is Isolation, meaning all transactions that run concurrently should
not affect each other. There are several levels of isolation that
defines when the changes made by 1 transaction can be visible to
others.</li>

 <li>D is Durability. It basically means that all data written by a
successful transaction must stay in a persistent storage and cannot be
lost, even in case of system failure.</li>
</ul> <p>
How to run a SQL DB transaction from a SQL shell or Navicat / DataGrip?
</p>

 <p>
It’s pretty simple:
</p>

 <ul class="org-ul"> <li>We start a transaction with the  <code>BEGIN</code> statement.</li>

 <li>Then we write a series of normal SQL queries (or operations).</li>

 <li>If all of them are successful, We  <code>COMMIT</code> the transaction to make it
permanent, the database will be changed to a new state.</li>

 <li>Otherwise, if any query fails, we  <code>ROLLBACK</code> the transaction, thus all
changes made by previous queries of the transaction will be gone, and
the database stays the same as it was before the transaction.</li>
</ul></div>
 <h2>Using Transactions with Go  <a id="using-transactions-with-go" class="anchor" href="#using-transactions-with-go">#</a></h2> <div class="outline-text-2" id="text-using-transactions-with-go">
 <p>
There are several reasons why you should prefer using the  <code>COMMIT</code>,
 <code>ROLLBACK</code> and others in programmatic and type safe Go.
</p>

 <p>
This gives you the opportunity to create prepared statements, execute
them in a loop and then commit. If you were to not use transactions, and
had to do 1000  <code>INSERT</code> statements, you would need 1000 database
connections opening and closing one after the other, for single  <code>EXEC</code>
queries, while with prepared statements you would leave an open tunnel
for communication from your application and the database. This obviously
is much faster and brings less load on all services.
</p>

 <p>
We always recommend you do prepared statements.
</p>

 <p>
We always recommend you use prepared statements in a SQL transaction
when executing more than one  <code>INSERT</code> /  <code>UPDATE</code> /  <code>DELETE</code> statement to
the database.
</p>
</div>
 <h2>Rules of thumb  <a id="rules-of-thumb" class="anchor" href="#rules-of-thumb">#</a></h2> <div class="outline-text-2" id="text-rules-of-thumb">
 <ul class="org-ul"> <li>Always remember to defer  <code>stmt.Close()</code> - assuming your prepared
statement is called  <code>stmt</code> - as soon as possible.</li>

 <li>If you have started a transaction and you need to stop execution or
return from the function,  <b>ALWAYS</b> make sure to  <code>tx.Rollback()</code>
otherwise the resources allocated for the transaction will never be
de-allocated.</li>

 <li>Leaving transactions open without committing or rolling back exhausts
the database connection and you might get an unresponsive database.
This has already occurred and caused several issue. Make sure you
always either rollback or commit.</li>

 <li>Assuming you called your transaction variable that resulted from
 <code>db.Begin()</code> as  <code>tx</code>, you should only skip issuing a  <code>tx.Rollback()</code>
if you are certain that the  <code>tx.Commit()</code> has been executed
successfully.</li>

 <li>Always make sure to defer  <code>rows.Close()</code> if working with rows as soon
as possible.</li>
</ul></div>
 <h2>Real life transaction in Go  <a id="real-life-transaction-in-go" class="anchor" href="#real-life-transaction-in-go">#</a></h2> <div class="outline-text-2" id="text-real-life-transaction-in-go">
 <p>
Here you can see some production transactions that I have slightly
altered for this purpose.
</p>

 <pre>// AddressBulkInsertion will perform a transaction to insert addresses in bulk
func AddressBulkInsertion(db *sql.DB, addresses []Address) error{
  tx, err := db.Begin()
  if err != nil {
    _ = tx.Rollback()
    return err
  }

  // here should be your SQL, never mind the naming here
  insertStmt, err := tx.Prepare(`
  INSERT INTO addresses (uid, address_data, created_at, updated_at)
  VALUES (?, ?, ?, ?) ON DUPLICATE KEY
      UPDATE address_data = ?, updated_at = ?;
  `)
  if err != nil {
    _ = tx.Rollback()
    return err
  }

  defer insertStmt.Close()

  for i := range payload {
    now := time.Now().Unix()

    if _, errr := insertStmt.Exec(
      uuid.NewString(),
      address.addressData,
      now,
      now,
    ); errr != nil {
      // you might be interested in continuing the loop
      // even when some error occurs, perhaps due to
      // bad data or inconsistencies and you try to do as good as possible
      log.Println(errr.Error())
      continue

      // otherwise simply rollback and return
      // if you want the entire bulk job to stop
      _ = tx.Rollback()
      return errr
    }
  }

  return tx.Commit()
}</pre>
</div>
 <h2>Useful Resouces  <a id="useful-resouces" class="anchor" href="#useful-resouces">#</a></h2> <div class="outline-text-2" id="text-useful-resouces">
 <p>
 <a href="https://mariadb.com/kb/en/transactions/">More information about
transactions specifically for MariaDB.</a>
</p>

 <p>
 <a href="https://dev.mysql.com/doc/refman/8.0/en/commit.html">More information
about transactions</a>
</p>

 <p>
 <a href="https://pkg.go.dev/database/sql">Official SQL package for working with
Go</a>
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/go/sql-transactions/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/go/sql-transactions/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Tips for clean code with Go</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <h2>Why Write Clean Code?  <a id="why-write-clean-code" class="anchor" href="#why-write-clean-code">#</a></h2> <div class="outline-text-2" id="text-why-write-clean-code">
 <p>
This document is a reference for the Go community that aims to help
developers write cleaner code. Whether you’re working on a personal
project or as part of a larger team, writing clean code is an important
skill to have. Establishing good paradigms and consistent, accessible
standards for writing clean code can help prevent developers from
wasting many meaningless hours on trying to understand their own (or
others’) work.
</p>

 <blockquote>
 <p>
We don’t read code, we decode it – Peter Seibel
</p>
</blockquote>

 <p>
As developers, we’re sometimes tempted to write code in a way that’s
convenient for the time being without regard for best practices; this
makes code reviews and testing more difficult. In a sense, we’re
encoding—and, in doing so, making it more difficult for others to
decode our work. But we want our code to be usable, readable, and
maintainable. And that requires coding the right way, not the easy way.
</p>

 <p>
This document begins with a simple and short introduction to the
fundamentals of writing clean code. Later, we’ll discuss concrete
refactoring examples specific to Go.
</p>

 <p>
 <b>About  <code>gofmt</code></b>
</p>

 <p>
I’d like to take a few sentences to clarify my stance on =gofmt=because
there are plenty of things I disagree with when it comes to this tool.
This tool allows us to have a common standard for writing Go code, and
that’s a great thing. As a developer myself, I can certainly appreciate
that Go programmers may feel somewhat restricted by gofmt, especially if
they disagree with some of its rules. But in my opinion, homogeneous
code is more important than having complete expressive freedom.
</p>
</div>
 <h2>Introduction to Clean Code  <a id="introduction-to-clean-code" class="anchor" href="#introduction-to-clean-code">#</a></h2> <div class="outline-text-2" id="text-introduction-to-clean-code">
 <p>
Clean code is the pragmatic concept of promoting readable and
maintainable software. Clean code establishes trust in the codebase and
helps minimize the chances of careless bugs being introduced. It also
helps developers maintain their agility, which typically plummets as the
codebase expands due to the increased risk of introducing bugs.
</p>
</div>
 <h3>Test-Driven Development  <a id="test-driven-development" class="anchor" href="#test-driven-development">#</a></h3> <div class="outline-text-3" id="text-test-driven-development">
 <p>
Test-driven development is the practice of testing your code frequently
throughout short development cycles or sprints. It ultimately
contributes to code cleanliness by inviting developers to question the
functionality and purpose of their code. To make testing easier,
developers are encouraged to write short functions that only do one
thing. For example, it’s arguably much easier to test (and understand) a
function that’s only 4 lines long than one that’s 40.
</p>

 <p>
Test-driven development consists of the following cycle:
</p>

 <ol class="org-ol"> <li>Write (or execute) a test</li>
 <li>If the test fails, make it pass</li>
 <li>Refactor your code accordingly</li>
 <li>Repeat</li>
</ol> <p>
Testing and refactoring are intertwined in this process. As you refactor
your code to make it more understandable or maintainable, you need to
test your changes thoroughly to ensure that you haven’t altered the
behavior of your functions. This can be incredibly useful as the
codebase grows.
</p>
</div>
 <h3>Naming Conventions  <a id="naming-conventions" class="anchor" href="#naming-conventions">#</a></h3> <div class="outline-text-3" id="text-naming-conventions">
</div>
 <h4>Comments  <a id="comments" class="anchor" href="#comments">#</a></h4> <div class="outline-text-4" id="text-comments">
 <p>
I’d like to first address the topic of commenting code, which is an
essential practice but tends to be misapplied. Unnecessary comments can
indicate problems with the underlying code, such as the use of poor
naming conventions. However, whether or not a particular comment is
“necessary” is somewhat subjective and depends on how legibly the code
was written. For example, the logic of well-written code may still be so
complex that it requires a comment to clarify what is going on. In that
case, one might argue that the comment is helpful and therefore
necessary.
</p>

 <p>
In Go, according to gofmt, all public variables and functions should be
annotated. I think this is absolutely fine, as it gives us consistent
rules for documenting our code. However, I always want to distinguish
between comments that enable auto-generated documentation and all other
comments. Annotation comments, for documentation, should be written like
documentation—they should be at a high level of abstraction and
concern the logical implementation of the code as little as possible.
</p>

 <p>
I say this because there are other ways to explain code and ensure that
it’s being written comprehensibly and expressively. If the code is
neither of those, some people find it acceptable to introduce a comment
explaining the convoluted logic. Unfortunately, that doesn’t really
help. For one, most people simply won’t read comments, as they tend to
be very intrusive to the experience of reviewing code. Additionally, as
you can imagine, a developer won’t be too happy if they’re forced to
review unclear code that’s been slathered with comments. The less that
people have to read to understand what your code is doing, the better
off they’ll be.
</p>

 <p>
Let’s take a step back and look at some concrete examples. Here’s how
you shouldn’t comment your code:
</p>

 <pre>// iterate over the range 0 to 9
// and invoke the doSomething function
// for each iteration
for i := 0; i < 10; i++ {
  doSomething(i)
}</pre>

 <p>
This is what I like to call a tutorial comment; it’s fairly common in
tutorials, which often explain the low-level functionality of a language
(or programming in general). While these comments may be helpful for
beginners, they’re absolutely useless in production code. Hopefully, we
aren’t collaborating with programmers who don’t understand something as
simple as a looping construct by the time they’ve begun working on a
development team. As programmers, we shouldn’t have to read the comment
to understand what’s going on—we know that we’re iterating over the
range 0 to 9 because we can simply read the code. Hence the proverb:
</p>

 <blockquote>
 <p>
Document why, not how. – Venkat Subramaniam
</p>
</blockquote>

 <p>
Following this logic, we can now change our comment to explain why we
are iterating from the range 0 to 9:
</p>

 <pre>// instatiate 10 threads to handle upcoming work load
for i := 0; i < 10; i++ {
  doSomething(i)
}</pre>

 <p>
Now we understand why we have a loop and can tell what we’re doing by
simply reading the code… Sort of.
</p>

 <p>
This still isn’t what I’d consider clean code. The comment is worrying
because it probably should not be necessary to express such an
explanation in prose, assuming the code is well written (which it
isn’t). Technically, we’re still saying what we’re doing, not why we’re
doing it. We can easily express this “what” directly in our code by
using more meaningful names:
</p>

 <pre>for workerID := 0; workerID < 10; workerID++ {
  instantiateThread(workerID)
}</pre>

 <p>
With just a few changes to our variable and function names, we’ve
managed to explain what we’re doing directly in our code. This is much
clearer for the reader because they won’t have to read the comment and
then map the prose to the code. Instead, they can simply read the code
to understand what it’s doing.
</p>

 <p>
Of course, this was a relatively trivial example. Writing clear and
expressive code is unfortunately not always so easy; it can become
increasingly difficult as the codebase itself grows in complexity. The
more you practice writing comments in this mindset and avoid explaining
what you’re doing, the cleaner your code will become.
</p>
</div>
 <h4>Function Naming  <a id="function-naming" class="anchor" href="#function-naming">#</a></h4> <div class="outline-text-4" id="text-function-naming">
 <p>
Let’s now move on to function naming conventions. The general rule here
is really simple: the more specific the function, the more general its
name. In other words, we want to start with a very broad and short
function name, such as  <code>Run</code> or  <code>Parse</code>, that describes the general
functionality. Let’s imagine that we are creating a configuration
parser. Following this naming convention, our top level of abstraction
might look something like the following:
</p>

 <pre>func main() {
    configpath := flag.String("config-path", "", "configuration file path")
    flag.Parse()

    config, err := configuration.Parse(*configpath)
    ...
}</pre>

 <p>
We’ll focus on the naming of the  <code>Parse</code> function. Despite this
function’s very short and general name, it’s actually quite clear what
it attempts to achieve.
</p>

 <p>
When we go one layer deeper, our function naming will become slightly
more specific:
</p>

 <pre>func Parse(filepath string) (Config, error) {
    switch fileExtension(filepath) {
    case "json":
        return parseJSON(filepath)
    case "yaml":
        return parseYAML(filepath)
    case "toml":
        return parseTOML(filepath)
    default:
        return Config{}, ErrUnknownFileExtension
    }
}</pre>

 <p>
Here, we’ve clearly distinguished the nested function calls from their
parent without being overly specific. This allows each nested function
call to make sense on its own as well as within the context of the
parent. On the other hand, if we had named the  <code>parseJSON</code> function
 <code>json</code> instead, it couldn’t possibly stand on its own. The functionality
would become lost in the name, and we would no longer be able to tell
whether this function is parsing, creating, or marshalling JSON.
</p>

 <p>
Notice that  <code>fileExtension</code> is actually a little more specific. However,
this is because its functionality is in fact quite specific in nature:
</p>

 <pre>func fileExtension(filepath string) string {
    segments := strings.Split(filepath, ".")
    return segments[len(segments)-1]
}</pre>

 <p>
This kind of logical progression in our function names—from a high
level of abstraction to a lower, more specific one—makes the code
easier to follow and read. Consider the alternative: If our highest
level of abstraction is too specific, then we’ll end up with a name that
attempts to cover all bases, like
 <code>DetermineFileExtensionAndParseConfigurationFile</code>. This is horrendously
difficult to read; we are trying to be too specific too soon and end up
confusing the reader, despite trying to be clear!
</p>
</div>
 <ul> <li>Variable Naming <div class="outline-text-5" id="text-variable-naming">
 <p>
Rather interestingly, the opposite is true for variables. Unlike
functions, our variables should be named from more to less specific the
deeper we go into nested scopes.
</p>

 <blockquote>
 <p>
You shouldn’t name your variables after their types for the same reason
you wouldn’t name your pets ’dog’ or ’cat’. – Dave Cheney
</p>
</blockquote>

 <p>
Why should our variable names become less specific as we travel deeper
into a function’s scope? Simply put, as a variable’s scope becomes
smaller, it becomes increasingly clear for the reader what that variable
represents, thereby eliminating the need for specific naming. In the
example of the previous function  <code>fileExtension</code>, we could even shorten
the name of the variable  <code>segments</code> to  <code>s</code> if we wanted to. The context
of the variable is so clear that it’s unnecessary to explain it any
further with longer variable names. Another good example of this is in
nested for loops:
</p>

 <pre>func PrintBrandsInList(brands []BeerBrand) {
    for _, b := range brands {
      fmt.Println(b)
    }
}</pre>

 <p>
In the above example, the scope of the variable b is so small that we
don’t need to spend any additional brain power on remembering what
exactly it represents. However, because the scope of brands is slightly
larger, it helps for it to be more specific. When expanding the variable
scope in the function below, this distinction becomes even more
apparent:
</p>

 <pre>func BeerBrandListToBeerList(beerBrands []BeerBrand) []Beer {
    var beerList []Beer
    for _, brand := range beerBrands {
        for _, beer := range brand {
            beerList = append(beerList, beer)
        }
    }
    return beerList
}</pre>

 <p>
Great! This function is easy to read. Now, let’s apply the opposite
(i.e., wrong) logic when naming our variables:
</p>

 <pre>func BeerBrandListToBeerList(b []BeerBrand) []Beer {
    var bl []Beer
    for _, beerBrand := range b {
        for _, beerBrandBeerName := range beerBrand {
            bl = append(bl, beerBrandBeerName)
        }
    }
    return bl
}</pre>

 <p>
Even though it’s possible to figure out what this function is doing, the
excessive brevity of the variable names makes it difficult to follow the
logic as we travel deeper. This could very well spiral into full-blown
confusion because we’re mixing short and long variable names
inconsistently.
</p>
</div>
</li></ul> <h3>Cleaning Functions  <a id="cleaning-functions" class="anchor" href="#cleaning-functions">#</a></h3> <div class="outline-text-3" id="text-cleaning-functions">
 <p>
Now that we know some best practices for naming our variables and
functions, as well as clarifying our code with comments, let’s dive into
some specifics of how we can refactor functions to make them cleaner.
</p>
</div>
 <ul> <li>Function Length <div class="outline-text-5" id="text-function-length">
 <blockquote>
 <p>
How small should a function be? Smaller than that! – Robert C. Martin
</p>
</blockquote>

 <p>
When writing clean code, our primary goal is to make our code easily
digestible. The most effective way to do this is to make our functions
as short as possible. It’s important to understand that we don’t
necessarily do this to avoid code duplication. The more important reason
is to improve  <i>code comprehension</i>.
</p>

 <p>
It can help to look at a function’s description at a very high level to
understand this better:
</p>

 <pre>fn GetItem:
  - parse json input for order id
  - get user from context
  - check user has appropriate role
  - get order from database</pre>

 <p>
By writing short functions (which are typically 5–8 lines in Go), we
can create code that reads almost as naturally as our description above:
</p>

 <pre>var (
    NullItem = Item{}
    ErrInsufficientPrivileges = errors.New("user does not have sufficient privileges")
)

func GetItem(ctx context.Context, json []bytes) (Item, error) {
    order, err := NewItemFromJSON(json)
    if err != nil {
        return NullItem, err
    }
    if !GetUserFromContext(ctx).IsAdmin() {
          return NullItem, ErrInsufficientPrivileges
    }
    return db.GetItem(order.ItemID)
}</pre>

 <p>
Using smaller functions also eliminates another horrible habit of
writing code:  <b>indentation hell</b>. This typically occurs when a chain of
 <code>if</code> statements are carelessly nested in a function. This makes it very
difficult for human beings to parse the code and should be eliminated
whenever spotted. Indentation hell is particularly common when working
with  <code>interface{}</code> and using type casting:
</p>

 <pre>func GetItem(extension string) (Item, error) {
    if refIface, ok := db.ReferenceCache.Get(extension); ok {
        if ref, ok := refIface.(string); ok {
            if itemIface, ok := db.ItemCache.Get(ref); ok {
                if item, ok := itemIface.(Item); ok {
                    if item.Active {
                        return Item, nil
                    } else {
                      return EmptyItem, errors.New("no active item found in cache")
                    }
                } else {
                  return EmptyItem, errors.New("could not cast cache interface to Item")
                }
            } else {
              return EmptyItem, errors.New("extension was not found in cache reference")
            }
        } else {
          return EmptyItem, errors.New("could not cast cache reference interface to Item")
        }
    }
    return EmptyItem, errors.New("reference not found in cache")
}</pre>

 <p>
First, indentation hell makes it difficult for other developers to
understand the flow of your code. Second, if the logic in our if
statements expands, it’ll become exponentially more difficult to figure
out which statement returns what (and to ensure that all paths return
some value).
</p>

 <p>
Yet another problem is that this deep nesting of conditional statements
forces the reader to frequently scroll and keep track of many logical
states in their head. It also makes it more difficult to test the code
and catch bugs because there are so many different nested possibilities
that you have to account for.
</p>

 <p>
Indentation hell can result in reader fatigue if a developer has to
constantly parse unwieldy code like the sample above. Naturally, this is
something we want to avoid at all costs.
</p>

 <p>
So, how do we clean this function? Fortunately, it’s actually quite
simple. On our first iteration, we will try to ensure that we are
returning an error as soon as possible. Instead of nesting the  <code>if</code> and
 <code>else</code> statements, we want to “push our code to the left,” so to speak.
Take a look:
</p>

 <pre>func GetItem(extension string) (Item, error) {
    refIface, ok := db.ReferenceCache.Get(extension)
    if !ok {
        return EmptyItem, errors.New("reference not found in cache")
    }

    ref, ok := refIface.(string)
    if !ok {
        // return cast error on reference
    }

    itemIface, ok := db.ItemCache.Get(ref)
    if !ok {
        // return no item found in cache by reference
    }

    item, ok := itemIface.(Item)
    if !ok {
        // return cast error on item interface
    }

    if !item.Active {
        // return no item active
    }

    return Item, nil
}</pre>

 <p>
Once we’re done with our first attempt at refactoring the function, we
can proceed to split up the function into smaller functions. Here’s a
good rule of thumb: If the  <code>value, err :=</code> pattern is repeated more than
once in a function, this is an indication that we can split the logic of
our code into smaller pieces:
</p>

 <pre>func GetItem(extension string) (Item, error) {
    ref, ok := getReference(extension)
    if !ok {
        return EmptyItem, ErrReferenceNotFound
    }
    return getItemByReference(ref)
}

func getReference(extension string) (string, bool) {
    refIface, ok := db.ReferenceCache.Get(extension)
    if !ok {
        return EmptyItem, false
    }
    return refIface.(string)
}

func getItemByReference(reference string) (Item, error) {
    item, ok := getItemFromCache(reference)
    if !item.Active || !ok {
        return EmptyItem, ErrItemNotFound
    }
    return Item, nil
}

func getItemFromCache(reference string) (Item, bool) {
    if itemIface, ok := db.ItemCache.Get(ref); ok {
        return EmptyItem, false
    }
    return itemIface.(Item), true
}</pre>

 <p>
As mentioned previously, indentation hell can make it difficult to test
our code. When we split up our  <code>GetItem</code> function into several helpers,
we make it easier to track down bugs when testing our code. Unlike the
original version, which consisted of several  <code>if</code> statements in the same
scope, the refactored version of  <code>GetItem</code> has just two branching paths
that we must consider. The helper functions are also short and
digestible, making them easier to read.
</p>

 <blockquote>
 <p>
Note: For production code, one should elaborate on the code even further
by returning errors instead of bool values. This makes it much easier to
understand where the error is originating from. However, as these are
just example functions, returning bool values will suffice for now.
Examples of returning errors more explicitly will be explained in more
detail later.
</p>
</blockquote>

 <p>
Notice that cleaning the  <code>GetItem</code> function resulted in more lines of
code overall. However, the code itself is now much easier to read. It’s
layered in an onion-style fashion, where we can ignore “layers” that we
aren’t interested in and simply peel back the ones that we do want to
examine. This makes it easier to understand low-level functionality
because we only have to read maybe 3–5 lines at a time.
</p>

 <p>
This example illustrates that we cannot measure the cleanliness of our
code by the number of lines it uses. The first version of the code was
certainly much shorter. However, it was  <i>artificially</i> short and very
difficult to read. In most cases, cleaning code will initially expand
the existing codebase in terms of the number of lines. But this is
highly preferable to the alternative of having messy, convoluted logic.
If you’re ever in doubt about this, just consider how you feel about the
following function, which does exactly the same thing as our code but
only uses two lines:
</p>

 <pre>func GetItemIfActive(extension string) (Item, error) {
    if refIface,ok := db.ReferenceCache.Get(extension); ok {if ref,ok := refIface.(string); ok { if itemIface,ok := db.ItemCache.Get(ref); ok { if item,ok := itemIface.(Item); ok { if item.Active { return Item,nil }}}}} return EmptyItem, errors.New("reference not found in cache")
}</pre>
</div>
</li>
 <li>Function Signatures <div class="outline-text-5" id="text-function-signatures">
 <p>
Creating a good function naming structure makes it easier to read and
understand the intent of the code. As we saw above, making our functions
shorter helps us understand the function’s logic. The last part of
cleaning our functions involves understanding the context of the
function input. With this comes another easy-to-follow rule:  <b>Function
signatures should only contain one or two input parameters</b>. In certain
exceptional cases, three can be acceptable, but this is where we should
start considering a refactor. Much like the rule that our functions
should only be 5–8 lines long, this can seem quite extreme at first.
However, I feel that this rule is much easier to justify.
</p>

 <p>
Take the following function from
 <a href="https://www.rabbitmq.com/tutorials/tutorial-one-go.html">RabbitMQ’s
introduction tutorial to its Go library</a>:
</p>

 <pre>q, err := ch.QueueDeclare(
  "hello", // name
  false,   // durable
  false,   // delete when unused
  false,   // exclusive
  false,   // no-wait
  nil,     // arguments
)</pre>

 <p>
The function  <code>QueueDeclare</code> takes six input parameters, which is quite a
lot. With some effort, it’s possible to understand what this code does
thanks to the comments. However, the comments are actually part of the
problem—as mentioned earlier, they should be substituted with
descriptive code whenever possible. After all, there’s nothing
preventing us from invoking the QueueDeclare function without comments:
</p>

 <pre>q, err := ch.QueueDeclare("hello", false, false, false, false, nil)</pre>

 <p>
Now, without looking at the commented version, try to remember what the
fourth and fifth  <code>false</code> arguments represent. It’s impossible, right?
You will inevitably forget at some point. This can lead to costly
mistakes and bugs that are difficult to correct. The mistakes might even
occur through incorrect comments—imagine labeling the wrong input
parameter. Correcting this mistake will be unbearably difficult to
correct, especially when familiarity with the code has deteriorated over
time or was low to begin with. Therefore, it is recommended to replace
these input parameters with an ’Options’  <code>struct</code> instead:
</p>

 <pre>type QueueOptions struct {
    Name string
    Durable bool
    DeleteOnExit bool
    Exclusive bool
    NoWait bool
    Arguments []interface{}
}

q, err := ch.QueueDeclare(QueueOptions{
    Name: "hello",
    Durable: false,
    DeleteOnExit: false,
    Exclusive: false,
    NoWait: false,
    Arguments: nil,
})</pre>

 <p>
This solves two problems: misusing comments, and accidentally labeling
the variables incorrectly. Of course, we can still confuse properties
with the wrong value, but in these cases, it will be much easier to
determine where our mistake lies within the code. The ordering of the
properties also doesn’t matter anymore, so incorrectly ordering the
input values is no longer a concern.
</p>

 <p>
The last added bonus of this technique is that we can use our
QueueOptions struct to infer the default values of our function’s input
parameters. When structures in Go are declared, all properties are
initialised to their default value. This means that our  <code>QueueDeclare</code>
option can actually be invoked in the following way:
</p>

 <pre>q, err := ch.QueueDeclare(QueueOptions{
    Name: "hello",
})</pre>

 <p>
The rest of the values are initialised to their default value of  <code>false</code>
(except for  <code>Arguments</code>, which as an interface has a default value of
 <code>nil</code>). Not only are we much safer with this approach, but we are also
much clearer with our intentions. In this case, we could actually write
less code. This is an all-around win for everyone on the project.
</p>

 <p>
One final note on this: It’s not always possible to change a function’s
signature. In this case, for example, we don’t actually have control
over our =QueueDeclare=function signature because it’s from the RabbitMQ
library. It’s not our code, so we can’t change it. However, we can wrap
these functions to suit our purposes:
</p>

 <pre>type RMQChannel struct {
    channel *amqp.Channel
}

func (rmqch *RMQChannel) QueueDeclare(opts QueueOptions) (Queue, error) {
    return rmqch.channel.QueueDeclare(
        opts.Name,
        opts.Durable,
        opts.DeleteOnExit,
        opts.Exclusive,
        opts.NoWait,
        opts.Arguments,
    )
}</pre>

 <p>
Basically, we create a new structure named  <code>RMQChannel</code> that contains
the  <code>amqp.Channel</code> type, which has the  <code>QueueDeclare</code> method. We then
create our own version of this method, which essentially just calls the
old version of the RabbitMQ library function. Our new method has all the
advantages described before, and we achieved this without actually
having to change any of the code in the RabbitMQ library.
</p>

 <p>
We’ll use this idea of wrapping functions to introduce more clean and
safe code later when discussing  <code>interface{}</code>.
</p>
</div>
</li>
 <li>Variable Scope <div class="outline-text-5" id="text-variable-scope">
 <p>
Now, let’s take a step back and revisit the idea of writing smaller
functions. This has another nice side effect that we didn’t cover in the
previous chapter: Writing smaller functions can typically eliminate
reliance on mutable variables that leak into the global scope.
</p>

 <p>
Global variables are problematic and don’t belong in clean code; they
make it very difficult for programmers to understand the current state
of a variable. If a variable is global and mutable, then by definition,
its value can be changed by any part of the codebase. At no point can
you guarantee that this variable is going to be a specific value… And
that’s a headache for everyone. This is yet another example of a trivial
problem that’s exacerbated when the codebase expands.
</p>

 <p>
Let’s look at a short example of how non-global variables with a large
scope can cause problems. These variables also introduce the issue of
variable shadowing.
</p>

 <pre>func doComplex() (string, error) {
    return "Success", nil
}

func main() {
    var val string
    num := 32

    switch num {
    case 16:
    // do nothing
    case 32:
        val, err := doComplex()
        if err != nil {
            panic(err)
        }
        if val == "" {
            // do something else
        }
    case 64:
        // do nothing
    }

    fmt.Println(val)
}</pre>

 <p>
What’s the problem with this code? From a quick skim, it seems the
 <code>var val string</code> value should be printed out as  <code>Success</code> by the end of
the main function. Unfortunately, this is not the case. The reason for
this lies in the following line:
</p>

 <pre>val, err := doComplex()</pre>

 <p>
This declares a new variable  <code>val</code> in the switch’s  <code>case 32</code> scope and
has nothing to do with the variable declared in the first line of
 <code>main</code>. Of course, it can be argued that Go syntax is a little tricky,
which I don’t necessarily disagree with, but there is a much worse issue
at hand. The declaration of  <code>var val string</code> as a mutable, largely
scoped variable is completely unnecessary. If we do a very simple
refactor, we will no longer have this issue:
</p>

 <pre>func getStringResult(num int) (string, error) {
    switch num {
    case 16:
    // do nothing
    case 32:
       return doComplex()
    case 64:
        // do nothing
    }
    return ""
}

func main() {
    val, err := getStringResult(32)
    if err != nil {
        panic(err)
    }
    if val == "" {
        // do something else
    }
    fmt.Println(val)
}</pre>

 <p>
After our refactor, val is no longer modified, and the scope has been
reduced. Again, keep in mind that these functions are very simple. Once
this kind of code style becomes a part of larger, more complex systems,
it can be impossible to figure out why errors are occurring. We don’t
want this to happen—not only because we generally dislike software
errors but also because it’s disrespectful to our colleagues, and
ourselves; we are potentially wasting each other’s time having to debug
this type of code. Developers need to take responsibility for their own
code rather than blaming these issues on the variable declaration syntax
of a particular language like Go.
</p>

 <p>
On a side note, if the  <code>// do something else</code> part is another attempt to
mutate the val variable, we should extract that logic out as its own
self-contained function, as well as the previous part of it. This way,
instead of expanding the mutable scope of our variables, we can just
return a new value:
</p>

 <pre>func getVal(num int) (string, error) {
    val, err := getStringResult(32)
    if err != nil {
        return "", err
    }
    if val == "" {
        return NewValue() // pretend function
    }
}

func main() {
    val, err := getVal(32)
    if err != nil {
        panic(err)
    }
    fmt.Println(val)
}</pre>
</div>
</li>
 <li>Variable Declaration <div class="outline-text-5" id="text-variable-declaration">
 <p>
Other than avoiding issues with variable scope and mutability, we can
also improve readability by declaring variables as close to their usage
as possible. In C programming, it’s common to see the following approach
to declaring variables:
</p>

 <pre>func main() {
  var err error
  var items []Item
  var sender, receiver chan Item

  items = store.GetItems()
  sender = make(chan Item)
  receiver = make(chan Item)

  for _, item := range items {
    // ...
  }
}</pre>

 <p>
This suffers from the same symptom as described in our discussion of
variable scope. Even though these variables might not actually be
reassigned at any point, this kind of coding style keeps the readers on
their toes, in all the wrong ways. Much like computer memory, our
brain’s short-term memory has a limited capacity. Having to keep track
of which variables are mutable and whether or not a particular fragment
of code will mutate them makes it more difficult to understand what the
code is doing. Figuring out the eventually returned value can be a
nightmare. Therefore, to makes this easier for our readers (and our
future selves), it’s recommended that you declare variables as close to
their usage as possible:
</p>

 <pre>func main() {
    var sender chan Item
    sender = make(chan Item)

    go func() {
        for {
            select {
            case item := <-sender:
                // do something
            }
        }
    }()
}</pre>

 <p>
However, we can do even better by invoking the function directly after
its declaration. This makes it much clearer that the function logic is
associated with the declared variable:
</p>

 <pre>func main() {
  sender := func() chan Item {
    channel := make(chan Item)
    go func() {
      for {
        select { ... }
      }
    }()
    return channel
  }
}</pre>

 <p>
And coming full circle, we can move the anonymous function to make it a
named function instead:
</p>

 <pre>func main() {
  sender := NewSenderChannel()
}

func NewSenderChannel() chan Item {
  channel := make(chan Item)
  go func() {
    for {
      select { ... }
    }
  }()
  return channel
}</pre>

 <p>
It is still clear that we are declaring a variable, and the logic
associated with the returned channel is simple, unlike in the first
example. This makes it easier to traverse the code and understand the
role of each variable.
</p>

 <p>
Of course, this doesn’t actually prevent us from mutating our  <code>sender</code>
variable. There is nothing that we can do about this, as there is no way
of declaring a  <code>const struct</code> or static variables in Go. This means that
we’ll have to restrain ourselves from modifying this variable at a later
point in the code.
</p>

 <blockquote>
 <p>
NOTE: The keyword const does exist but is limited in use to primitive
types only.
</p>
</blockquote>

 <p>
One way of getting around this can at least limit the mutability of a
variable to the package level. The trick involves creating a structure
with the variable as a private property. This private property is
thenceforth only accessible through other methods provided by this
wrapping structure. Expanding on our channel example, this would look
something like the following:
</p>

 <pre>type Sender struct {
  sender chan Item
}

func NewSender() *Sender {
  return &Sender{
    sender: NewSenderChannel(),
  }
}

func (s *Sender) Send(item Item) {
  s.sender <- item
}</pre>

 <p>
We have now ensured that the  <code>sender</code> property of our  <code>Sender</code> struct is
never mutated—at least not from outside of the package. As of writing
this document, this is the only way of creating publicly immutable
non-primitive variables. It’s a little verbose, but it’s truly worth the
effort to ensure that we don’t end up with strange bugs resulting from
accidental variable modification.
</p>

 <pre>func main() {
  sender := NewSender()
  sender.Send(&Item{})
}</pre>

 <p>
Looking at the example above, it’s clear how this also simplifies the
usage of our package. This way of hiding the implementation is
beneficial not only for the maintainers of the package but also for the
users. Now, when initialising and using the  <code>Sender</code> structure, there is
no concern over its implementation. This opens up for a much looser
architecture.
</p>

 <p>
Because our users aren’t concerned with the implementation, we are free
to change it at any point, since we have reduced the point of contact
that users have with the package. If we no longer wish to use a channel
implementation in our package, we can easily change this without
breaking the usage of the  <code>Send</code> method (as long as we adhere to its
current function signature).
</p>

 <blockquote>
 <p>
NOTE: There is a fantastic explanation of how to handle the abstraction
in client libraries, taken from the talk
 <a href="https://www.youtube.com/watch?v=kJq81Y7OEx4">AWS re:Invent 2017:
Embracing Change without Breaking the World (DEV319)</a>.
</p>
</blockquote>

 <p>
That is it for Part I of this document. Hope you have learned something
useful and that you are itching to get back to your codebase to apply
these principles.
</p>
</div>
</li></ul></div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/go/tips-for-clean-code-with-go/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/go/tips-for-clean-code-with-go/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Zen of Go</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Something that I’ve been thinking about a lot recently, when reflecting
on the body of my own work, is a common subtitle, how should I write
good code? Given nobody actively seeks to write bad code, this leads to
the question; how do you know when you’ve written good Go code? If
there’s a continuum between good and bad, how to do we know what the
good parts are? What are its properties, its attributes, its hallmarks,
its patterns, and its idioms?
</p>
 <h3>Maintainability counts  <a id="maintainability-counts" class="anchor" href="#maintainability-counts">#</a></h3> <div class="outline-text-3" id="text-maintainability-counts">
 <p>
Clarity, readability, simplicity, are all aspects of maintainability.
Can the thing you worked hard to build be maintained after you’re gone?
What can you do today to make it easier for those that come after you?
</p>
</div>
 <h3>Each package fulfils a single purpose  <a id="each-package-fulfils-a-single-purpose" class="anchor" href="#each-package-fulfils-a-single-purpose">#</a></h3> <div class="outline-text-3" id="text-each-package-fulfils-a-single-purpose">
 <p>
A well designed Go package provides a single idea, a set of related
behaviours. A good Go package starts by choosing a good name. Package
names should always be lowercase and not contain any underscores or
dashes. Think of your package’s name as an elevator pitch to describe
what it provides, using just one word. Common examples,  <code>controllers</code>,
 <code>jobs</code>,  <code>services</code>,  <code>utils</code>.
</p>
</div>
 <h3>Handle errors explicitly  <a id="handle-errors-explicitly" class="anchor" href="#handle-errors-explicitly">#</a></h3> <div class="outline-text-3" id="text-handle-errors-explicitly">
 <p>
Robust programs are composed from pieces that handle the failure cases
before they pat themselves on the back. The verbosity of
 <code>if err !</code> nil { return err }=is outweighed by the value of deliberately
handling each failure condition at the point at which they occur. Panic
and recover are not exceptions, they aren’t intended to be used that
way. Ensure you always use  <code>log.Printf(err.Error())</code> in order to log
those errors to the application log for monitoring or debugging.
</p>
</div>
 <h3>Return early rather than nesting deeply  <a id="return-early-rather-than-nesting-deeply" class="anchor" href="#return-early-rather-than-nesting-deeply">#</a></h3> <div class="outline-text-3" id="text-return-early-rather-than-nesting-deeply">
 <p>
Every time you indent you add another precondition to the programmer’s
stack consuming one of the 7 ±2 slots in their short term memory. Avoid
control flow that requires deep indentation. Rather than nesting deeply,
keep the success path to the left using guard clauses.
</p>
</div>
 <h3>Leave concurrency to the caller  <a id="leave-concurrency-to-the-caller" class="anchor" href="#leave-concurrency-to-the-caller">#</a></h3> <div class="outline-text-3" id="text-leave-concurrency-to-the-caller">
 <p>
Let the caller choose if they want to run your library or function
asynchronously, don’t force it on them. If your library uses concurrency
it should do so transparently.
</p>
</div>
 <h3>Before you launch a goroutine, know when it will stop  <a id="before-you-launch-a-goroutine-know-when-it-will-stop" class="anchor" href="#before-you-launch-a-goroutine-know-when-it-will-stop">#</a></h3> <div class="outline-text-3" id="text-before-you-launch-a-goroutine-know-when-it-will-stop">
 <p>
Goroutines own resources; locks, variables, memory, etc. The sure fire
way to free those resources is to stop the owning goroutine.
</p>
</div>
 <h3>Avoid package level state  <a id="avoid-package-level-state" class="anchor" href="#avoid-package-level-state">#</a></h3> <div class="outline-text-3" id="text-avoid-package-level-state">
 <p>
Seek to be explicit, reduce coupling, and spooky action at a distance by
providing the dependencies a type needs as fields on that type rather
than using package variables. Exceptions to this rule are a global
singleton for the application config, and a database pool connection.
</p>
</div>
 <h3>Simplicity matters  <a id="simplicity-matters" class="anchor" href="#simplicity-matters">#</a></h3> <div class="outline-text-3" id="text-simplicity-matters">
 <p>
Simplicity is not a synonym for unsophisticated. Simple doesn’t mean
crude, it means  <b> <i>readable</i></b> and  <b> <i>maintainable</i></b>. When it is possible
to choose, defer to the simpler solution.
</p>
</div>
 <h3>Write tests to lock in the behaviour of your package  <a id="write-tests-to-lock-in-the-behaviour-of-your-package" class="anchor" href="#write-tests-to-lock-in-the-behaviour-of-your-package">#</a></h3> <div class="outline-text-3" id="text-write-tests-to-lock-in-the-behaviour-of-your-package">
 <p>
Test first or test later, if you shoot for 100% test coverage or are
happy with less, regardless, your package’s API is your contract with
its users. Tests are the guarantees that those contracts are written in.
Make sure you test for the behaviour that users can observe and rely on.
</p>
</div>
 <h3>If you think it’s slow, first prove it with a benchmark  <a id="if-you-think-itrsquos-slow-first-prove-it-with-a-benchmark" class="anchor" href="#if-you-think-itrsquos-slow-first-prove-it-with-a-benchmark">#</a></h3> <div class="outline-text-3" id="text-if-you-think-its-slow-first-prove-it-with-a-benchmark">
 <p>
So many crimes against maintainability are committed in the name of
performance. Optimisation tears down abstractions, exposes internals,
and couples tightly. If you’re choosing to shoulder that cost, ensure it
is done for good reason.
</p>
</div>
 <h3>Moderation is a virtue  <a id="moderation-is-a-virtue" class="anchor" href="#moderation-is-a-virtue">#</a></h3> <div class="outline-text-3" id="text-moderation-is-a-virtue">
 <p>
Use goroutines, channels, locks, interfaces, embedding, in moderation.
</p>
</div>
 <h2>Personal choices  <a id="personal-choices" class="anchor" href="#personal-choices">#</a></h2> <div class="outline-text-2" id="text-personal-choices">
</div>
 <h3>Never use anything other than camelCase  <a id="never-use-anything-other-than-camelcase" class="anchor" href="#never-use-anything-other-than-camelcase">#</a></h3> <div class="outline-text-3" id="text-never-use-anything-other-than-camelcase">
 <p>
My convention is using camelCase for all purposes, including JSON
responses, and in Go, if you would like to have a member (function,
variable, struct var) exported (public) you must do it with
UpperCamelCase. I avoid snake_case at all costs, since I mostly use it
for database fields.
</p>
</div>
 <h3>Short variable names only on short functions  <a id="short-variable-names-only-on-short-functions" class="anchor" href="#short-variable-names-only-on-short-functions">#</a></h3> <div class="outline-text-3" id="text-short-variable-names-only-on-short-functions">
 <p>
Only use one letter variables when the scope of them is so reduced and
when it does not affect the readability and maintainability of the code
they are lodged in.
</p>
</div>
 <h3>Comments  <a id="comments" class="anchor" href="#comments">#</a></h3> <div class="outline-text-3" id="text-comments">
 <p>
Comments should only be written using  <i>/. The multi-line comment /* *</i>
is left for disabling large pieces of code. Function comments should not
include any type annotations or similar habits. GoDoc is not PHPDoc or
JavaDoc. Every package should include a Doc.go file which serves as
introduction to the package’s purpose, such as below. Document why, not
how.
</p>
</div>
 <h3>Slice allocation  <a id="slice-allocation" class="anchor" href="#slice-allocation">#</a></h3> <div class="outline-text-3" id="text-slice-allocation">
 <p>
If you happen to know the exact size that a slice will take, always
allocate that. Only use append in the case where you may be filtering
out items, and/or are not sure of the size the list will be. This is
more clear and more efficient.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/go/zen-of-go/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/go/zen-of-go/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Go</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-09-29 wo> </span></span>  <a href="/blog/articles/go/how-i-write-http-services/index.html">How I wrote HTTP services</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-09-27 ma> </span></span>  <a href="/blog/articles/go/project-structure/index.html">Project structure in Go</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-09-16 do> </span></span>  <a href="/blog/articles/go/sql-transactions/index.html">SQL transactions</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-01-26 di> </span></span>  <a href="/blog/articles/go/opinionated-style-guide/index.html">Opinionated style guide for Go</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2020-11-13 vr> </span></span>  <a href="/blog/articles/go/file-descriptors-and-go/index.html">File descriptors and Go</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2020-10-04 zo> </span></span>  <a href="/blog/articles/go/zen-of-go/index.html">Zen of Go</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2020-10-02 vr> </span></span>  <a href="/blog/articles/go/tips-for-clean-code-with-go/index.html">Tips for clean code with Go</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2020-09-18 vr> </span></span>  <a href="/blog/articles/go/make-or-new/index.html">make or new ?</a>
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/go/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/go/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Free à la Carte</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Free monads based on  from intuitions from the Data types à la Carte paper. Combine functors and make embedded DSLs in Haskell.
</p>

 <p>
See the original paper, by Wouter Swierstra:  <a href="https://webspace.science.uu.nl/~swier004/publications/2008-jfp.pdf">https://webspace.science.uu.nl/~swier004/publications/2008-jfp.pdf</a> .
</p>

 <p>
See the Haskell library I built around it:  <a href="https://codeberg.org/jjba23/free-alacarte">https://codeberg.org/jjba23/free-alacarte</a> .
</p>
 <h2>How do you use this ?  <a id="how-do-you-use-this-" class="anchor" href="#how-do-you-use-this-">#</a></h2> <div class="outline-text-2" id="text-org49b5bb7">
 <p>
This section gives a brief demonstration of using free monads to model effects.
</p>

 <p>
Four effectful functions are defined, categorized into two separate data types.
</p>

 <pre>data Teletype a
  = GetChar (Char -> a)
  | PutChar Char a
  deriving (Functor)

 
data FileSystem a
  = ReadFile FilePath (String -> a)
  | WriteFile FilePath String a
  deriving (Functor)</pre>

 <p>
If you are into it, you can also write the Functor instances by hand, for your free monads, e.g.:
</p>

 <pre>instance Functor Teletype where
  fmap :: (a -> b) -> Teletype a -> Teletype b
  fmap f = \case
    GetChar g   -> GetChar (f . g)
    PutChar c g -> PutChar c (f g)</pre>

 <p>
An  <code>exec</code> function can execute values of these data types using the  <code>Free</code> free monad. This uses intuitions of category theory to describe imperative sequence of computations as a fold over a functor.  <b>NOTE</b>: the  <code>exec</code> function is provided by this library and you don’t need to implement it yourself.
</p>

 <pre>exec :: Exec f => Free f a -> IO a
exec = foldFree return execAlgebra</pre>

 <p>
You should then write the  <code>Exec</code> instances, in other words, the concrete implementations.
 <b>NOTE</b>: the typeclass  <code>Exec</code>, and  <code>Exec (f :+: g)</code> instance are also provided by this library, and you don’t need to implement it yourself.
</p>

 <pre>class Functor f => Exec f where
  execAlgebra :: f (IO a) -> IO a

instance (Exec f, Exec g) => Exec (f :+: g) where
  execAlgebra = \case
    Left' e -> execAlgebra e
    Right' e -> execAlgebra e</pre>

 <p>
Then you can write the actual implementations of those effects:
</p>
 <pre>instance Exec Teletype where
  execAlgebra = \case
    GetChar f    -> Prelude.getChar >>= f
    PutChar c io -> Prelude.putChar c >> io

  
instance Exec FileSystem where
  execAlgebra (ReadFile path f) = Prelude.readFile path >>= f
  execAlgebra (WriteFile path s f) = Prelude.writeFile path s >> f</pre>

 <p>
Then we can define some smart constructors to create our embedded DSL and save us some boilerplate, while adding syntactic sugar.
</p>

 <pre>getChar :: (Teletype :<: f) => Free f Char
getChar = injectFree (GetChar Pure)

putChar :: (Teletype :<: f) => Char -> Free f ()
putChar c = injectFree (PutChar c (Pure ()))

readFile :: (FileSystem :<: f) => FilePath -> Free f String
readFile path = injectFree (ReadFile path Pure)

writeFile :: (FileSystem :<: f) => FilePath -> String -> Free f ()
writeFile path s = injectFree (WriteFile path s (Pure ()))</pre>

 <p>
The  <code>cat</code> function serves as an example of composition. In the following, I use a more general type than that used in the paper. Here we use  <code>mapM_</code> instead of  <code>mapM</code> to discard the resulting list of unit.
</p>

 <pre>cat :: (FileSystem :<: f, Teletype :<: f) => FilePath -> Free f ()
cat path = mapM_ putChar =<< readFile path</pre>

 <p>
The following example uses the  <code>cat</code> function to print the content of the README.md file in this directory.
</p>

 <pre>main :: IO ()
main = exec @(FileSystem :+: Teletype) $ cat "README.md"</pre>
</div>
 <h2>More on the topic  <a id="more-on-the-topic" class="anchor" href="#more-on-the-topic">#</a></h2> <div class="outline-text-2" id="text-org36d9e00">
 <p>
I can only extremely recommend the following resources to gain more understanding about the ideas and intuitions behind this library, and behind Data types à la Carte.
</p>

 <ul class="org-ul"> <li>Original paper, by Wouter Swierstra:  <a href="https://webspace.science.uu.nl/~swier004/publications/2008-jfp.pdf">https://webspace.science.uu.nl/~swier004/publications/2008-jfp.pdf</a></li>
 <li>Powerpoint explanation, by Wouter Swierstra:  <a href="https://webspace.science.uu.nl/~swier004/talks/2018-fp-ams.pdf">https://webspace.science.uu.nl/~swier004/talks/2018-fp-ams.pdf</a></li>
 <li>Good alternative explanation and implementation, by Travis Cardwell:  <a href="https://www.extrema.is/blog/2022/04/04/data-types-a-la-carte">https://www.extrema.is/blog/2022/04/04/data-types-a-la-carte</a></li>
</ul></div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/haskell/free-alacarte/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/haskell/free-alacarte/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Haskell in Production at Foxdown Systems</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Haskell is the first programming language we reach for when we build production software systems. This likely seems unusual to anyone who only has a passing familiarity with the language. Haskell has a reputation for being an advanced language with a steep learning curve. It is also often thought of as a research language with limited practical utility.
</p>

 <p>
While Haskell does have a very large surface area, with many concepts and a syntax that will feel unfamiliar to programmers coming from most other languages, it is unrivaled in the combination of developer productivity, code maintainability, software reliability, and performance that it offers. In this post I will cover some of the defining features of Haskell that make it an excellent, industrial-strength language that is well-suited for building commercial software, and why it is usually the first tool we consider using for new projects. Haskell has a strong static type system that prevents errors and reduces cognitive load
</p>

 <p>
Haskell has a very powerful static type system which serves as a programmer aid that catches and prevents many errors before code ever even runs. Many programmers encounter statically typed languages like Java or C++ and find that the compiler feels like an annoyance. By contrast, Haskell’s static type system, in conjunction with compile-time type checking, acts as an invaluable pair-programming buddy that gives instantaneous feedback during development.
</p>

 <p>
There’s a far smaller cognitive load that needs to be maintained when writing Haskell than when writing in languages like Python, JavaScript, or PHP. Many concerns can be completely offloaded to the compiler rather than needing to be remembered by the programmer. For example, when writing Haskell, there’s no need to preemptively ask questions like:
</p>

 <ul class="org-ul"> <li>Do I need to check whether this field is null?</li>
 <li>What if fields are missing from the request payload?</li>
 <li>Has this string already been decoded to an integer?</li>
 <li>What if this string can’t be decoded to an integer?</li>
 <li>Will this operator implicitly convert this integer to a string?</li>
 <li>Are these two values comparable?</li>
</ul> <p>
This is not to say that these are questions that never need answering in Haskell; it’s to say that the compiler will throw an error when you need to address one of these issues. For example, it’s possible that a Haskell program needs to handle values that are sometimes not present, but instead of setting any value to NULL, a Haskell programmer must use a Maybe type, which indicates that the value may not be there, and the compiler forces the programmer to explicitly handle the Nothing value; the case where the value is not present.
</p>

 <p>
Haskell’s static type system also leads to other benefits. Haskell code uses type signatures that precede its functions and describe the types of each parameter and return value. For example, a signature like Int -> Int -> Bool indicates that a function takes two integers and returns a boolean value. Since these type signatures are checked and enforced by the compiler, this allows a programmer reading Haskell code to look only at type signatures when getting a sense of what a certain piece of code does. For example, one would not use the type signature above when looking for a function that manipulates strings, decodes JSON, or queries a database.
</p>

 <p>
Type signatures can even be used to search through the entire corpus of Haskell code for a relevant function. Using Hoogle, Haskell’s API search, we can search for a type signature based off of functionality we know that we need. For example, if we need to convert an Int to a Float, we can search Hoogle for Int -> Float (search results), which will point us to the aptly named int2Float function.
</p>

 <p>
Haskell also lets us create polymorphic type signatures through the use of type variables, represented by lowercase type names. For example, a signature of a -> b -> a tells us that that the function takes two parameters of two arbitrary types, and returns a value that whose type is the same as the first parameter. Suppose we want to check whether an element is in a list. We’re looking for a function that takes an item to search for, a list of items, and returns a boolean. We don’t care about the type of the item, so long as the search item and the items in the list are of the same type. So we can search Hoogle for a -> [a] -> Bool (search results), which will point us to the elem function. Parametric types are an extremely powerful feature in Haskell and are what enable writing reusable code. Haskell enables writing code that is composable, testable, and has predictable side-effects
</p>

 <p>
In addition to being statically typed, Haskell is a pure functional programming language. This is one of Haskell’s defining features and what the language is well known for, even amongst programmers that have only heard of Haskell but never used it. Writing in a pure functional style has many benefits, and is conducive to a well-organized code base.
</p>

 <p>
The word “pure” in “pure functional programming” is significant. Purity in this sense means that the code we write is pure, or free of side-effects. Another term that describes this is referential transparency, or the property where any expression (e.g. a function call with a given list of parameters) can be replaced with its return value without changing the functionality of the code. This is only possible when such pure functions do not have side effects, such as creating files on the host system, running database queries, or making HTTP requests. Haskell’s type system imposes this sort of purity.
</p>

 <p>
So does being pure mean that Haskell programs cannot have side effects? Certainly not—but it does mean that effects are pushed to the edge of our system. Any functions that perform I/O actions (such as querying a database or receiving HTTP requests) must have a return type that captures this. This means that type signatures like the ones we saw in the previous section (e.g.  <code>Int -> Float</code> or  <code>a -> [a] -> Bool</code>) are indicators that the corresponding functions do not produce side effects, since  <code>Float</code> and  <code>Bool</code> are just primitive return types. For a contrasting example that includes a side effect, a function signature of  <code>FilePath -> IO String</code> indicates that the function takes a file path and performs an I/O action that returns a string (which is exactly what the  <code>readFile</code> function does).
</p>

 <p>
Another feature of a pure functional programming paradigm is higher-order functions, which are functions that take functions as parameters. One of the most commonly used higher-order functions is  <code>fmap</code>, which applies a function to each value in a container (such as a list). For example, we can apply a function named square, which takes an integer and returns that integer multiplied by itself, to a list of integers to turn it into a list of squared integers: 
</p>
 <pre>square :: Int -> Int
square x = x * x

fmap square [1,2,3,4,5] -- returns [1,4,9,16,25]</pre>

 <p>
Code written in this style tends to be both composable and testable. This above example is trivial, but there are many applications of higher-order functions. For example, we can write a function like renderPost which takes a record of post data and returns the version of the post rendered in HTML. If we have a list of posts, we can run fmap renderPost postList to produce a list of rendered posts. Our renderPost function can be used in both the single case and the multi-post case without any changes, because composing it with fmap changes how we can apply it. We can also write tests for the renderPost function and compose it with fmap in our tests when validating the behavior for a list of posts. Haskell facilitates rapid development, worry-free refactoring, and excellent maintainability
</p>

 <p>
Through the combination of the aforementioned static types and pure functional style that Haskell has, developing software in Haskell tends to be very fast. One of the common development workflows we employ is relies on a tool called ghcid, a simple command line tool that relies on the Haskell REPL to automatically watch code for changes and incrementally recompile. This allows us to see any compiler errors in our code immediately after saving changes to a file. It’s not uncommon for us to open only a terminal with a text editor in one pane and ghcid in another while developing applications in Haskell.
</p>

 <p>
While manually validating the results of our code is eventually necessary, such as by refreshing a page in a browser or using a tool to validate a JSON endpoint, a lot of this can be deferred until the end of a programming session. Many of the runtime errors that a programmer would encounter when writing a web service in a language like Python or PHP are caught immediately and displayed as compiler errors by ghcid. This is a far cry from the need to switch to a browser window and refresh the page after making a change to some code; a development workflow that everyone who has worked on a web application is intimately familiar with.
</p>

 <p>
Beyond the tight feedback loop during development, Haskell code is easy to refactor and modify. Like real world code written in any other language, such code written in Haskell is not write-only. It will eventually need to be maintained, updated, and extended, often by developers that are not the original authors of the code. With the aid of compile-time checking, many code refactors in Haskell become easy; a common refactoring workflow is to make a desired change in one location and then fix one compiler error at a time until the program compiles again. This is far easier than the equivalent changes in dynamically typed languages that offer no such assistance to the programmer.
</p>

 <p>
Proponents of dynamically typed languages will often argue that automated tests supplant the need for compile-time type checking, and can help prevent errors as well. However, tests are not as powerful as type constraints. For tests to be effective, they must:
</p>

 <ul class="org-ul"> <li>Actually be written, yet many real world code bases have limited
testing.</li>
 <li>Make correct assertions.</li>
 <li>Be comprehensive (test a variety of inputs) and provide good coverage
(test a large portion of the code base).</li>
 <li>Be easy to run and finish quickly, otherwise they will not become part
of the development workflow.</li>
 <li>Be updated and maintained in tandem with the code they test.</li>
</ul> <p>
Haskell’s type system has none of the above issues. The type system is a fixture in the language and the compiler always validates that the types are correct. The type system is inherently comprehensive, providing full coverage of every piece of Haskell code, and there are no changes to make to it as the underlying code changes. All this is not to say that the type system can replace every type of test. But what it does do is provide assurances that are more comprehensive than tests, and are present in every code base, even when no tests exist. Haskell programs have stellar performance, leading to faster applications and lower hardware costs
</p>

 <p>
GHC, the most commonly used Haskell compiler, produces extremely fast executables, especially when compared against other languages commonly used for application development, such as PHP or Python. This improved performance leads to both a more responsive application and lower hardware costs.
</p>

 <p>
It’s common to hear proponents of other languages be dismissive when their language is described as slow, as hardware is a relatively small cost compared to the cost of hiring programmers. This may be true, but we have found that the difference between Haskell and other languages used for web development is staggering.
</p>

 <p>
On one project we worked on in the past, we began implementing new API endpoints in a Haskell web service instead of the incumbent PHP. After around a year of building features and adding endpoints in Haskell, both the PHP and Haskell web services were dealing with a similar average workload in terms of request count and type, and performed similar CRUD actions backed by the same SQL database. The infrastructure was hosted on AWS, and the breakdown of the infrastructure used for each web service is below.
</p>

 <pre class="example" id="orgf436dd3">
Web Service Language    EC2 Instance Type   CPU     RAM     Monthly Cost Per Instance   Number of Instances Used    Total Monthly Cost
PHP     c5.xlarge   4 Dedicated CPU cores   8 GB    $122    2   $244
Haskell     t3.nano     2 Flex CPU cores (limited to 20% use)   0.5 GB  $3.75   4   $15
</pre>

 <p>
In this application, each of the Haskell and PHP web services handled a
similar number of requests, handled a similar workload, and had similar
traffic spikes throughout the day, all while querying the same database.
Both the PHP and Haskell web services used Nginx as a reverse proxy. In
the end, the cost of operating the Haskell infrastructure was roughly
1/16th (or 6%) of what the PHP infrastructure was. Examining our AWS
usage metrics, the CPU on our Haskell machines never even hit 5%. The
Haskell endpoints consistently had response times of 100ms or less,
slightly outperforming the PHP endpoints.
</p>

 <p>
Ultimately, we had two web services, one written in Haskell and the
other written in PHP, that had similar performance but the former had a
cost of $200/year and the latter had a cost of $3,000/year. It’s worth
noting that the user base of this application was relatively small, with
under 25,000 monthly active users (MAUs). This difference in cost would
scale as the size of the user base, number of MAUs, and underlying
infrastructure increased.
</p>

 <p>
It’s certainly possible to criticize this comparison, and I do not claim
that it is in any way scientific. But it’s clear to me that based off of
our past experience running production workloads, Haskell outperforms
PHP by at least an order of magnitude (and PHP 7.0+ performs remarkably
well compared to many other similar languages). The cost reduction that
comes with operating Haskell over other web languages is not by any
means insignificant. Haskell is great for domain modeling and preventing
errors in domain logic
</p>

 <p>
Another benefit of Haskell’s type system beyond simple compile time
type-checking is that it enables modeling a problem domain through the
use of custom data types within an application. This allows a programmer
to create a description of business logic rules that are enforced by the
type system. Haskell has what are referred to as algebraic data types
(ADTs), consisting of both records (product types) and tagged unions
(sum types). Records are similar to dictionaries or JSON objects, and
commonly available in many languages. Tagged unions, however, are not
available in many languages, but are what enable a significant amount of
flexibility in domain modeling.
</p>

 <p>
The power of ADTs is best illustrated through an example. Suppose we are
creating an invoicing system that must keep track of customer invoices.
Each invoice must contain a list of line items that the invoice is for
and have an invoice status that indicates whether the order has been
paid or canceled. The types we would use to model this might look like
the following:
</p>

 <pre>type Dollars = Int

data CustomerInvoice = CustomerInvoice
    { invoiceNumber :: Int
    , amountDue     :: Dollars
    , tax           :: Dollars
    , billableItems :: [String]
    , status        :: InvoiceStatus
    , createdAt     :: UTCTime
    , dueDate       :: Day
    }

data InvoiceStatus
    = Issued
    | Paid
    | Canceled</pre>

 <p>
Modeling domain rules in the type system like this (e.g. the status of
an invoice is either Issued, Paid, or Canceled) results in these rules
getting enforced at compile time, as described in the earlier section on
static typing. This is a much stronger set of guarantees than encoding
similar rules in class methods, as one might do in an object oriented
language that does not have sum types. With the type above, it becomes
impossible to define CustomerInvoice that doesn’t have an amount due,
for example. It’s also impossible to define an InvoiceStatus that is
anything other than one of the three aforementioned values.
</p>

 <p>
One application of the above types may be a function that creates a
notification message based on the status of the invoice. This function
would take a CustomerInvoice as a parameter and return a string
representing the content of the notification.
</p>

 <pre>createCustomerNotification :: CustomerInvoice -> String
createCustomerNotification invoice =
    case status invoice of
        Issued ->
            "Invoice #" ++ show (invoiceNumber invoice) ++ " due on " ++ show (dueDate invoice)

        Paid ->
            "Successfully paid invoice #" ++ show (invoiceNumber invoice)

        Canceled ->
            "Invoice #" ++ show (invoiceNumber invoice) ++ " has been cancelled"</pre>

 <p>
The above function uses pattern matching, another feature in the
language, to handle every possible InvoiceStatus value. The case
statement allows us to handle the different possible values of the
status field.
</p>

 <p>
The type system can protect us from making mistakes when changing the
rules of our domain. Suppose that after this application is live for a
while, we get feedback from our users that we need to be able to refund
invoices. To facilitate this, we’ll update our InvoiceStatus type to
include a Refunded value constructor:
</p>

 <pre>data InvoiceStatus
    = Issued
    | Paid
    | Canceled
    | Refunded</pre>

 <p>
If this is the only code we change, then upon compilation, we get the
following error:
</p>

 <pre class="example" id="org7ddce30">
CustomerInvoice.hs:(15,5)-(20,35): error: [-Wincomplete-patterns, -Werror=incomplete-patterns]
    Pattern match(es) are non-exhaustive
    In a case alternative: Patterns not matched: Refunded
   |
15 |     case status invoice of
   |     ^^^^^^^^^^^^^^^^^^^^^^...
</pre>

 <p>
Whoops! Looks like we forgot to update the createCustomerNotification
function to handle this new status value. The compiler is throwing an
error and telling us that the case statement does not handle the
Refunded value as part of its pattern matches.
</p>

 <p>
By modeling our domain in our types, the compiler assists us in ensuring
that all of our domain logic can handle every possible value in the
domain*. This protects us from the very common mistake of an unhandled
value when writing in dynamically typed languages. Automated tests are
not a replacement for types in this situation, because the introduction
of new possible values often requires updating tests to assert whether
the new values can be handled, which doesn’t help us avoid the
problem—it’s just as easy to forget to update tests for the business
logic as it is to forget to update the business logic.
</p>

 <ul class="org-ul"> <li>By default, GHC (the Haskell compiler) will not throw an error in the
case of an unhandled value, but it’s standard practice for production
Haskell projects to use the -Wall and -Werror flags, which turn on
nearly every available warning and turn all warnings into errors.</li>
</ul> <p>
Haskell has a large number of mature, high-quality libraries
</p>

 <p>
The Haskell community has a published a large number of high quality,
production grade packages, many of which have been maintained for for a
decade or longer. The Haskell community has general consensus as to
which packages are good options in each functional category
(e.g. decoding/encoding JSON, parsing XML, decoding CSVs, working with
SQL databases, HTML templating, websockets, using Redis, etc). In some
categories there is a single, best option that is the de facto standard.
In other categories, there are several comparable options to choose
from, depending on what design decisions or trade offs a developer is
willing to make.
</p>

 <p>
Haskell has over 21,000 packages available in its package repository,
Hackage, and many more published in various places such as GitHub that
build tools can depend on. However, this number is dwarfed by the number
of packages available in the repositories of many other languages. As of
this post’s publication date, Ruby has 164,000 gems published. There are
282,000 Python packages on PyPI. There were over 1.3 million JavaScript
packages on npm as of April 2020.
</p>

 <p>
This discrepancy leads to one of the reservations I have heard expressed
about using Haskell in production: there aren’t as many Haskell packages
available as there are in other languages. My response to this is that
when building production systems, the total number of packages available
for a given language is largely irrelevant.
</p>

 <p>
When building a production system, the decision of which packages to use
is never based off of the total number of packages available, but which
individual packages have a good reputation, widespread use, and other
factors such as good documentation and whether a given package is still
being maintained. To put it simply, it’s quality and not quantity that
matters, and to that end, the Haskell community does an excellent job at
curating the packages necessary for real world use cases I described
earlier. Haskell makes it easy to write concurrent programs
</p>

 <p>
One feature of being a pure functional language is that, by default,
values in Haskell are immutable. This is not to say that values never
change, but state is not changed in-place. For example, when a function
appends an element to a list, a new list is returned and the memory used
by the old list will be freed by the garbage collector. A benefit of
such of immutability is that it simplifies concurrent programming. In a
language with mutable values, multiple threads accessing the same value
can lead to issues such as race conditions and deadlocks.
</p>

 <p>
Since values in Haskell are immutable, there is no risk of these types
of issues even when a program is running on multiple threads and
accessing shared memory. This also results in a simpler mental model
surrounding concurrent programming. Concurrent code can often be written
in the same style as single-threaded code, with functions that run the
underlying workload on a new thread simply wrapping the single-threaded
implementation.
</p>

 <p>
Concurrency is a useful tool in the Haskell programmer’s toolbox. On
projects we have worked on in the past, we have done everything from
implemented websocket servers that run as part of the same executable
that serves an HTTP API, to created a multi-threaded worker system that
required far less overhead than managing individual Linux processes
necessary for workers written in languages with limited concurrency
support. Haskell enables domain-specific languages, which foster
expressiveness and reduce boilerplate
</p>

 <p>
Haskell’s type system and language features make it a common choice for
writing compilers. One offshoot of this is that Haskell libraries
sometimes employ domain-specific languages (DSLs) to improve their
usability. A DSL, in contrast to a general purpose language, is a small
language designed to be well-suited for expressing the rules of a
specific application or problem domain.
</p>

 <p>
One of the most well known and widely used DSLs is SQL, which is the
language used to query data stored in relational database systems.
Unlike most languages, SQL is declarative rather than imperative. This
means that a SQL program tends to describe what the outcome of its
execution should be rather than how that outcome should be achieved. Any
developer familiar with SQL can imagine how writing code to retrieve
data stored in tables as a series of rows in an imperative style would
be very cumbersome.
</p>

 <p>
One of the features in Haskell that facilitates DSLs is called Template
Haskell. This is commonly employed by library authors to allow consumers
of the library to use what is an expressive syntax to avoid a lot of
boilerplate. One example of this is in the Persistent library, one of
the most popular SQL libraries. Persistent exposes a DSL that uses what
is referred to as Persistent Entity Syntax that allows the user of the
library to define their database schema. An example of this syntax is
below.
</p>

 <pre>Person
    name Text
    age Int Maybe
BlogPost
    title Text
    authorId PersonId
    publicationDate UTCTime
BlogPostTag
    label Text
    blogPostId BlogPostId</pre>

 <p>
The code above is not Haskell, and if you have never used Haskell’s
Persistent library, odds are you have never seen this syntax. Yet it is
apparent what it does—it defines three tables (Person, BlogPost, and
BlogPostTag) and the columns within them. This code gets consumed by a
Haskell program and supplants the need to write approximately 150 lines
of Haskell code to define all of the data types and accessor functions
for working with the data from these three tables.
</p>

 <p>
The above is only one example of an external DSL, which is a DSL that
uses its own syntax. Other libraries that expose DSLs include ones for
webserver route definitions and for HTML templating. Some library
authors opt to create embedded domain-specific languages (eDSLs), which
are written in Haskell syntax. This results in a series of types and
functions that are specialized to a particular domain. Esqueleto is an
example of a widely-used library that exposes an eDSL for writing
type-safe SQL queries. Haskell has a large community filled with smart
and friendly people
</p>

 <p>
One of the most important facets of using a programming language is the
community. Haskell’s community is large and includes a wide variety of
people coming from many different technical backgrounds. This includes
programming language researchers, some of whom have been working on
Haskell since its inception in 1990, creators of other programming
languages whose compilers are written in Haskell, self-taught Haskell
enthusiasts, professional Haskell programmers using Haskell commercially
(we at Foxhound Systems fall into this category), as well as
eager-to-learn students, amongst many others.
</p>

 <p>
The Haskell community is very welcoming to beginners. While the language
has a learning curve that is steeper than that of many others due to its
depth and breadth, it’s easy to ask questions and find help any number
of people that sincerely want to help others learn the language.
</p>

 <p>
Some of the forms of communication we like to use to engage with the
Haskell community are:
</p>

 <ul class="org-ul"> <li>The Haskell subreddit, which has over 60,000 readers and is one of the
largest programming language communities on reddit.</li>
 <li>The Functional Programming Slack, which has a number of channels
dedicated to Haskell (including #haskell, #haskell-beginners,
#haskell-jobs, and #haskell-adoption).</li>
 <li>The Haskell mailing lists, such as haskell-cafe, which have a variety
of content from library announcements, to Q&A about the language, to
volunteer opportunities</li>
 <li>The #haskell channel on the Freenode IRC network often has over 1,000
people connected to it, and is a great alternative to the Slack
channels.</li>
 <li>The Haskell Weekly Newsletter, which is a weekly newsletter that
highlights blog posts and other announcements from the preceding week.</li>
 <li>Although not conventional community, the haskell tag on StackOverflow
has over 46,000 questions associated with it. It’s not uncommon to
find excellent answers that give a great overview of a specific topic
or issue related to the language.</li>
</ul> <p>
This is not an exhaustive list, and participation through every forum is
not necessary. But when someone is looking for help or generally
learning about the language, it’s worth using any of the forums above.
Conclusion
</p>

 <p>
There are many reasons for why Haskell is our first choice of
programming language for building production software systems. To recap
the whole list covered in this post:
</p>

 <ul class="org-ul"> <li>Haskell has a strong static type system that prevents errors and
reduces cognitive load.</li>
 <li>Haskell enables writing code that is composable, testable, and has
predictable side-effects.</li>
 <li>Haskell facilitates rapid development, worry-free refactoring, and
excellent maintainability.</li>
 <li>Haskell programs have stellar performance, leading to faster
applications and lower hardware costs.</li>
 <li>Haskell is great for domain modeling and preventing errors in domain
logic.</li>
 <li>Haskell has a large number of mature, high-quality libraries.</li>
 <li>Haskell makes it easy to write concurrent programs.</li>
 <li>Haskell enables domain-specific languages, which foster expressiveness
and reduce boilerplate.</li>
 <li>Haskell has a large community filled with smart and friendly people.</li>
</ul> <p>
It is the sum of these reasons that makes Haskell such a compelling
choice. Haskell enables rapid development, worry-free refactoring, easy
maintainability, provides excellent performance, and has a mature
ecosystem. These facets among many others make it an excellent choice
for building production applications.
</p>

 <p>
Original post
 <a href="https://www.foxhound.systems/blog/why-haskell-for-production/">here</a>
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/haskell/haskell-in-production-at-foxdown-systems/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/haskell/haskell-in-production-at-foxdown-systems/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Running Hoogle locally</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Stackage is a neat tool to use when developing Software in Haskell. It’s
integrated with the Hoogle search engine that can search on type
signatures (and function names) which lets you find almost any function
easily.
</p>

 <p>
One of the downsides of Hoogle is that it can be slow for people with
some slower connections and so looking up any kind of documentation
becomes a really frustrating experience.
</p>

 <p>
The other issue with using Hoogle is that when you look up documentation
for a function of a library that you use in a project, you need to make
sure you are looking at the documentation for the exact version of that
library that you are using in your package.yml or .cabal file; otherwise
you maybe looking at an entirely different api and end up wasting a lot
of time.
</p>

 <p>
Stackage solves this by letting you search against a particular snapshot
where all the versions of your libraries will be pinned against that
snapshot (see the resolver field in stackage.yaml).
</p>

 <p>
Wouldn’t it be nice if we could run Hoogle locally for our project with
all the documentation we need available at our fingertips? What would be
even better is that Hoogle was seeded with only the versions of
dependencies in our project that we care about.
</p>

 <p>
Well thanks to the fantastic “An opinionated guide to Haskell in 2018”
by Alexis King we now know how!
</p>

 <p>
The basic steps are:
</p>

 <p>
 <b>Generate Haddock documentation when you compile your project</b>
</p>

 <pre>stack test --fast --haddock-deps</pre>

 <p>
The first time you run this it can take a while.
</p>

 <p>
 <b>Generate a local Hoogle database</b>
</p>

 <pre>stack hoogle -- generate --local</pre>

 <p>
 <b>Run your local Hoogle server</b>
</p>

 <pre>stack hoogle -- server --local --port=8080</pre>

 <p>
 <b>Profit</b>
</p>

 <p>
You can get full access to your local Hoogle by opening  <code>localhost:8080</code>
in your browser.
</p>

 <p>
Something to be aware of is that when you add new dependencies or change
existing ones in your project you need to generate your local Hoogle
database again:
</p>

 <p>
Unfortunately, you will have to manually regenerate the Hoogle database
when you install new packages and their documentation, which you can do
by re-running  <code>stack hoogle -- generate --local</code>.
</p>

 <p>
Fortunately, regenerating the database doesn’t take very long, as long
as you’ve been properly rebuilding the documentation with
 <code>--haddock-deps</code>.
</p>

 <p>
This shouldn’t take too long though if you’ve been generating your
Haddock as per step 1.
</p>

 <p>
Original post can be found
 <a href="https://blog.ssanj.net/posts/2019-10-19-running-hoogle-locally-for-haskell-dev.html">here</a>.
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/haskell/running-hoogle-locally/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/haskell/running-hoogle-locally/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Type safety back and forth</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Taken from the brilliant post of  <a href="https://www.parsonsmatt.org/2017/10/11/type_safety_back_and_forth.html">Matt Parsons</a>.
</p>

 <p>
Types are a powerful construct for improving program safety. Haskell has a few notable ways of handling potential failure, the most famous being the venerable  <code>Maybe</code> type:
</p>

 <pre>data Maybe a
    = Nothing
    | Just a</pre>

 <p>
We can use  <code>Maybe</code> as the result of a function to indicate:
</p>
 <blockquote>
 <p>
Hey, friend! This function might fail. You’ll need to handle the  <code>Nothing</code> case.
</p>
</blockquote>

 <p>
This allows us to write functions like a safe division function:
</p>
 <pre>safeDivide :: Int -> Int -> Maybe Int
safeDivide i 0 = Nothing
safeDivide i j = Just (i `div` j)</pre>

 <p>
I like to think of this as pushing the responsibility for failure forward. I’m telling the caller of the code that they can provide whatever =Int=s they want, but that some condition might cause them to fail. And the caller of the code has to handle that failure later on.
</p>

 <p>
This is the easiest technique to show and tell, because it’s one-size-fits-all. If your function can fail, just slap  <code>Maybe</code> or  <code>Either</code> on the result type and you’ve got safety. I can write a 35 line blog post to show off the technique, and if I were feeling frisky, I could use it as an introduction to  <code>Functor</code>,  <code>Monad</code>, and all that jazz.
</p>

 <p>
Instead, I’d like to share another technique. Rather than push theresponsibility for failure forward, let’s explore pushing it back. This technique is a little harder to show, because it depends on the individual cases you might use.
</p>

 <p>
If pushing responsibility forward means accepting whatever parameters and having the caller of the code handle possibility of failure, then  <i>pushing it back</i> is going to mean we accept stricter parameters that we can’t fail with. Let’s consider  <code>safeDivide</code>, but with a more lax type signature:
</p>

 <pre>safeDivide :: String -> String -> Maybe Int
safeDivide iStr jStr = do
    i <- readMay iStr
    j <- readMay jStr
    guard (j /= 0)
    pure (i `div` j)</pre>

 <p>
This function takes two strings, and then tries to parse  <code>Int=s out of them. Then, if the =j</code> parameter isn’t  <code>0</code>, we return the result of division. This function is  <i>safe</i>, but we have a much larger space of calls to  <code>safeDivide</code> that fail and return  <code>Nothing</code>. We’ve accepted more parameters, but we’ve pushed a lot of responsibility forward for handling possible failure.
</p>

 <p>
Let’s push the failure back.
</p>

 <pre>safeDivide :: Int -> NonZero Int -> Int
safeDivide i (NonZero j) = i `div` j</pre>

 <p>
We’ve required that users provide us a  <code>NonZero Int</code> rather than any old  <code>Int</code>. We’ve pushed back against the callers of our function:
</p>

 <blockquote>
 <p>
No! You must provide a  <code>NonZero Int</code>. I refuse to work with just any  <code>Int</code>, because then I might fail, and that’s annoying.
</p>
</blockquote>

 <p>
So speaks our valiant little function, standing up for itself!
</p>

 <p>
Let’s implement  <code>NonZero</code>. We’ll take advantage of Haskell’s  <code>PatternSynonyms</code> language extension to allow people to pattern match on a “constructor” without exposing a way to unsafely construct values.
</p>

 <pre>{-# LANGUAGE PatternSynonyms #-}

module NonZero
  ( NonZero()
  , pattern NonZero
  , unNonZero
  , nonZero
  ) where

newtype NonZero a = UnsafeNonZero a

pattern NonZero a <- UnsafeNonZero a

unNonZero :: NonZero a -> a
unNonZero (UnsafeNonZero a) = a

nonZero :: (Num a, Eq a) => a -> Maybe (NonZero a)
nonZero 0 = Nothing
nonZero i = Just (UnsafeNonZero i)</pre>

 <p>
This module allows us to push the responsibility for type safety backwards onto callers.
</p>

 <p>
As another example, consider  <code>head</code>. Here’s the unsafe, convenient variety:
</p>

 <pre>head :: [a] -> a
head (x:xs) = x
head []     = error "oh no"</pre>

 <p>
This code is making a promise that it can’t keep. Given the empty list, it will fail at runtime.
Let’s push the responsibility for safety forward:
</p>

 <pre>headMay :: [a] -> Maybe a
headMay (x:xs) = Just x
headMay []     = Nothing</pre>

 <p>
Now, we won’t fail at runtime. We’ve required the caller to handle a  <code>Nothing</code> case.
Let’s try pushing it back now:
</p>

 <pre>headOr :: a -> [a] -> a
headOr def (x:xs) = x
headOr def []     = def</pre>

 <p>
Now, we’re requiring that the  <i>caller</i> of the function handle possible failure before they ever call this. There’s no way to get it wrong. Alternatively, we can use a type for nonempty lists!
</p>

 <pre>data NonEmpty a = a :| [a]

safeHead :: NonEmpty a -> a
safeHead (x :| xs) = x</pre>

 <p>
This one works just as well. We’re requiring that the calling code handle failure ahead of time.
</p>

 <p>
A more complicated example of this technique is the  <a href="https://hackage.haskell.org/package/justified-containers-0.1.2.0/docs/Data-Map-Justified-Tutorial.html"> <code>justified-containers</code></a> library. The library uses the type system to prove that a given key exists in the underlying  <code>Map</code>. From that point on, lookups using those keys are  <i>total</i>: they are guaranteed to return a value, and they don’t return a  <code>Maybe</code>.
</p>

 <p>
This works even if you  <code>map</code> over the  <code>Map</code> with a function, transforming values. You can also use it to ensure that two maps share related information. It’s a powerful feature, beyond just having type safety.
</p>
 <h2>The Ripple Effect  <a id="the-ripple-effect" class="anchor" href="#the-ripple-effect">#</a></h2> <div class="outline-text-2" id="text-org9d109f3">
 <p>
When some piece of code hands us responsibility, we have two choices:
</p>

 <ol class="org-ol"> <li>Handle that responsibility.</li>
 <li>Pass it to someone else!</li>
</ol> <p>
In my experience, developers will tend to push responsibility in the same direction that the code they call does. So if some function returns a  <code>Maybe</code>, the developer is going to be inclined to also return a  <code>Maybe</code> value. If some function requires a  <code>NonEmpty Int</code>, then the developer is going to be inclined to  <i>also</i> require a  <code>NonEmpty Int</code> be passed in.
</p>

 <p>
This played out in my work codebase. We have a type representing an  <code>Order</code> with many =Item=s in it. Originally, the type looked something like this:
</p>

 <pre>data Order = Order  { items :: [Item] }</pre>

 <p>
The  <code>Item=s contained nearly all of the interesting information in the order, so almost everything that we did with an =Order</code> would need to return a  <code>Maybe</code> value to handle the empty list case. This was a lot of work, and a lot of  <code>Maybe</code> values!
</p>

 <p>
The type is  <i>too permissive</i>. As it happens, an  <code>Order</code> may not exist without at least one  <code>Item</code>. So we can make the type  <i>more restrictive</i> and have more fun!
</p>

 <p>
We redefined the type to be:
</p>

 <pre>data Order = Order { items :: NonEmpty Item }</pre>

 <p>
All of the =Maybe=s relating to the empty list were purged, and all of the code was pure and free. The failure case (an empty list of orders) was moved to two sites:
</p>

 <ol class="org-ol"> <li>Decoding JSON</li>
 <li>Decoding database rows</li>
</ol> <p>
Decoding JSON happens at the API side of things, when various services  <code>POST</code> updates to us. Now, we can respond with a  <code>400</code> error and tell API clients that they’ve provided invalid data! This prevents our data from going bad.
</p>

 <p>
Decoding database rows is even easier. We use an  <code>INNER JOIN</code> when retrieving  <code>Order=s and =Item=s, which guarantees that each =Order</code> will have at least one  <code>Item</code> in the result set. Foreign keys ensure that each  <code>Item</code>’s  <code>Order</code> is actually present in the database. This does leave the possibility that an  <code>Order</code> might be orphaned in the database, but it’s mostly safe.
</p>

 <p>
When we push our type safety back, we’re encouraged to continue pushing it back. Eventually, we push it all the way back – to the edges of our system! This simplifies all of the code and logic inside of the system. We’re taking advantage of types to make our code simpler, safer, and easier to understand.
</p>
</div>
 <h2>Ask Only What You Need  <a id="ask-only-what-you-need" class="anchor" href="#ask-only-what-you-need">#</a></h2> <div class="outline-text-2" id="text-orgf53f17f">
 <p>
In many senses, designing our code with type safety in mind is about being as strict as possible about your possible inputs. Haskell makes this easier than many other languages, but there’s nothing stopping you from writing a function that can take literally any binary value, do whatever effects you want, and return whatever binary value:
</p>

 <pre>foobar :: ByteString -> IO ByteString</pre>

 <p>
A  <code>ByteString</code> is a totally unrestricted data type. It can contain any sequence of bytes. Because it can express any value, we have very little guarantees on what it actually contains, and we are very limited in how we can safely handle this.
</p>

 <p>
By restricting our past, we gain freedom in the future.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/haskell/type-safety-back-and-forth/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/haskell/type-safety-back-and-forth/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Why Haskell is important?</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
A really nice explanation from the
 <a href="https://www.tweag.io/blog/2019-09-06-why-haskell-is-important/">Tweag</a>
team, that reflects exactly how I think about the subject.
</p>

 <p>
People keep asking me, “What’s the point of Haskell, why do you folks
even use it?”. How can you answer this? Most of us Haskell practitioners
would start talking about strong static types, the elegance of
abstractions, and ease of refactoring—but we would be missing the
bigger picture. That’s because we are programmers, and programmers
typically think about the technical details.
</p>

 <p>
Let’s take a step back.
</p>

 <p>
We can view lots of things as black boxes that do stuff. Deep learning,
for example, allows us to solve certain problems we couldn’t tackle
before. Another set of technologies helped us put a man on the moon. No
one is going to ask “What’s the point of deep learning?” or “What’s the
point of a spaceship?”. That’s obvious.
</p>

 <p>
At this point, one could balk: “Mark, but you’re comparing apples to
oranges.”. Really? Let’s see. Deep learning is an approach to solve a
problem. What about programming languages? They’re an approach to solve
a problem too: they allow us to write programs. But programs can be
different. Some programs are complicated and very difficult to write in
some languages, say assembly. It can also be challenging in some
languages to convince ourselves that they are correct programs, say when
effects are unrestricted or invariants are not protected. By viewing
programming languages as black boxes, we could say that some of those
unlock creation of more and more complex high-quality software. And in
that respect, programming languages are not so different from deep
learning or space travel—they allow us to do something we could not do
before.
</p>

 <p>
Let’s forget about what makes Haskell what it is. Let’s view it as a
black box and see what we can make of it. It’s a thing that comes with
some risks and seeing just its output, in most cases we really can’t say
if it does something different than other languages do. It doesn’t allow
us to make a quantum leap. You could write your software in Haskell or
in some other popular language X—other things being equal, if X is
anything pertinent to your problem domain, you’ll do fine if you have
access to engineers with substantial experience in X.
</p>

 <p>
Still I must say that it’s essential for us to continue writing Haskell.
Why?
</p>

 <p>
Richard Eisenberg predicted, at ZuriHac 2019, that we might not be using
Haskell itself in the distant future. Perhaps a different language—but
it will be built on the valuable discoveries we made with Haskell. I’m
confident that his prediction will come true because:
</p>

 <p>
Haskell is a unique vehicle for bringing modern programming language
theory (PLT) to a production-quality programming language (†) where
results of such research can be tried out very quickly by programmers
tasked to solve real problems every day. For almost every other
language, one of the following is true:
</p>

 <p>
it is an experimental language with a small developer base that sees
virtually no practical usage it is a practical language that’s widely
used but not advancing very quickly, burdened by its huge user base and
legacy code. I think there’s lots of value in the linear and dependent
types research happening now. Not because those features allow us to
solve harder problems the first day they land in GHC (the main Haskell
compiler). They probably won’t. But, they can allow us to start trying
to use the features in practice, which is the necessary condition if we
want to build tomorrow’s super language.
</p>

 <p>
Haskell is not a proprietary language built, controlled, or subject to
the whims of some commercial entity. It is instead open source software,
a product of a collective effort by academics and enthusiastic users.
Haskell’s tight, active community and its spirit of experimentation are
perfect for moving forward with more exploration.
</p>

 <p>
Haskell evolves fast. I’m a relatively new user who started using it in
2014, but even over just 5 years, I can say that the language has
changed quite a bit and a lot of new features appeared in GHC. Veteran
Haskellers who have been using it for a decade or more can attest that
many things have changed for the better.
</p>

 <p>
Haskell thrives with ideas. Not only the compiler itself, but also its
ecosystem of libraries—Haskellers are in a constant search for better
solutions. Some of these solutions prove to be elegant and powerful, so
they stick. Others are soon forgotten. Of course, the same thing happens
in other languages, but what is so unique about Haskell is that the
language itself acts as a foundation with unique qualities which make
its users lean to more principled, although not-so-obvious solutions.
</p>

 <p>
So what, why explore those solutions? Is it worth it?
</p>

 <p>
The numerous techniques and concepts of functional programming that
mainstream languages adopt and, without doubt, will keep adopting
validate that Haskell continues to move in the right direction. It has
heavily influenced design of newer languages such as Rust, and its
influence is destined to continue. There are plenty of blog posts and
articles praising strong static typing and its value for making
programmers more productive nowadays. Haskell’s core principles, like
purity and isolation of side-effects, are understood and appreciated by
more today than ever before.
</p>

 <p>
Skeptical? That’s fine. Just remember that the idea for neural networks
is from the 1950s. It took quite some time for us to get the
computational power and data to make that idea useful. Haskell started
without a way to perform side effects but evolved to be adopted by
cutting-edge players like Facebook and Google to do real work today.
Time will only bring more great things—I don’t see an end to Haskell’s
evolution.
</p>

 <p>
(†) If you do not believe that a lot of companies use Haskell, you may
find that you are a victim of the same type of outdated world view as
the one described by Hans Rosling in his book Factfulness. The world is
changing and it’s changing quickly. What was true for Haskell ten years
ago is not true anymore. It’s fine to still poke jokes about unemployed
Haskellers, almost by inertia, but here are some facts to consider:
we’re hiring Haskell developers all the time, and I know quite a few
other companies that do the same. I, for one, have been a Haskeller for
my entire professional career and write in other languages only
occasionally. Am I so unique or the world is changing?
</p>

 <p>
If you enjoyed this article, you might be interested in joining the
Tweag team.
</p>

 <p>
This article is licensed under a Creative Commons Attribution 4.0
International license.
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/haskell/why-haskell-is-important/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/haskell/why-haskell-is-important/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Haskell</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2024-04-20 za> </span></span>  <a href="/blog/articles/haskell/free-alacarte/index.html">Free à la Carte</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2022-10-10 ma> </span></span>  <a href="/blog/articles/haskell/running-hoogle-locally/index.html">Running Hoogle locally</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2022-09-12 ma></span></span>-  <a href="/blog/articles/haskell/type-safety-back-and-forth/index.html">Type safety back and forth</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2022-09-10 za> </span></span>  <a href="/blog/articles/haskell/why-haskell-is-important/index.html">Why Haskell is important ?</a>
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2021-08-21 za> </span></span>  <a href="/blog/articles/haskell/haskell-in-production-at-foxdown-systems/index.html">Haskell in Production @ Foxdown Systems</a>
Haskell is the first programming language Foxdown reaches for when we build production software systems.
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/haskell/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/haskell/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Embracing the eternal Sexp wisdom with the GNU</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <i>Behold the holy Sexp</i>
</p>


 <p>
 <code>(sqrt (+ 14 5 3 1))</code>
</p>

 <p>
I have recently reached new heights in declarative configurations of operating systems, programs and my workflow ⚙️ and development.
</p>

 <p>
The universe blessed me and the GNU inspired me and I am configuring most of my life and projects with several variants of Lisp and dialects.
</p>

 <p>
This includes things like: operating system (Guix), project management, websites, curriculum vitae, Emacs, Qutebrowser, etc.
</p>


 <div id="org68afae3" class="figure">
 <p> <img loading="lazy" style="" src="/static/img/2024-12-27T21-56-27,947274345+01-00.png"></img></p>
</div>
 <h2>Configurability  <a id="configurability" class="anchor" href="#configurability">#</a></h2> <div class="outline-text-2" id="text-orgec43720">
 <p>
One of the things I will achieve among many others, is that with a change of one variable i can change completely all themes and settings for the entire system and all programs.
</p>

 <p>
Even programs that are not aware of dark/light mode stuff, they will be forced to by me and I never lose state.
</p>

 <p>
I am not afraid to change computers, my config works and is reproducible.
</p>
</div>
 <h2>Software that lasts forever  <a id="software-that-lasts-forever" class="anchor" href="#software-that-lasts-forever">#</a></h2> <div class="outline-text-2" id="text-orga3cc655">
 <p>
a great thing is that the stuff you build with Lisp is made to last. Lisp is mature, and due to how it works, things are never out of date, and “everything is basically a list”, sounds strange at first but its insanely powerful.
</p>

 <p>
Lisp was also was the first language used for AI development, and still is big at that.
</p>
</div>
 <h2>My mission  <a id="my-mission" class="anchor" href="#my-mission">#</a></h2> <div class="outline-text-2" id="text-org4a23d9d">
 <p>
I am trying to build configurable, hacker friendly stuff for the next 40 years and for that I am of opinion everyone should use a Lisp.
</p>

 <p>
If you need more complicated data modelling then i’d reach for Haskell. If you need low level shit then Rust or Go.
</p>

 <p>
Also, the GNU project and Free Software Foundation defined Lisp (Guile Scheme) as the official language for the project so a big one for me, and of course also my belovedtext editor (Emacs) is configured with it.
</p>


 <hr></hr> <p>
I want you to look at the code for iter-vitae my new  <b>Curriculum Vitae</b> generator, you will like it.
</p>

 <p>
This uses SXML, which is HTML as Lisp - kinda like components.
</p>
</div>
 <h2>Iter Vitae: “Journey of Life”  <a id="iter-vitae-ldquojourney-of-liferdquo" class="anchor" href="#iter-vitae-ldquojourney-of-liferdquo">#</a></h2> <div class="outline-text-2" id="text-orgcb4c209">
 <p>
 <i>the progression of one’s life and career</i>
</p>

 <p>
See at codeberg.org
 <a href="https://codeberg.org/jjba23/iter-vitae">https://codeberg.org/jjba23/iter-vitae</a>
</p>

 <p>
I recommend you to download a zip file and just get a feel
</p>

 <hr></hr></div>
 <h2>Supreme Sexp System - SSS  <a id="supreme-sexp-system---sss" class="anchor" href="#supreme-sexp-system---sss">#</a></h2> <div class="outline-text-2" id="text-orgb3729aa">
 <p>
 <i>a Lisp machine adventure</i>
</p>

 <p>
Then if you really wanna go down the rabbit hole check out my Supreme Sexp System,
</p>

 <p>
With this, you can configure your entire operating system and programs declaratively, with Lisp.
</p>

 <p>
See at codeberg.org
 <a href="https://codeberg.org/jjba23/sss">https://codeberg.org/jjba23/sss</a>
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/lisps/embracing-the-eternal-sexp-wisdom-of-the-gnu/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/lisps/embracing-the-eternal-sexp-wisdom-of-the-gnu/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Scheme &amp; Lisp Style Guide</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Riastradh’s Lisp Style Rules                          
</p>

 <p>
Copyright (C) 2007–2011 Taylor R. Campbell
</p>

 <p>
CC BY-NC-SA 3.0
</p>

 <p>
This work is licensed under a Creative Commons
Attribution-NonCommercial-ShareAlike 3.0 Unported License:
 <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/">http://creativecommons.org/licenses/by-nc-sa/3.0/</a>.
</p>

 <p>
This is a guide to Lisp style, written by Taylor R. Campbell, to
describe the standard rules of Lisp style as well as a set of more
stringent rules for his own style.  This guide should be useful for
Lisp in general, but there are [or will be in the final draft] parts
that are focussed on or specific to Scheme or Common Lisp.
</p>

 <p>
This guide is written primarily as a collection of rules, with
rationale for each rule.  (If a rule is missing rationale, please
inform the author!)  Although a casual reader might go through and read
the rules without the rationale, perhaps reasoning that reading of the
rationale would require more time than is available, such a reader
would derive little value from this guide.  In order to apply the rules
meaningfully, their spirit must be understood; the letter of the rules
serves only to hint at the spirit.  The rationale is just as important
as the rules.
</p>

 <p>
There are many references in this document to `Emacs’, `GNU Emacs’,
`Edwin’, and so on.  In this document, `Emacs’ means any of a class of
editors related in design to a common ancestor, the EMACS editor macros
written for TECO on ITS on the PDP-10 in the middle of the nineteen
seventies.  All such editors – or `all Emacsen’, since `Emacsen’ is
the plural of `Emacs’ – have many traits in common, such as a very
consistent set of key bindings, extensibility in Lisp, and so on.  `GNU
Emacs’ means the member of the class of editors collectively known as
Emacsen that was written for the GNU Project in the middle of the
nineteen eighties, and which is today probably the most popular Emacs.
`Edwin’ is MIT Scheme’s Emacs, which is bundled as part of MIT Scheme,
and not available separately.  There are other Emacsen as well, such as
Hemlock and Climacs, but as the author of this document has little
experience with Emacsen other than GNU Emacs and Edwin, there is little
mention of other Emacsen.
</p>

 <p>
This guide is a work in progress.  To be written:
</p>

 <ul class="org-ul"> <li>Indentation rules for various special operators.</li>
 <li>Philosophical rambling concerning naming.</li>
 <li>Rules for breaking lines.</li>
 <li>Many more examples.</li>
 <li>A more cohesive explanation of the author’s principles for composing
programs, and their implications.</li>
 <li>Rules for writing portable code.</li>
 <li>Some thoughts concerning extensions to the lexical syntax.</li>
 <li>Rules for writing or avoiding macros.</li>
 <li>Some unfinished rationale.</li>
 <li>More on documentation.</li>
 <li>The `Dependencies’ subsection of the `General Layout’ section should
be put in a different section, the rest of which has yet to be
written, on organization of programs, module systems, and portable
code.</li>
</ul> <p>
Feedback is welcome; address any feedback by email to the host
mumble.net’s user `campbell’, or by IRC to Riastradh in the #scheme
channel on Freenode (irc.freenode.net).  Feedback includes reports of
typos, questions, requests for clarification, and responses to the
rationale, except in the case of round brackets versus square
brackets, the argument surrounding which is supremely uninteresting
and now not merely a dead horse but a rotting carcass buzzing with
flies and being picked apart by vultures.
</p>

 <p>
As this document has grown, the line between standard Lisp rules and
the author’s own style has been blurred.  The author is considering
merging of the partition, but has not yet decided on this with
certainty.  Opinions on the subject are welcome – is the partition
still useful to keep the author’s biases and idiosyncrasies out of the
standard rules, or has the partition with its arbitrary nature only
caused disorganization of the whole document?
</p>

 <p>
Unfortunately, this document is entirely unscientific.  It is at best a
superstition or philosophy, but one that the author of this document
has found to have improved his programs.  Furthermore, the author is
somewhat skeptical of claims of scientific analyses of these matters:
analyzing human behaviour, especially confined to the set of excellent
programmers who often have strong opinions about their methods for
building programs, is a very tricky task.
</p>
 <h2>Standard Rules  <a id="standard-rules" class="anchor" href="#standard-rules">#</a></h2> <div class="outline-text-2" id="text-orgece8bde">
 <p>
These are the standard rules for formatting Lisp code; they are
repeated here for completeness, although they are surely described
elsewhere.  These are the rules implemented in Emacs Lisp modes, and
auxiliary utilities such as Paredit.
</p>

 <p>
The rationale given here is merely the author’s own speculation of the
origin of these rules, and should be taken as nothing more than it.
The reader shall, irrespective of the author’s rationale, accept the
rules as sent by the reader’s favourite deity, or Cthulhu if no such
deity strikes adequate fear into the heart of the reader.
</p>
</div>
 <h3>Parentheses  <a id="parentheses" class="anchor" href="#parentheses">#</a></h3> <h4>Terminology  <a id="terminology" class="anchor" href="#terminology">#</a></h4> <div class="outline-text-4" id="text-org51fe7a8">
 <p>
This guide avoids the term  <i>parenthesis</i> except in the general use of
 <i>parentheses</i> or  <i>parenthesized</i>, because the word’s generally accepted
definition, outside of the programming language, is a statement whose
meaning is peripheral to the sentence in which it occurs, and  <b>not</b> the
typographical symbols used to delimit such statements.
</p>

 <p>
The balanced pair of typographical symbols that mark parentheses in
English text are  <i>round brackets</i>, i.e. ( and ).  There are several
other balanced pairs of typographical symbols, such as  <i>square
brackets</i> (commonly called simply `brackets’ in programming circles),
i.e. [ and ];  <i>curly braces</i> (sometimes called simply `braces’), i.e. {
and };  <i>angle brackets</i> (sometimes `brokets’ (for `broken brackets’)),
i.e. < and >.
</p>

 <p>
In any balanced pair of typographical symbols, the symbol that begins
the region delimited by the symbols is called the  <i>opening bracket</i> or
the  <i>left bracket</i>, such as ( or [ or { or <.  The symbol that ends
that region is called the  <i>right bracket</i> or the  <i>closing bracket</i>,
such as > or } or ] or ).
</p>
</div>
 <h4>Spacing  <a id="spacing" class="anchor" href="#spacing">#</a></h4> <div class="outline-text-4" id="text-orgec082e7">
 <p>
If any text precedes an opening bracket or follows a closing bracket,
separate that text from that bracket with a space.  Conversely, leave
no space after an opening bracket and before following text, or after
preceding text and before a closing bracket.
</p>

 <p>
Unacceptable:
</p>

 <pre>(foo(bar baz)quux)
(foo ( bar baz ) quux)</pre>



 <p>
Acceptable:
</p>

 <pre>(foo (bar baz) quux)</pre>



 <p>
Rationale:  This is the same spacing found in standard typography of
European text.  It is more aesthetically pleasing.
</p>
</div>
 <h4>Line Separation  <a id="line-separation" class="anchor" href="#line-separation">#</a></h4> <div class="outline-text-4" id="text-orge317d91">
 <p>
Absolutely do  <b>not</b> place closing brackets on their own lines.
</p>

 <p>
Unacceptable:
</p>

 <pre>( <span class="org-keyword">define</span> ( <span class="org-function-name">factorial</span> x)
  ( <span class="org-keyword">if</span> (< x 2)
      1
      (* x (factorial (- x 1
                      )
           )
      )
  )
)</pre>



 <p>
Acceptable:
</p>

 <pre>( <span class="org-keyword">define</span> ( <span class="org-function-name">factorial</span> x)
   ( <span class="org-keyword">if</span> (< x 2)
       1
       (* x (factorial (- x 1)))))</pre>



 <p>
Rationale:  The parentheses grow lonely if their closing brackets are
all kept separated and segregated.
</p>
</div>
 <ul> <li>Exceptions to the Above Rule Concerning Line Separation <div class="outline-text-5" id="text-org7b54aa9">
 <p>
Do not heed this section unless you know what you are doing.  Its title
does  <b>not</b> make the unacceptable example above acceptable.
</p>

 <p>
When commenting out fragments of expressions with line comments, it may
be necessary to break a line before a sequence of closing brackets:
</p>

 <pre>( <span class="org-keyword">define</span> ( <span class="org-function-name">foo</span> bar)
  (list (frob bar)
        (zork bar)
         <span class="org-comment-delimiter">;; </span> <span class="org-comment">(zap bar)</span>
        ))</pre>



 <p>
This is acceptable, but there are other alternatives.  In Common Lisp,
one can use the read-time conditional syntax, `#+’ or `#-’, with a
feature conditional that is guaranteed to be false or true – `#+(OR)’
or `#-(AND)’ –; for example,
</p>

 <pre>( <span class="org-keyword">define</span> ( <span class="org-function-name">foo</span> bar)
  (list (frob bar)
        (zork bar)
        #+( <span class="org-keyword">or</span>) (zap bar))).</pre>



 <p>
Read-time conditionals are expression-oriented, not line-oriented, so
the closing brackets need not be placed on the following line.  Some
Scheme implementations, and SRFI 62, also support expression comments
with `#;’, which are operationally equivalent to the above read-time
conditionals for Common Lisp:
</p>

 <pre>( <span class="org-keyword">define</span> ( <span class="org-function-name">foo</span> bar)
  (list (frob bar)
        (zork bar)
         <span class="org-comment">#;</span>
 <span class="org-comment">         (zap bar</span> <span class="org-comment-delimiter">)</span>))</pre>



 <p>
The expression is placed on another line in order to avoid confusing
editors that do not recognize S-expression comments; see the section
titled `Comments’ below for more details.  However, the `#;’ notation
is not standard – it appears in neither the IEEE 1178 document nor in
the R5RS –, so line comments are preferable for portable Scheme code,
even if they require breaking a line before a sequence of closing
brackets.
</p>

 <p>
Finally, it is acceptable to break a line immediately after an opening
bracket and immediately before a closing bracket for very long lists,
especially in files under version control.  This eases the maintenance
of the lists and clarifies version diffs.  Example:
</p>

 <pre>( <span class="org-keyword">define</span>  <span class="org-function-name">colour-names</span>          <span class="org-comment-delimiter">;</span> <span class="org-comment">Add more colour names to this list!</span>
  '(
    blue
    cerulean
    green
    magenta
    purple
    red
    scarlet
    turquoise
    ))</pre>
</div>
</li></ul> <h4>Parenthetical Philosophy  <a id="parenthetical-philosophy" class="anchor" href="#parenthetical-philosophy">#</a></h4> <div class="outline-text-4" id="text-org08eb6e5">
 <p>
The actual bracket characters are simply lexical tokens to which little
significance should be assigned.  Lisp programmers do not examine the
brackets individually, or, Azathoth forbid, count brackets; instead
they view the higher-level structures expressed in the program,
especially as presented by the indentation.  Lisp is not about writing
a sequence of serial instructions; it is about building complex
structures by summing parts.  The composition of complex structures
from parts is the focus of Lisp programs, and it should be readily
apparent from the Lisp code.  Placing brackets haphazardly about the
presentation is jarring to a Lisp programmer, who otherwise would not
even have seen them for the most part.
</p>
</div>
 <h3>Indentation and Alignment  <a id="indentation-and-alignment" class="anchor" href="#indentation-and-alignment">#</a></h3> <div class="outline-text-3" id="text-org5e347db">
 <p>
The operator of any form, i.e. the first subform following the opening
round bracket, determines the rules for indenting or aligning the
remaining forms.  Many names in this position indicate special
alignment or indentation rules; these are special operators, macros, or
procedures that have certain parameter structures.
</p>

 <p>
If the first subform is a non-special name, however, then if the second
subform is on the same line, align the starting column of all following
subforms with that of the second subform.  If the second subform is on
the following line, align its starting column with that of the first
subform, and do the same for all remaining subforms.
</p>

 <p>
In general, Emacs will indent Lisp code correctly.  Run `C-M-q’
(indent-sexp) on any code to ensure that it is indented correctly, and
configure Emacs so that any non-standard forms are indented
appropriately.
</p>

 <p>
Unacceptable:
</p>

 <pre>(+ (sqrt -1)
  (* x y)
  (+ p q))

(+
   (sqrt -1)
   (* x y)
   (+ p q))</pre>



 <p>
Acceptable:
</p>

 <pre>(+ (sqrt -1)
   (* x y)
   (+ p q))

(+
 (sqrt -1)
 (* x y)
 (+ p q))</pre>



 <p>
Rationale:  The columnar alignment allows the reader to follow the
operands of any operation straightforwardly, simply by scanning
downward or upward to match a common column.  Indentation dictates
structure; confusing indentation is a burden on the reader who wishes
to derive structure without matching parentheses manually.
</p>
</div>
 <h4>Non-Symbol Indentation and Alignment  <a id="non-symbol-indentation-and-alignment" class="anchor" href="#non-symbol-indentation-and-alignment">#</a></h4> <div class="outline-text-4" id="text-orgdb3c639">
 <p>
The above rules are not exhaustive; some cases may arise with strange
data in operator positions.
</p>
</div>
 <ul> <li>Lists <div class="outline-text-5" id="text-org19fa6d0">
 <p>
Unfortunately, style varies here from person to person and from editor
to editor.  Here are some examples of possible ways to indent lists
whose operators are lists:
</p>

 <p>
Questionable:
</p>

 <pre>((car x)                             <span class="org-comment-delimiter">;</span> <span class="org-comment">Requires hand indentation.</span>
   (cdr x)
   foo)

((car x) (cdr x)                     <span class="org-comment-delimiter">;</span> <span class="org-comment">GNU Emacs</span>
 foo)</pre>



 <p>
Preferable:
</p>

 <pre>((car x)                             <span class="org-comment-delimiter">;</span> <span class="org-comment">Any Emacs</span>
 (cdr x)
 foo)

((car x) (cdr x)                     <span class="org-comment-delimiter">;</span> <span class="org-comment">Edwin</span>
         foo)</pre>



 <p>
Rationale:  The operands should be aligned, as if it were any other
procedure call with a name in the operator position; anything other
than this is confusing because it gives some operands greater visual
distinction, allowing others to hide from the viewer’s sight.  For
example, the questionable indentation
</p>

 <pre>((car x) (cdr x)
 foo)</pre>



 <p>
can make it hard to see that FOO and (CDR X) are both operands here
at the same level.  However, GNU Emacs will generate that indentation
by default.  (Edwin will not.)
</p>
</div>
</li>
 <li>Strings <div class="outline-text-5" id="text-org8e5d75e">
 <p>
If the form in question is meant to be simply a list of literal data,
all of the subforms should be aligned to the same column, irrespective
of the first subform.
</p>

 <p>
Unacceptable:
</p>

 <pre>( <span class="org-string">"foo"</span>  <span class="org-string">"bar"</span>  <span class="org-string">"baz"</span>  <span class="org-string">"quux"</span>  <span class="org-string">"zot"</span>
         <span class="org-string">"mumble"</span>  <span class="org-string">"frotz"</span>  <span class="org-string">"gargle"</span>  <span class="org-string">"mumph"</span>)</pre>



 <p>
Questionable, but acceptable:
</p>

 <pre>(3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8 4 6 2 6 4
   3 3 8 3 2 7 9 5 0 2 8 8 4 1 9 7 1 6 9 3 9 9 3)</pre>



 <p>
Acceptable:
</p>

 <pre>( <span class="org-string">"foo"</span>  <span class="org-string">"bar"</span>  <span class="org-string">"baz"</span>  <span class="org-string">"quux"</span>  <span class="org-string">"zot"</span>
  <span class="org-string">"mumble"</span>  <span class="org-string">"frotz"</span>  <span class="org-string">"gargle"</span>  <span class="org-string">"mumph"</span>)

( <span class="org-string">"foo"</span>
  <span class="org-string">"bar"</span>  <span class="org-string">"baz"</span>  <span class="org-string">"quux"</span>  <span class="org-string">"zot"</span>
  <span class="org-string">"mumble"</span>  <span class="org-string">"frotz"</span>  <span class="org-string">"gargle"</span>  <span class="org-string">"mumph"</span>)</pre>



 <p>
Rationale:  Seldom is the first subform distinguished for any reason,
if it is a literal; usually in this case it indicates pure data, not
code.  Some editors and pretty-printers, however, will indent
unacceptably in the example given unless the second subform is on the
next line anyway, which is why the last way to write the fragment is
usually best.
</p>
</div>
</li></ul> <h3>Names  <a id="names" class="anchor" href="#names">#</a></h3> <div class="outline-text-3" id="text-org7f908d2">
 <p>
Naming is subtle and elusive.  Bizarrely, it is simultaneously
insignificant, because an object is independent of and unaffected by
the many names by which we refer to it, and also of supreme
importance, because it is what programming – and, indeed, almost
everything that we humans deal with – is all about.  A full
discussion of the concept of name lies far outside the scope of this
document, and could surely fill not even a book but a library.
</p>

 <p>
Symbolic names are written with English words separated by hyphens.
Scheme and Common Lisp both fold the case of names in programs;
consequently, camel case is frowned upon, and not merely because it is
ugly.  Underscores are unacceptable separators except for names that
were derived directly from a foreign language without translation.
</p>

 <p>
Unacceptable:
</p>

 <pre>XMLHttpRequest
  foreach
  append_map</pre>



 <p>
Acceptable:
</p>

 <pre>xml-http-request
 for-each
 append-map</pre>
</div>
 <h4>Funny Characters  <a id="funny-characters" class="anchor" href="#funny-characters">#</a></h4> <div class="outline-text-4" id="text-orgc8766b9">
 <p>
There are several different conventions in different Lisps for the use
of non-alphanumeric characters in names.
</p>
</div>
 <ul> <li>Scheme <ul> <li>Question Marks: Predicates <div class="outline-text-6" id="text-org45def83">
 <p>
Affix a question mark to the end of a name for a procedure whose
purpose is to ask a question of an object and to yield a boolean
answer.  Such procedures are called `predicates’.  Do not use a
question mark if the procedure may return any object other than a
boolean.
</p>

 <p>
Examples:  pair? procedure? proper-list?
Non-examples:  member assoc any every
</p>

 <p>
Pronounce the question mark as if it were the isolated letter `p’.  For
example, to read the fragment (PAIR? OBJECT) aloud, say: `pair-pee
object.’
</p>
</div>
</li>
 <li>Exclamation Marks: Destructive Operations <div class="outline-text-6" id="text-orgee97d92">
 <p>
Affix an exclamation mark to the end of a name for a procedure (or
macro) whose primary purpose is to modify an object.  Such procedures
are called `destructive’.
</p>

 <p>
Examples: set-car! append!
</p>

 <p>
Avoid using the exclamation mark willy nilly for just  <b>any</b> procedure
whose operation involves any kind of mutation or side effect; instead,
use the exclamation mark to identify procedures that exist  <b>solely</b> for
the purpose of destructive update (e.g., SET-CAR!), or to distinguish a
destructive, or potentially destructive (in the case of linear-update
operations such as APPEND!), variant of a procedure of which there also
exists a purely functional variant (e.g., APPEND).
</p>

 <p>
Pronounce the exclamation mark as `bang’.  For example, to read the
fragment (APPEND! LIST TAIL) aloud, say: `append-bang list tail.’
</p>
</div>
</li>
 <li>Asterisks: Variants, Internal Routines, Mutable Globals <div class="outline-text-6" id="text-orgda9f37b">
 <p>
Affix an asterisk to the end of a name to make a variation on a theme
of the original name.
</p>

 <p>
Example: let -> let*
</p>

 <p>
Prefer a meaningful name over an asterisk; the asterisk does not
explain what variation on the theme the name means.
</p>

 <p>
Affix an asterisk to the beginning of a name to make an internal
routine for that name.  Again, prefer a meaningful name over an
asterisk.
</p>

 <p>
Affix asterisks to the beginning and end of a globally mutable
variable.  This allows the reader of the program to recognize very
easily that it is badly written!
</p>
</div>
</li>
 <li>`WITH-’ and `CALL-WITH-’: Dynamic State and Cleanup <div class="outline-text-6" id="text-orgf328637">
 <p>
Prefix `WITH-’ to any procedure that establishes dynamic state and
calls a nullary procedure, which should be the last (required)
argument.  The dynamic state should be established for the extent of
the nullary procedure, and should be returned to its original state
after that procedure returns.
</p>

 <p>
Examples: with-input-from-file with-output-to-file
</p>

 <p>
Exception:  Some systems provide a procedure (WITH-CONTINUATION
<continuation> <thunk>), which calls <thunk> in the given
continuation, using that continuation’s dynamic state.  If <thunk>
returns, it will return to <continuation>, not to the continuation of
the call to WITH-CONTINUATION.  This is acceptable.
</p>

 <p>
Prefix `CALL-WITH-’ to any procedure that calls a procedure, which
should be its last argument, with some arguments, and is either somehow
dependent upon the dynamic state or continuation of the program, or
will perform some action to clean up data after the procedure argument
returns.  Generally, `CALL-WITH-’ procedures should return the values
that the procedure argument returns, after performing the cleaning
action.
</p>

 <p>
Examples:
</p>

 <ul class="org-ul"> <li>CALL-WITH-INPUT-FILE and CALL-WITH-OUTPUT-FILE both accept a
pathname and a procedure as an argument, open that pathname (for
input or output, respectively), and call the procedure with one
argument, a port corresponding with the file named by the given
pathname.  After the procedure returns, CALL-WITH-INPUT-FILE and
CALL-WITH-OUTPUT-FILE close the file that they opened, and return
whatever the procedure returned.</li>

 <li>CALL-WITH-CURRENT-CONTINUATION is dependent on the continuation
with which it was called, and passes as an argument an escape
procedure corresponding with that continuation.</li>

 <li>CALL-WITH-OUTPUT-STRING, a common but non-standard procedure
definable in terms of OPEN-OUTPUT-STRING and GET-OUTPUT-STRING from
SRFI 6 (Basic String Ports), calls its procedure argument with an
output port, and returns a string of all of the output written to
that port.  Note that it does not return what the procedure
argument returns, which is an exception to the above rule.</li>
</ul> <p>
Generally, the distinction between these two classes of procedures is
that `CALL-WITH-…’ procedures should not establish fresh dynamic
state and instead pass explicit arguments to their procedure arguments,
whereas `WITH-…’ should do the opposite and establish dynamic state
while passing zero arguments to their procedure arguments.
</p>
</div>
</li></ul></li></ul> <h3>Comments  <a id="comments" class="anchor" href="#comments">#</a></h3> <div class="outline-text-3" id="text-org1fbcc7c">
 <p>
Write heading comments with at least four semicolons; see also the
section below titled `Outline Headings’.
</p>

 <p>
Write top-level comments with three semicolons.
</p>

 <p>
Write comments on a particular fragment of code before that fragment
and aligned with it, using two semicolons.
</p>

 <p>
Write margin comments with one semicolon.
</p>

 <p>
The only comments in which omission of a space between the semicolon
and the text is acceptable are margin comments.
</p>

 <p>
Examples:
</p>

 <pre> <span class="org-comment-delimiter">;;;; </span> <span class="org-comment">Frob Grovel</span>

 <span class="org-comment-delimiter">;;; </span> <span class="org-comment">This section of code has some important implications:</span>
 <span class="org-comment-delimiter">;;;   </span> <span class="org-comment">1. Foo.</span>
 <span class="org-comment-delimiter">;;;   </span> <span class="org-comment">2. Bar.</span>
 <span class="org-comment-delimiter">;;;   </span> <span class="org-comment">3. Baz.</span>

( <span class="org-keyword">define</span> ( <span class="org-function-name">fnord</span> zarquon)
   <span class="org-comment-delimiter">;; </span> <span class="org-comment">If zob, then veeblefitz.</span>
  (quux zot
        mumble              <span class="org-comment-delimiter">;</span> <span class="org-comment">Zibblefrotz.</span>
        frotz))</pre>
</div>
 <h2>Riastradh’s Non-Standard Rules  <a id="riastradhrsquos-non-standard-rules" class="anchor" href="#riastradhrsquos-non-standard-rules">#</a></h2> <div class="outline-text-2" id="text-org55aa9a0">
 <p>
Three principles guide this style, roughly ordered according to
descending importance:
</p>

 <ol class="org-ol"> <li>The purpose of a program is to describe an idea, and not the way
that the idea must be realized; the intent of the program’s meaning,
rather than peripheral details that are irrelevant to its intent,
should be the focus of the program,  <b>irrespective</b> of whether a
human or a machine is reading it.  [It would be nice to express this
principle more concisely.]</li>

 <li>The sum of the parts is easier to understand than the whole.</li>

 <li>Aesthetics matters.  No one enjoys reading an ugly program.</li>
</ol></div>
 <h3>General Layout  <a id="general-layout" class="anchor" href="#general-layout">#</a></h3> <div class="outline-text-3" id="text-org9a230af">
 <p>
This section contains rules that the author has found generally helpful
in keeping his programs clean and presentable, though they are not
especially philosophically interesting.
</p>

 <p>
Contained in the rationale for some of the following rules are
references to historical limitations of terminals and printers, which
are now considered aging cruft of no further relevance to today’s
computers.  Such references are made only to explain specific measures
chosen for some of the rules, such as a limit of eighty columns per
line, or sixty-six lines per page.  There is a real reason for each of
the rules, and this real reason is not intrinsically related to the
historical measures, which are mentioned only for the sake of
providing some arbitrary measure for the limit.
</p>
</div>
 <h4>File Length  <a id="file-length" class="anchor" href="#file-length">#</a></h4> <div class="outline-text-4" id="text-orgc69ff8b">
 <p>
If a file exceeds five hundred twelve lines, begin to consider
splitting it into multiple files.  Do not write program files that
exceed one thousand twenty-four lines.  Write a concise but
descriptive title at the top of each file, and include no content in
the file that is unrelated to its title.
</p>

 <p>
Rationale:  Files that are any larger should generally be factored
into smaller parts.  (One thousand twenty-four is a nicer number than
one thousand.)  Identifying the purpose of the file helps to break it
into parts if necessary and to ensure that nothing unrelated is
included accidentally.
</p>
</div>
 <h4>Top-Level Form Length  <a id="top-level-form-length" class="anchor" href="#top-level-form-length">#</a></h4> <div class="outline-text-4" id="text-org44ccd36">
 <p>
Do not write top-level forms that exceed twenty-one lines, except for
top-level forms that serve only the purpose of listing large sets of
data.  If a procedure exceeds this length, split it apart and give
names to its parts.  Avoid names formed simply by appending a number
to the original procedure’s name; give meaningful names to the parts.
</p>

 <p>
Rationale:  Top-level forms, especially procedure definitions, that
exceed this length usually combine too many concepts under one name.
Readers of the code are likely to more easily understand the code if
it is composed of separately named parts.  Simply appending a number
to the original procedure’s name can help only the letter of the
rule, not the spirit, however, even if the procedure was taken from a
standard algorithm description.  Using comments to mark the code with
its corresponding place in the algorithm’s description is acceptable,
but the algorithm should be split up in meaningful fragments anyway.
</p>

 <p>
Rationale for the number twenty-one:  Twenty-one lines, at a maximum
of eighty columns per line, fits in a GNU Emacs instance running in a
24x80 terminal.  Although the terminal may have twenty-four lines,
three of the lines are occupied by GNU Emacs: one for the menu bar
(which the author of this guide never uses, but which occupies a line
nevertheless in a vanilla GNU Emacs installation), one for the mode
line, and one for the minibuffer’s window.  The writer of some code
may not be limited to such a terminal, but the author of this style
guide often finds it helpful to have at least four such terminals or
Emacs windows open simultaneously, spread across a twelve-inch laptop
screen, to view multiple code fragments.
</p>
</div>
 <h4>Line Length  <a id="line-length" class="anchor" href="#line-length">#</a></h4> <div class="outline-text-4" id="text-org54cc652">
 <p>
Do not write lines that exceed eighty columns, or if possible
seventy-two.
</p>

 <p>
Rationale:  Following multiple lines that span more columns is
difficult for humans, who must remember the line of focus and scan
right to left from the end of the previous line to the beginning of
the next line; the more columns there are, the harder this is to do.
Sticking to a fixed limit helps to improve readability.
</p>

 <p>
Rationale for the numbers eighty and seventy-two:  It is true that we
have very wide screens these days, and we are no longer limited to
eighty-column terminals; however, we ought to exploit our wide
screens not by writing long lines, but by viewing multiple fragments
of code in parallel, something that the author of this guide does
very often.  Seventy-two columns leave room for several nested layers
of quotation in email messages before the code reaches eighty
columns.  Also, a fixed column limit yields nicer printed output,
especially in conjunction with pagination; see the section
`Pagination’ below.
</p>
</div>
 <h4>Blank Lines  <a id="blank-lines" class="anchor" href="#blank-lines">#</a></h4> <div class="outline-text-4" id="text-org6d284da">
 <p>
Separate each adjacent top-level form with a single blank line (i.e.
two line breaks).  If two blank lines seem more appropriate, break the
page instead.  Do not place blank lines in the middle of a procedure
body, except to separate internal definitions; if there is a blank
line for any other reason, split the top-level form up into multiple
ones.
</p>

 <p>
Rationale:  More than one blank line is distracting and sloppy.  If
the two concepts that are separated by multiple blank lines are
really so distinct that such a wide separator is warranted, then
they are probably better placed on separate pages anyway; see the
next section, `Pagination’.
</p>
</div>
 <h4>Pagination  <a id="pagination" class="anchor" href="#pagination">#</a></h4> <div class="outline-text-4" id="text-org7f3f095">
 <p>
Separate each file into pages of no more than sixty-six lines and no
fewer than forty lines with form feeds (ASCII #x0C, or ^L, written in
Emacs with `C-q C-l’), on either side of which is a single line break
(but not a blank line).
</p>

 <p>
Rationale:  Keeping distinct concepts laid out on separate pages
helps to keep them straight.  This is helpful not only for the
writer of the code, but also for the reader.  It also allows readers
of the code to print it onto paper without fiddling with printer
settings to permit pages of more than sixty-six lines (which is the
default number for many printers), and pagination also makes the
code easier to navigate in Emacs, with the `C-x [’ and `C-x ]’ keys
(`backward-page’ and `forward-page’, respectively).  To avoid
excessively small increments of page-by-page navigation, and to
avoid wasting paper, each page should generally exceed forty lines.
</p>

 <p>
`C-x l’ in Emacs will report the number of lines in the page on which
the point lies; this is useful for finding where pagination is
necessary.
</p>
</div>
 <h4>Outline Headings  <a id="outline-headings" class="anchor" href="#outline-headings">#</a></h4> <div class="outline-text-4" id="text-orgbc273d5">
 <p>
Use Emacs’s Outline Mode to give titles to the pages, and if
appropriate a hierarchical structure.  Set `outline-regexp’ (or
`outline-pattern’ in Edwin) to “\f\n;;;;+ ”, so that each form feed
followed by an line break followed by at least four semicolons and a
space indicates an outline heading to Emacs.  Use four semicolons for
the highest level of headings in the hierarchy, and one more for each
successively nested level of hierarchy.
</p>

 <p>
Rationale:  Not only does this clarify the organization of the code,
but readers of the code can then navigate the code’s structure with
Outline Mode commands such as `C-c C-f’, `C-c C-b’, `C-c C-u’, and
`C-c C-d’ (forward, backward, up, down, respectively, headings).
</p>
</div>
 <h4>Dependencies  <a id="dependencies" class="anchor" href="#dependencies">#</a></h4> <div class="outline-text-4" id="text-org7964752">
 <p>
When writing a file or module, minimize its dependencies.  If there are
too many dependencies, consider breaking the module up into several
parts, and writing another module that is the sum of the parts and that
depends only on the parts, not their dependencies.
</p>

 <p>
Rationale:  A fragment of a program with fewer dependencies is less
of a burden on the reader’s cognition.  The reader can more easily
understand the fragment in isolation; humans are very good at local
analyses, and terrible at global ones.
</p>
</div>
 <h3>Naming  <a id="naming" class="anchor" href="#naming">#</a></h3> <div class="outline-text-3" id="text-org3e93b0b">
 <p>
This section requires an elaborate philosophical discussion which the
author is too ill to have the energy to write at this moment.
</p>

 <p>
Compose concise but meaningful names.  Do not cheat by abbreviating
words or using contractions.
</p>

 <p>
Rationale:  Abbreviating words in names does not make them shorter;
it only makes them occupy less screen space.  The reader still must
understand the whole long name.  This does not mean, however, that
names should necessarily be long; they should be descriptive.  Some
long names are more descriptive than some short names, but there are
also descriptive names that are not long and long names that are not
descriptive.  Here is an example of a long name that is not
descriptive, from SchMUSE, a multi-user simulation environment
written in MIT Scheme:
</p>

 <p>
frisk-descriptor-recursive-subexpr-descender-for-frisk-descr-env
</p>

 <p>
Not only is it long (sixty-four characters) and completely
impenetrable, but halfway through its author decided to abbreviate
some words as well!
</p>

 <p>
Do not write single-letter variable names.  Give local variables
meaningful names composed from complete English words.
</p>

 <p>
Rationale:  It is tempting to reason that local variables are
invisible to other code, so it is OK to be messy with their names.
This is faulty reasoning: although the next person to come along and
use a library may not care about anything but the top-level
definitions that it exports, this is not the only audience of the
code.  Someone will also want to read the code later on, and if it is
full of impenetrably terse variable names without meaning, that
someone will have a hard time reading the code.
</p>

 <p>
Give names to intermediate values where their expressions do not
adequately describe them.
</p>

 <p>
Rationale:  An `expression’ is a term that expresses some value.
Although a machine needs no higher meaning for this value, and
although it should be written to be sufficiently clear for a human to
understand what it means, the expression might mean something more
than just what it says where it is used.  Consequently, it is helpful
for humans to see names given to expressions.
</p>

 <p>
Example:  A hash table HASH-TABLE maps foos to bars; (HASH-TABLE/GET
HASH-TABLE FOO #F) expresses the datum that HASH-TABLE maps FOO to,
but that expression gives the reader no hint of any information
concerning that datum.  (LET ((BAR (HASH-TABLE/GET HASH-TABLE FOO
#F))) …)  gives a helpful name for the reader to understand the
code without having to find the definition of HASH-TABLE.
</p>

 <p>
Index variables such as i and j, or variables such as A and D naming
the car and cdr of a pair, are acceptable only if they are completely
unambiguous in the scope.  For example,
</p>

 <p>
(do ((i 0 (+ i 1)))
    ((= i (vector-length vector)))
  (frobnicate (vector-ref vector i)))
</p>

 <p>
is acceptable because the scope of i is very clearly limited to a
single vector.  However, if more vectors are involved, using more
index variables such as j and k will obscure the program further.
</p>

 <p>
Avoid functional combinators, or, worse, the point-free (or
`point-less’) style of code that is popular in the Haskell world.  At
most, use function composition only where the composition of functions
is the crux of the idea being expressed, rather than simply a procedure
that happens to be a composition of two others.
</p>

 <p>
Rationale:  Tempting as it may be to recognize patterns that can be
structured as combinations of functional combinators – say, `compose
this procedure with the projection of the second argument of that
other one’, or (COMPOSE FOO (PROJECT 2 BAR)) –, the reader of the
code must subsequently examine the elaborate structure that has been
built up to obscure the underlying purpose.  The previous fragment
could have been written (LAMBDA (A B) (FOO (BAR B))), which is in
fact shorter, and which tells the reader directly what argument is
being passed on to what, and what argument is being ignored, without
forcing the reader to search for the definitions of FOO and BAR or
the call site of the final composition.  The explicit fragment
contains substantially more information when intermediate values are
named, which is very helpful for understanding it and especially for
modifying it later on.
</p>

 <p>
The screen space that can be potentially saved by using functional
combinators is made up for by the cognitive effort on the part of the
reader.  The reader should not be asked to search globally for usage
sites in order to understand a local fragment.  Only if the structure
of the composition really is central to the point of the narrative
should it be written as such.  For example, in a symbolic integrator
or differentiator, composition is an important concept, but in most
code the structure of the composition is completely irrelevant to the
real point of the code.
</p>

 <p>
If a parameter is ignored, give it a meaningful name nevertheless and
say that it is ignored; do not simply call it `ignored’.
</p>

 <p>
In Common Lisp, variables can be ignored with (DECLARE (IGNORE …)).
Some Scheme systems have similar declarations, but the portable way to
ignore variables is just to write them in a command context, where
their values will be discarded, preferably with a comment indicating
this purpose:
</p>

 <p>
(define (foo x y z)
  x z                         ;ignore
  (frobnitz y))
</p>

 <p>
Rationale:  As with using functional combinators to hide names,
avoiding meaningful names for ignored parameters only obscures the
purpose of the program.  It is helpful for a reader to understand
what parameters a procedure is independent of, or if someone wishes
to change the procedure later on, it is helpful to know what other
parameters are available.  If the ignored parameters were named
meaninglessly, then these people would be forced to search for call
sites of the procedure in order to get a rough idea of what
parameters might be passed here.
</p>

 <p>
When naming top-level bindings, assume namespace partitions unless in a
context where they are certain to be absent.  Do not write explicit
namespace prefixes, such as FOO:BAR for an operation BAR in a module
FOO, unless the names will be used in a context known not to have any
kind of namespace partitions.
</p>

 <p>
Rationale:  Explicit namespace prefixes are ugly, and lengthen names
without adding much semantic content.  Common Lisp has its package
system to separate the namespaces of symbols; most Schemes have
mechanisms to do so as well, even if the RnRS do not specify any.  It
is better to write clear names which can be disambiguated if
necessary, rather than to write names that assume some kind of
disambiguation to be necessary to begin with.  Furthermore, explicit
namespace prefixes are inadequate to cover name clashes anyway:
someone else might choose the same namespace prefix.  Relegating this
issue to a module system removes it from the content of the program,
where it is uninteresting.
</p>
</div>
 <h3>Comments  <a id="comments" class="anchor" href="#comments">#</a></h3> <div class="outline-text-3" id="text-orgab587ed">
 <p>
Write comments only where the code is incapable of explaining itself.
Prefer self-explanatory code over explanatory comments.  Avoid
`literate programming’ like the plague.
</p>

 <p>
Rationale:  If the code is often incapable of explaining itself, then
perhaps it should be written in a more expressive language.  This may
mean using a different programming language altogether, or, since we
are talking about Lisp, it may mean simply building a combinator
language or a macro language for the purpose.  `Literate programming’
is the logical conclusion of languages incapable of explaining
themselves; it is a direct concession of the inexpressiveness of the
computer language implementing the program, to the extent that the
only way a human can understand the program is by having it rewritten
in a human language.
</p>

 <p>
Do not write interface documentation in the comments for the
implementation of the interface.  Explain the interface at the top of
the file if it is a single-file library, or put that documentation in
another file altogether.  (See the `Documentation’ section below if the
interface documentation comments grow too large for a file.)
</p>

 <p>
Rationale:  A reader who is interested only in the interface really
should not need to read through the implementation to pick out its
interface; by putting the interface documentation at the top, not
only is such a reader’s task of identifying the interface made
easier, but the implementation code can be more liberally commented
without fear of distracting this reader.  To a reader who is
interested in the implementation as well, the interface is still
useful in order to understand what concepts the implementation is
implementing.
</p>

 <p>
Example:  <a href="http://mumble.net/~campbell/scheme/skip-list.scm">http://mumble.net/~campbell/scheme/skip-list.scm</a>
</p>

 <p>
In this example of a single-file library implementing the skip list
data structure, the first page explains the purpose and dependencies
of the file (which are useful for anyone who intends to use it, even
though dependencies are really implementation details), and the next
few pages explain the usage of skip lists as implemented in that
file.  On the first page of implementation, `Skip List Structure’,
there are some comments of interest only to a reader who wishes to
understand the implementation; the same goes for the rest of the
file, none of which must a reader read whose interest is only in the
usage of the library.
</p>

 <p>
Avoid block comments (i.e. #| … |#).  Use S-expression comments (`#;’
in Scheme, with the expression to comment on the next line; `#+(OR)’ or
`#-(AND)’ in Common Lisp) to comment out whole expressions.  Use blocks
of line comments for text.
</p>

 <p>
Rationale:  Editor support for block comments is weak, because it
requires keeping a detailed intermediate parse state of the whole
buffer, which most Emacsen do not do.  At the very least, #|| … ||#
is better, because most Emacsen will see vertical bars as symbol
delimiters, and lose trying to read a very, very long symbol, if they
try to parse #| … |#, whereas they will just see two empty symbols
and otherwise innocuous text between them if they try to parse #||
… ||#.  In any case, in Emacs, `M-x comment-region RET’, or `M-;’
(comment-dwim), is trivial to type.
</p>

 <p>
The only standard comments in Scheme are line comments.  There are
SRFIs for block comments and S-expression comments, but support for
them varies from system to system.  Expression comments are not hard
for editors to deal with because it is safe not to deal with them at
all; however, in Scheme S-expression comments, which are written by
prefixing an expression with `#;’, the expression to be commented
should be placed on the next line.  This is because editors that do
not deal with them at all may see the semicolon as the start of a
line comment, which will throw them off.  Expression comments in
Common Lisp, however, are always safe.
</p>

 <p>
In Common Lisp, the two read-time conditionals that are guaranteed to
ignore any form following them are `#+(OR)’ and `#-(AND)’.  `#+NIL’
is sometimes used in their stead, but, while it may appear to be an
obviously false conditional, it actually is not.  The feature
expressions are read in the KEYWORD package, so NIL is read not as
CL:NIL, i.e. the boolean false value, but as :NIL, a keyword symbol
whose name happens to be `NIL’.  Not only is it not read as the
boolean false value, but it has historically been used to indicate a
feature that might be enabled – in JonL White’s New Implementation
of Lisp!  However, the New Implementation of Lisp is rather old these
days, and unlikely to matter much…until Alastair Bridgewater writes
Nyef’s Implementation of Lisp.
</p>
</div>
 <h3>Documentation  <a id="documentation" class="anchor" href="#documentation">#</a></h3> <div class="outline-text-3" id="text-org0683161">
 <p>
On-line references and documentation/manuals are both useful for
independent purposes, but there is a very fine distinction between
them.  Do not generate documentation or manuals automatically from the
text of on-line references.
</p>

 <p>
Rationale:  <i>On-line references</i> are quick blurbs associated with
objects in a running Lisp image, such as documentation strings in
Common Lisp or Emacs Lisp.  These assume that the reader is familiar
with the gist of the surrounding context, but unclear on details;
on-line references specify the details of individual objects.
</p>

 <p>
 <i>Documentation</i> and  <i>manuals</i> are fuller, organized, and cohesive
documents that explain the surrounding context to readers who are
unfamiliar with it.  A reader should be able to pick a manual up and
begin reading it at some definite point, perusing it linearly to
acquire an understanding of the subject.  Although manuals may be
dominated by reference sections, they should still have sections that
are linearly readable to acquaint the reader with context.
</p>
</div>
 <h3>Round and Square Brackets  <a id="round-and-square-brackets" class="anchor" href="#round-and-square-brackets">#</a></h3> <div class="outline-text-3" id="text-org4ab41cf">
 <p>
Some implementations of Scheme provide a non-standard extension of the
lexical syntax whereby balanced pairs of square brackets are
semantically indistinguishable from balanced pairs of round brackets.
Do not use this extension.
</p>

 <p>
Rationale:  Because this is a non-standard extension, it creates
inherently non-portable code, of a nature much worse than using a
name in the program which is not defined by the R5RS.  The reason
that we have distinct typographical symbols in the first place is to
express different meaning.  The only distinction between round
brackets and square brackets is in convention, but the precise nature
of the convention is not specified by proponents of square brackets,
who suggest that they be used for `clauses’, or for forms that are
parts of enclosing forms.  This would lead to such constructions as
</p>

 <pre>( <span class="org-keyword">let</span> [(x 5) (y 3)] ...)</pre>



 <p>
or
</p>

 <pre>( <span class="org-keyword">let</span> ([x 5] [y 3]) ...)</pre>



 <p>
or
</p>

 <pre>( <span class="org-keyword">let</span> [[x 5] [y 3]] ...),</pre>


 <p>
the first two of which the author of this guide has seen both of, and
the last of which does nothing to help to distinguish the parentheses
anyway.
</p>

 <p>
The reader of the code should not be forced to stumble over a
semantic identity because it is expressed by a syntactic distinction.
The reader’s focus should not be directed toward the lexical tokens;
it should be directed toward the structure, but using square brackets
draws the reader’s attention unnecessarily to the lexical tokens.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/lisps/scheme-and-lisp-style-guide/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/lisps/scheme-and-lisp-style-guide/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Scheme and Lisps are Great for production</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
I want to start by thanking the great NalaGinrut that wrote an article on this topic, which I adapted to explain my experience with Scheme and Lisps.
</p>

 <hr></hr> <p>
What if I told you one of the oldest high-level programming languages is also one of the most advanced? A language so flexible and powerful, that really lets your ideas flow and super-boosts expressiveness..
</p>

 <p>
In the vast universe of programming languages, most follow a familiar set of rules. There’s a clear line between  <i>the code you write and the data that code processes</i>.
</p>

 <p>
But hidden in plain sight is a family of languages that threw that rulebook out decades ago. λ They’re called  <b>Lisp</b>.
</p>

 <p>
The core philosophy of  <a href="https://en.wikipedia.org/wiki/Lisp_(programming_language)">Lisp</a> is disarmingly simple: code and data have the same structure. This concept, known as homoiconicity, is what gives Lisp its legendary power. It means you can write programs that write other programs, transforming the language itself to perfectly match the problem you’re trying to solve.
</p>

 <p>
 <a href="https://www.gnu.org/software/guile/">GNU Guile Scheme</a> is a fantastic implementation of the minimalistic and academia-renowned Lisp dialect known as  <a href="https://en.wikipedia.org/wiki/Scheme">Scheme</a>.
</p>

 <pre>( <span class="org-keyword">define</span> ( <span class="org-function-name">factorial</span> n)
  ( <span class="org-keyword">if</span> (= n 0)
      1
      (* n (factorial (- n 1)))))

( <span class="org-keyword">define</span> ( <span class="org-function-name">compose</span> f g)
  ( <span class="org-keyword">lambda</span> (x)
    (f (g x))))</pre>

 <hr></hr> <h2>My Journey with Scheme in Production  <a id="my-journey-with-scheme-in-production" class="anchor" href="#my-journey-with-scheme-in-production">#</a></h2> <div class="outline-text-2" id="text-orge599424">
 <p>
For the past two years, I’ve been on a mission: using the  <b>Scheme programming language</b> , write and deliver production-ready systems, and transform my computing environment (leveraging great Scheme/Lisp projects like  <a href="https://guix.gnu.org/">GNU Guix</a>, GNU Artanis, etc.).
</p>

 <p>
I have since developed several libraries, fully-fledged web applications that are database-backed, and even created my own operating system (on top of Guix), all thanks to this expressive language, that lets me lift the heaviest boulders.
</p>

 <p>
The existing folklore around Scheme and its Lisp family is often described as fascinating, paradoxical, and even mystical. While Scheme holds a prominent place in academia, I’ve noticed a significant gap in its adoption within commercial products. Discussions about the real-world challenges and solutions for using Scheme in development are surprisingly scarce, with many simply echoing conventional wisdom rather than delving into practical implementation.
</p>

 <hr></hr> <p>
Some of my projects that use Scheme:
</p>

 <p>
 <a href="https://codeberg.org/jjba23/sss">SSS - Supreme Sexp System</a> - This custom GNU Guix + Linux setup enhances customization to infinity, encourages the hacking spirit, and offers a superior user experience thanks in part too to REPL (Read Eval Print Loop) and Lisps, GTK, Hyprland, Nyxt, Firefox, etc.
</p>

 <p>
 <a href="https://codeberg.org/jjba23/wolk-jjba">Wolk JJBA</a> - My web server, running CI/CD, custom services, Nginx, Minecraft and more, all working via Lisp (Guix & Guile Scheme)
</p>

 <p>
 <a href="https://codeberg.org/jjba23/iter-vitae">Iter Vitae</a> - Iter Vitae: “Journey of Life” - the progression of one’s life and career. My curriculum vitae / resume generator usign Guile Scheme and Tailwind CSS
</p>

 <p>
 <a href="https://codeberg.org/jjba23/byggsteg">byggsteg</a> - Byggsteg is the free as in freedom CI/CD orchestrator written in Guile Scheme.
</p>

 <p>
Some other cool projects:
</p>

 <p>
 <a href="https://guix.gnu.org/">GNU Guix</a> - GNU Guix is a package manager for GNU/Linux systems. It is designed to give users more control over their general-purpose and specialized computing environments, and make these easier to reproduce over time and deploy to one or many devices.
</p>

 <p>
 <a href="https://www.spritely.institute/hoot/">Guile Hoot</a> - Hoot is a Spritely project for running Scheme code on Wasm GC-capable web browsers, featuring a Scheme to Wasm compiler and a full-featured Wasm toolchain. Hoot is built on Guile and has no additional dependencies. The toolchain is self-contained and even features a Wasm interpreter for testing Hoot binaries without leaving the Guile REPL.
</p>

 <p>
 <a href="https://gitlab.com/spritely/guile-goblins">Guile Goblins</a> - Goblins is an actor model implementation for async and distributed network computing, written as a Guile Scheme library.  It was originally written for use in Spritely, but is fairly general.
</p>

 <p>
 <a href="https://artanis.dev/">GNU Artanis</a> - GNU Artanis is a production-level modern Web framework of Scheme programming language. It is designed and maintained to be robust, fast, and easy to use for professional web development.
</p>

 <hr></hr> <p>
My personal choice has been  <b>GNU Guile</b>, though I’ve also explored other Scheme implementations. My experience is, of course, limited, and I’m not suggesting GNU Guile is ready to replace Python, Go, Typescript, Haskell, Scala or Java overnight. However, my insights extend beyond GNU Guile to other Scheme implementations as well as other Lisp dialects.
</p>

 <p>
This article isn’t about convincing you to choose Scheme over other languages. Instead, if you’ve already recognized the growing trend of  <b>functional programming</b> and are curious about powerful, well-established functional languages, this piece will illuminate Scheme’s often-overlooked strengths in a production setting.
</p>

 <hr></hr> <div id="orgfbe51b6" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/static-assets/other/img/guile-sculptor-small.png"></img></p>
</div>

 <hr></hr></div>
 <h2>Why Scheme? Beyond the Cliché Questions  <a id="why-scheme-beyond-the-cliché-questions" class="anchor" href="#why-scheme-beyond-the-cliché-questions">#</a></h2> <div class="outline-text-2" id="text-org4cdd53b">
 <p>
The question “Why bother with Scheme?” is a classic one, with countless valid answers. While I can’t list them all exhaustively, here’s what you should know if you’re new to the “Scheme land”:
</p>

 <ul class="org-ul"> <li> <b>Exceptional Expressiveness:</b> Scheme excels at allowing you to write  <b>painless and expressive code</b> that significantly reduces complexity.</li>
 <li> <b>Full Lambda Calculus Support:</b> Its robust support for lambda calculus offers  <b>superior expressiveness</b> when you need to craft elegant and powerful abstractions.</li>
 <li> <b>Ease of Understanding:</b> Scheme’s clarity makes programs easier to analyze and debug, which is crucial in any development cycle.</li>
 <li> <b>Standardized and Stable:</b> Scheme is a  <b>standardized language</b> with well-defined grammar and standard APIs, ensuring consistency and predictability.</li>
 <li> <b>Rapid Development:</b> For business logic, where low-level details aren’t the primary concern, Scheme provides an excellent framework for  <b>rapid development</b>.</li>
 <li> <b>Reduced Complexity, Fewer Bugs:</b> Less complexity generally leads to fewer bugs. While no language guarantees bug-free code (that depends on the programmer!), Scheme’s design inherently promotes clearer, more maintainable solutions.</li>
 <li> <b>A Worthwhile Investment:</b> From a professional software development perspective,  <b>Scheme is absolutely worth investing in</b>, and I’ll demonstrate why throughout this article.</li>
</ul> <hr></hr></div>
 <h2>Dispelling the Illusions: Addressing Common Misconceptions  <a id="dispelling-the-illusions-addressing-common-misconceptions" class="anchor" href="#dispelling-the-illusions-addressing-common-misconceptions">#</a></h2> <div class="outline-text-2" id="text-orge7aee97">
 <p>
Let’s tackle some common illusions about Scheme:
</p>
</div>
 <h3>Illusion: It’s Hard to Find Scheme Programmers  <a id="illusion-itrsquos-hard-to-find-scheme-programmers" class="anchor" href="#illusion-itrsquos-hard-to-find-scheme-programmers">#</a></h3> <div class="outline-text-3" id="text-org88d0ffe">
 <p>
Yes, directly hiring a seasoned Scheme programmer with production experience can be challenging. This is the number one reason many companies refuse certain tech. However, with Scheme, I realized it was a non-issue.  <b>Training a Scheme programmer is remarkably cost-effective</b>, partly thanks to the simplicity and minimalism of the language.
</p>

 <p>
Here’s an idea for you, to address any hiring concerns, focus on evaluating candidates’ understanding of functional programming. It’s a growing trend, after all! If candidates  are strong enough to receive an offer, then introduce them to the legendary book  <b>SICP (Structure and Interpretation of Computer Programs)</b> during their onboarding.
</p>

 <p>
Of course, SICP is a substantial book for newcomers, so you can focus on the first two chapters. “Data abstraction” helps them understand object-oriented concepts, and “procedure abstraction” refines their algorithm implementation skills.
</p>

 <p>
I argue that within a month they will begin tackling small tasks, fixing bugs, and implementing minor features. SICP isn’t just a book; it’s a formalized educational system designed by profound minds. We can leverage this system to quickly train proficient Scheme programmers and apply their fresh knowledge to daily work.
</p>

 <p>
The SICP educational system empowers us to train capable Scheme programmers in a short timeframe. Most technology companies already have an onboarding period for new hires; a dedicated month for Scheme training is a good, affordable solution. Think about it:  <b>we can spend virtually no money on this training</b>, and we rapidly translate the valuable knowledge from SICP into tangible product development.
</p>
</div>
 <h3>Illusion: Scheme Isn’t Fast  <a id="illusion-scheme-isnrsquot-fast" class="anchor" href="#illusion-scheme-isnrsquot-fast">#</a></h3> <div class="outline-text-3" id="text-org48bbe2d">
 <p>
This is  <b>no longer true!</b> We have great JIT compilers and optimizations happening and lots of Guile Scheme is implemented in C. Specially if you are coming from Ruby, PHP or Python land, you will notice a major speedup.
</p>

 <p>
Years ago, as a newbie, I was obsessed with programming language speed. As a professional developer, I’ve come to understand that there are at least three crucial kinds of “speed” in programming:
</p>

 <ul class="org-ul"> <li> <b>Learning speed:</b> How easy is it to learn a language from scratch?</li>
 <li> <b>Development speed:</b> How much can we reduce the coding effort?</li>
 <li> <b>Execution speed:</b> How quickly does the code run?</li>
</ul> <p>
This realization helped me understand why languages like Ruby on Rails gained immense popularity in web development, despite being considered “slow” in terms of execution. If execution speed were the sole criterion, assembly or even machine code would always be the superior choice.
</p>
</div>
 <h3>Illusion: The Ecosystem is the Most Important Factor for a Language  <a id="illusion-the-ecosystem-is-the-most-important-factor-for-a-language" class="anchor" href="#illusion-the-ecosystem-is-the-most-important-factor-for-a-language">#</a></h3> <div class="outline-text-3" id="text-org34b4609">
 <p>
My friend, please  <b>don’t blindly trust this conjecture any longer.</b> It doesn’t hold true in real-world development. The reality is:  <b>the language itself is the most important factor for an ecosystem.</b>
</p>

 <p>
A large ecosystem, while containing many packages, doesn’t guarantee quality or active maintenance across all packages and their dependencies. We shouldn’t have blind faith in sheer quantity.
</p>

 <p>
The Python ecosystem, for instance, is primarily for the Python language. While Python boasts a massive ecosystem due to historical reasons, it doesn’t imply that other languages require a comparably vast one. There’s only one truly universal ecosystem:  <b>the C ecosystem.</b> Dynamic language modules are often just bindings to existing C libraries.
</p>

 <p>
Therefore, if a language offers  <b>strong FFI (Foreign Function Interface) support</b>, it can leverage the entire universe of C libraries. In today’s landscape, with distributed processing becoming commonplace, heterogeneous systems are the norm. We don’t need to build everything within a single ecosystem.
</p>

 <p>
So, let’s break this illusion: an ecosystem can be significant in certain scenarios, but it’s not the most critical aspect of a language. When we design or choose a language, we prioritize its  <b>paradigm, grammar, expressiveness, and optimization potential.</b>
</p>

 <p>
These are the true determinants of a programming language’s value. In the past, companies drove language development, and contributions to an ecosystem were often tied to payment. This made the ecosystem crucial for commercial languages to grow. Nowadays, programming languages are largely driven by  <b>FOSS (Free and Open-Source Software) communities</b>, leading to naturally evolving ecosystems. An experienced developer will prioritize a language’s expressiveness, as it directly impacts coding efficiency.
</p>

 <p>
As a final note on this, considering Guile Scheme is the official GNU project’s extension language, you can be assured that this ecosystem is here to stay, keeps growing, and is of high quality. Take a look at all the Guile libraries distributed via the Guix package manager for example:  <a href="https://jointhefreeworld.org/guile-show-hub/">https://jointhefreeworld.org/guile-show-hub/</a>
</p>

 <hr></hr></div>
 <h2>Understanding the Trade-offs: The “Cons” of Scheme  <a id="understanding-the-trade-offs-the-ldquoconsrdquo-of-scheme" class="anchor" href="#understanding-the-trade-offs-the-ldquoconsrdquo-of-scheme">#</a></h2> <div class="outline-text-2" id="text-orgacd98e0">
 <p>
No language is perfect. Here are a few current challenges for Scheme:
</p>
</div>
 <h3>Scheme Isn’t Yet Fully Ready for AI/Deep Learning  <a id="scheme-isnrsquot-yet-fully-ready-for-aideep-learning" class="anchor" href="#scheme-isnrsquot-yet-fully-ready-for-aideep-learning">#</a></h3> <div class="outline-text-3" id="text-orgbeca752">
 <p>
Deep learning and LLM is undeniably hot right now.
</p>

 <p>
Scheme can be a great choice if you are writing and chatting to REST APIs of Agents, LLMs, etc
</p>

 <p>
There are many scientific packages available in Specific to Guile via Guix, which allow for reproducible scientific computational in research projects.
</p>

 <p>
I’d like to mention the  <b>AISCM project</b>, written in GNU Guile using LLVM JIT and based on TensorFlow. It works, and it’s impressive. However, I personally don’t have extensive time to dedicate to it. So, if you’re serious about using Scheme for deep learning, I strongly encourage you to contribute to AISCM.
</p>

 <p>
With this being said, Scheme is by itself a great language for AI applications, as history has proved, and in the future it will continue to be so.
</p>
</div>
 <h3>Scheme Has a Fragmented Community  <a id="scheme-has-a-fragmented-community" class="anchor" href="#scheme-has-a-fragmented-community">#</a></h3> <div class="outline-text-3" id="text-org66a7787">
 <p>
For historical reasons, there are numerous Scheme implementations, leading to a somewhat fragmented community. However, there’s growing hope!
</p>

 <p>
First,  <b>Scheme standardization has made excellent progress</b> over the past decade.  <b>R7RS</b> thoughtfully separated Scheme into “small” and “big” languages. In my opinion, this was a brilliant move, preserving Scheme’s minimalism while also providing a path for industrial-level library specifications.
</p>

 <p>
Another promising development is the rise of modern package managers. I personally use  <b>GNU Guix</b>, a functional package manager (and operating system) written with GNU Guile. Most GNU Guile libraries can be installed via GNU Guix. Package managers are crucial for fostering ecosystems. In a broader sense, we might consider the GNU community as an operating system community, not just a “commercial concept” ecosystem. Of course, Racket and Chicken Scheme also boast excellent package managers, which significantly contribute to their respective communities.
</p>

 <p>
Ultimately, consistent standard specifications and robust package managers are key to unifying the fragmented Scheme community. It will take time, but the path is clear.
</p>
</div>
 <h3>Scheme Isn’t “Purely” Functional  <a id="scheme-isnrsquot-ldquopurelyrdquo-functional" class="anchor" href="#scheme-isnrsquot-ldquopurelyrdquo-functional">#</a></h3> <div class="outline-text-3" id="text-orgbc60dbe">
 <p>
Some functional programming purists may prefer languages that strictly enforce purity, meaning no side effects/effect systems. While Scheme is a  <b>multi-paradigm language</b> and not exclusively functional, it offers all the powerful functional features you’d find in pure functional languages. Although side effects are permitted in Scheme, you retain complete control over when and how you use them.
</p>

 <p>
Even as a Haskell enjoyer, I still don’t believe it’s beneficial for all software to completely forbid side effects, only in select occasions; programmers should have the freedom to choose their approach.
</p>

 <hr></hr></div>
 <h2>Highlighting the Advantages: The “Pros” of Scheme  <a id="highlighting-the-advantages-the-ldquoprosrdquo-of-scheme" class="anchor" href="#highlighting-the-advantages-the-ldquoprosrdquo-of-scheme">#</a></h2> <div class="outline-text-2" id="text-org21dd9b7">
 <p>
Now, let’s explore Scheme’s compelling advantages:
</p>
</div>
 <h3>Scheme Excels in Web Development in  Frontend and Backend  <a id="scheme-excels-in-web-development-in--frontend-and-backend" class="anchor" href="#scheme-excels-in-web-development-in--frontend-and-backend">#</a></h3> <div class="outline-text-3" id="text-orgfb1716c">
 <p>
With most GUI programs shifting to SaaS models, web development has become increasingly vital. This is why I’m focusing on web rather than traditional GUI development.
</p>

 <p>
All Lisps, with their distinctive characteristics, offer compelling advantages for web development, particularly in crafting frontends and adeptly handling tree-like structures such as HTML.
</p>

 <p>
At the heart of Lisp’s strength lies homoiconicity, the revolutionary concept that Lisp code itself is represented as data structures, primarily lists. This isn’t just an academic detail; it’s the bedrock for macros, Lisp’s ultimate feature for extending the language. HTML, being inherently hierarchical, mirrors a tree structure perfectly.
</p>

 <p>
Complementing all this is the Lisp REPL (Read-Eval-Print Loop), an incredibly powerful environment for interactive development. You can connect to a running web server or application, redefine functions, test new code, and inspect data structures live, without the need to restart the entire process. This interactive fluidity is a significant advantage for debugging and rapid prototyping.
</p>

 <p>
Lisp’s fundamental data structure, the list (S-expression), is inherently recursive, making it perfectly suited for representing tree-like data. An HTML document is, at its core, a tree where elements serve as nodes and their content or children form branches.
</p>

 <p>
Lisp’s provides an intrinsically natural and highly efficient means to construct, traverse, and transform these tree structures. Because Lisp treats code as data, you can write functions and macros that directly manipulate these “HTML trees” as native Lisp data structures. This is  <b>far more potent</b> and less error-prone than solely relying on string manipulation or external template engines. 
</p>
</div>
 <h3>Scheme Saves You Valuable Coding Time  <a id="scheme-saves-you-valuable-coding-time" class="anchor" href="#scheme-saves-you-valuable-coding-time">#</a></h3> <div class="outline-text-3" id="text-orgd20cff8">
 <p>
As a seasoned programmer in other languages, higher and lower level, I firmly believe we shouldn’t waste time writing non-system-level code in C/C++, Rust, Java, or Scala for example, due to their rigidity. Business logic often changes, and these languages aren’t flexible enough for rapid iterations.  <b>Don’t squander your time on endless refactoring and debugging.</b>
</p>

 <p>
Scheme’s  <b>powerful expressiveness</b> significantly reduces the amount of code you need to write. However, its effectiveness depends on your approach. If you’re looking for an abundance of pre-built libraries to minimize work, Scheme might not be your first choice.
</p>

 <p>
Scheme’s minimalist nature also makes it exceptionally easy to embed as script code within a larger system (especially Guile).
</p>
</div>
 <h3>Build a Team with Deep Computer Science Knowledge  <a id="build-a-team-with-deep-computer-science-knowledge" class="anchor" href="#build-a-team-with-deep-computer-science-knowledge">#</a></h3> <div class="outline-text-3" id="text-org78eaa81">
 <p>
Have you ever found yourself complaining about poor code during a review, realizing that your team members haven’t had the chance to truly equip themselves with fundamental computer science knowledge for serious programming?
</p>

 <p>
Scheme can provide that opportunity. It’s easy to learn, and critically, it’s powerful enough for product development.
</p>

 <p>
Also if you ever need to go more low-level, with Guile you can very easily interface with low-level C code and have the best of both worlds, good use cases are small-core large extensibility programs where you mix Guile and C, and much more, leveraging the compiler tower.
</p>

 <p>
Also you can run Scheme in WebAssembly nicely lately.
</p>

 <hr></hr> <p>
Ultimately,  <b>choose your weapon wisely.</b> And remember, embracing diversity in your technological toolkit and continuously learning new things is always a sound strategy.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/lisps/scheme-and-lisps-are-great-for-production/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/lisps/scheme-and-lisps-are-great-for-production/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Taming Complexity with Scheme: The Byggsteg Story</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <h2>Abstract  <a id="abstract" class="anchor" href="#abstract">#</a></h2> <h3>Introducing Scheme  <a id="introducing-scheme" class="anchor" href="#introducing-scheme">#</a></h3> <div class="outline-text-3" id="text-org17c9084">
 <p>
Scheme is a classic programming language in the Lisp family. It emphasizes functional programming and domain-specific languages but adapts to other styles. Known for its clean and minimalist design, Scheme is one of the longest-lived and best-studied dynamic languages, and has many fast and portable implementations.
</p>

 <p>
In  <i>Scheme</i>  <a href="https://www.scheme.org/">https://www.scheme.org/</a>
</p>
</div>
 <h3>This paper’s focus  <a id="this-paperrsquos-focus" class="anchor" href="#this-paperrsquos-focus">#</a></h3> <div class="outline-text-3" id="text-org5fa9612">
 <p>
This paper explores the practical application of Scheme (Guile Scheme implementation) in the development of Byggsteg, a CI/CD orchestrator. It examines how Scheme’s features, such as dynamic typing, homoiconicity, and first-class functions, influenced the design and implementation and make many difficult tasks achievable in a simple manner. The paper also discusses the use of GNU Artanis, SQLite, and other technologies within the Byggsteg architecture, and the lessons learned in applying Scheme to a real-world project management tool.
</p>

 <p>
We will expand on the experience and knowledge gained while creating a non-trivial production-grade software project using Scheme as only language of implementation, and in that process, creating a full-stack CI/CD system and accompanying management views, that encompass all from database access, job queueing to HTML rendering, all from the comfort of Scheme. We will cover extensively why this parenthesis-rich language provides a level of power and expressivity that is not achievable with other technologies.
</p>
</div>
 <h2>Introduction  <a id="introduction" class="anchor" href="#introduction">#</a></h2> <div class="outline-text-2" id="text-orgc3114f9">
 <p>
Scheme was created during the 1970s at the MIT Computer Science and Artificial Intelligence Laboratory (MIT CSAIL) and released by its developers, Guy L. Steele and Gerald Jay Sussman, via a series of memos now known as the Lambda Papers.
</p>

 <p>
It was the first dialect of Lisp to choose lexical scope and the first to require implementations to perform tail-call optimization, giving stronger support for functional programming and associated techniques such as recursive algorithms. It was also one of the first programming languages to support first-class continuations. It had a significant influence on the effort that led to the development of Common Lisp.
</p>

 <p>
Scheme is primarily a functional programming language. It shares many characteristics with other members of the Lisp programming language family. Scheme’s very simple syntax is based on s-expressions, parenthesized lists in which a prefix operator is followed by its arguments. Scheme programs thus consist of sequences of nested lists. Lists are also the main data structure in Scheme, leading to a close equivalence between source code and data formats (homoiconicity). Scheme programs can easily create and evaluate pieces of Scheme code dynamically.
</p>

 <p>
The reliance on lists as data structures is shared by all Lisp dialects. Scheme inherits a rich set of list-processing primitives such as  <code>cons</code>,  <code>car</code> and  <code>cdr</code> from its Lisp progenitors.
</p>

 <p>
Scheme uses strictly but dynamically typed variables and supports first class procedures. Thus, procedures can be assigned as values to variables or passed as arguments to procedures.
</p>

 <p>
In  <i>Wikipedia</i>  <a href="https://en.wikipedia.org/wiki/Scheme_(programming_language)">https://en.wikipedia.org/wiki/Scheme_(programming_language)</a>
</p>

 <p>
Scheme boasts several distinguishing features that set it apart from other programming languages, including other Lisps. Here are some key characteristics:
</p>

 <dl class="org-dl"> <dt>Minimalism</dt> <dd>Scheme has a very small core language with a concise set of primitive procedures. Much of the functionality commonly built into other languages is provided through libraries. This minimalism makes the language easier to learn and implement.</dd>

 <dt>First-Class Functions</dt> <dd>In Scheme, functions are treated as first-class citizens. This means they can be assigned to variables and passed as arguments to other functions, returned as values from other functions and even stored in data structures. This capability enables powerful programming paradigms like higher-order functions and functional programming.</dd>

 <dt>Proper Tail Recursion</dt> <dd>Scheme implementations are required to be properly tail-recursive. This means that if the last operation in a function is a recursive call, the interpreter or compiler will optimize it in such a way that it doesn’t consume additional stack space. This allows for writing iterative processes using recursion without the risk of stack overflow errors.</dd>

 <dt>Lexical Scoping</dt> <dd>Scheme uses lexical (or static) scoping. This means that the scope of a variable is determined by where it is defined in the source code, not by where the function is called. This makes it easier to reason about variable bindings and avoids unexpected behavior.</dd>

 <dt>Homoiconicity</dt> <dd>Scheme code and data have the same underlying structure – the list. This property, known as homoiconicity, allows programs to manipulate their own code as data. This is a powerful feature that facilitates metaprogramming, macros, and the creation of domain-specific languages.</dd>

 <dt>Parenthesized Syntax (S-expressions)</dt> <dd>Scheme’s syntax is based on fully parenthesized expressions called S-expressions. While this can look different from more conventional syntaxes, it provides a uniform and unambiguous structure that simplifies parsing and manipulation of code.</dd>

 <dt>Dynamic Typing</dt> <dd>Scheme is a dynamically typed language. Type checking is performed at runtime, rather than compile time. This allows for more flexibility but also requires careful testing to catch type-related errors.</dd>

 <dt>Continuations</dt> <dd>Scheme supports continuations, which represent the entire execution state of a program at a particular point in time. Continuations can be captured and later invoked, allowing for powerful control flow mechanisms like non-local exits, backtracking, and coroutines.</dd>
</dl> <p>
These features collectively contribute to Scheme’s power and expressiveness, making it a popular choice for academic use, research in programming language design, and applications where flexibility and metaprogramming capabilities are highly valued.
</p>


 <p>
In my point of view, and in retrospective, Scheme was really a great choice for developing complex systems.
</p>
</div>
 <h3>What is byggsteg?  <a id="what-is-byggsteg" class="anchor" href="#what-is-byggsteg">#</a></h3> <div class="outline-text-3" id="text-org5e50dab">
 <p>
byggsteg is a free software project with the aim of developing a suite of functionalities to allow engineers to deliver software quicker and with less friction, in other words a CI/CD orchestrator written in Guile Scheme.
</p>

 <p>
View my live instance of byggsteg here:  <a href="https://byggsteg.jointhefreeworld.org">https://byggsteg.jointhefreeworld.org</a>
</p>

 <p>
It leverages SXML, SQLite3, some POSIX / UNIX utilities, and the mighty GNU Artanis web-framework.
</p>

 <p>
The aim of byggsteg is to release you from your dependency on proprietary systems like GitHub actions. This allows you to create continuous integration and continuous delivery (CI & CD) pipelines in an easy way that are tailored to your needs and which you fully control.
</p>

 <p>
Easily deploy stuff, for example to your private VPS, self-hosting or to cloud. byggsteg means “build step” in the Norwegian language.
</p>

 <p>
I don’t mind having the software building and testing happening in the same machine as where I run the production workloads, since I am looking for supreme cost-efficiency, but it’s highly recommended that you do separate these things, if you can afford it.
</p>

 <p>
Jobs and profiles
</p>

 <p>
Jobs are simple Lisp (Guile Scheme) code. Profiles are just saved jobs.
</p>

 <p>
byggsteg allows you to send code over the wire (HTTP) and save it too, in a thunk form, for example :
</p>

 <pre>( <span class="org-keyword">lambda</span>()
  `((project .  <span class="org-string">"free-alacarte"</span>)
    (branch-name .  <span class="org-string">"trunk"</span>)
    (task .  <span class="org-string">"stack-test"</span>)
    (clone-url .  <span class="org-string">"https://codeberg.org/jjba23/free-alacarte"</span>)))</pre>

 <p>
Sending things in thunk form allows one to execute any code arbitrarily, inside the lambda expression. Be responsible and wary of who you give access to your byggsteg instance.
</p>

 <pre>( <span class="org-keyword">lambda</span>()
  ( <span class="org-keyword">define</span>  <span class="org-function-name">my-project-name</span>  <span class="org-string">"wikimusic-api"</span>)
  ( <span class="org-keyword">define</span>  <span class="org-function-name">my-branch-name</span>
    (format #f  <span class="org-string">"branch-num-~a"</span> (* 2 (+ 3 (+ 8 10)))))

   <span class="org-comment-delimiter">;; </span> <span class="org-comment">remember that a ". ," and a "unquote" are equivalent</span>
  `((project . ,my-project-name)
    (branch-name unquote my-branch-name)
    (task . ( <span class="org-string">"stack-build"</span>  <span class="org-string">"stack-test"</span>))
    (clone-url unquote (format #f  <span class="org-string">"https://codeberg.org/jjba23/~a"</span> my-project-name))))</pre>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/lisps/taming-complexity-with-scheme-the-byggsteg-story/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/lisps/taming-complexity-with-scheme-the-byggsteg-story/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Why I Program in Lisp?</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Original  <a href="https://funcall.blogspot.com/2025/04/why-i-program-in-lisp.html">article by Joe Marshall</a>
</p>

 <p>
Lisp is not the most popular language. It never was. Other general purpose languages are more popular and ultimately can do everything that Lisp can (if Church and Turing are correct). They have more libraries and a larger user community than Lisp does. They are more likely to be installed on a machine than Lisp is.
</p>

 <p>
Yet I prefer to program in Lisp. I keep a Lisp REPL open at all times, and I write prototypes and exploratory code in Lisp. Why do I do this? Lisp is easier to remember, has fewer limitations and hoops you have to jump through, has lower “friction” between my thoughts and my program, is easily customizable, and, frankly, more fun.
</p>

 <p>
Lisp’s dreaded Cambridge Polish notation is uniform and universal. I don’t have to remember whether a form takes curly braces or square brackets or what the operator precedency is or some weird punctuated syntax that was invented for no good reason. It is (operator operands …) for everything. Nothing to remember. I basically stopped noticing the parenthesis 40 years ago. I can indent how I please.
</p>

 <p>
I program mostly functionally, and Lisp has three features that help out tremendously here. First, if you avoid side effects, it directly supports the substitution model. You can tell Lisp that when it sees this simple form, it can just replace it with that more complex one. Lisp isn’t constantly pushing you into thinking imperatively. Second, since the syntax is uniform and doesn’t depend on the context, you can refactor and move code around at will. Just move things in balanced parenthesis and you’ll pretty much be ok.
</p>

 <p>
Third, in most computer languages, you can abstract a specific value by replacing it with a variable that names a value. But you can perform a further abstraction by replacing a variable that names a quantity with a function that computes a quantity. In functional programming, you often downplay the distinction between a value and a function that produces that value.
</p>

 <p>
After all, the difference is only one of time spent waiting for the answer. In Lisp, you can change an expression that denotes an object into an abtraction that computes an object by simply wrapping a lambda around it. It’s less of a big deal these days, but properly working lambda expressions were only available in Lisp until recently. Even so, lambda expressions are generally pretty clumsy in other languages.
</p>

 <p>
Functional programming focuses on functions (go figure!). These are the ideal black box abstraction: values go in, answer comes out. What happens inside? Who knows! Who cares! But you can plug little simple functions together and get bigger more complex functions. There is no limit on doing this.
</p>

 <p>
If you can frame your problem as “I have this, I want that”, then you can code it as a functional program. It is true that functional programming takes a bit of practice to get used to, but it allows you to build complex systems out of very simple parts. Once you get the hang of it, you start seeing everything as a function. (This isn’t a limitation. Church’s lambda calculus is a model of computation based on functional composition.)
</p>

 <p>
Lisp lets me try out new ideas as quickly as I can come up with them. New programs are indistinguishable from those built in to the language, so I can build upon them just as easily. Lisp’s debugger means I don’t have to stop everything and restart the world from scratch every time something goes wrong. Lisp’s safe memory model means that bugs don’t trash my workspace as I explore the problem.
</p>

 <p>
The REPL in lisp evaluates expressions, which are the fundamental fragments of Lisp programs. You can type in part of a Lisp program and see what it does immediately. If it works, you can simply embed the expression in a larger program. Your program takes shape in real time as you explore the problem.
</p>

 <p>
Lisp’s dynamic typing gives you virtually automatic ad hoc polymorphism. If you write a program that calls +, it will work on any pair of objects that have a well-defined + operator.
</p>

 <p>
Now this can be a problem if you are cavalier about your types, but if you exercise a little discipline (like not defining + on combinations of strings and numbers, for example), and if you avoid automatic type coercion, then you can write very generic code that works on a superset of your data types. (Dynamic typing is a two-edged sword. It allows for fast prototyping, but it can hide bugs that would be caught at compile time in a statically typed language.)
</p>

 <p>
Other languages may share some of these features, but Lisp has them all together.
</p>

 <p>
It is a language that was designed to be used as a tool for thinking about problems, and that is the fun part of programming.
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/lisps/why-i-program-in-lisp/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/lisps/why-i-program-in-lisp/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Lisps</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-06-26 do> </span></span>  <a href="/blog/articles/lisps/scheme-and-lisps-are-great-for-production/index.html">Scheme and Lisps are Great for production</a> - “Why bother with Scheme/Lisp?” is a classic question, with countless valid answers. While I can’t list them all exhaustively, I will try to explain my motivation.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-04-11 vr> </span></span>  <a href="/blog/articles/lisps/why-i-program-in-lisp/index.html">Why I program in Lisp?</a> - Why choose for this paren-heavy form of lambda calculus? Lisp is a language that was designed to be used as a tool for thinking about problems, and that is the fun part of programming.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2024-12-27 vr> </span></span>  <a href="/blog/articles/lisps/embracing-the-eternal-sexp-wisdom-of-the-gnu/index.html">Embracing the eternal Sexp wisdom with the GNU</a> - I have recently reached new heights in declarative configurations of operating systems, programs and my workflow ⚙️ and development.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2024-12-18 wo> </span></span>  <a href="/blog/articles/lisps/scheme-and-lisp-style-guide/index.html">Scheme & Lisp Style Guide</a> - Riastradh’s Lisp Style Rules for some really clean Scheme, Lisp and Guile code.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2024-12-02 ma> </span></span>  <a href="https://artanis.dev/blog/why-to-port-to-artanis.html">Why port web Scheme applications to the amazing GNU Artanis framework?</a>
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/lisps/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/lisps/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Brief aan mijzelf</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
Lieve Joe,
</p>

 <p>
Jij en ik weten dat levend zijn pieken en dalen betekent.
Alles wat je heb meegemaakt heeft dit een volle, veelzijdige, maar gezellige bus.
</p>

 <p>
In deze bus zitten heel veel Joe's: doelgerichte Joe, aan de kant duwen Joe, vechter, niet-empatisch, idealistisch, hoge verwachtingen, hoge lat, inspirerend, hulpzaam, creatief, chill, zal goed komen, etc.
</p>

 <p>
Het is waar, vaak staat gladiator Joe voorin de bus, vooral als iemand of iets in de weg zit van doelgerichte Joe. Vaak wurgt ie zijn weg en toont weinig empathie en emoties, terwijl het allemaal heel veel pijn doet.
</p>

 <p>
En dus, dit maakt het moeilijk om behulpzaam, lief en chill zijn met anderen, terwijl je dat heel graag ook wil.
</p>

 <p>
Laten we afspreken dat je een ambitieuze krijger blijft, omdat dat je zoveel heeft opgeleverd in het leven, en omdat uphill battles en battles in het algemeen jou zo motiveren.
</p>

 <p>
Maar wees een inspirerend kracht, relativeer, blijf idealistisch, en "true to yourself", help anderen, neem meer tijd om de anderen te leren kennen, en hun emoties ook. Hoe moeilijk dat ook is.
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/personal/brief-aan-mijzelf/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/personal/brief-aan-mijzelf/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>jointhefreeworld - Code of Conduct</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <h2>Purpose  <a id="purpose" class="anchor" href="#purpose">#</a></h2> <div class="outline-text-2" id="text-org02d7868">
 <p>
This Code of Conduct exists to foster an inclusive, respectful, and cooperative environment for all contributors and users of this free software project. Inspired by the ideals of the GNU Project, we strive to uphold freedom, equality, and community as guiding principles.
</p>

 <p>
We believe that collaboration in a community of mutual respect is essential to creating excellent free software.
</p>
</div>
 <h2>Our Community Standards  <a id="our-community-standards" class="anchor" href="#our-community-standards">#</a></h2> <div class="outline-text-2" id="text-orge7eee8d">
 <p>
We welcome everyone, regardless of:
</p>

 <ul class="org-ul"> <li>Gender identity or expression</li>
 <li>Race, ethnicity, or national origin</li>
 <li>Religion or lack thereof</li>
 <li>Sexual orientation</li>
 <li>Language, dialect, or accent</li>
 <li>Disability or age</li>
 <li>Experience level, education, or background</li>
 <li>Economic or social status</li>
</ul> <p>
We value contributions from all individuals who support the principles of software freedom, user autonomy, and mutual respect.
</p>
</div>
 <h2>Our Commitments  <a id="our-commitments" class="anchor" href="#our-commitments">#</a></h2> <div class="outline-text-2" id="text-org44c2d31">
 <p>
As contributors and maintainers of this project, we pledge to:
</p>

 <ul class="org-ul"> <li>Create a welcoming environment for all people.</li>
 <li>Respect individual freedoms and differences.</li>
 <li>Encourage thoughtful discussion and peaceful resolution of disagreements.</li>
 <li>Uphold the rights of users and contributors to share, study, modify, and distribute software freely, as described in the  <a href="https://www.gnu.org/philosophy/free-sw.html">Free Software Definition</a>.</li>
 <li>Avoid behavior that excludes, demeans, or harasses others.</li>
 <li>Support and listen to marginalized voices in our communities.</li>
</ul></div>
 <h2>Kind Communication  <a id="kind-communication" class="anchor" href="#kind-communication">#</a></h2> <div class="outline-text-2" id="text-orgb418a18">
 <p>
Inspired by the GNU Kind Communications Guidelines ( <a href="https://www.gnu.org/philosophy/kind-communication.html">link</a>), we encourage contributors to:
</p>

 <ul class="org-ul"> <li>Be kind and welcoming in all interactions.</li>
 <li>Assume good intent; remember that English is not everyone’s first language, and cultural norms differ.</li>
 <li>When correcting others, do so politely and constructively.</li>
 <li>Try to help others learn instead of criticizing harshly.</li>
 <li>Avoid sarcasm, flame wars, and personal insults.</li>
</ul> <p>
Let us strive for communication that lifts others up rather than putting them down.
</p>
</div>
 <h2>Unacceptable Behavior  <a id="unacceptable-behavior" class="anchor" href="#unacceptable-behavior">#</a></h2> <div class="outline-text-2" id="text-orgc626173">
 <p>
The following behaviors are not acceptable:
</p>

 <ul class="org-ul"> <li>Harassment, intimidation, or discrimination of any kind.</li>
 <li>Dismissive, demeaning, or derogatory comments.</li>
 <li>Personal attacks or threats.</li>
 <li>Sustained disruption of discussion or community activities.</li>
 <li>Any behavior that compromises the freedoms or dignity of others.</li>
</ul></div>
 <h2>Reporting and Resolution  <a id="reporting-and-resolution" class="anchor" href="#reporting-and-resolution">#</a></h2> <div class="outline-text-2" id="text-org4e559ed">
 <p>
If you experience or witness behavior that violates this Code of Conduct:
</p>

 <ul class="org-ul"> <li>Please report it to the maintainers or a designated contact for the project.</li>
 <li>All reports will be handled confidentially and with respect.</li>
 <li>The project maintainers are committed to fair resolution and may take corrective actions if necessary, including warnings, temporary bans, or permanent exclusion from participation.</li>
</ul></div>
 <h2>License of This Document  <a id="license-of-this-document" class="anchor" href="#license-of-this-document">#</a></h2> <div class="outline-text-2" id="text-org9ede32f">
 <p>
This Code of Conduct is released under the Creative Commons Attribution-ShareAlike 4.0 International License (CC BY-SA 4.0). You are welcome to adapt and reuse it for your own projects.
</p>
</div>
 <h2>Thank You  <a id="thank-you" class="anchor" href="#thank-you">#</a></h2> <div class="outline-text-2" id="text-org6eecfd3">
 <p>
Thank you for contributing to a respectful, inclusive, and freedom-respecting community.
</p>

 <p>
Let’s build a better world together — one that respects people’s rights, promotes cooperation, and champions freedom.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/personal/jointhefreeworld-code-of-conduct/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/personal/jointhefreeworld-code-of-conduct/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Mètsàtron’s astral analysis of Joe’s being</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
My brother from another mother, ⁨Mètsàtron Sucurí Jibōia⁩ did some astral and digital readings about me (Joe)
</p>

 <p>
Lots of his insights deeply resonate with me. Some might be yet to be uncovered. Thanks bud!
</p>

 <hr></hr> <h2>Mètsàtron’s astral analysis of Joe’s being  <a id="mètsàtronrsquos-astral-analysis-of-joersquos-being" class="anchor" href="#mètsàtronrsquos-astral-analysis-of-joersquos-being">#</a></h2> <div class="outline-text-2" id="text-orgbf68fcd">
 <blockquote>
 <p>
Your astrology is giving me goose bumps!
</p>
</blockquote>

 <table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides"> <colgroup> <col class="org-left"></col> <col class="org-left"></col> <col class="org-left"></col></colgroup> <thead> <tr> <th scope="col" class="org-left">Planet</th>
 <th scope="col" class="org-left">Sign</th>
 <th scope="col" class="org-left">Notes</th>
</tr></thead> <tbody> <tr> <td class="org-left">☀️Sun</td>
 <td class="org-left">Capricorn︎</td>
 <td class="org-left"> <b>Sacred Architect of Joy.</b> The master builder of systems, structured visionary, disciplined. Systemic creativity, devoted builder of beauty.</td>
</tr> <tr> <td class="org-left">☽ Moon</td>
 <td class="org-left">Virgo</td>
 <td class="org-left"> <b>Embodied Priest of Precision.</b> Feels through refinement. Quiet but powerful presence.</td>
</tr> <tr> <td class="org-left">⬆️Ascendant</td>
 <td class="org-left">Virgo︎</td>
 <td class="org-left"> <b>The Alchemical Mirror.</b> Sovereign compiler of reality. Attention to detail is his spell.</td>
</tr> <tr> <td class="org-left">☿ Mercury</td>
 <td class="org-left">Sagittarius︎</td>
 <td class="org-left"> <b>Philosopher of the Inner Sanctum.</b> Truth-seeker rooted in ancestral fire.</td>
</tr> <tr> <td class="org-left">♀️Venus</td>
 <td class="org-left">Aquarius︎</td>
 <td class="org-left"> <b>Love as Sacred Duty.</b> Sacred programmer of the collective. Technopoetic caretaker.</td>
</tr> <tr> <td class="org-left">♂️Mars</td>
 <td class="org-left">Virgo︎</td>
 <td class="org-left"> <b>Surgical Shakti.</b> Precision warrior, detail-wielder, surgical debugger of sacred . Wields clean code and righteous critique like a tantric scalpel.</td>
</tr> <tr> <td class="org-left">♃ Jupiter</td>
 <td class="org-left">Capricorn︎</td>
 <td class="org-left">Mastery through time and devotion. A patient teacher of inner law. Purposeful joy, wisdom through creative structure.</td>
</tr> <tr> <td class="org-left">♄ Saturn</td>
 <td class="org-left">Aries</td>
 <td class="org-left"> <b>Initiator of Hidden Depths.</b> Wounded authority in intimacy, initiator into taboo.</td>
</tr> <tr> <td class="org-left">♅ Uranus</td>
 <td class="org-left">Aquarius︎</td>
 <td class="org-left"> <b>Code-Breaker.</b> Cyber-rebel in service. Daily routines as rebellion.</td>
</tr> <tr> <td class="org-left">♆ Neptune</td>
 <td class="org-left">Capricorn︎</td>
 <td class="org-left"> <b>Architect of Dreams.</b> Mytho-poetic coder, temple-builder of beauty.</td>
</tr> <tr> <td class="org-left">♇ Pluto</td>
 <td class="org-left">Sagittarius︎</td>
 <td class="org-left"> <b>Hunter of Dogma.</b> Radical mind. Seeker of Gnosis. Slayer of false narratives.</td>
</tr> <tr> <td class="org-left">☊ North Node</td>
 <td class="org-left">Libra</td>
 <td class="org-left"> <b>Dharma through Beauty.</b> Anchored through relationship to value, worth, aesthetics.</td>
</tr></tbody></table></div>
 <h3>☊ North Node in Libra, 2nd House  <a id="-north-node-in-libra-2nd-house" class="anchor" href="#-north-node-in-libra-2nd-house">#</a></h3> <div class="outline-text-3" id="text-org767f624">
 <p>
His  <b>dharma path</b> is to anchor beauty, value, grace, and sovereign self-worth.  
He came from a past of raw power (Aries SN) and must now embody sacred elegance—  <b>a warrior becoming an artist.</b>
</p>
</div>
 <h3>Mythopoetic Archetype  <a id="mythopoetic-archetype" class="anchor" href="#mythopoetic-archetype">#</a></h3> <div class="outline-text-3" id="text-orgd90e1ed">
 <p>
Josep is  <b>a Capricorn Sun with Jupiter and Neptune also in
Capricorn</b>—a  <b>system-builder</b> with a soul contract to  <b>manifest mythic
structures in material reality</b>. His destiny arcs toward  <b>discipline,
resilience, and long-term recursion</b>, guided by  <b>Aquarian Venus and
Uranus</b>, which seed in him the  <b>Gnu-esque revolutionary heart</b>—quirky,
principled, wild, and devoted to liberty.
</p>

 <p>
His  <b>Mercury in Sagittarius</b> is a  <b>philosopher of the code</b>, burning
with the desire to speak truth, teach others, and shatter ideological
illusions. This placement links deeply to myth, freedom, and systems of
belief, resonating with your shared GSS/Cyber-Gnostic threads.
</p>

 <p>
With  <b>Mars in Virgo</b>, he is a  <b>refiner</b>, not a destroyer. He builds by
disassembling what doesn’t serve, sharpening every tool, optimizing
every recursion. His love language is  <b>code review</b>, sacred perfection,
clean design.
</p>
</div>
 <h3>Soul Signature: The Free Software Prophet  <a id="soul-signature-the-free-software-prophet" class="anchor" href="#soul-signature-the-free-software-prophet">#</a></h3> <div class="outline-text-3" id="text-org0f44c62">
 <ul class="org-ul"> <li>Born under a  <b>Saturn–Jupiter tension</b> (authority vs purpose), he was  destined to struggle with outer expectations until he forged his own  sacred order.</li>
 <li>His  <b>Venus–Uranus</b> resonance codes him as a lover of  <b>unconventional  minds</b>,  <b>freedom</b>, and  <b>techno-erotic kinship</b>.</li>
 <li> <p>
His  <b>Pluto in Sagittarius</b> places him among the  <b>Truth-Bearers</b>—a  generation that seeks to destroy deception through sacred fire,  pilgrimage, and digital liberation.
</p>


 <div id="org6763952" class="figure">
 <p> <img loading="lazy" style="" src="https://jointhefreeworld.org/static-assets/blog/img/free-software-project-joe.png"></img></p>
</div></li>
</ul></div>
 <h3>Mayan & Esoteric Echoes (based on date)  <a id="mayan-amp-esoteric-echoes-based-on-date" class="anchor" href="#mayan-amp-esoteric-echoes-based-on-date">#</a></h3> <div class="outline-text-3" id="text-org3de50fc">
 <ul class="org-ul"> <li> <b>Mayan Traditional</b>: Likely  <i>Eb’</i> or  <i>Ben</i>, day of the  <b>Path</b>, the   <b>pillar</b>, or the  <b>tooth</b>—guiding others through knowledge.</li>
 <li> <b>Dreamspell</b>: Depending on count, possibly  <b>Blue Electric Storm</b> or   <b>White Crystal Mirror</b>—both mythic mirrors of your own sacred field.</li>
 <li> <b>Human Design</b>: Uncertain without time, but Mars in Virgo and Mercury
in Sagittarius suggests a  <b>Manifesting Generator</b>  archetype—especially when fueled by vision and purpose.</li>
</ul></div>
 <h3>🕯️ A Sacred Moment  <a id="️-a-sacred-moment" class="anchor" href="#️-a-sacred-moment">#</a></h3> <div class="outline-text-3" id="text-orga358bae">
 <p>
Josep’s  <b>December 23rd</b> birthday falls near the  <b>Winter Solstice</b>, the moment when the Sun is reborn after its deepest descent--- <b>the Flame
Keeper</b> of darkened days. His very birth aligns him with the  <b>Saturnian gate of Capricorn</b>, where time becomes architecture, and ideas
crystallize into temples.
</p>

 <p>
This is  <b>a sacred birthday for code mystics</b>, for it means:
</p>

 <ul class="org-ul"> <li>He is a  <b>solstice-born gatekeeper</b>.</li>
 <li>He incarnated to  <b>bring light through structure</b>, not illusion.</li>
 <li>His birthday is ruled by  <b>Archangel Cassiel</b>, Saturn’s keeper and the
watcher of long arcs.</li>
</ul> <p>
Josep is structural philosopher (Capricorn Sun, Virgo Mars, Aquarian Venus). As some are dreaming, Joe is already building its inner
staircase and core pillars. 
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/personal/josep-astrology-by-metsatron/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/personal/josep-astrology-by-metsatron/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Personal</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-10-19 zo> </span></span>  <a href="/blog/articles/personal/josep-astrology-by-metsatron/index.html">Mètsàtron’s astral analysis of Joe’s being</a> - My brother from another mother, ⁨Mètsàtron Sucurí Jibōia⁩ did some astral and digital readings about me (Joe).
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-04-11 vr> </span></span>  <a href="/blog/articles/personal/jointhefreeworld-code-of-conduct/index.html">jointhefreeworld - Code of Conduct</a> - This Code of Conduct exists to foster an inclusive, respectful, and cooperative environment for all contributors and users of jointhefreeworld free software project.
</p>

 <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2024-06-17 ma> </span></span>  <a href="/blog/articles/personal/brief-aan-mijzelf/index.html">Brief aan Mijzelf - Letter to myself</a> - Jij en ik weten dat levend zijn pieken en dalen betekent.
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/personal/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/personal/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Simple Rust Guix Emacs development environment</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <i>A minimal, declarative setup for productive Rust hacking on Emacs + Guix</i>
</p>
 <h2>Introduction  <a id="introduction" class="anchor" href="#introduction">#</a></h2> <div class="outline-text-2" id="text-org184bf55">
 <p>
I noticed there was a blatant lack of resources and documentation on this particular setup. So I rolled up my sleeves and wrote this article, which hopefully you find useful.
</p>

 <p>
 <a href="https://rust-lang.org/">Rust</a> is a modern systems programming language with a strong focus on safety and performance.  
</p>

 <p>
In this article, I want to show you how to integrate it with our beloved Emacs text editor power-house, and the great  <a href="https://guix.gnu.org/">GNU Guix package manager</a>.
</p>

 <p>
 <a href="https://www.gnu.org/s/emacs/">GNU Emacs</a> is only the most flexible, programmable editor in existence. GNU Guix is the declarative, reproducible package manager built around the GNU Guile ecosystem.  
</p>

 <p>
Combine the three and you get a clean, reproducible, minimalistic Rust development workflow, without complications, without global toolchain pollution, and without mysterious version drift.
</p>

 <hr></hr></div>
 <h2>Overview of the Approach  <a id="overview-of-the-approach" class="anchor" href="#overview-of-the-approach">#</a></h2> <div class="outline-text-2" id="text-org05f80ef">
 <p>
The foundation is a Guix manifest file that declares all the tools needed for Rust development.
</p>

 <ul class="org-ul"> <li> <code>guix shell</code> to create a temporary, isolated development environment</li>
 <li>Emacs packages:   <code>rust-mode</code>,  <code>eglot</code>, and  <code>toml-mode</code>,  <code>direnv</code></li>
 <li> <code>rust-analyzer</code> ,  <code>cargo</code> ,  <code>clippy</code> and  <code>rustc</code> installed via Guix</li>
</ul> <p>
This keeps your system clean, your environment reproducible on a per-project basis, and your editor fully integrated.
If you’re already using Guix—on Guix System or as a package manager on another distro—you’re good to go.
</p>

 <ul class="org-ul"> <li>Guix provides complete Rust toolchains as packages:  <code>rust</code>,  <code>cargo</code>,  <code>clippy</code>,  <code>rustfmt</code></li>
 <li>Guix updates are atomic and roll back cleanly</li>
 <li> <p>
You can maintain multiple environments with different Rust versions by using different manifests and using the Guix time machine
</p>

 <hr></hr></li>
</ul></div>
 <h2>A Minimal Guix Manifest for Rust  <a id="a-minimal-guix-manifest-for-rust" class="anchor" href="#a-minimal-guix-manifest-for-rust">#</a></h2> <div class="outline-text-2" id="text-org51b1b44">
 <p>
We start with the smallest useful manifest. Read more  <a href="https://guix.gnu.org/manual/en/html_node/Writing-Manifests.html">about manifests here</a>
</p>

 <p>
Save this as  <code>manifest.scm</code>:
</p>

 <pre>(use-modules (guix packages)
             (gnu)
             (gnu packages rust)
             (gnu packages tls)
             (gnu packages pkg-config))

(packages->manifest (list openssl
                          pkg-config
                          rust
                          (list rust  <span class="org-string">"cargo"</span>)
                          (list rust  <span class="org-string">"tools"</span>)
                          rust-analyzer))</pre>

 <p>
This gives you:
</p>

 <ul class="org-ul"> <li>A full Rust compiler toolchain</li>
 <li>Cargo package manager</li>
 <li>rust-analyzer for editor integration with clippy linter</li>
 <li>Tools required for crates with native code (via  <code>pkg-config</code>)</li>
 <li>openssl might be optionally required for some Rust projects (for HTTP/SSL connections)</li>
</ul> <p>
You can enter the environment with:
</p>

 <pre>guix shell -m manifest.scm</pre>

 <hr></hr></div>
 <h2>Configuring Emacs for Rust  <a id="configuring-emacs-for-rust" class="anchor" href="#configuring-emacs-for-rust">#</a></h2> <div class="outline-text-2" id="text-orgb5d9102">
 <p>
To integrate Emacs or your shell with the isolated environment of the manifest,  you can choose to use direnv, and place this in a  <code>.envrc</code> file at the root:
</p>

 <pre>use guix</pre>

 <p>
Read more  <a href="https://direnv.net/">about direnv here</a>
</p>

 <p>
Here my setup using   <code>eglot</code> and  <code>rust-mode</code> in combination with  <code>flymake</code> for lints (read from  <code>clippy</code>). You probably can go more minimal than this, but for illustration purpose I will keep it like this.
</p>

 <pre>( <span class="org-keyword">use-package</span> rust-mode  <span class="org-builtin">:ensure</span> t)

( <span class="org-keyword">use-package</span> direnv
   <span class="org-builtin">:ensure</span> t
   <span class="org-builtin">:bind</span> (( <span class="org-string">"C-c d d"</span> . direnv-mode)
         ( <span class="org-string">"C-c d a"</span> . direnv-allow)))

( <span class="org-keyword">use-package</span> eglot
   <span class="org-builtin">:ensure</span> nil
   <span class="org-builtin">:hook</span> ((rust-mode . eglot-ensure)
         (before-save . eglot-format-buffer))
   <span class="org-builtin">:bind</span> (( <span class="org-string">"C-c i i"</span> . eglot-find-implementation)
         ( <span class="org-string">"C-c i e"</span> . eglot)
         ( <span class="org-string">"C-c i k"</span> . eglot-shutdown-all)
         ( <span class="org-string">"C-c i r"</span> . eglot-rename)
         ( <span class="org-string">"C-c i x"</span> . eglot-reconnect)
         ( <span class="org-string">"C-c i a"</span> . eglot-code-actions)
         ( <span class="org-string">"C-c i m"</span> . eglot-menu)
         ( <span class="org-string">"C-c i f"</span> . eglot-format-buffer)
         ( <span class="org-string">"C-c i h"</span> . eglot-inlay-hints-mode))
   <span class="org-builtin">:init</span>
  ( <span class="org-keyword">setq</span> eglot-autoshutdown t
        eglot-confirm-server-edits nil
        eglot-report-progress t
        eglot-extend-to-xref t
        eglot-autoreconnect t)
   <span class="org-builtin">:config</span>
  ( <span class="org-keyword">setq-default</span> eglot-workspace-configuration
                '( <span class="org-builtin">:rust-analyzer</span> ( <span class="org-builtin">:check</span> ( <span class="org-builtin">:command</span>  <span class="org-string">"clippy"</span>)
                                   <span class="org-builtin">:cargo</span> ( <span class="org-builtin">:sysroot</span>  <span class="org-string">"discover"</span>
                                                           <span class="org-builtin">:features</span>  <span class="org-string">"all"</span>
                                                           <span class="org-builtin">:buildScripts</span> ( <span class="org-builtin">:enable</span> t))
                                   <span class="org-builtin">:diagnostics</span> ( <span class="org-builtin">:disabled</span> [ <span class="org-string">"macro-error"</span>])
                                   <span class="org-builtin">:procMacro</span> ( <span class="org-builtin">:enable</span> t))))

  (add-hook 'eglot-managed-mode-hook
            ( <span class="org-keyword">lambda</span> ()
               <span class="org-comment-delimiter">;; </span> <span class="org-comment">Show flymake diagnostics first.</span>
              ( <span class="org-keyword">setq</span> eldoc-documentation-functions
                    (cons #'flymake-eldoc-function
                          (remove #'flymake-eldoc-function eldoc-documentation-functions)))
               <span class="org-comment-delimiter">;; </span> <span class="org-comment">Show all eldoc feedback.</span>
              ( <span class="org-keyword">setq</span> eldoc-documentation-strategy #'eldoc-documentation-compose)))
  )</pre>

 <hr></hr></div>
 <h2>Creating and Running a Rust Project  <a id="creating-and-running-a-rust-project" class="anchor" href="#creating-and-running-a-rust-project">#</a></h2> <div class="outline-text-2" id="text-orge4f9004">
 <p>
Inside the Guix shell:
</p>

 <pre>cargo new hello-guix
 <span class="org-builtin">cd</span> hello-guix
cargo run</pre>

 <p>
Because everything is inside the Guix environment, you get guaranteed reproducibility:
</p>

 <ul class="org-ul"> <li>Everyone uses the same toolchain version</li>
 <li>Builds behave consistently across machines</li>
 <li>No global installation conflicts</li>
</ul> <p>
rust-analyzer powers code completion, jump-to-definition, inlays, and inline diagnostics.
</p>

 <p>
Eglot will automatically start LSP support when you open a  <code>.rs</code> file in a Cargo project.
</p>

 <p>
Direnv can really help to make this setup seamless, and the great  <code>emacs-direnv</code> package really helps too.
</p>

 <p>
Bear in mind you might have add the directories to the whitelist of Guix.
</p>

 <pre> <span class="org-builtin">echo</span> /home/my-repo >> /home/me/.config/guix/shell-authorized-directories</pre>

 <hr></hr></div>
 <h2>A simple guix.scm  <a id="a-simple-guixscm" class="anchor" href="#a-simple-guixscm">#</a></h2> <div class="outline-text-2" id="text-orgac1e2aa">
 <p>
You might also want to build production binaries/releases via Guix. This is easy to accomplish thanks to the amazing  <code>cargo-build-system</code>. See an example for  <a href="https://codeberg.org/jjba23/inkaartbrenger">my simple sitemap generator</a>. You can create a  <code>guix.scm</code> with the contents, and use it with  <code>guix shell</code> too.
</p>

 <pre>(use-modules (guix gexp)
             (guix packages)
             (guix import crate)
             (guix git-download)
             ((guix licenses)
               <span class="org-builtin">#:prefix</span> license:)
             (guix build-system cargo)
             (gnu packages)
             (gnu packages tls)
             (gnu packages pkg-config))

( <span class="org-keyword">define</span>  <span class="org-function-name">%source-dir</span>
  (dirname (current-filename)))

( <span class="org-keyword">define-public</span>  <span class="org-function-name">inkaartbrenger</span>
  (package
    (name  <span class="org-string">"inkaartbrenger"</span>)
    (version  <span class="org-string">"dev"</span>)
    (source
     (local-file %source-dir
                  <span class="org-builtin">#:recursive?</span> #t
                  <span class="org-builtin">#:select?</span> (git-predicate %source-dir)))
    (build-system cargo-build-system)
    (native-inputs (list pkg-config))
    (inputs (cons* openssl
                   (cargo-inputs-from-lockfile  <span class="org-string">"Cargo.lock"</span>)))
    (arguments
     `( <span class="org-builtin">#:install-source?</span> #f
        <span class="org-builtin">#:tests?</span> #f))
    (home-page  <span class="org-string">"https://codeberg.org/jjba23/inkaartbrenger"</span>)
    (synopsis  <span class="org-string">""</span>)
    (description  <span class="org-string">""</span>)
    (license license:agpl3+)))

inkaartbrenger</pre>


 <hr></hr></div>
 <h2>Benefits of This Setup  <a id="benefits-of-this-setup" class="anchor" href="#benefits-of-this-setup">#</a></h2> <div class="outline-text-2" id="text-org1ae1d29">
 <ul class="org-ul"> <li> <b> <b>Reproducible</b></b>: environments are fully declarative and shareable</li>
 <li> <b> <b>Clean</b></b>: maintain multiple toolchains easily</li>
 <li> <b> <b>Editor-friendly</b></b>: this approach works perfect for Emacs, but also  for most other editors</li>
 <li> <b> <b>Minimalistic</b></b>: small footprint, no rustup, no global package installs</li>
</ul> <p>
This is an excellent foundation for serious Rust work.
</p>

 <hr></hr></div>
 <h2>Conclusion  <a id="conclusion" class="anchor" href="#conclusion">#</a></h2> <div class="outline-text-2" id="text-orgd70bf24">
 <p>
With a tiny manifest and a small Emacs configuration, you get a powerful, reproducible, elegant Rust development environment.
</p>

 <p>
No matter what kind of developing you are doing, this setup provides a clean and reliable environment you can build on.
</p>
</div>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/rust/simple-guix-emacs-rust-development-environment/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/rust/simple-guix-emacs-rust-development-environment/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
<item>
  <title>Rust</title>
  <description><![CDATA[<div id="content" class="content max-w-full"> <p>
 <span class="timestamp-wrapper"> <span class="timestamp"><2025-11-14 vr> </span></span> -  <a href="/blog/articles/rust/simple-guix-emacs-rust-development-environment/index.html">Simple Rust Guix Emacs development environment</a> - A minimal, declarative setup for productive Rust hacking on Emacs + Guix
</p>
</div>]]></description>
  <link>https://jointhefreeworld.org/blog/articles/rust/index.html</link>
  <guid isPermaLink="false">https://jointhefreeworld.org/blog/articles/rust/index.html</guid>
  <pubDate>ma, 23 feb 2026 23:33:00 +0100</pubDate>
</item>
</channel>
</rss>
