Skip to content

software development

Gitmojis are not just cute emojis

When you first encounter Gitmoji, it might feel like a whimsical idea — adding emojis to your Git commit messages? Surely that is just a fun way to decorate your history, right?

Well… yes. But also, no. Gitmojis are much more than just cute little icons. They are a powerful convention that improves collaboration, commit clarity, and even automation in your development workflow. In this post, we will explore how Gitmojis can boost your Git hygiene, help your team, and make your commits more expressive — without writing a novel in every message.


What is Gitmoji?

Gitmoji is a project by Carlos Cuesta that introduces a standardized set of emojis to prefix your Git commit messages. Each emoji represents a common type of change. For example:

EmojiCodeDescription
:sparkles:New feature
🐛:bug:Bug fix
📝:memo:Documentation change
♻️:recycle:Code refactor
🚀:rocket:Performance upgrade

Why Use Gitmoji?

1. Readable History at a Glance

Reading a log full of generic messages like fix stuff, more changes, or final update is painful. Gitmojis help you scan through history and immediately understand what types of changes were made. Think of it as color-coding your past.

🧱 Example — Traditional Git log:

git log --oneline
b11d9b3 Fix things
a31cbf1 Final touches
7c991e8 Update again

🔎 Example — Gitmoji-enhanced log:

🐛 Fix overflow issue on mobile nav
✨ Add user onboarding wizard
📝 Update README with environment setup
🔥 Remove unused CSS classes

2. Consistency Without Bureaucracy

Git commit conventions like Conventional Commits are excellent for automation but can be intimidating and verbose. Gitmoji offers a simpler, friendlier alternative — a consistent prefix without strict formatting.

You still write meaningful commit messages, but now with context that is easy to scan.


3. Tooling Support with gitmoji-cli

Gitmoji CLI is a command-line tool that makes committing with emojis seamless.

🛠 Installation:

npm install -g gitmoji-cli

🧪 Usage:

gitmoji -c

You will be greeted with an interactive prompt:

✔ Gitmojis fetched successfully, these are the new emojis:
? Choose a gitmoji: (Use arrow keys or type to search)
❯ 🎨  - Improve structure / format of the code. 
  ⚡️  - Improve performance. 
  🔥  - Remove code or files. 
  🐛  - Fix a bug. 
  🚑️  - Critical hotfix. 
  ✨  - Introduce new features. 
  📝  - Add or update documentation. 
(Move up and down to reveal more choices)

The CLI also supports conventional formatting and custom scopes. Want to tweak your settings?

gitmoji --config

You can also use it in CI/CD pipelines or with Git hooks to enforce Gitmoji usage across teams.


4. Better Collaboration and Code Review

Your teammates will thank you when your commits say more than “fix” or “update”. Gitmojis provide context and clarity — especially during code review or when you are scanning a pull request with dozens of commits.

🧠 Before:

fix
update styles
final commit

After:

🐛 Fix background image issue on Safari
💄 Adjust padding for login form
✅ Add final e2e test for login flow

This is how a pull request with Gitmoji commits looks like on GitHub:


5. Automation Ready

Need to generate changelogs or trigger actions based on commit types? Gitmoji messages are easy to parse, making them automation-friendly.

Example with a simple script:

git log --oneline | grep "^✨"

You can even integrate this into release workflows with tools like semantic-release or your own custom tooling.


Do Not Let the Cute Icons Fool You

Yes, emojis are fun. But behind the smiling faces and sparkles is a thoughtful system that improves your Git workflow. Whether you are working solo or as part of a team, Gitmoji brings:

  • ✅ More readable commit history
  • ✅ Lightweight commit standards
  • ✅ Easy automation hooks
  • ✅ A dash of joy to your development day

So next time you commit, try it:

gitmoji -c

Because Gitmojis are not just cute.
They are practical, powerful — and yes, still pretty adorable.


🚀 Get Started

🎉 Happy committing!

vibrant jester figure in dramatic lighting

Reduce unit tests boilerplate with Jest’s .each syntax

When writing unit tests, especially in JavaScript/TypeScript with Jest, you often run into a common problem: repetition.
Imagine testing a function with several input-output pairs. The tests can become bloated and harder to read.
This is where Jest’s .each syntax shines. It lets you write cleaner, data-driven tests with minimal duplication.

The Problem: Repetitive Test Cases

Take a simple sum function:

function sum(a, b) {
  return a + b;
}

Without .each, you might write your tests like this:

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

test('adds 2 + 3 to equal 5', () => {
  expect(sum(2, 3)).toBe(5);
});

test('adds -1 + -1 to equal -2', () => {
  expect(sum(-1, -1)).toBe(-2);
});

These tests work, but they are verbose. You repeat the same logic over and over with only the inputs and expected results changing.

