GeistHaus
log in · sign up

https://fabiendubosson.com/index.xml

rss
9 posts
Polling state
Status active
Last polled May 18, 2026 22:19 UTC
Next poll May 20, 2026 00:55 UTC
Poll interval 86400s
ETag W/"6981848c-4507a"
Last-Modified Tue, 03 Feb 2026 05:15:56 GMT

Posts

And you, do you see retirement as a goal, or as a deadline?

Two of my passions are outdoor adventures and ecology, and thankfully we have more and more people making films about such adventures. Yesterday, I watched Alpine Quest: “From Vienna to Monaco: A Women’s Alpine Challenge”. Three women traversed the alps from Vienna to Monaco by combining cycling, ski mountaineering and trail running. 54 days, 1’600 km, 67’000 m of elevation gain. It is quite an impressive feat, the kind of adventure you want to go make for yourself 1.

I started imagining myself in this adventure, considering if I would be able to finish such an expedition. The biking and trail running parts, probably, and the ski mountaineering part, maybe within my reach with a mountain guide. So when one of the women, Loubna, mentioned she was 57 years old, I started calculating the number of years I could have left to envision such an adventure: at least 20 years or so, provided I keep a good fitness level.

But my thoughts did not stop there. What about in 30 years? Would I still be able to aim for such a challenge? In Switzerland, the legal retirement age is 65, and with the current social context it will likely be 67 when I retire. So I have 30 years left before retirement, give or take. Would I still be able to do this when I retire? Nobody knows, but it’s certainly much less likely than when I’m 57. There is a limit to how old you can be to tackle such crazy adventures.

I’m already considering myself lucky enough to have realized in my mid-thirties that, to achieve some of my trail running dreams, I needed to be in good health and have a certain level of fitness, and those are not guaranteed forever. This came to mind while discussing with people older than me, who told me they can’t run anymore because of some health condition, usually knee or ankle problems. I understood that to achieve some of my running dreams, like completing a mountain ultramarathon, I should start doing them as soon as possible, while I still can.

Today, I went one step further. While reflecting on yesterday’s thoughts, I noticed that it was not the first time I was counting down the years until retirement. We all went through discussions with friends during our early twenties that go like this: “Oh man, still 45 years left before I retire.” But this time, the counting was different. I counted the years down not towards a goal, but towards a deadline.

Retirement is often seen as a life goal, the moment when you stop working and start enjoying the good life. But now I’m starting to see retirement as a deadline, and I’m even more motivated to squeeze in as many adventures as possible before it. It makes it much less fun to think about retirement, but I’m sure I’ll have a richer life.

And you, do you see retirement as a goal, or as a deadline?


  1. Ok, maybe not, but at least I do ;) ↩︎

https://fabiendubosson.com/blog/and-you-do-you-see-retriement-as-a-goal-or-as-a-dealdine/
Morrowind Moments: Taking a Holiday to Level Up in Real Life

I don’t know about you, but I always feel different when coming back to work after the end-of-year holidays. Not just rested, but also with a different mindset. One year ago, I told my engineering manager that I needed rest to level up, like in the game Morrowind. Seeing his face made me realize that The Elder Scrolls III: Morrowind may not be such a well-known reference as I thought1.

In tech, we spend most of the year with our heads down, focusing on execution. Doing so, we are constantly learning and accumulating experiences. We develop new skills, like sharper prioritization, clearer communication, or better technical judgment. We take on new responsibilities and build more context. But we rarely take the time to stop and synthesize what we have learned. We are busy progressing, but not clearly “leveling up”.

That’s where I made the connection with Morrowind. When starting a new adventure in Morrowind, you choose a character that has some initial characteristics, like the screenshot2 below:

Screenshot of Morrowind's character menu
Your Morrowind character attributes and skills

If it looks complex, rest assured we don’t need to dive into the full mechanics of the game. Instead, let’s focus on the “Level” of our character. The way it increases is by doing actions in the game, like moving, fighting, or even reading books. Those actions develop skills, which in turn contribute to leveling up.

Once you have developed enough skills, you are ready to move to the next level. The screenshot below is an example of such progress:

Screenshot of Morrowind's tracking skills progress
Morrowind tracks developed skills

The level-up isn’t triggered by actions; rest triggers it. Once you’re ready, the game tells you, “You should rest and meditate on what you’ve learned.”

Screenshot of Morrowind's popup suggesting to level-up
Morrowind suggests resting to level up

And once you do so, the level-up screen wakes your character up and lets you pick three attributes you want to develop.

Screenshot of Morrowind's level-up menu
Morrowind level-up screen

I believe there is a direct parallel with real life. When we have our heads down, focusing on execution, we develop skills. But those don’t really compound together until we take time to rest and level up.

While in Morrowind taking a nap is enough to trigger a level up, in real life we need holidays. Longer breaks create the space to let things settle down. And the magic is that it does not require a formal process nor a structured retrospective. Letting our brains wander naturally and connect the dots subconsciously is often enough.

We assimilate what happened during the year, how challenges were handled, what we learned, and everything else we went through. The level-up happens almost accidentally.

The way it materializes for me is that I come back from holidays with a clearer understanding of my role, a better perspective on responsibilities, and more confidence and calm. This is often the moment when I also realize any increase in influence or leadership.

Leveling up doesn’t always require effort; sometimes all we need is a holiday.


  1. Even though people are still actively developing and maintaining a modern engine to play the game 24 years after its release. ↩︎

  2. Did I reinstall the game to make the screenshots? Yes. Did I do it for the blog post or for the nostalgia? Both ;) ↩︎

https://fabiendubosson.com/blog/morrowind-moments-taking-a-holiday-to-level-up-in-real-life/
Secure AWS Access Keys on Your Laptop
Introduction

Whenever I have to store an AWS access key on my machine, I’m always concerned about setting it up in clear text in my home folder. Even though I have LUKS encryption protecting my filesystem when the laptop is off, it is most of the time either running or suspended, which means the filesystem is accessible.

If my laptop is stolen while suspended, there is a small chance that an attacker would figure out a way to access the data. Such a scenario is more likely to come from a targeted attack though, as a simple theft would result in someone formatting the laptop and selling it for the hardware money. And as we all know there are much simpler ways to do targeted attacks anyway. So I’m going to ignore this threat model in this article.

I’m more concerned about all the time my laptop is running. With AWS credentials stored in clear text and in a known location (~/.aws/credentials), most processes can easily read them, which means a vulnerability in any single piece of code running on my machine can compromise those keys. This opens a much larger surface for opportunistic attacks, such as we have seen recently with Shai-Hulud.

