Bi-dimensional commit messages
The “conventional commit” format advocates prefixing commit messages with keywords to give both humans and machines a quick idea of what’s affected:
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 mostly answers the question: “How does this modify existing code?” It fixes or refactors it, enhances its performance, or adds a new feature on top. Sometimes,however, it answers the question: “What area does this affect?” It affects the build process or the docs. Yet other times, it answers both questions by adding a parenthesized “scope”: it’s a fix to the api; it’s a performance enhancement to the (ui).
And if you’re fixing a doc? Improving the build’s performance?
Having to stop and think in these loaded, non-orthogonal terms, to come up with only moderately descriptive descriptions, feels like too high of a cost for the benefit.
Fortunately, a few extra keystrokes are all that’s need to lower the burden on the writer and boost the value for the reader.
Meet the “-ilities” #
A great question one can ask about a change is: “What quality of the system does this directly improve?”  A change to the front end might improve usability; one to the back end, observability; another to the docs, understandability.
The book Building Evolutionary Architectures has a long list of these “-ilities”:
- (…two more pages)
You can use them to better describe, and think about, changes.
Value-focused, bi-dimensional commit messages #
What qualities matter to your team and project? Pick a few, e.g.: functionality, usability, devability , stability, and security.
What quality does a change affect? That’s the first dimension:
|“notify user on new messages”||makes the application more useful||func|
|“enable caching to decrease build times”||makes the system easier to develop||dev|
|“detect invalid query parameter”||makes the system more stable||stab|
How does the change improve the quality? That’s the second dimension:
|“notify user on new messages”||adds something that wasn’t there before||feat|
|“enable caching to decrease build times”||makes something better||enh|
|“detect invalid query parameter”||makes something right||fix|
And the original example becomes:
- 41e7be2 feat: notify user on new messages
+ 41e7be2 usab,feat: notify user on new messages
- f3b33ab build: 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(api): detect invalid query parameter
- f5baa4d docs: typo
+ f5baa4d dev,fix: typo
- 06e851a perf(ui): optimize loading time
+ 06e851a usab,enh(ui): optimize loading time
This strategy is surprisingly quick to pick up, generates informative descriptions, and gently nudges one to focus on the fundamental question:
What value does this change deliver?
“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. ↩︎
Think of devability as of usability for developers: a mixture of code understandability, debuggability, and tool ergonomy. ↩︎