The “conventional commit” format encourages prefixing commit messages with a small number of keywords:

41e7be2 feat: notify user on new messages
f3b33ab build: enable caching to decrease build times
7501fb2 fix(api): detect invalid query parameter
f5baa4d docs: typo
06e851a perf(ui): optimize loading time

The keyword usually answers the question: “How does this commit modify existing code?” It fixes or refactors it, enhances its performance, or adds a new feature on top. Sometimes it answers a different question: “What area does this affect?” The build process, or the docs. Yet other times, it answers both by adding a “scope”: it’s a fix to the (api); it’s a performance enhancement to the (ui).

What if you’re fixing a doc, or improving the build’s performance?

To stop and think in these loaded, non-orthogonal terms, recently started to feel like a bump in the road to me. Enough things threaten a programmer’s flow already. The resulting descriptions aren’t as descriptive as they could, either, so it’s not a clear win.

Luckily, I found out that a few extra keystrokes are all you need to lower the burden on the writer and boost the value for the reader.

Meet the “-ilities”

A more useful question you can ask about a change is: “What quality of the system does this change directly improve?” (“Directly” because everything, eventually, aims at improving end-user functionality, business profitability, and similar bottom lines, so those aren’t good descriptors at a local level.) A change to the front end might improve usability; one to the back end might improve observability; another to the API docs might improve understandability.

The book Building Evolutionary Architectures has a long list of these qualities. It calls them a system’s “-ilities”:

  • accessibility
  • adaptability
  • administrability
  • auditability
  • availability
  • compatibility
  • (…two more pages)

Another way to express the same question in, to speak, Conway terms, is: “Whose life does this directly improve?”

You can use these qualities to better describe, and think of, changes.

Value-based, bi-dimensional commit messages

What qualities matter to your team and project right now? Pick a manageable number, e.g.: functionality, usability, devability (a mixture of code understandability, debuggability, and tool ergonomy), stability, observability, and security.

When you change these qualities, whose life improves?

Quality Whose life does it improve?
usability end users
functionality a subsystem’s users (end-users for a UI, developers for a service)
devability developers
stability operators
observability operators, developers
security operators

An element of this list should the your answer to the above question: “What quality of the system does this change directly improve?”

This “what” is the first dimension:

- 41e7be2 feat: notify user on new messages
+ 41e7be2 func: notify user on new messages
- f3b33ab build: enable caching to decrease build times
+ f3b33ab dev: enable caching to decrease build times
- 7501fb2 fix(api): detect invalid query parameter
+ 7501fb2 stab: detect invalid query parameter

Next, answer the question: “How does this change improve that quality?”

“How” is the second dimension:

Keyword In what way does this change improve the specified quality?
fix changes what’s there so it’s less bad
enh changes what’s there so it’s better
feat adds something new

(Note the absence of refactor, which is an enhancement in devability.)

- 41e7be2 usab: notify user on new messages
+ 41e7be2 usab,func: notify user on new messages
- f3b33ab dev: enable caching to decrease build times
+ f3b33ab dev,enh: enable caching to decrease build times
- 7501fb2 fix(api): detect invalid query parameter
+ 7501fb2 stab,fix: detect invalid query parameter

On larger projects, it makes sense to keep the optional scope to answer the question, “Which component does this affect?”

- 7501fb2 fix(api): detect invalid query parameter
+ 7501fb2 stab,fix(api): detect invalid query parameter

Final result:

41e7be2 usab,feat: notify user on new messages
f3b33ab dev,enh: enable caching to decrease build times
7501fb2 stab,fix(api): detect invalid query parameter
f5baa4d dev,fix: typo
06e851a usab,enh(ui): optimize loading time

In the end, this is just a strategy to systematically answer — in a way that allows both being informative and diverting little focus from coding — the critical question:

What VALUE does this change deliver?

References