While storing AWS access keys GPG encrypted is not a bulletproof solution to all security risks, it is nonetheless a welcome additional layer of security. This can be the difference between being the victim of an opportunistic attack or not. It protects the credentials at rest; once they are decrypted, any process that can read them can still misuse them.

In this post, I’ll guide you through a low-friction way to store your access keys encrypted. The method uses GPG for credentials encryption, the credential_process AWS configuration, and a bash script to act as a wrapper between the two.

AWS-recommended solutions

Before we get started, please note that AWS is encouraging alternatives to access keys for the command line interface (CLI) and other use cases. If you can follow the suggested approaches, you should likely go with those.

Screenshot of AWS CLI recommendation
Recommended alternatives to access keys for CLI

There are, however, situations where you don’t have a choice, and you have to resort to using access keys. In such cases, the AWS wizard recommends never storing credentials in plain text:

Screenshot of AWS CLI recommendation
AWS recommendations regarding access keys

I haven’t heard yet about an official way to store access keys encrypted, at least not on Linux. It’s of course possible to script your way through, but that usually adds extra friction in the process: running extra commands before usage, remembering to clean up after usage, etc. In the past I’ve used aws-vault for this, but the project looks abandoned now.

This article is for such cases, where:

  • you have to use access keys;
  • you want to store them encrypted; and
  • you want to keep the process low-friction.

If that’s what you need, please keep reading!

Encrypting your AWS access keys

Let’s start with a simple setup to build a mental model of how it works. Later we will extend it to more advanced use cases, but the building blocks will stay the same.

The high-level process is the following:

  1. Put the credentials in a GPG-encrypted file
  2. Create a wrapper script that decrypts the file and returns it in the right format
  3. Configure AWS to use this wrapper script to obtain credentials

This blog post assumes you already use GPG. If that’s not the case, you can find tutorials online, like for instance this blog post from Red Hat.

If you don’t want to use GPG, the approach presented in this blog post can easily be adapted to use other tools that manage credentials, such as the OS keyring or an external service like Bitwarden.

1. Put the credentials in a GPG-encrypted file

We start by putting the credentials in a GPG-encrypted file.

AWS_ACCESS_KEY_ID="..."
AWS_SECRET_ACCESS_KEY="..."

Personally, I have placed this in .aws/credentials.gpg. This is not a special file, and it is not supported by AWS. But if we are not going to have a .aws/credentials file, placing it there makes it discoverable and easy to understand that credentials are stored there, but GPG encrypted.

Don’t forget to get rid of the .aws/credentials file once your new setup is finalized, there is no point in storing your credentials encrypted if they are still available in the clear somewhere else. Also ensure the encrypted file is not world-readable (for example, chmod 600 ~/.aws/credentials.gpg).

2. Create a wrapper script

The script has two purposes:

  1. Decrypting the credentials from the file
  2. Formatting them in the way that AWS expects

The AWS setting we will use in the next step expects the credentials in the following format:

{
 "Version": 1,
 "AccessKeyId": "...",
 "SecretAccessKey": "...",
 "SessionToken": null,
 "Expiration": null
}

Don’t worry about the session token and expiration fields for now, the only parts that are required for long-lived credentials are the access key ID and the secret access key.

Here is a basic script that would get the credentials from the GPG-encrypted file and return them in the expected format as follows:

#!/usr/bin/env bash

set -euo pipefail

# Decrypt the credentials and load them
source <(gpg --quiet --decrypt ~/.aws/credentials.gpg)

# Output in the expected format
cat <<EOF
{
 "Version": 1,
 "AccessKeyId": "$AWS_ACCESS_KEY_ID",
 "SecretAccessKey": "$AWS_SECRET_ACCESS_KEY",
 "SessionToken": null,
 "Expiration": null
}
EOF

You can place it wherever you like. I personally use ~/.local/bin/aws-decrypt-credentials.sh, simply because ~/.local/bin is already in my PATH so I can refer to the script name and not the full path in my AWS config later on. Make the script executable and restrict it, for example with chmod 700 ~/.local/bin/aws-decrypt-credentials.sh.

Note that this script uses source <(gpg ...), which executes whatever is in the decrypted file. This is fine if the GPG-encrypted file is trusted and only created by you, but it’s another reason to keep it locked down.

3. Configure AWS

The last step is to configure AWS to use the decryption script we just made. This is done by defining a credential_process and pointing it to the wrapper script. Add this to your ~/.aws/config, either to the [default] section if you have only one config, or to specific profiles if that’s how you have it configured.

[default]
credential_process = aws-decrypt-credentials.sh

If the script is not in the PATH, you need to provide the full path instead (e.g. /home/fabien/.local/bin/aws-decrypt-credentials.sh).

That’s all.

Testing it

You can run the following command to test if the whole process is working:

$ # Don't forget to set an AWS_PROFILE if you configured it in a specific profile
$ # export AWS_PROFILE=...
$ aws sts get-caller-identity
{
 "UserId": "AIDA01234567890123456",
 "Account": "012345678901",
 "Arn": "arn:aws:iam::012345678901:user/fabien.dubosson"
}

Note that if you have set up the credential_process in a specific profile, don’t forget to set it first (i.e. with export AWS_PROFILE="...").

If needed, you can debug the script by executing it manually, so that you can see any error messages.

Going further

This setup works well for a simple use case with just one set of credentials, but this system can be adapted to support advanced use cases:

  • Using something other than GPG to secure the credentials
  • Dealing with multiple access keys
  • Using temporary session credentials
Using something other than GPG to secure the credentials

If you don’t want to use GPG, you can easily swap it for another way to secure the credentials (e.g. your OS keyring, pass, Bitwarden CLI, etc) by changing this line to retrieve and parse the credentials:

source <(gpg --quiet --decrypt ~/.aws/credentials.gpg)
Dealing with multiple access keys

The credential_process supports commands with arguments, so an easy way to handle multiple keys is to split them into different GPG-encrypted files, and specify the name of the file as parameter of the script in the AWS configuration file.

For instance, I can create a GPG-encrypted file .aws/fabien.dubosson.gpg with my personal credentials, and configure my personal profile to decrypt this file:

[fabien.dubosson]
credential_process = aws-decrypt-credentials.sh fabien.dubosson

This requires changing the script to take the filename as parameter. For that you need to change the following gpg line in the script above:

- source <(gpg --quiet --decrypt ~/.aws/credentials.gpg)
+ source <(gpg --quiet --decrypt ~/.aws/${1}.gpg)