The Solution: Jest’s .each Syntax

Jest’s .each allows you to define test cases as data and reuse the same test body.
Here is the same example using .each:

describe('sum', () => {
  test.each([
    [1, 2, 3],
    [2, 3, 5],
    [-1, -1, -2],
  ])('returns %i when %i + %i', (a, b, expected) => {
    expect(sum(a, b)).toBe(expected);
  });
});

This single block of code replaces three separate test cases.
Each array in the .each list corresponds to a test run, and Jest automatically substitutes the values.

Bonus: Named Arguments with Tagged Template Literals

You can also use named arguments for clarity:

test.each`
  a    | b    | expected
  ${1} | ${2} | ${3}
  ${2} | ${3} | ${5}
  ${-1}| ${-1}| ${-2}
`('returns $expected when $a + $b', ({ a, b, expected }) => {
  expect(sum(a, b)).toBe(expected);
});

This syntax is more readable, especially when dealing with longer or more descriptive variable names.
It reads like a mini table of test cases.

Why Use .each?

  • Less boilerplate: Define the test once and reuse it.
  • Better readability: Data-driven tests are easier to scan.
  • Easier maintenance: Add or remove cases without duplicating test logic.
  • Fewer mistakes: Repeating the same code invites copy-paste errors.

Use Case: Validating Multiple Inputs

Suppose you are testing a validation function like isEmail. You can define all test cases in one place:

test.each([
  ['user@example.com', true],
  ['not-an-email', false],
  ['hello@world.io', true],
  ['@missing.local', false],
])('validates %s as %s', (input, expected) => {
  expect(isEmail(input)).toBe(expected);
});

This approach scales better than writing individual test blocks for every email address.

Conclusion

Jest’s .each is a powerful way to reduce duplication in your test suite.
It helps you write cleaner, more maintainable, and more expressive tests.
Next time you find yourself writing nearly identical test cases, reach for .each—your future self will thank you.

My take on the Gilded Rose kata

The Gilded Rose Kata by Emily Bache is a staple in refactoring exercises. It offers a deceptively simple problem: refactor an existing codebase while preserving its behavior. I recently worked through the TypeScript version of the kata, and this post documents the transformation from a legacy mess into clean, testable code—with examples along the way.

But before diving into the code, I should mention: this was my very first encounter with TypeScript. I had never written a single line in the language before this exercise. That added an extra layer of learning—on top of refactoring legacy code, I was also picking up TypeScript’s type system, syntax, and tooling from scratch.


🧪 Development Workflow

Pre-Commit Hooks

pre-commit.com is a framework for managing and maintaining multi-language pre-commit hooks. It allows you to define a set of checks (such as code formatting, linting, or security scans) that automatically run before every commit, helping ensure code quality and consistency across a team. Hooks are easily configured in a .pre-commit-config.yaml file and can be reused from popular repositories or custom scripts. It integrates seamlessly with Git and supports many languages and tools out of the box.

I added eslint and gitlint:

- repo: https://github.com/pre-commit/mirrors-eslint
  hooks:
    - id: eslint

  - repo: https://github.com/jorisroovers/gitlint
    hooks:
      - id: gitlint

GitHub Actions

GitHub Actions was used to automate the testing workflow, ensuring that every push runs the full test suite. This provides immediate feedback when changes break functionality, which was especially important while refactoring the legacy Gilded Rose code. The setup installs dependencies with npm, runs tests with yarn, and ensures consistent results across different environments—helping maintain code quality and giving confidence to refactor freely while learning TypeScript.

name: Build

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [12.x]

    steps:
      - uses: actions/checkout@v2
      - name: Node.js
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm install -g yarn
        working-directory: ./TypeScript
      - name: yarn install, compile and test
        run: |
          yarn
          yarn compile
          yarn test
        working-directory: ./TypeScript

🔍 Starting Point: Legacy Logic

Originally, everything was handled in a massive updateQuality() function using nested if statements like this:

if (item.name !== 'Aged Brie' && item.name !== 'Backstage passes') {
    if (item.quality > 0) {
        item.quality--;
    }
} else {
    if (item.quality < 50) {
        item.quality++;
    }
}

The function mixed different concerns and was painful to extend.


🧪 Building Safety Nets

Golden master tests are a technique used to protect legacy code during refactoring by capturing the current behavior of the system and comparing it against future runs. In this project, I recorded the output of the original updateQuality() function across many item variations. As changes were made to clean up and restructure the logic, the tests ensured that the external behavior remained identical. This approach was especially useful when the codebase was poorly understood or untested, offering a reliable safety net while improving internal structure.

expect(goldenMasterOutput).toEqual(currentOutput);

🧹 Refactoring: Toward Structure and Simplicity

1. Extracting Logic