Then setting up additional access keys gets simple:

  • Create a new encrypted file containing the new access key
  • Reference this new file in the credential_process of the relevant profile
[work.account]
# Filename: ~/.aws/work.account.gpg
credential_process = aws-decrypt-credentials.sh work.account

[personal.account]
# Filename: ~/.aws/personal.account.gpg
credential_process = aws-decrypt-credentials.sh personal.account
Using temporary session credentials

Instead of just returning the long-lived credentials stored in the GPG-encrypted file, your script can use them to obtain and return temporary session credentials. This can be done by modifying the wrapper script as follows:

#!/usr/bin/env bash

set -euo pipefail

# Decrypt the long-lived credentials and load them
source <(gpg --quiet --decrypt ~/.aws/${1}.gpg)

# Use the long-lived credentials to request temporary session credentials
creds_json="$(
 env -i \
 AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" \
 AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" \
 aws sts get-session-token --duration-seconds 3600 --output json)"

# Extract the temporary credentials
TMP_ACCESS_KEY_ID="$(jq -r '.Credentials.AccessKeyId' <<<"$creds_json")"
TMP_SECRET_ACCESS_KEY="$(jq -r '.Credentials.SecretAccessKey' <<<"$creds_json")"
TMP_SESSION_TOKEN="$(jq -r '.Credentials.SessionToken' <<<"$creds_json")"
TMP_EXPIRATION="$(jq -r '.Credentials.Expiration' <<<"$creds_json")"

# Output the temporary credentials in the expected format
cat <<EOF
{
 "Version": 1,
 "AccessKeyId": "$TMP_ACCESS_KEY_ID",
 "SecretAccessKey": "$TMP_SECRET_ACCESS_KEY",
 "SessionToken": "$TMP_SESSION_TOKEN",
 "Expiration": "$TMP_EXPIRATION"
}
EOF

There is an additional dependency needed, jq, to parse the JSON answer obtained from the call to get-session-token.

With this approach, the long-lived AWS credentials are never shared outside of the script. All software that interacts with AWS or the script to obtain credentials will only get temporary session credentials. If those get compromised, they are only valid for the duration specified on the call to get-session-token in the script, 1 hour in the example above.

Note that this version of the script expects the base name of the GPG-encrypted file as a parameter, as configured in the previous section.

Limitations

While this setup works great, I have observed some limitations, which I describe below.

GPG decryption and security

An obvious issue with this setup is that you either have to enter the GPG password every time a script or tool requests AWS credentials, which can be surprisingly often, or to use gpg-agent, but then any software running on your machine could steal the credentials once the agent has cached the decrypted key.

To overcome this problem, I’m using a YubiKey-based GPG setup:

  • The GPG private key is only stored on my YubiKey.
  • The YubiKey is configured to allow for 5 password tries before locking completely.
  • I’m using the GPG agent to avoid typing the password all the time.
  • I configured the YubiKey to require a touch for each GPG operation.

This results in a quite safe GPG setup: my private key can’t be extracted as it resides in the YubiKey, access can’t be brute-forced as it’s limited to 5 password tries, and the touch-to-operate acts as a two-factor mechanism, requiring me to do a physical action before the key does any GPG operation.

The first time I need to authenticate with AWS, the GPG agent asks for my YubiKey password, then I have to physically touch the YubiKey to allow the GPG decryption of the AWS credentials. Then all subsequent AWS credential requests only require me to touch the YubiKey.

If you use the same setup as me, you can use yubikey-touch-detector to set up a visual indicator when your YubiKey is asking for a touch. Applications support

This setup works great with applications using the AWS CLI or AWS SDK, but not with applications that parse the configuration or read credentials by themselves.

Thankfully, there is a simple solution to this problem, which at the same time solves the problem of having to enter the GPG decryption password each time the credentials are needed. The solution is to export the credentials as environment variables in the current terminal session:

eval "$(aws configure export-credentials --format env)"

This command, available in AWS CLI v2, works nicely with the script that generates session credentials, as those are temporary and expire after a certain time anyway. This is not recommended when using long-lived credentials, as that would expose them to all commands that you will launch from the terminal session.

Limited session duration with some specific setup

I observed a limitation in a quite specific configuration:

  • When using the version of the script that delivers temporary session credentials; and
  • Using a session duration longer than one hour (i.e. a duration_seconds greater than 3600); and
  • Assuming a role with role_arn and source_profile; and
  • The role_arn points to another AWS account.
An error occurred (ValidationError) when calling the AssumeRole operation: The
requested DurationSeconds exceeds the 1 hour session limit for roles assumed by
role chaining.

My research led me to this documentation page, which states that source_profile uses sts:AssumeRole behind the scenes. This would explain why assuming a role_arn right after is considered role chaining.

This is a quite specific setup, but I cannot exclude that you will find some other weird cases like this if you experiment with this method. A practical workaround is to lower the session duration to one hour or avoid role chaining in that flow. Overall it is not a big limitation, but more of an annoyance to be aware of.

https://fabiendubosson.com/blog/secure-aws-access-keys-on-your-laptop/
The Eleven Laws of Showrunning

While reading a discussion on HN, I noticed a comment mentioning “The Eleven Laws of Showrunning.” Following through the links leads to a typewriter-style essay in PDF form, written in 2016 by Javier Grillo-Marxuach1.

The essay is about showrunners, more specifically, writers and producers of television shows. It’s a bit surprising to see it referenced in an HN discussion on software engineering, but it’s late here, and I don’t have the energy to read 25 pages about running a television show to find out if there’s anything interesting in there.

Out of curiosity, I asked ChatGPT to summarize the article, and after reading the summary, I understand why it can be cited in a software development context: it’s about good leadership, something that applies well beyond television production. Of course, not all the laws apply verbatim in a software engineering context. But this interestingly forces some reflection on how they map to managing your own software projects.

Sharing the summary here in the hope that it might inspire some reflection for you as well.

Core Premise

The author argues that being a showrunner is both a creative and managerial role. To succeed, one must subordinate ego, communicate vision clearly, make decisions, and manage people wisely. The eleven laws are guidelines to help a showrunner lead a television show efficiently, humanely, and with integrity.

The Eleven Laws (Key Ideas)
  1. It’s All About You — Stop Making It All About You > As the showrunner, your name is tied to the show. Use that power to empower your team, but don’t make everything about your ego.

  2. Know Your Show and Tell Everyone What It Is > You must have a clear vision (tone, style, theme) and constantly communicate it to your team, so everyone aligns toward the same goal.

  3. Always Describe a Path to Success > At the end of any meeting, people should know what’s next — what deliverables are expected and by when.

  4. Make Decisions Early and Often > Indecision drains momentum. Commit quickly, explain your reasoning, then move forward — rather than letting ambiguity slow everything down.

  5. Do Not Demand a Final Product at the Idea Stage > Don’t expect fully polished output right from the start. Ideas need development, iteration, and feedback. Let your writers develop the story before pushing for perfection.

  6. Write and Rewrite Quickly > Scripts are the core artifact. Fast drafts and edits help the entire production chain stay in sync and avoid bottlenecks or uncertainty.

  7. Track Multiple Targets Efficiently by Delegating Responsibility > There are many parallel tracks (writing, production, post, editing, etc.). You can’t micromanage all of them. Delegate to trusted lieutenants (senior writers, producers) who can act as extensions of your vision.

  8. Resist the Siren Call of the “Sexy, Glamorous Jobs” > It’s tempting to intervene in departments like costumes, set design, casting, or editing — but doing so can steal time from the bigger job: overseeing story, writers, and the whole show’s cohesion.

  9. Expect Your Staff to Perform at Varying Levels of Competence > Writers and staff will differ in experience and quality. Mentor them, give feedback tailored to where they are, but don’t expect everyone to deliver at your level from the get-go.

  10. Deliver Good and Bad News Early and Often > Secrets, delays, and surprises corrode trust. Be transparent (especially when things go wrong) — it’s better that people hear it from you than via rumors.

  11. Share Credit for Success to a Fault > Your name is already prominent; giving credit to your team builds loyalty, morale, and a healthier working culture. It also enhances your reputation as a leader.

Additional Observations & Philosophy
  • Grillo-Marxuach cautions against the romantic notion of the “tortured genius” showrunner. He insists that professionalism, structure, and respect for collaborators should not be sacrificed for artistic mythos.

  • He emphasizes that many dysfunctions stem from ego, fear of appearing weak, or insecurity. Admitting mistakes, owning up to them, and being transparent often strengthen leadership rather than weaken it.

  • The author frames the showrunner’s job as analogous to that of managing a startup or production company. You need to keep financial, scheduling, and human variables in balance.

  • Throughout, he encourages humility: your show is bigger than any single person, and the right balance of control plus delegation is what sustains success over a season (or more).


  1. I had never heard his name, but if you are also wondering, he is the writer-producer of episodes of Charmed and Lost, among others. ↩︎

https://fabiendubosson.com/blog/the-eleven-laws-of-showrunning/
Fixing My Linux Webcam to Look Alive in Meetings

If there is one change that Linux users fear the most, it’s switching to a brand new laptop. Even though hardware support is much better than when I first started 25 years ago, it is still a gamble to know if you picked one that will get all functionalities supported.

If you ever tried installing Linux on a Pentium 4 with a blurry CRT, you’ll remember the joy and pain of hardware compatibility (and maybe Compiz cubes). Some things haven’t changed.

Nowadays, the main hardware troubles on Linux come from the webcam. New generation laptops come with MIPI webcams for which Linux support is lacking, to say the least. Fully aware of this fact, I managed to order a laptop that has a good old USB webcam that has a better chance of being supported on Linux — it’s more challenging than it sounds. For the curious out there, it’s a Lenovo ThinkPad X1 Carbon Gen 13, but be warned, it is sold with both types of cameras.

After several evenings and weekend days installing and configuring Linux (sounds like a lot? May I introduce you to Arch Linux?) I finally got to the webcam test 🥁 … and it worked!

Laptop's webcam on automatic white balance
Image of the webcam with default settings, including automatic white balance

When I’m in meetings, I usually use the background seen above. The webcam worked, but I look rather pale in this picture. Not super pleasant for others, and not radiating a positive image. Webcam support is there, but it’s not the out-of-the-box MacOS experience, for sure. That’s the advantage when you control both the software and the hardware.

The downside of Linux is also one of its strengths: hackability. A few messages to ChatGPT later, I found out the command that shows the camera settings:

$ v4l2-ctl --list-ctrls
User Controls
brightness 0x00980900 (int) : min=0 max=255 step=1 default=128 value=128 flags=has-min-max
contrast 0x00980901 (int) : min=0 max=100 step=1 default=32 value=32 flags=has-min-max
saturation 0x00980902 (int) : min=0 max=100 step=1 default=64 value=64 flags=has-min-max
hue 0x00980903 (int) : min=-180 max=180 step=1 default=0 value=0 flags=has-min-max
white_balance_automatic 0x0098090c (bool) : default=1 value=1
gamma 0x00980910 (int) : min=90 max=150 step=1 default=120 value=120 flags=has-min-max
power_line_frequency 0x00980918 (menu) : min=0 max=2 default=1 value=1 (50 Hz)
white_balance_temperature 0x0098091a (int) : min=2800 max=6500 step=10 default=4600 value=4600 flags=inactive, has-min-max
sharpness 0x0098091b (int) : min=0 max=7 step=1 default=3 value=3 flags=has-min-max
backlight_compensation 0x0098091c (int) : min=0 max=2 step=1 default=1 value=1 flags=has-min-max
region_of_interest_rectangle 0x00981ae1 (rect) : value=(0,0)/1x1 flags=has-payload, has-min-max
region_of_interest_auto_ctrls 0x00981ae2 (bitmask): max=0x00000001 default=0x00000001 value=0 flags=has-min-max
Camera Controls
auto_exposure 0x009a0901 (menu) : min=0 max=3 default=3 value=3 (Aperture Priority Mode)
exposure_time_absolute 0x009a0902 (int) : min=2 max=1250 step=1 default=156 value=156 flags=inactive, has-min-max
exposure_dynamic_framerate 0x009a0903 (bool) : default=0 value=1
privacy 0x009a0910 (bool) : default=0 value=0 flags=read-only

This may look intimidating at first, but brightness, contrast, saturation, hue, white balance temperature, sharpness… that’s all familiar from photo editing! So I started by disabling automatic white balance — which, on this hardware at least, seems to make things worse — and began playing around with other parameters.

I spent a while tweaking brightness, contrast, and white balance settings, running dozens of variations until I hit something that I liked. Those numbers ended up in a script that runs at startup to set up the webcam, so I can finally look like a living human:

i_am_a_living_creature_fix_the_webcam___please() {
 v4l2-ctl -c brightness=97
 v4l2-ctl -c contrast=29
 v4l2-ctl -c saturation=64
 v4l2-ctl -c white_balance_automatic=0
 v4l2-ctl -c white_balance_temperature=4100
 v4l2-ctl -c sharpness=7
 echo "Applied favorite webcam configuration."
}