I moved logic to a separate method:

private doUpdateQuality(item: Item) {
    // clean, focused logic
}

This isolated the business rules from boilerplate iteration.

2. Replacing Conditionals with a switch

Using a switch statement instead of multiple if/else if blocks makes the code cleaner, more readable, and easier to maintain—especially when checking a single variable (like item.name) against several known values. It clearly separates each case, making it easier to scan and reason about the logic. In the Gilded Rose project, switching to switch also made it easier to later refactor into specialized handlers or classes for each item type, as each case represented a clear and distinct behavior to isolate.

switch (item.name) {
    case 'Aged Brie':
        this.updateBrie(item);
        break;
    case 'Sulfuras':
        break; // no-op
    case 'Backstage passes':
        this.updateBackstage(item);
        break;
    default:
        this.updateNormal(item);
}

This increased clarity and prepared the ground for polymorphism or factory patterns later.


🛠 Polishing the Code

Constants and Math Utilities

Instead of magic strings and numbers, I introduced constants:

const MAX_QUALITY = 50;
const MIN_QUALITY = 0;

I replaced verbose checks with:

item.quality = Math.min(MAX_QUALITY, item.quality + 1);

Factory Pattern

The factory pattern is a design pattern that creates objects without exposing the exact class or construction logic to the code that uses them. Instead of instantiating classes directly with new, a factory function or class decides which subclass to return based on input—like item names in the Gilded Rose kata. This makes it easy to add new behaviors (e.g., “Conjured” items) without changing existing logic, supporting the Open/Closed Principle and keeping the code modular and easier to test or extend.

switch (true) {
    case /^Conjured/.test(item.name):
        return new ConjuredItem(item);
    case item.name === 'Sulfuras':
        return new SulfurasItem(item);
    // ...
}

🌟 Feature Additions

With structure in place, adding Conjured Items was straightforward:

class ConjuredItem extends ItemUpdater {
    update() {
        this.decreaseQuality(2);
        this.decreaseSellIn();
    }
}

A corresponding test was added to confirm behavior.


🎯 Conclusion

The journey from legacy to clean architecture was iterative and rewarding. Key takeaways:

  • Set up CI and hooks early to enforce consistency.
  • Use golden master tests for safety.
  • Start small with extractions and switch statements.
  • Add structure gradually—factories, constants, classes.
  • With a clean base, adding features like “Conjured” is trivial.

All this while learning TypeScript for the first time!

You can explore the full codebase and history here:
📦 Gilded Rose Refactoring Kata — TypeScript branch

Curious to try it yourself, also in other languages?
Fork Emily Bache’s repo here: GildedRose-Refactoring-Kata on GitHub

green snake

A small rant about dependencies (and a promise)

Every now and then I run into some awesome open source project on GitHub, that is written in some cool programming language, and it assumes that the development tools for that language are already installed. My assumption is that they have a specific target audience in mind: an already existing developer community around that specific language. People who already have those tools installed.

The annoying thing is when someone like me, who doesn’t really need to know if a thing is written in Python or Ruby or JavaScript or whatever, tries to follow instructions like these:

$ pip install foo
Command 'pip' not found
$ gem install bar
Command 'gem' not found
$ yarn install baz
Command 'yarn' not found
$ ./configure && make && sudo make install
Command 'make' not found

By now, I already know that I first need to do sudo apt install python3-pip (or the equivalent installation commands for RubyGems, Yarn, build-essential,…). I also understand that, within the context of a specific developer community, this is so obvious that it is often assumed. That being said, I am making a promise:

For every open source project that I will henceforth publish online (on Github or any other code sharing platforms), I promise to do the following things:
(1) Test the installation on at least one clean installed operating system – which will be documented.
(2) Include full installation steps in the documentation, including all frameworks, development tools, etc. that would otherwise be assumed.
(3) Where possible and useful, provide an installation script.

The operating system I’m currently targeting, is Ubuntu, which means I’ll include apt commands. I’m counting on Continuous Integration to help me test on other operating systems that I don’t personally use.

Mijn kleine bijdrage aan Awstats

Vandaag is mijn eerste bijdrage aan een Free Software project online gekomen. Yay me!
Ik heb namelijk bijgedragen aan de Nederlandse vertaling van Awstats, een programma om bezoekersstatistieken van websites te analyseren.
Een van de kleine details die ik er in gesmokkeld heb, is het gebruik van de binaire prefixen kibi, mebi, gibi. 😉

Wie is Amedee Van Gasse? (1998)

Gevonden in de Wayback Machine, op 9 juli 2001. De pagina zelf moet van ergens in 1998 of 1999 zijn. Commentaren van 4 juni 2013.

If you would like to read an English version
of this page, let me know at avgasse@dds.nl,

Nu: amedee@vangasse.eu