We probably won’t all agree on the best configuration, but I think we can all agree that this version looks much better than the default one:

Laptop's webcam with custom settings
Image of the webcam after fine-tuning webcam settings manually

Let me know you have any suggestions to improve my appearance. And no, shaving the beard is not an option 😜

Update 2025-08-15: A colleague pointed out that automatic white balance is often unreliable in wooden environments, such as mountain cabins, which was my setting when writing this article. The automatic white balance works much better in typical home or office settings. That said, the solutions described above remain useful when working in wooden spaces.
https://fabiendubosson.com/blog/fixing-my-linux-webcam-to-look-alive-in-meetings/
Finding My Blogging Flow: Lessons From Early Months

I started this blog at the beginning of the year, hoping to publish about one article per month. In reality, I managed only three articles in the first six months. It’s time to reflect and adapt my approach.

The main reason for this slower pace is that I set out to write only in-depth articles. Getting into “focus mode” for such writing requires uninterrupted time and serious commitment—something that’s hard to find in our busy lives. My original motivation was to produce quality content for readers, but to be realistic, I should probably take inspiration from Henrik Karlsson:

Not that many people will care about what you write, at least for the first few years, so make the writing useful to you. Write in a way that lets you refine your thoughts about the things that matter. Write to experience what you care about in higher resolution, write to enhance your feeling of aliveness. — Henrik Karlsson

Another blogger I follow, Simon Willison, publishes several blog posts per day. Most are quotes or brief reflections, but as a reader, I still find value in them; they act as creativity pills for my own thoughts. This made me realize that posting shorter, more frequent reflections could help me build a sustainable writing habit by lowering the commitment threshold. It feels unnatural to relax my quality standards, but I’m also drawn to Jack Vanlightly’s perspective: focusing on quantity can actually improve quality over time.

There is a well known story of a pottery class where the teacher split them into two groups. Half were told to focus on quantity and they would be judged by the number of works they produced. The other half were told they should go for quality over quantity, and would be judged by the quality of their work. The surprising result, as the story goes, was that the quantity over quality group produced more great pottery works than the group going for perfection.

My own anecdotal experience with writing aligns with this story quite well. — Jack Vanlightly

Of course, these two pieces of conventional wisdom—“write for yourself” and “quantity over quality”—are cited everywhere online. Will they work for me? I don’t know, but if I don’t try, I’ll never know. Still, if in six months I find myself just churning out shallow content, I’ll need to reconsider this approach.

Lowering the bar for post length will also allow me to experiment with topics beyond tech. I’ve started reorganizing the blog with content categories. For now, there’s a “Tech” category, which includes all published posts. This change will make it easier to introduce an “Adventures” category later, where I can write about outdoor and sporty endeavors. The goal isn’t to split the blog in two—some posts may fit both categories—but to let readers filter what interests them.

If you’ve made it this far, thanks for reading. I hope to publish more soon—across a broader range of topics.

Update 2025-11-20: I’ve reverted the addition of the “Tech” category to keep the blog simpler to navigate.
https://fabiendubosson.com/blog/finding-my-blogging-flow-lessons-from-early-months/
Exploring Your Confluence Realm
A Question of Ownership

If your company uses Atlassian products, especially Confluence, you’ve probably received an email like this at some point:

Example email from Confluence
Example email from Confluence informing you that you have been made the owner of a page

Congratulations, you’ve just been made the owner of a Confluence page. From now on, anyone viewing the page will see your name at the top:

Confluence page header
Header of a Confluence page showing the owner

That’s probably not the first page you own. In fact, any page you create is automatically owned by you, so you’re likely the proud owner of more pages than you realize.

Naturally, that got me wondering: what Confluence pages do I own? There are a few good reasons to ask this:

  • Plain curiosity
  • Cleaning up stale or forgotten content
  • Transferring ownership of pages I’m no longer responsible for
  • Keeping the content updated: if my name’s on it, I should probably maintain it

Then comes the inevitable thought: “Oh no… Confluence search.” If you’ve used it, you know. If it works great for you, please tell me your secrets.

Anyway, I gave it a shot:

Confluence search filters
Filters available in Confluence search

No luck. There’s no way to filter by “owner.” The “Created or Edited by” filter is too broad: I may own pages I never created or edited, and there are many more pages that I have created or edited than I actually own.

Time to dig deeper.

Enter CQL: Confluence Query Language

After some web searching, I stumbled upon this community post, where someone mentioned CQL, Confluence’s equivalent of Jira’s JQL. First good bit of information: there is a way to search for pages you own through a CQL query:

owner = currentUser()

Now the accepted answer? You can use CQL… but not through the regular UI, unless you install a third-party app.

No, thanks.

But now I’m curious: how hard is it to use CQL without the app? Turns out, not very. This older article shows that you can run CQL by constructing the URL manually like this:

https://<confluence-base-url>/dosearchsite.action?cql=<CQL in the example below>.

Wait, is it really that easy? No need for a third-party app to run a CQL query? Let’s try it out using the query above through the following URL:

https://company.atlassian.net/wiki/dosearchsite.action?cql=owner %3D currentUser()

It works!

CQL search results of pages that you own
First results of a Confluence search for pages that you own using CQL

It shows the first 25 results of… NaN. It seems that indexing might not be straightforward with CQL queries, so we can overlook this minor issue.

The search field is also left blank, but the query is visible in the address bar:

Address bar showing the query
The query is only visible in the address bar

Even better: the request redirected to the normal search URL, so you can simply append ?cql=… to the URL when you are on the search page to run a CQL search. Convenient!

Trimming Results

Coming back to my realm, here’s what I want to search for:

  • Pages
  • That I own
  • That are not in my space (because I already know I own what’s there).

The corresponding CQL query is:

owner = currentUser() AND type = "page" AND space.key != "~XXX"

Your browser should automatically encode the equal sign as %3D, but if that’s not the case, you can do it manually.

To find your personal space key, just open your space and look at the URL: it’s usually something like ~username, which can also be composed only of digits if it hasn’t been named.

There’s even proper documentation for the CQL advanced search functionality. I haven’t read it, but depending on what you may want to do, you might find your answers there.

Bonus: The REST API

Someone in the thread also mentioned you can query CQL via a REST API. The URL differs slightly:

https://company.atlassian.net/wiki/rest/api/content/search?cql=…

My first reaction: meh, not in the mood to deal with API keys.

But I tried the modified URL and, to my surprise, it worked with my browser session. A clean JSON response popped up:

JSON results of pages that you own
The REST API providing the pages you own in JSON format

I’m not building a production service here, so copy-pasting the JSON into an editor to do some scripting locally works just fine for my needs. I don’t need to find a way to integrate with the API and its permissions.

Wrapping Up

So there you have it. With a little CQL magic and a custom search URL, you can easily find all the Confluence pages you own—your Confluence realm.

https://company.atlassian.net/wiki/search?cql=owner %3D currentUser() AND type %3D "page"

Replace company with your Atlassian domain, and you’re good to go. If you want to go the extra step of filtering your own space, you can add AND space.key != "~XXX" (see reference above). And if there are too many pages, you can get them as JSON as explained here.

Now, if you’ll excuse me, I’ve got 68 pages to take care of.

Happy exploring 👑

https://fabiendubosson.com/blog/exploring-your-confluence-realm/
Unpacking Dijkstra’s Note on “Why Numbering Should Start at Zero”
Introduction

Edsger W. Dijkstra wrote a famous note titled “Why numbering should start at zero” This three-page handwritten document is often cited in discussions about why indexing in programming languages should start at zero. While his reasoning is relatively straightforward, the document lacks the structure and examples needed to fully grasp it—at least for me—without resorting to pen and paper. As a result, I decided to read it thoroughly and unpack his reasoning into explicit arguments, expressed in my own words and illustrated with examples.

Screenshot of the first page of Dijkstra's note
First page of Dijkstra's note

The argument is built in two steps: first, by defining a preferred way to denote subsequences of natural numbers, and then by using this result to make the case for subscripting sequences, allowing him to conclude that numbering should start at zero.

Denoting subsequences of natural numbers

The note begins by specifying the problem of denoting subsequences of natural numbers:

Screenshot of Dijkstra's paragraph on denoting subsequences

The natural numbers are the first numbers we learn as children. We use them constantly to count things (cardinal) or to order things (ordinal). These numbers are 1:

0,1,2,3,4,…0, 1, 2, 3, 4, …0,1,2,3,4,…

A subsequence of these natural numbers is a sequence of consecutive numbers within the range, with a defined beginning and end. For instance, consider the example given in the note, 2,3,…,122, 3, \dots, 122,3,…,12, which expands to:

2,3,4,5,6,7,8,9,10,11,12 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 2,3,4,5,6,7,8,9,10,11,12

Instead of listing all the numbers exhaustively as shown above, or using the pernicious three dots (sic), we can represent the sequence by defining its lower and upper bounds, such as:

2≤i≤12 2 \leq i \leq 12 2≤i≤12

There are two ways to compare values with the bounds: either inclusive, using “smaller or equal to” (≤\leq≤), or exclusive, using “strictly smaller than” (<\lt<). Since we need to perform two comparisons, and each can use two operators, we end up with 2×2=42 \times 2 = 42×2=4 possible notations:

  • a) 2≤i<132 \leq i \lt 132≤i<13
  • b) 1<i≤121 \lt i \leq 121<i≤12
  • c) 2≤i≤122 \leq i \leq 122≤i≤12
  • d) 1<i<131 \lt i \lt 131<i<13

Let’s explore Dijkstra’s four arguments that led him to define a preferred way of denoting subsequences.

First argument
Screenshot of Dijkstra's first argument

The first argument concerns the length of the subsequence. As we can see, the subsequence we are working with contains 11 numbers:

2,3,4,5,6,7,8,9,10,11,12⏟11 numbers \underbrace{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}_{\normalsize \text{11 numbers}} 11 numbers2,3,4,5,6,7,8,9,10,11,12​​

If we refer back to our previous notations, we can see that the difference between the upper and lower bounds in notations a) and b) equals the subsequence length:

  • a) 2≤i<13→13−2=11{\bf\color{blue}2} \leq i \lt {\bf\color{blue}13} \hspace{2em} \rightarrow \hspace{2em} 13 - 2 = {\bf\color{green}11}2≤i<13→13−2=11 ✅
  • b) 1<i≤12→12−1=11{\bf\color{blue}1} \lt i \leq {\bf\color{blue}12} \hspace{2em} \rightarrow \hspace{2em} 12 - 1 = {\bf\color{green}11}1<i≤12→12−1=11 ✅
  • c) 2≤i≤12→12−2=10{\bf\color{blue}2} \leq i \leq {\bf\color{blue}12} \hspace{2em} \rightarrow \hspace{2em} 12 - 2 = {\bf\color{red}10}2≤i≤12→12−2=10 ❌
  • d) 1<i<13→13−1=12{\bf\color{blue}1} \lt i \lt {\bf\color{blue}13} \hspace{2em} \rightarrow \hspace{2em} 13 - 1 = {\bf\color{red}12}1<i<13→13−1=12 ❌
Second argument
Screenshot of Dijkstra's second argument

The second argument concerns adjacent subsequences. Let’s split our initial subsequence into two:

2,3,4,5,6,7⏟_first,8,9,10,11,12⏟_second \underbrace{2, 3, 4, 5, 6, 7}\_{\normalsize \text{first}}, \underbrace{ 8, 9, 10, 11, 12}\_{\normalsize \text{second}} 2,3,4,5,6,7​_first,8,9,10,11,12​_second

If we represent these two subsequences using the four notations, we can observe that for a) and b), the upper bound of the first subsequence matches the lower bound of the second subsequence.

  • a) 2≤i<8⏞first\overbrace{2 \leq i \lt {\bf\color{green}8}}^{\text{first}}2≤i<8​first​ ✅ 8≤i<13⏞second\overbrace{{\bf\color{green}8} \leq i \lt 13}^{\text{second}}8≤i<13​second​
  • b) 1<i≤71 \lt i \leq {\bf\color{green}7}1<i≤7 ✅ 7<i≤12{\bf\color{green}7} \lt i \leq 127<i≤12
  • c) 2≤i≤72 \leq i \leq {\bf\color{red}7}2≤i≤7 ❌ 8≤i≤12{\bf\color{red}8} \leq i \leq 128≤i≤12
  • d) 1<i<81 \lt i \lt {\bf\color{red}8}1<i<8 ❌ 7<i<13{\bf\color{red}7} \lt i \lt 137<i<13

This is a nice property that lets us easily split a subsequence at any point, or easily identify subsequences that can be merged if they have matching bounds:

2≤i<8,8≤i<13⏟2≤i<13 \underbrace{{\bf\color{blue}2} \leq i \lt {\bf\color{magenta}8} \hspace{0.5em}, \hspace{1em} {\bf\color{magenta}8} \leq i \lt {\bf\color{blue}13}}_{\normalsize {\bf\color{blue}2} \leq i \lt {\bf\color{blue}13}} 2≤i<132≤i<8,8≤i<13​​Third argument
Screenshot of Dijkstra's third argument