and I’ll try to find my English dictionary.
😀

Wie is Amedee Van Gasse?

Inhoud

  • Informatie over mezelf
  • Lijst van favorieten
  • Contactinformatie
  • Commentaar en suggesties
  • Informatie over mezelf

Geboortedatum en -plaats: 1 september 1976, Sint-Niklaas

Ik ben student aan de KaHo Sint-Lieven, departement Sint-Niklaas, (vergeet geen adem te halen!) campus BNS-OLVP. Daar hou ik mij al voor het derde jaar onledig met het regentaat wetenschappen-aardrijkskunde.
Ik koos voor deze vakkencombinatie omdat wetenschappen mij altijd al geïnteresserd hebben, en ook omdat het zo’n complementair pakket is. Soms heb je chemische achtergronden nodig in de fysica of de biologie, of moet je wat biologische kennis hebben in de aardrijkskunde. Zodus. En ook omdat ik geen zin had om wiskunde te doen 🙂

Uiteindelijk ben ik nooit in het onderwijs beland.

Ik ben ook hoofdleider op speelplein Blij en Trouw in Sint-Niklaas, en dit sinds zomer 1996. In de paasvakantie van 1992 stond ik er voor het eerst in leiding, na een cursus van VDS.

Ik heb van 1992 tot 1999 speelplein gedaan. Best wel lang.

Ik zit in de stedelijke jeugdraad van Sint-Niklaas voor het speelplein. Daar neem ik deel aan twee werkgroepen: de werkgroep speelpleinwerkingen (vanneigens) en de werkgroep Groene Ruimten.

Een van de verwezelijkingen van die werkgroep was het stadsbestuur van Sint-Niklaas bewust maken van een bosgebied van ongeveer 60 hectare (Puitvoet), aan de rand van de stad (geklemd tussen woonzone en industrie), dat daar maar lag te verloederen en te verkavelen, terwijl het een ideaal speelbos is voor jeugdbewegingen. Ook heel wat werknemers van de vlakbij gelegen bedrijven gaan er tijdens hun middagpauze regelmatig joggen.

In de vakanties sta ik niet alleen in leiding op het speelplein, maar ik begeleid ook vakanties bij Jeugd en Gezondheid. Het liefst van al ga ik naar de bergen. Ik heb in zomer ’97 dan ook een bergcursus gevolgd. Andere dingen die ik doe voor J&G is af en toe eens een artikel schrijven voor ‘t Moniteur-trice-ken, en tappen op het tweewekelijkse praatcafé.

Af en toe vraagt men mij om in de bibliotheek Het Centrum (Grote Markt, Sint-Niklaas) lessen internet voor beginners te geven. Dat brengt mij bij een van mijn andere interesses: het Net. Denk nu niet dat ik zo’n computerfreak ben. Alhoewel. Al wat ik weet heb ik op eigen houtje geleerd. Het is begonnen met het overtypen van BASIC-programma’s voor de ZX-Spectrum (zie ook: dinosaurus) op mijn XT (zie ook: prehistorie). Later heb ik ooit eens een cursus Pascal gevolgd, maar ik keek altijd een paar bladzijden verder dan waar de lesgever zat. Op de universiteit heb ik dan het Internet leren kennen. En dat leer je pas goed kennen door er veel gebruik van te maken. Maar dat ging een beetje ten koste van mijn studies, vrees ik.

Ik ben ondertussen nog altijd keihard een computernerd. Al wat met Linux en Free Software te maken heeft, is mijn ding. Java is een programmeertaal die ik redelijk kan, met het Android platform kan ik overweg als developer, en er zijn mensen mij aan het kietelen om eens met C# te beginnen. Ruby en Python staan ook nog op mijn TODO-lijstje.

Dit zijn de websites die ik ontworpen heb:

Vlaamse Landbouwkundige Kring (februari ’96)
Roderoestraat 27 – mijn vroeger kot (mei ’96)
Speelpleinwerking Blij en Trouw (juli ’96)
Jeugd en Gezondheid verbond Waasland (april ’97)
biotoopstudie Puitvoet (februari ’98)
Geertje De Ceuleneer-fansite (maart ’98)
Procordia (oktober ’98)

Mijn andere hobby’s (in willekeurige volgorde):

wandelen – ooit doe ik wel eens mee aan de Dodentocht (100 km wandelen in Bornem)

Meer dan een decennium later ben ik daar eindelijk voor aan het trainen.

films
lezen (voral de betere SF&F: Tolkien, Heinlein, Herbert, LeGuin, Vance, Pratchett,… en wetenschappelijke boeken over o.a. fysica: Hawking, Penrose, Prigogine, Sagan,…)
muziek (ongeveer 3/4 van wat ze draaien op Radio 1)

Terug naar begin