The third argument states that there is a smallest natural number, which in our case is zero 2. If we want to represent the subsequence 0,1,2,30, 1, 2, 30,1,2,3, notations b) and d), with an exclusive lower bound, would require us to use the unnatural number −1-1−1 to define it:

  • a) ✅ 0≤i<4{\bf\color{green}\hspace{0.8em}0} \leq i \lt 40≤i<4
  • b) ❌ −1<i≤3{\bf\color{red}-1} \lt i \leq 3−1<i≤3
  • c) ✅ 0≤i≤3{\bf\color{green}\hspace{0.8em}0} \leq i \leq 30≤i≤3
  • d) ❌ −1<i<4{\bf\color{red}-1} \lt i \lt 4−1<i<4
Fourth argument
Screenshot of Dijkstra's fourth argument

The fourth argument is a bit more subtle. Let’s say we want to iterate over the subsequences of 0, 1, 2 using an algorithm that removes one element at a time from the larger side. Each step reduces the sequence by one element, like this:

  1. [0, 1, 2]
  2. [0, 1]
  3. [0]
  4. []

If we use notation a) to denote each step, we obtain:

  1. 0≤i<30 \leq i \lt 30≤i<3
  2. 0≤i<20 \leq i \lt 20≤i<2
  3. 0≤i<10 \leq i \lt 10≤i<1

The issue arises when reaching the last step with the empty sequence. Representing it with an inclusive upper bound would—just like in the previous argument—require using the unnatural number -1:

  • a) 0≤i<0\hspace{0.8em}0 \leq i \lt {\bf\color{green}\hspace{0.8em}0}0≤i<0 ✅
  • b) −1<i≤−1-1 \lt i \leq {\bf\color{red}-1}−1<i≤−1 ❌
  • c) 0≤i≤−1\hspace{0.8em}0 \leq i \leq {\bf\color{red}-1}0≤i≤−1 ❌
  • d) −1<i<0-1 \lt i \lt {\bf\color{green}\hspace{0.8em}0}−1<i<0 ✅
The convention a) has to be preferred
Screenshot of Dijkstra's conclusion on denotation of subsequence

Dijkstra concludes the first part about the denotation of subsequences by stating that a) should be the preferred convention for denoting subsequences. Indeed, the only notation that successfully passes the 4 arguments is notation a).

Preferred denotation of a subsequence:x≤i<y□{\small\text{Preferred denotation of a subsequence:}} \hspace{1em} x \leq i \lt y \hspace{2em} {\footnotesize\square}Preferred denotation of a subsequence:x≤i<y□Subscripting sequences

The second part of his argument tackles the question of why numbering should start at zero. He begins by formally stating the following question:

Screenshot of Dijkstra's paragraph on subscripting subsequences

This means that for a given sequence of length NNN, such as:

2,3,4,5,6⏟N = 5 \underbrace{2, 3, 4, 5, 6}_{\normalsize \text{N = 5}} N = 52,3,4,5,6​​

If we want to use subscript notation xix_{i}xi​ for each value, what subscript value iii should we pick for the first element? There are two meaningful possibilities: starting at either 0 or 1.

x0,x1,x2,x3,x4orx1,x2,x3,x4,x5 x_{0}, x_{1}, x_{2}, x_{3}, x_{4} \\\\ \text{or} \\\\ x_{1}, x_{2}, x_{3}, x_{4}, x_{5} x0​,x1​,x2​,x3​,x4​orx1​,x2​,x3​,x4​,x5​

Side note: subscripting elements relates to enumerating them—i.e the zeroth, the first, the second, etc.—so the subscripts are, therefore, ordinal numbers.

The argument
Screenshot of Dijkstra's argument on subscripting subsequences

If we use the result obtained in the first section of this article, which states that the notation x≤i<yx \leq i \lt yx≤i<y is to be preferred, it follows that starting at subscript 1 sets the upper bound to N+1N + 1N+1. Returning to our previous example, it gives us:

x1,x2,x3,x4,x5⏞N elements=xi⏟1≤i<N+1 \overbrace{x_{1}, x_{2}, x_{3}, x_{4}, x_{5}}^{\text{\scriptsize{\color{blue}N} elements}} = x_{\underbrace{\small{i}}_{\mathclap{\scriptsize{1\leq i \lt {\bf\color{red}N+1}}}}} x1​,x2​,x3​,x4​,x5​​N elements​=x1≤i<N+1i​​​

While starting at subscript 000, the range ends at NNN:

x0,x1,x2,x3,x4⏞N elements=xi⏟0≤i<N \overbrace{x_{0}, x_{1}, x_{2}, x_{3}, x_{4}}^{\text{\scriptsize{\color{blue}N} elements}} = x_{\underbrace{\small{i}}_{\mathclap{\scriptsize{0\leq i \lt {\bf\color{green}N}}}}} x0​,x1​,x2​,x3​,x4​​N elements​=x0≤i<Ni​​​

According to Dijkstra, the latter approach is nicer (sic) because a sequence of length NNN has subscripts in the range 0≤i<N0 \leq i \lt N0≤i<N, with no extra offset required.

Numbering should start at zero
Screenshot of Dijkstra's conclusion on why numbering should start at zero

Dijkstra concludes his argument by stating that ordinal numbering should therefore start at subscript zero, and, as a moral of the story, that zero is the most natural number.

x0,x1,x2,x3,x4⏞N elements=xi⏟0≤i<N⇒numbering should start at zero■ \overbrace{x_{0}, x_{1}, x_{2}, x_{3}, x_{4}}^{\text{\scriptsize{\color{blue}N} elements}} = x_{\underbrace{\small{i}}_{\mathclap{\scriptsize{{\bf\color{green}0}\leq i \lt {\bf\color{blue}N}}}}} \hspace{2em} \Rightarrow \hspace{1em} \text{numbering should start at zero} \hspace{2em} {\footnotesize\blacksquare} x0​,x1​,x2​,x3​,x4​​N elements​=x0≤i<Ni​​​⇒numbering should start at zero■Conclusion

This concludes the unpacking of Dijkstra’s note on “Why numbering should start at zero”. You can find more information and discussion about this topic on Wikipedia’s article Zero-based numbering.

Dijkstra’s note also contains two side remarks on programming languages, and concludes with the context that motivated him to write it. These are not included here, but feel free to read the entire note if you are curious.


  1. Whether natural numbers are considered to start at 000 or 111 does not affect Dijkstra’s arguments. ↩︎

  2. I assume that natural numbers start at 000. The argument would also hold true if we consider 111 as the first natural number; Indeed, if 000 is not part of the natural numbers, then to represent a sequence starting at 111, we would need to use the number 000, which is not included in the definition of natural numbers. ↩︎

https://fabiendubosson.com/blog/unpacking-dijkstra-note-on-why-numbering-should-start-at-zero/
Overcoming Perfectionism

Starting a blog has been in the back of my mind for more than 15 years. And to be honest, this website is far from my first attempt at building one. I believe I’m not the only engineer who has faced this problem, so in this post, I reflect on what finally made publishing this first article possible for me.

The past

All my previous blogging attempts started the same way: I would read someone’s article and think, “This is great, I want to do the same!” And, as a software developer, my first thought would always be, “Of course, I’ll develop my own website.” After all, who wouldn’t want to create amazing interactive articles like those by Bartosz Ciechanowski?

Days go by, spent picking a name, setting up automation, designing the interface, spending hours aligning boxes pixel-perfect, deciding on image border radii, and creating color palettes. Eventually, a draft of the website gets deployed. But it’s an empty shell—it contains no content.

If other people were successful at producing articles, it surely meant they were working harder than me, didn’t it? I must be procrastinating. So, I worked late into the night, further improving the website with keyboard shortcuts and fancy CSS animations. But alas, no content ever saw the light of day.

The motivation to work on these projects eventually fades, and they end up in limbo. These setbacks reinforced the idea that writing wasn’t meant for me, or at the very least, that I wasn’t good at it.

The problem

I felt comfortable working on these technical aspects though… was I afraid to write and publish actual content? My last blogging attempt was about five years ago, and since then, I’ve developed the habit of reading. One article made me realize that I had a procrastination problem—but not due to laziness. It was a procrastination problem linked to perfectionism, rooted in emotions:

One reason why people procrastinate is perfectionism. For example, perfectionistic students might be so critical of themselves for making mistakes in school assignments, that they will postpone doing homework to avoid dealing with the associated negative emotions. Similarly, perfectionistic writers might be so worried about their book being criticized, that they will delay sending the book for feedback. — Itamar Shatz

This reading was enlightening because it revealed a potential root cause of my previous failures. Exposing my ideas was definitely outside my comfort zone back then. Confronting your thoughts with the world is stressful—it opens you up to criticism. To protect myself, I wanted my articles to be perfect. As a result, even when I managed to start drafting articles, they never made it to the website because they were never good enough.

A second layer of perfectionism was hidden in there. Even if I procrastinated on producing content, nothing was forcing me to nitpick over every detail of the website. I wanted to make the form perfect as well. This wasn’t driven by negative emotions, as it was with the content, but rather by the positive emotions that came from the satisfaction of building something great.

The observation

While great form can aid the reader, the most important part is the content itself. I’ve noticed that smart people sometimes have simple websites and that insightful content doesn’t require a fancy interface. Two examples of such websites come to mind, in no particular order and without any specific significance: John Walker, founder of Autodesk Inc., and his fourmilab.ch website, and Paul Graham, co-founder of Hacker News, with his essays on paulgraham.com.

Speaking of Hacker News, I also believe it falls into the “focus on the content, not on the form” category. Despite some valid criticism, it is a great example of a platform for civilized and insightful discussions. All of this happens on a website with no images, no emojis, and almost no markup—just text.

These examples of content versus form remind me of the following note-taking meme. This meme suggests that people in the normal IQ range use a complex setup to take notes—such as Notion, OneNote, Readwise, and Pocket—while people with low IQ simply use Apple Notes. The irony of the meme is that people with higher IQ also simply use Apple Notes. I interpret this to mean that people with high IQ focus on the content, not the form.

Note-taking meme
A classical note-taking meme

While I wouldn’t dare to compare myself to the people mentioned above, I can certainly take inspiration from them if I want to progress and try moving to the right of the normal curve. In fact, it would be easy to create a variant of this meme for blogging. It might look something like the one below. It’s, of course, an exaggeration—but isn’t that the point of a meme after all?

Blogging meme
An adaptation of the classical note-taking meme to blogging

So, if I were to give blogging another try, I would need to imitate smart people and opt for simple tools that allow me to focus on the content rather than getting distracted by the form.

The present

Some recent reading 1 2 3 on the topic of writing has changed my perception of the act itself. Writing is not just a way to share and communicate knowledge; it is also a powerful tool for developing your thinking. Over the past year, I started writing for myself and have come to truly appreciate its value.

It is like training for your thinking, it makes you more powerful which translates to better understanding and greater insight. Blogging is less popular now than it was but don’t let that stop you, in the end the person that benefits most, even if few people read it, is you. — Jack Vanlightly

Writing for myself is undoubtedly useful, but without the pressure of public scrutiny, the temptation to take shortcuts becomes all too strong. If I truly want to develop and challenge my thinking, I need to publish my articles. The two weeks of end-of-year holidays provided the perfect opportunity to work on this, so I set myself the challenge of building a website and publishing my first blog article during this time—while enjoying the holidays as well, of course. Challenge accepted.

To move towards the right side of the normal curve, I chose existing, simple tools that would help me avoid the pitfalls of perfectionism. I selected Hugo as the static site generator and GitHub Pages for hosting. There’s nothing more standard than that for a tech blog of this kind, but that also means these are proven technologies. Finally, the topic for the first article was all found: Overcoming Perfectionism.

Armed with an understanding of the root cause of my procrastination, I found it easy to notice when I started avoiding work on the content—because I would be doing, quite literally, anything else. The time constraint was also a great help, as it prevented me from going too far with nitpicking the form.

The finale

As expected, writing this first article forced me to organize my thoughts and allowed me to identify two key actions that helped me succeed this time:

  • Setting a soft deadline to prevent nitpicking perfectionism
  • Observing my behavior to recognize when my emotions are distracting me from the main task

These are the lessons I’ll carry with me for my future writings and projects. And maybe they’ll also strike a chord with you?

Well, it’s now time for me to overcome my perfectionism and push this imperfect article to GitHub to share it with the world.

Happy reading!


  1. https://rmoff.net/2023/07/19/blog-writing-for-developers/ ↩︎

  2. https://www.henrikkarlsson.xyz/p/writing-to-think ↩︎

  3. https://jack-vanlightly.com/blog/2022/1/25/write-for-others-but-mostly-for-yourself ↩︎

https://fabiendubosson.com/blog/overcoming-perfectionism/